PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m2s
PR Checks / Backend Smoke (pull_request) Successful in 8s
PR Checks / Build Backend (no push) (pull_request) Successful in 16s
PR Checks / Build Frontend (no push) (pull_request) Successful in 44s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Canceled after 1m21s
Someone on a place page is usually looking for a school they can name, so the order should serve scanning for it rather than ranking. /api/rankings keeps its league-table ordering; this is a place-page decision, not a site-wide one. Sorted case-insensitively, or a capitalised name would sort ahead of every lowercase one. The change made five pieces of copy untrue, so they go with it. The phase variant titled itself "— Ranked", and all four route families described themselves as "ranked by SATs and GCSE results". A page that opens by claiming an order it does not keep is worse than one that claims nothing. The ItemList markup carried `position` with no declared order, which reads as a ranking. It now declares ItemListOrderAscending, so the structured data says what the table does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
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.