The home page caught every fetch failure and rendered its empty state, so a backend outage looked like a site with no schools in it. School pages turned any error into notFound(), which told visitors — and crawlers — that a real school had ceased to exist. Place fetches did the same by returning [] and null. Failures now reach a retryable error boundary; only a genuine 404 still calls notFound(). "Load more" and the map fetch resolved against whatever state existed when they returned, so results from an abandoned search appended themselves to the new ones. Each fetch now carries an AbortController and checks that its search scope is still current before touching state. The map only records its cache key on success, so a failed load retries instead of pinning the stale marker set. Jest ignored .next/, whose build output otherwise shadowed real suites. 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.