PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 10m0s
PR Checks / Backend Smoke (pull_request) Successful in 48s
PR Checks / Build Backend (no push) (pull_request) Successful in 17s
PR Checks / Build Frontend (no push) (pull_request) Successful in 41s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 24s
- pr-checks.yml: PR gate — frontend typecheck+jest, backend import smoke, image builds (no push), Claude AI review posted as PR comment (severe findings block merge) - deploy.yml (replaces build-and-push.yml): merge to main builds+pushes images tagged sha-<sha>/staging, deploys the staging Portainer stack via webhook, runs Playwright E2E journeys against staging, then retags the verified images :prod (previous kept as :prod-previous) and deploys prod - docker-compose.portainer.staging.yml: second Portainer stack — :staging images, sc_staging_* names, own macvlan IPs, Airflow on 8081; data bootstrapped from source via the staging Airflow DAGs - prod compose now pins :prod instead of :latest (only the promotion step moves it; :latest is no longer published) - e2e/: 6 Playwright journeys (search, postcode, detail, compare, rankings) driven by BASE_URL — the promotion gate - scripts/ci/ai_review.py: Claude review with structured JSON findings - docs/DEPLOY.md: full SDLC doc incl. one-time setup checklist and rollback - replaced removed 'next lint' with tsc typecheck; fixed stale jest tests (slug URLs, N/A formatting, stable trend, fake-timer setup) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqGhF93UrpDNvXBLMjJENL
4.7 KiB
4.7 KiB
SchoolCompare.co.uk - Project Context
Overview
SchoolCompare is a web application for comparing UK primary school (KS2) performance data. It allows users to:
- Search and browse schools by name, location (postcode), or local authority
- Compare multiple schools side-by-side with charts and tables
- View school rankings by various KS2 metrics
- See historical performance trends across years
Architecture
Backend (Python/FastAPI)
- Framework: FastAPI with uvicorn
- Database: PostgreSQL with SQLAlchemy ORM
- Data Source: UK Government "Compare School Performance" CSV downloads
Key files:
backend/app.py- Main FastAPI application, API routesbackend/config.py- Configuration via pydantic-settings (env vars, .env file)backend/database.py- SQLAlchemy engine, session managementbackend/models.py- Database models (School, SchoolResult)backend/data_loader.py- Data queries, geocoding, legacy DataFrame compatibilitybackend/schemas.py- Column mappings, metric definitions, LA code mappings
Frontend (Vanilla JS)
- Single-page application with hash-based routing
- Chart.js for data visualization
- No build step required
Key files:
frontend/index.html- Main HTML structurefrontend/app.js- All application logic, API calls, renderingfrontend/styles.css- Styling (CSS variables, responsive design)
Database Schema
schools school_results
├── id (PK) ├── id (PK)
├── urn (unique, indexed) ├── school_id (FK → schools.id)
├── school_name ├── year (indexed)
├── local_authority ├── rwm_expected_pct
├── school_type ├── reading_expected_pct
├── postcode ├── ... (all KS2 metrics)
├── latitude, longitude └── unique(school_id, year)
└── results → SchoolResult[]
Configuration
Environment variables (or .env file):
DATABASE_URL- PostgreSQL connection string (default:postgresql://schoolcompare:schoolcompare@localhost:5432/schoolcompare)HOST,PORT- Server binding (default:0.0.0.0:80)ALLOWED_ORIGINS- CORS origins
Running Locally
-
Start PostgreSQL:
docker compose up -d db -
Run migration to import CSV data:
python scripts/migrate_csv_to_db.py --drop # Add --geocode to geocode postcodes (slower, adds lat/long) -
Start the app:
uvicorn backend.app:app --host 0.0.0.0 --port 8000
Docker Deployment
docker compose up -d
This starts:
db- PostgreSQL 16 with persistent volumeapp- FastAPI application on port 80
Data
- Source: UK Government Compare School Performance downloads
- Location:
data/directory with year folders (e.g.,2023-2024/england_ks2final.csv) - The
scripts/download_data.pycan fetch data from the government website
Key Features
- Location Search: Enter postcode to find nearby schools (uses postcodes.io API)
- Multi-school Comparison: Select multiple schools, view metrics across years
- Rankings: Top schools by any KS2 metric, filterable by local authority
- Variability Analysis: Shows standard deviation of scores across years
API Endpoints
GET /api/schools- List/search schools (supports pagination, location search)GET /api/schools/{urn}- School details with all yearly dataGET /api/compare?urns=123,456- Compare multiple schoolsGET /api/rankings- School rankings by metricGET /api/filters- Available filter options (LAs, types, years)GET /api/metrics- Metric definitions (single source of truth)GET /api/data-info- Database stats
SDLC
Full details in docs/DEPLOY.md. The short version:
- Never push to
maindirectly. Work on a feature branch and open a PR; branch protection requires the PR checks (typecheck, tests, builds, AI review) to pass before merge. - Merging to
maindeploys automatically: images are built once, deployed to the staging Portainer stack, verified by the Playwright journeys ine2e/, and only then retagged:prodand rolled out to production. - If you change user-facing behaviour, update or extend the
e2e/journey tests in the same PR — they are the promotion gate.
Recent Changes
- Added staging environment + automated staging→prod pipeline (Gitea Actions)
- Migrated from CSV file storage to PostgreSQL database
- Added location-based search using postcode geocoding
- Added local authority filter to rankings
- Improved frontend with featured schools, loading states, API caching
Important
- Do not attempt to start a local server to test the application, it does not work