feat(arch): add API-007 rule to enforce layered architecture

Add architecture rule that detects when API routes import database
models directly, enforcing Routes → Services → Models pattern.

Changes:
- Add API-007 rule to .architecture-rules/api.yaml
- Add _check_no_model_imports() validation to validator script
- Update customer imports to use canonical module location
- Add storefront module restructure implementation plan

The validator now detects 81 violations across 67 API files where
database models are imported directly instead of going through
services. This is Phase 1 of the storefront restructure plan.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-29 22:23:00 +01:00
parent de83875d0a
commit 228163d920
19 changed files with 466 additions and 16 deletions

View File

@@ -204,3 +204,53 @@ api_endpoint_rules:
file_pattern: "app/api/v1/shop/**/*.py"
discouraged_patterns:
- "db.query(.*).all()"
- id: "API-007"
name: "API endpoints must NOT import database models directly"
severity: "error"
description: |
API endpoints must follow the layered architecture: Routes → Services → Models.
Routes should NEVER import database models directly.
WHY THIS MATTERS:
- Layered architecture: Each layer has clear responsibilities
- Testability: Routes can be tested without database
- Flexibility: Database schema changes don't affect route signatures
- Type safety: Schemas define the API contract, not database structure
For dependency injection (e.g., current user/customer), use schemas instead
of database models as return types.
WRONG:
from models.database.customer import Customer
from models.database.order import Order
from app.modules.customers.models.customer import Customer
@router.get("/orders")
def get_orders(customer: Customer = Depends(get_current_customer)):
...
RIGHT:
from app.modules.customers.schemas import CustomerContext
from app.modules.orders.services import order_service
@router.get("/orders")
def get_orders(customer: CustomerContext = Depends(get_current_customer)):
return order_service.get_orders(db, customer.id, customer.vendor_id)
ALLOWED IMPORTS IN API ROUTES:
- Schemas: from models.schema.* or from app.modules.*.schemas
- Services: from app.services.* or from app.modules.*.services
- Dependencies: from app.api.deps
- Database session: from app.core.database import get_db
NOT ALLOWED:
- from models.database.*
- from app.modules.*.models.*
pattern:
file_pattern: "app/api/**/*.py"
anti_patterns:
- "from models\\.database\\."
- "from app\\.modules\\.[a-z_]+\\.models\\."
exclude_files:
- "app/api/deps.py" # Dependencies may need model access for queries