# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Working principles (read before touching any code)

### 1. Think before coding

Don't assume. Don't hide confusion. Surface tradeoffs.

Before implementing:

- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them — don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.

### 2. Simplicity first

Minimum code that solves the problem. Nothing speculative.

- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.

Ask yourself: *"Would a senior engineer say this is overcomplicated?"* If yes, simplify.

### 3. Surgical changes

Touch only what you must. Clean up only your own mess.

When editing existing code:

- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it — don't delete it.

When your changes create orphans:

- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.

The test: every changed line should trace directly to the user's request.

### 4. Goal-driven execution

Define success criteria. Loop until verified.

Transform tasks into verifiable goals:

- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"

For multi-step tasks, state a brief plan:

```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```

Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.

## What this is

A classic WordPress theme (no parent/child, no block theme) for a fictional 1,200-seat receiving house. Built as a portfolio piece for UK public-sector theatre tenders. Requires **WordPress 6.3+** and **PHP 8.0+**.

**There is no build step.** No webpack, no Sass, no npm. CSS and JS ship as-is. Gutenberg blocks are server-rendered PHP, not React. Do not introduce a build pipeline without discussing it first.

## Working with the theme

- **Activate / run repair:** Appearance → Themes → Activate triggers the setup that imports events, creates content pages, builds menus, and sets the static front page. If activation ran on an older revision and pages are missing, visit **Tools → Northfield Repair** (`/wp-admin/admin.php?page=northfield-repair`). All repair steps are idempotent.
- **Re-import events:** Tools → Import Events (optionally "Force" to wipe first). CLI: `wp eval 'northfield_import_events();'` or `wp eval 'northfield_import_events(true);'` to force.
- **Flush rewrite rules** after any change to CPT slugs or page slugs — the repair page does this for you.
- **No automated test suite.** Verify changes by loading the pages in a browser and checking the relevant REST endpoints.

## Architecture — things that require reading multiple files to understand

### Data layer: JSON → CPT → REST (three tiers)

The frontend never reads JSON directly. Flow:

1. `data/events.json`, `data/instances.json`, `data/ticket-types.json` are the source of truth.
2. `inc/import-events.php` reads JSON and creates `nt_event` + `nt_instance` posts on activation, linked via `_nt_event_json_id` post meta.
3. `inc/data-helpers.php` provides `northfield_get_events()`, `northfield_get_instances()`, `northfield_get_event_ticket_types()` which read from JSON (not the CPTs). **These helpers are the abstraction boundary for swapping in the real Spektrix API v3** — keep their signatures and return shapes stable.
4. `inc/spektrix-mock-api.php` registers REST routes under the `spektrix-mock/v1` namespace. The routes call the data helpers. The mock API response shape mirrors Spektrix v3 so the frontend JS is identical to what would run against production Spektrix.

When adding frontend behaviour, hit the REST namespace via `northfieldData.restUrl` — do not read CPTs directly from JS.

### Basket lifecycle

Server-side state lives in a WP **transient** keyed by a session cookie (see `inc/spektrix-mock-api.php`). The JS in `assets/js/basket.js` + `basket-summary.js` mirrors the server state and updates the header icon count on every page. There is no localStorage-only fallback — all mutations round-trip through `POST/PATCH/DELETE /basket/items`.

### Asset loading order matters

`inc/enqueue.php` conditionally loads CSS/JS per template (`is_front_page()`, `is_page_template()`, `is_singular('nt_event')` etc.). Two invariants:

- `northfield-main` is the dependency root for every other stylesheet.
- `northfield-elevate` (`assets/css/elevate.css`) **must load last** — it contains overrides that depend on all other styles being declared first. When adding a new stylesheet, add it to `elevate.css`'s dependency array.

All non-critical JS uses `'strategy' => 'defer'`. No jQuery is enqueued — don't add it.

### Custom post types

- `nt_event` — the show (rewrites to `/events/...`, archive enabled).
- `nt_instance` — a single performance date linked to an event (via `_nt_instance_event_id` meta).
- `event_category` taxonomy — seeded with Drama, Comedy, Music, Dance, Family, Other.

Single-event templates: `single-event.php` (used for the `events/*` page-based routes) and `single-nt_event.php` (CPT permalink). They should stay in sync.

### Gutenberg blocks

Three blocks in `blocks/`: `hero-gallery`, `event-grid`, `alert-banner`. Each has a `block.json` + `render.php` (server-rendered). Editor preview uses `ServerSideRender` (`assets/js/blocks-editor.js`). **No block build output** — do not add `src/` or webpack for blocks; write PHP render callbacks.

### Brand tokens

CSS custom properties in `assets/css/main.css` under `:root` (section 2) are the single source of truth for colour, spacing, typography. Inter and Fraunces are self-hosted variable fonts under `assets/fonts/` and preloaded in `inc/enqueue.php::northfield_preload_fonts()`.

### Analytics gate

`inc/analytics.php` only injects GA4 **after** cookie consent is accepted and **never** for logged-in admins. The GA4 measurement ID is the placeholder `G-XXXXXXXXXX` — replace before deploy.

## Swapping the mock API for real Spektrix

Only three files need to change (call out in PRs):

1. `inc/data-helpers.php` — replace function bodies with HTTP calls to Spektrix v3, keep signatures.
2. `inc/spektrix-mock-api.php` — either delete or repoint the REST handlers to proxy to Spektrix.
3. Basket session — swap transients for Spektrix's cookie-based basket API.

Frontend JS does not change.

## Reference

- `README.md` — install / deployment / customisation.
- `plan.md` — original project scope and design decisions. Treat as historical context; the code is canonical.
