Files
school_compare/docs/LEGACY_CODE.md
TudorandClaude Opus 5 1d8858fbda
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 1m18s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 1m2s
chore: remove the code the legacy CSV importer left behind
`backend/migration.py` and `scripts/migrate_csv_to_db.py` import `School`,
`SchoolResult`, `init_db` and `set_db_schema_version` — names that no longer
exist. `scripts/geocode_schools.py` imports the same removed ORM model. None of
the three can be imported against the current backend, so they were not dormant
utilities anyone could fall back on; they were files that would fail on the
first line. `backend/version.py` existed only to hand `SCHEMA_VERSION` to that
importer, and the FastAPI lifespan performs no version-triggered import.

Three symbols go with them, each confirmed to have no caller: the unvectorised
`haversine_distance`, superseded by the inline NumPy calculation in search;
`fetcher`, an SWR helper for a dependency this project does not install; and
`kmToMiles`. `calculateDistance` stays — CutoffMapPanel uses it.

Two comments pointed at `migrate_csv_to_db.py --drop` to explain why Payload
owns its own schema. The reason survives the script: blog content must stay
clear of the school marts and Airflow's metadata. Reworded rather than deleted,
so the constraint keeps its justification.

docs/LEGACY_CODE.md records what was removed and where to find it in history. It
also records what was deliberately *not* removed, which is the more useful half:
unused UI components awaiting a design decision, manual data utilities whose
operators a repository search cannot see, and fallbacks that look obsolete but
are load-bearing — `data_loader.py`'s older-mart branches, the generated GIAS
dictionary copies, and the `legacy`-named dbt models that annual DAG selectors
explicitly include. A zero-import count is evidence, not a verdict.

The scripts that fetch DfE CSVs are marked historical and kept, pending
confirmation that nobody runs them by hand.

Checked: 190 backend tests, 429 frontend tests, `tsc --noEmit` clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016y2J6bs8gbuSJbH18w7Tan
2026-09-14 23:01:22 +01:00

7.3 KiB

Legacy and unused-code inventory

Reviewed 2026-09-14. This inventory records source evidence, not production usage telemetry. A command with no repository caller may still be run manually or from an external scheduler. Historical specs and prototypes are not runtime imports.

Method and scope

Searched backend imports, tests, CLI scripts, Airflow DAGs, Meltano configuration, Gitea workflows, Dockerfiles and documentation. For frontend candidates, inspected TypeScript imports, re-exports, literal dynamic imports and require calls, resolving relative and @/ paths while excluding tests, dependencies and build output. Checked candidates again with text searches including tests.

Next.js route files, generated Payload import-map entries and plugin discovery are entry points even without ordinary imports. This is why a zero-import count alone is not sufficient grounds for deletion. Computed imports and external operators are outside this static audit.

Removed in this cleanup

These names are recorded for Git-history lookup; they are no longer file links.

Removed path or symbol Evidence and replacement
backend/migration.py Imported School and SchoolResult, which no longer exist in backend/models.py. Only the legacy CSV CLI imported it. Current tables are built by dbt.
backend/version.py Only the legacy importer consumed SCHEMA_VERSION. FastAPI lifespan does not perform version-triggered imports. This is unrelated to active Payload migrations.
scripts/migrate_csv_to_db.py Imported removed init_db/set_db_schema_version helpers and the obsolete models indirectly. No runtime, DAG or workflow calls it. Use the managed pipeline for current marts.
scripts/geocode_schools.py Imported the removed School ORM model. No pipeline/workflow calls it. Coordinates now come from GIAS/PostGIS; a separate mart-aware manual utility remains under pipeline/scripts/.
backend.data_loader.haversine_distance No callers. Search uses its inline vectorised NumPy calculation.
nextjs-app/lib/api.ts: fetcher No callers; SWR is not installed. Application fetches use the named API wrappers.
nextjs-app/lib/api.ts: kmToMiles No callers. calculateDistance remains because CutoffMapPanel uses it.

The removed command files could not import successfully against the current backend. This cleanup does not run replacements, migrate data or modify databases. Their previous implementations remain recoverable from Git history.

