Review catch, and a bad one: the previous commit anchored its insertion on `padding: 0.5rem 0.75rem;` and closed .sectionNav there. Everything that followed in the rule — margin-bottom, box-shadow, display: flex, align-items, gap — was orphaned into .sectionNavSheetOpen, which is only applied while the mobile jump sheet is open. So the sticky nav lost its flex layout, spacing and shadow in the closed state, which is virtually every page view on every school detail page. A site-wide regression introduced by a fix for one mobile menu. Redone by anchoring on the complete rule, closing brace included, so nothing can be orphaned. .sectionNav is now byte-identical to main and the diff is purely additive; .sectionNavSheetOpen carries the z-index and nothing else. The staging experiment that validated this fix set nav.style.zIndex = '1100' with every other declaration intact, so it was always testing this version rather than the broken one. 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.