backend-architecture-enforcer
Installation
SKILL.md
Contains Hooks
This skill uses Claude hooks which can execute code automatically in response to events. Review carefully before installing.
Enforce FastAPI Clean Architecture with BLOCKING validation.
Architecture Overview
+-------------------------------------------------------------------+
| ROUTERS LAYER |
| HTTP concerns only: request parsing, response formatting |
| Files: router_*.py, routes_*.py, api_*.py |
+-------------------------------------------------------------------+
| SERVICES LAYER |
| Business logic: orchestration, validation, transformations |
| Files: *_service.py |
+-------------------------------------------------------------------+
| REPOSITORIES LAYER |
| Data access: database queries, external API calls |
| Files: *_repository.py, *_repo.py |
+-------------------------------------------------------------------+
| MODELS LAYER |
| Data structures: SQLAlchemy models, Pydantic schemas |
| Files: *_model.py (ORM), *_schema.py (Pydantic) |
+-------------------------------------------------------------------+
Validation Rules (BLOCKING)
| Rule | Check | Layer |
|---|---|---|
| No DB in Routers | Database operations blocked | routers/ |
| No HTTP in Services | HTTPException blocked | services/ |
| No Business Logic in Routers | Complex logic blocked | routers/ |
| Use Depends() | Direct instantiation blocked | routers/ |
| Async Consistency | Sync calls in async blocked | all |
| File Naming | Must follow naming convention | all |
File Naming Conventions
Quick Reference
| Layer | Allowed Patterns | Blocked Patterns |
|---|---|---|
| Routers | router_*.py, routes_*.py, api_*.py, deps.py |
users.py, UserRouter.py |
| Services | *_service.py |
users.py, UserService.py, service_*.py |
| Repositories | *_repository.py, *_repo.py |
users.py, repository_*.py |
| Schemas | *_schema.py, *_dto.py, *_request.py, *_response.py |
users.py, UserSchema.py |
| Models | *_model.py, *_entity.py, *_orm.py, base.py |
users.py, UserModel.py |
Layer Separation Summary
Routers (HTTP Only)
- Request parsing and response formatting
- HTTP status codes and auth checks
- Delegate to services via
Depends()
Services (Business Logic)
- Validation and orchestration
- Data transformations
- Raise domain exceptions (NOT HTTPException)
Repositories (Data Access)
- Database queries and persistence
- External API calls
- Return domain objects or None
Dependency Injection Quick Reference
# deps.py - Dependency providers
def get_user_repository(
db: AsyncSession = Depends(get_db),
) -> UserRepository:
return UserRepository(db)
def get_user_service(
repo: UserRepository = Depends(get_user_repository),
) -> UserService:
return UserService(repo)
# router_users.py - Usage
@router.get("/{user_id}")
async def get_user(
user_id: int,
service: UserService = Depends(get_user_service),
):
return await service.get_user(user_id)
Blocked DI Patterns
# BLOCKED - Direct instantiation
service = UserService()
# BLOCKED - Global instance
user_service = UserService()
# BLOCKED - Missing Depends()
async def get_users(db: AsyncSession): # Missing Depends()
Common Violations
| Violation | Detection | Fix |
|---|---|---|
| DB in router | db.add, db.execute in routers/ |
Move to repository |
| HTTPException in service | raise HTTPException in services/ |
Use domain exceptions |
| Direct instantiation | Service() without Depends |
Use Depends(get_service) |
| Wrong naming | Missing suffix/prefix | Rename per convention |
| Sync in async | Missing await |
Add await or use executor |
Exception Pattern
# Domain exceptions (services/repositories)
class UserNotFoundError(DomainException):
def __init__(self, user_id: int):
super().__init__(f"User {user_id} not found")
# Router converts to HTTP
@router.get("/{user_id}")
async def get_user(user_id: int, service: UserService = Depends(get_user_service)):
try:
return await service.get_user(user_id)
except UserNotFoundError:
raise HTTPException(404, "User not found")
Async Rules
# GOOD - Async all the way
result = await db.execute(select(User))
# BLOCKED - Sync in async function
result = db.execute(select(User)) # Missing await
# For sync code, use executor
await loop.run_in_executor(None, sync_function)
References
For detailed patterns and examples, see:
| Reference | Content |
|---|---|
| layer-rules.md | Detailed layer separation rules with code examples |
| dependency-injection.md | DI patterns, authentication, testing with overrides |
| violation-examples.md | Common violations with proper patterns and auto-fix suggestions |
Related Skills
clean-architecture- DDD patternsfastapi-advanced- Advanced FastAPI patternsdependency-injection- DI patternsproject-structure-enforcer- Folder structure
Capability Details
layer-separation
Keywords: router, service, repository, layer, clean architecture, separation Solves:
- Prevent database operations in routers
- Block business logic in route handlers
- Ensure proper layer boundaries
dependency-injection
Keywords: depends, dependency injection, DI, fastapi depends, inject Solves:
- Enforce use of FastAPI Depends() pattern
- Block direct instantiation in routers
- Ensure testable code structure
file-naming
Keywords: naming convention, file name, router_, _service, _repository Solves:
- Enforce consistent file naming patterns
- Validate router/service/repository naming
- Maintain codebase consistency
async-patterns
Keywords: async, await, sync, blocking call, asyncio Solves:
- Detect sync calls in async functions
- Prevent blocking operations in async code
- Ensure async consistency
Weekly Installs
13
Repository
yonatangross/orchestkitGitHub Stars
150
First Seen
Jan 22, 2026
Security Audits
Installed on
claude-code10
gemini-cli8
antigravity8
windsurf7
opencode7
codex6