Install
$ agentstack add skill-aps08-fullstack-clean-architecture-python ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Python & FastAPI Coding & Architecture Guidelines
Use this skill when extending the Python backend, writing routes, services, or repositories, or working with core server logic.
1. FastAPI & Dependency Injection
We use dependency-injector for wiring application components together.
- Wiring: The container is defined in
server/app/core/container.pyand wired inserver/app/main.py. - Dependency injection in Routes:
- Decorate endpoints with
@inject(fromdependency_injector.wiring). - Create clean dependency type aliases using
AnnotatedandDepends(Provide[Container.service_name]). - Example:
```python TodoServiceDep = Annotated[TodoService, Depends(Provide[Container.todo_service])]
@router.get("/todos/") @inject async def list_todos(service: TodoServiceDep): ... ```
- No Direct Instantiation: Do not manually instantiate services or repositories; resolve them via the container.
2. FastAPI Route & Handler Best Practices
Use Annotated
Always prefer the Annotated style for parameter and dependency declarations.
from typing import Annotated
from fastapi import Path, Query
@router.get("/items/{item_id}")
async def read_item(
item_id: Annotated[UUID, Path(description="The item ID")],
q: Annotated[str | None, Query(max_length=50)] = None,
):
...
Return Types & response_model
- Specify explicit return type annotations (
-> Model) for FastAPI validation, filtering, and serialization (running Pydantic's Rust-based serialization). - If the returned object differs from the API response contract (e.g. returning a database model that needs filtering/serialization to a public schema), use
response_modelon the router decorator instead:
@router.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: UUID) -> Any:
...
No Ellipsis (...) for Required Fields
Do not use ... as a default value for required fields or query parameters.
# CORRECT
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...
# INCORRECT
async def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...
Declaring APIRouters
Prefer defining path prefixes and tags on the router itself, rather than in include_router():
router = APIRouter(prefix="/todos", tags=["todos"])
Async vs Sync Handlers
- Use
async defonly when callingawait-compatible non-blocking code. - If a route calls blocking code (like synchronous DB queries or filesystem operations), use standard
definstead ofasync defso FastAPI runs it in an external threadpool.
Do not use Pydantic RootModel
Instead, use regular type annotations with Annotated and validation utilities:
@router.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
return items
One HTTP Method Per Function
Keep handler functions dedicated to a single HTTP operation. Do not use @router.api_route for multiple methods in a single function.
3. Layered Architecture
Always structure backend logic using the established 3-layer architecture:
- Routes/Endpoints (
app/routes): Parse requests, validate inputs via Pydantic, call services, and handle HTTP routing. Keep business logic out of this layer. - Services (
app/services): Implement business logic, orchestration, and validation checks. Inherit fromBaseServicefor CRUD operations. - Repositories (
app/repositories): Handle raw database persistence and queries using SQLAlchemy. Inherit fromBaseRepository.
4. Database Scopes & Transactions
- Scoped Sessions: Uses
async_scoped_sessionkeyed by a unique request-based UUID context variable. - Transactions:
- Service-level or middleware-level functions run within
async with db.session_scope():to ensure automatic rollback on failure and commit on success. - Always perform queries asynchronously (e.g.
await session.execute(...)). - Timezones: Use timezone-aware datetime objects (
TIMESTAMP(timezone=True)) or Pydantic UTC validation.
5. Code Quality & Type Safety
- Type Annotations: Annotate all function signatures and variables. Use
Annotated,TypeVar, andGenericfor generic classes like repositories. - Pydantic Models: Define explicit request/response schemas under
app/schemas/. - Ensure they map accurately to database models.
- Configure
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True, from_attributes=True)for camelCase serialization support. - Error Handling: Centralize errors using specific exceptions defined in
app/core/exceptions.py(e.g.NotFoundError,DuplicatedError).
6. Background Tasks
- Always use
BackgroundTaskswhen sending emails or other long-running tasks to prevent user delays in response to user requests.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aps08
- Source: aps08/fullstack-clean-architecture
- License: Apache-2.0
- Homepage: https://aps08.medium.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.