# Repository guide ## Project and layout Contínuos CRR is a server-rendered shift rota application. It uses Python (the Docker runtime is 3.12), FastAPI, synchronous SQLAlchemy, SQLite, Jinja2, and Alembic. Dependencies live in `requirements.txt`; development dependencies live in `requirements-dev.txt`. - `app/main.py`: FastAPI application, lifespan, middleware, templates, static files. - `app/web.py`: routes, session authentication, CSRF, administration, swap workflows. - `app/models.py`: SQLAlchemy schema and relationships. - `app/database.py`: engine, sessions, migrations, SQLite backups. - `app/config.py`: Pydantic settings, environment/`.env` loading, proxy-path helpers. - `app/scheduling.py`: monthly pattern and rotation generation. - `app/bootstrap.py`: initial administrator and seeded schedules. - `app/calendar.py`: iCalendar feeds; `app/i18n.py`: Portuguese labels and formatting. - `app/pdf.py`: single-page A4 schedule lists using ReportLab. - `app/notifications.py`: synchronous SMTP delivery and notification history. - `app/security.py`: password hashing and CSRF token generation. - `app/cli.py`: database initialization/migration, demo seeding, shell, reminders. - `app/templates/`, `app/static/`: Jinja HTML and CSS/assets; no frontend build step. - `migrations/`: Alembic environment and the squashed `0001_initial` revision. - `alembic.ini`: migration paths and logging; the database URL comes from settings. - `compose.yaml`: example production deployment with persistent SQLite storage. - `tests/`: export behavior tests and isolated database/client fixtures. Read `docs/DOMAIN.md` for business rules and `docs/ARCHITECTURE.md` for lifecycle and deployment details. See `README.md` for the test workflow. ## Local development Run `make dev` to create/reuse `.venv`, install development dependencies, create `data/`, and start Uvicorn with auto-reload on `127.0.0.1:8000`. Use `make dev PORT=8001` to change the port. Application settings come from the environment and optional `.env`; database migrations and initial seeding run on startup. No separate setup command is needed. ## Development conventions - Follow existing typed Python, snake_case names, and SQLAlchemy 2 mapped models. Keep database and request handling synchronous, consistent with the application. - Keep scheduling calculations in `app/scheduling.py`, persistence in models/database, and HTTP orchestration in `app/web.py`. Reuse existing helpers. - Keep user-facing text in Portuguese and reuse `app/i18n.py` and template filters. - Build internal links with `settings.url()` (`app_path` in templates) and use `_redirect()` in routes so deployments under `ROOT_PATH` keep working. - Preserve session authorization and CSRF checks when adding form actions. - Change the model and add an Alembic revision together for schema changes. `app/database.py` builds the migration configuration using the root `alembic.ini` and the database URL from settings. ## Domain invariants - Users are logins; teams own shifts. One user may control several teams. - Night assignments follow a repeating day-of-month pattern. Saturday and Sunday lunch rotations are independent and continue from the previous actual assignee. - Ordinary generation fills missing assignments only. Existing assignments change through explicit administration or swap actions; preserve manual/swapped rows when an operation calls for changing only generated rows. - Swaps exchange two shifts in the same schedule atomically. Check current ownership and cancel conflicting open requests when assignments change. - Commit scheduling changes before notifications. Email failures must not undo them. ## Testing Run from the repository root: ```sh make test ``` This creates/reuses `.venv`, installs development dependencies, and runs pytest. No activation, application server, Docker service, or separate setup command is needed. Python 3.12+ with `venv`/pip and `make` are prerequisites. - Use pytest functions and plain assertions in `tests/test_*.py`. - Use FastAPI's `TestClient` (backed by HTTPX) for HTTP tests. - Add shared fixtures to `tests/conftest.py` when needed. Fixtures must manage temporary databases, initialization, dependency overrides, and cleanup so `make test` remains the only command required. - Settings and the database engine are created at import time. Set test environment values before importing app modules; use temporary SQLite data, disable real SMTP, and keep tests independent of local `.env` values and persistent application data. - Prefer behavior and domain invariants over assertions about implementation details. - An empty suite succeeds through `make test`; test failures and pytest errors still fail the command. PDF tests inspect downloaded documents with pypdf. Run `make test` after relevant changes and report its result accurately. An empty suite verifies the runner only, not application behavior.