Server-rendered cards inside a client carousel that scrolls rather than paginates, so all six links stay in the initial HTML and the row still works with JavaScript off. Three client islands, split by what each needs: a school, the whole selection, a DOM ref. The lede claims a similar intake only when no card came from tier 3, chips list what a school actually shares, a missing figure reads "Not published", and the neighbour's number carries no valence colour — green and terracotta mean "against England" everywhere else, and colouring it here would read as ranking the neighbours. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SchoolCompare frontend and CMS
Next.js App Router with React, TypeScript, CSS Modules, Chart.js, Leaflet and Payload CMS. It serves school search, comparisons, rankings, school/place detail pages and editorial content across England.
Start with the repository overview, architecture and development checks.
Source map
| Path | Purpose |
|---|---|
app/(frontend)/ |
Public root layout, server pages and FastAPI proxy |
app/(payload)/ |
Payload root layout, /admin and /cms-api |
app/robots.ts, app/opengraph-image.tsx, root icons |
Site-wide metadata endpoints |
components/ |
Client views and reusable display components |
components/school/ |
School detail sections |
lib/api.ts, lib/types.ts |
Fetch wrappers and manual school API types |
lib/schoolSections.ts, lib/compareLogic.ts |
Presentation decisions and data preparation |
context/, hooks/ |
Comparison state, suggestion state and responsive behaviour |
collections/, blocks/, migrations/ |
CMS schema and production migrations |
__tests__/ |
Jest and React Testing Library tests |
Do not introduce a shared app/layout.tsx: public pages and Payload have separate
root layouts. Keep root metadata files outside the route groups.
Data and state
Server pages fetch initial data directly from FASTAPI_URL. Browser fetches use
/api by default, forwarded by app/(frontend)/api/[...path]/route.ts.
FASTAPI_URL must include /api. See .env.example for CMS and API settings.
State uses React hooks/context, URL search parameters and localStorage for the comparison basket. SWR is not installed. Maps use dynamic Leaflet wrappers. Revalidation intervals are configured in fetch wrappers and pages; they vary by resource. Backend reloads do not automatically invalidate every Next.js cache.
Commands
npm ci
npm run typecheck
npm test -- --runInBand
npm run build
test:watch and test:coverage are also available. There is no lint script.
A running application needs the backend/data environment described in the
development guide.
After CMS field or editor changes, run npm run generate:importmap. Keep
payload-types.ts generated from the CMS schema rather than editing it by hand.
The build must work without a database connection; avoid module-scope CMS queries
and DB-backed generateStaticParams functions.
See publishing for CMS operations and deployment for staging and production promotion.