Skip to main content
Every BackAnt project enforces a strict four-layer architecture. Understanding this structure is the single most important thing before you start writing code.

The one rule

Request flow

Each layer has exactly one responsibility. No layer skips another.

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.
Rules:
  • 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.
Rules:
  • All business logic lives here
  • No direct database access (no SQLAlchemy queries)
  • Call repository methods only
  • Raise APIException for 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.
Rules:
  • 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.
Rules:
  • No methods (except SQLAlchemy defaults)
  • No business logic
  • Column definitions only

File naming by resource

For a resource named users: Generated identifiers follow the same pattern:

Dependency direction

Each layer only imports from the layer directly below it. Routes never import repositories. Services never import models directly.

Where does this code go?

Full example: creating a user

Route receives the request and delegates:
Service validates and orchestrates:
Repository writes to the database:
Model defines the table: