Files
school_compare/nextjs-app
TudorandClaude Opus 5 c9a1892bfb
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m4s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 16s
PR Checks / Build Frontend (no push) (pull_request) Successful in 45s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Failing after 3m17s
feat(admissions): publish the latest cut-off only, holding history back
Earlier years are to become a paid feature, so they stop being published.

The load-bearing part is that this is a change to the API, not only to the
page. /api/schools/{urn} is public and unauthenticated: leaving
admission_distance_history in the payload while declining to render it would
have handed the whole record to anyone who opened the network tab. It is
withheld at the source, and the page follows.

Nothing changes upstream. The tap, the plausibility band and
fact_admission_distance are untouched and still load every published year, so
restoring history for entitled callers is a change to one function in
data_loader rather than a re-collection.

What the reader now gets is the latest figure on the Admissions tile, and a
Distance section that answers the question the number alone cannot: whether
their own address falls inside it. Retitled to "How far away are you?", which
is what it now does — the previous title described a record that is no longer
there.

Removed with the history: the trend chart, the year-by-year table, the
per-year verdict strip, the trend summary and the coverage note, along with
their CSS. The section goes from 743px to 417px.

One consequence worth naming. A run of years used to soften a single close
call — a home just outside one year's cut-off was usually inside another. With
one year published, the "too close to call" band is the entire safety margin
between a parent and a place they do not have, so the verdict now names its
year, and the three outcomes are tinted apart rather than distinguished by
wording alone.

The existing stylesheet test earned its keep here: the three verdict classes
were referenced before they were written, and it caught them. Unstyled, a
"beyond the cut-off" result would have been indistinguishable from an "inside"
one — the exact failure the longhand class map was written to prevent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WDvkyqqHABm4bmth2kjAxE
2026-08-20 18:44:57 +01:00
..

SchoolCompare Next.js Application

Modern Next.js application for comparing primary school KS2 performance across England.

Features

  • Server-Side Rendering (SSR): Fast initial page loads with pre-rendered content
  • Individual School Pages: Dedicated pages for each school with full SEO optimization
  • Side-by-Side Comparison: Compare up to 5 schools simultaneously
  • School Rankings: Top-performing schools by various metrics
  • Interactive Maps: Leaflet integration for geographic visualization
  • Performance Charts: Chart.js visualizations for historical data
  • Responsive Design: Mobile-first approach with full responsive support
  • SEO Optimized: Dynamic sitemaps, meta tags, and structured data

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript 5
  • Styling: CSS Modules + CSS Variables
  • State Management: React Context API + URL state
  • Data Fetching: SWR (client-side) + Next.js fetch (server-side)
  • Charts: Chart.js + react-chartjs-2
  • Maps: Leaflet + react-leaflet
  • Testing: Jest + React Testing Library
  • Validation: Zod

Getting Started

Prerequisites

  • Node.js 24+ (using nvm recommended)
  • FastAPI backend running on port 8000

Installation

# Install dependencies
npm install

# Copy environment variables
cp .env.example .env.local

# Update .env.local with your configuration

Development

# Start development server
npm run dev

# Open http://localhost:3000

Building

# Build for production
npm run build

# Start production server
npm start

Testing

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

Linting

# Run ESLint
npm run lint

Project Structure

nextjs-app/
├── app/                      # App Router pages
│   ├── layout.tsx           # Root layout
│   ├── page.tsx             # Home page
│   ├── compare/             # Compare page
│   ├── rankings/            # Rankings page
│   ├── school/[urn]/        # Individual school pages
│   ├── sitemap.ts           # Dynamic sitemap
│   └── robots.ts            # Robots.txt
├── components/              # React components
│   ├── SchoolCard.tsx       # School card component
│   ├── FilterBar.tsx        # Search/filter controls
│   ├── ComparisonView.tsx   # Comparison interface
│   ├── RankingsView.tsx     # Rankings table
│   └── ...
├── lib/                     # Utility libraries
│   ├── api.ts              # API client
│   ├── types.ts            # TypeScript types
│   └── utils.ts            # Helper functions
├── hooks/                   # Custom React hooks
├── context/                 # React Context providers
├── styles/                  # Global styles
├── public/                  # Static assets
└── __tests__/              # Test files

Environment Variables

Variable Description Default
NEXT_PUBLIC_API_URL Public API endpoint (client-side) http://localhost:8000/api
FASTAPI_URL Server-side API endpoint http://localhost:8000/api
NODE_ENV Environment mode development

Performance Optimizations

  • Server-Side Rendering: Initial HTML rendered on server
  • Static Generation: Where possible, pages are pre-generated
  • Image Optimization: Next.js Image component with AVIF/WebP support
  • Code Splitting: Automatic route-based code splitting
  • Dynamic Imports: Heavy components loaded on demand
  • API Caching: Configurable revalidation for data fetching
  • Bundle Optimization: Tree shaking and minification
  • Compression: Gzip compression enabled

SEO Features

  • Dynamic Meta Tags: Generated per page with Next.js Metadata API
  • Open Graph: Social media optimization
  • JSON-LD: Structured data for search engines
  • Sitemap: Auto-generated from database
  • Robots.txt: Search engine crawling rules
  • Canonical URLs: Duplicate content prevention

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

License

Proprietary - SchoolCompare

Support

For issues and questions, please contact the development team.