| name | learn-backend |
| description | FastAPI + SQLModel conventions, request dependencies, transaction safety, and backend architecture |
| user-invocable | false |
Backend
Backend conventions for FastAPI + SQLModel/SQLAlchemy services, request dependencies, transaction safety, and SQLAlchemy-first implementation style.
When To Use
- You are adding or changing API endpoints in
backend/app.
- You are modifying models, dependencies, auth, or DB-access code.
- You are changing data-manipulation logic, especially assignment/map workflows.
Canonical Files
backend/app/main.py
backend/app/models.py
backend/app/core/db.py
backend/app/core/config.py
backend/app/core/dependencies.py
backend/app/core/security.py
backend/app/core/io.py
backend/app/core/models.py
backend/app/utils.py
backend/app/assignments/assignments.py
backend/app/comments/*
backend/app/cms/*
backend/app/save_share/*
backend/app/exports/*
backend/app/sql/* - legacy UDF SQL files (do not expand; see learn-db-query)
Hard Invariants
- SQLAlchemy-First: new backend logic defaults to SQLAlchemy/SQLModel query composition and set-based SQL. See learn-db-query for full DB query policy.
- Use dependency helpers consistently (
get_document, get_protected_document, parse_document_id).
- Preserve public/private document ID semantics and access guarantees.
- Keep write paths transaction-safe; commit only after full operation success.
- Keep API behavior aligned with frontend contracts in
app/src/app/utils/api/apiHandlers/types.ts.
- Avoid in-memory Python processing for large spatial/tabular operations when DB can perform set-based operations.
Shattered Parent Assignment Data Contract
When a parent unit is shattered, every one of its children must have a row in document.assignments, with zone = NULL for unassigned children.
The frontend requires this to know which child block IDs to render as interactive. All write paths — interactive shattering (shatter_parent.sql) and CSV import (_heal_or_fill) — must uphold this invariant.
Preferred Patterns
- Use SQLAlchemy text/bindparams safely when dynamic SQL is unavoidable.
- Keep endpoint handlers thin when shared logic already exists in modules (
assignments, utils, etc.).
- Add/adjust tests under
backend/tests for endpoint or DB behavior changes.
Anti-Patterns
- Bypassing existing dependency guards and leaking private IDs.
- Mixing unrelated concerns inside one endpoint without reusable helper boundaries.
Change Checklist
- Confirm endpoint auth/dependency behavior for public vs protected access.
- Confirm DB writes are atomic and rollback-safe.
- Verify response schema alignment with frontend types.
- Confirm tests cover changed logic and edge/error paths.
- If touching legacy UDF paths, follow learn-db-query.
Validation Commands
cd backend && pytest -v
docker-compose exec backend pytest -v
docker-compose up pre-commit
See Also
Common Failure Modes
- Access-control regressions from using
get_document where get_protected_document was intended.
- Partial writes caused by commit timing mistakes in multi-step operations.
- API schema drift that breaks frontend parsing.