Unused candidates retained for a separate cleanup

Candidate Evidence Recommended next step
nextjs-app/components/LoadingSkeleton.tsx and its CSS No application or test imports found. Remove together after confirming no planned use.
nextjs-app/components/Pagination.tsx and its CSS No application or test imports found; HomeView implements load-more behaviour. Remove as a pair if numbered pagination will not return.
nextjs-app/components/SchoolCard.tsx and its CSS Imported by its own tests, not application code. HomeView uses SchoolRow/SecondarySchoolRow. Decide whether to retire the card design; if removed, remove its dedicated tests as well. Passing tests do not establish runtime use.
backend/database.py: get_db, get_db_session No remaining callers after removing the importer. Current code creates SessionLocal directly. Either adopt these helpers during session-lifecycle cleanup or remove them; do not rewrite active sessions in a documentation change.
backend/schemas.py: COLUMN_MAPPINGS, NULL_VALUES, LA_CODE_TO_NAME No remaining Python consumers found after importer removal. Other constants in this module are active. Remove individual constants after checking external data utilities; retain the module.
backend/config.py: data_dir, max_page_size, rate_limit_burst No active consumers found. default_page_size appears only in a branch that expects None, although the route supplies a concrete default. Reconcile settings with route validation in a focused API change.

Legacy/manual paths requiring operational verification

Path Status and reason to retain for now
FastAPI /, /compare, /rankings, /favicon.svg, /robots.txt, and conditional /static Old frontend-serving routes reference a frontend/ directory absent from the checkout and backend image. Next.js owns these public surfaces. Removal changes externally callable routes, so first check proxy/operator usage and define replacement responses.
scripts/fetch_real_data.py, scripts/download_data.py Historical standalone CSV utilities. The fetch script targets Wandsworth/Merton; neither is wired into the managed pipeline. Marked historical, retained pending confirmation of manual use.
pipeline/scripts/geocode_postcodes.py Mart-aware postcode fallback, not called by the current DAGs. Do not confuse it with the removed legacy ORM geocoder. Verify the target schema before manual use.
docker-compose.yml Uses unpublished :latest release tags and lacks frontend Payload DB/secret/media configuration. Retained as an old development topology, not recommended onboarding.
nextjs-app/docker-compose.yml Standalone legacy recipe with old backend port assumptions and no CMS persistence setup. Retained until its consumers are checked.
MIGRATION_SUMMARY.md, docs/superpowers/, mockups/ Historical designs and prototypes. Retain as history; do not follow as current deployment instructions.
scripts/sql/drop_fact_parent_view.sql One-off maintenance SQL. Not an application entry point; repository call-site searches cannot establish whether it is still needed operationally.

Active code that can look obsolete

  • backend/data_loader.py older-mart query fallbacks are covered by backend tests and support databases at different migration stages. Remove only after verifying the deployed schemas in every supported environment.
  • backend/gias_codes.py and pipeline/scripts/gias_codes.py are intentionally generated copies for separate runtime images. Their parity is tested.
  • nextjs-app/migrations/, payload-types.ts and the Payload import map are active CMS artifacts, not remnants of the removed school importer.
  • get_available_years, get_available_local_authorities and get_schools_count in data_loader.py are called through get_data_info, which serves the backend data-info endpoint. They are not dead functions.
  • get_supplementary_data is an intentional single-school wrapper around the batch implementation.
  • pipeline/transform models named legacy can be active data sources: annual DAG selectors explicitly include legacy KS2/KS4 lineage. Names alone do not establish obsolescence.

Suggested next passes

  1. Decide the fate of the three unused UI components and remove paired assets/tests.
  2. Consolidate backend session usage and remove abandoned settings/constants.
  3. Verify external consumers, then retire static-serving API routes and old compose recipes.
  4. Audit manual data utilities with pipeline operators before deleting them.
  5. Revisit compatibility fallbacks only after documenting supported schema versions.

Validation for this cleanup should include frontend typechecking/tests, Python syntax checks, reference searches and documentation link checks. Live database, external scheduler and deployed route usage require separate integration evidence.