Files
school_compare/docs/DEVELOPMENT.md
T
TudorandClaude Opus 5 0c901cd0d1
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m11s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 18s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m19s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 36s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 6m3s
feat(ci): gate promotion on the image set that actually passed E2E
Staging health polling asked only whether something answered HTTP 200 at
the base URL. It could not tell the new deployment from the old one, so
journeys could pass against the previous release, and concurrent merges
could move the staging tags underneath a run in flight.

Each staging run now mints a build ID and stamps all three images with
the commit and that ID, as labels and — for frontend and backend — as a
build-time JSON file that environment overrides cannot rewrite.
/release.json reports both identities uncached, and scripts/ci/release.py
polls for the expected pair before and after the journeys. Only then are
the captured build digests tagged verified-<sha>.

Promotion resolves those verified tags to immutable digests, revalidates
their labels, and refuses a mixed or incomplete set before any :prod tag
moves. The whole staging workflow shares one concurrency group with
cancellation disabled, so releases serialise.

The scripts are stdlib-only and unit-tested against mocked registry and
HTTP behaviour; PR checks now run the pipeline and CI suites too. The
runbook records what this cannot prove locally, and that the first
rollout needs a commit built by this workflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 10:17:50 +01:00

3.8 KiB

Development and validation

Prerequisites and environment boundaries

Use a feature branch. The deployed stack is the integration environment; do not assume a local server can run from a fresh checkout. This cleanup did not start local servers or provision databases. Unit tests use fixtures and mocks.

The current versions are not yet aligned:

Component Container PR checks
Backend Python 3.11 Python 3.12
Frontend Node 24 Node 22
Pipeline Python 3.13 Pipeline image build

Use the component's container version when reproducing deployment behaviour. The backend dependency pins predate Python 3.14; do not assume the system Python can install or run them. Version alignment is a separate maintenance task.

Frontend checks

cd nextjs-app
npm ci
npm run typecheck
npm test -- --runInBand

npm run build is the production build check. There is no lint script. Tests live in __tests__/ and use Jest/React Testing Library. These checks do not prove that live PostgreSQL queries, Typesense or a deployed proxy work.

The frontend .env.example documents runtime variables. Browser traffic normally uses /api; FASTAPI_URL is an absolute server-side URL ending in /api. Payload additionally needs DATABASE_URL and PAYLOAD_SECRET when used at runtime. Never commit credentials or real .env files.

Backend checks

From the repository root, using an available Python 3.11 or 3.12 interpreter:

python3.11 -m venv /tmp/schoolcompare-backend-venv
/tmp/schoolcompare-backend-venv/bin/python -m pip install -r requirements.txt pytest 'httpx<0.28' pyyaml
/tmp/schoolcompare-backend-venv/bin/python -m pytest backend/tests pipeline/tests scripts/ci/tests -q

Substitute python3.12 if matching PR CI. The test dependencies above match the current workflow; they are not yet captured in a dedicated development lockfile. Backend configuration is defined in backend/config.py; .env.example documents commonly used values. ALLOWED_ORIGINS uses a JSON array, not a comma-separated string.

Data and pipeline work

The app needs populated marts.* tables. A new Postgres instance alone is not a working school-data environment. Use the existing managed pipeline or an approved snapshot; the removed CSV importer cannot build the current schema.

The pipeline container includes Meltano, dbt/Postgres, Airflow and the custom taps. Airflow commands/selectors live in pipeline/dags/. Schema tests live in pipeline/transform/tests/ and model YAML files. Run the relevant dbt build selector in an isolated data environment for model changes; it writes tables and is not a read-only smoke test. Prefer python -m dbt.cli.main as the DAGs do.

GIAS dictionaries are generated together by pipeline/scripts/generate_gias_codes.py. The backend and pipeline copies are intentional; backend/tests/test_gias_codes.py checks that they stay identical.

For Payload collection/editor changes, run npm run generate:importmap in nextjs-app/ and include the generated map. Preserve CMS migrations and the separate payload schema. See publishing.

End-to-end checks

Against an existing, authorised test environment:

cd e2e
npm ci
npx playwright install chromium
BASE_URL=https://your-test-environment.example npx playwright test

The suite does not start a web server. CI installs Chromium with system dependencies and runs against staging. Use the configured staging target: docs/DEPLOY.md records the public staging proxy limitation. User-visible behaviour changes should update the corresponding journeys.

Before requesting review

Run checks relevant to the change, inspect git diff --check, and report checks that could not run. Do not publish or promote as part of local validation. DEPLOY.md documents the PR and human promotion gates.