The one rule
Request flow
The four layers
1. Route — api/routes/<name>_route.py
Routes are Flask Blueprints. They receive HTTP requests, call the service, and return a JSON response. Nothing else.
- No business logic
- No database queries
- No imports from repositories or models
- Only import from the service layer
2. Service — api/services/<name>_service.py
Services contain all business logic: validation, calculations, transformations, and orchestration. They call repositories to read and write data.
- All business logic lives here
- No direct database access (no SQLAlchemy queries)
- Call repository methods only
- Raise
APIExceptionfor expected errors
3. Repository — api/repositories/<name>_repository.py
Repositories own all database interaction. They extend the Repository base class and use DBSession for queries. They return model instances.
- All SQLAlchemy queries live here
- No business logic, no validation
- Return model instances
- Use
self.add(),self.delete(),self.add_all()from the base class
4. Model — api/models/<Name>_model.py
Models are SQLAlchemy dataclasses that define the database table schema. They inherit from Base and contain only column definitions.
- No methods (except SQLAlchemy defaults)
- No business logic
- Column definitions only
File naming by resource
For a resource namedusers:
Generated identifiers follow the same pattern: