Release notes
# Changelog
All notable changes to this project will be documented in this file.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html) — PATCH for fixes, MINOR for features, MAJOR for breaking changes (VER-SEM-*).
## [Unreleased]
## [0.4.0] - 2026-04-24
### Added
- `/display` audience view — big-screen surface with 3-phase state machine (idle → tumbling → revealed), driven by polling `GET /api/draw/latest`. Idle shows huge entry counter + countdown cells; tumbling plays an 8s digit-reel (pure CSS, no GSAP); reveal slams the winning File No. + name onto the screen. Navy ground, reversed logo, Citrus accents, triangle motif.
- `GET /api/draw/latest` — public RLS-compliant snapshot using `winner_card_for_event` + `entry_count_for_event` SECURITY DEFINER RPCs. No PII beyond first+last name + file number.
- Middleware: `/api/draw/latest` is public; `/api/draw` exact path stays operator-gated.
- `GET /api/operator/export/entries` — operator-guarded CSV export for post-event follow-up. Plain RFC 4180 encoder + 6 unit tests (40 suite-wide).
- "Download entries.csv" action on `/operator` console.
## [0.3.0] - 2026-04-24
### Added
- Sharedo integration — OAuth2 Impersonate.Fixed token client with in-process caching (30s safety margin before expiry), intake-API payload builder (matches `enquiry-intake-api.md §3` including `contact.entryConsent` + `entryConsentTosVersion`), and outbox drainer with full 201/200/400/401/403/409/429/5xx handling.
- `/api/cron/drain-outbox` — bearer-guarded endpoint for external scheduler; CRON_BEARER env per environment.
- Fire-and-forget drain kicked at the tail of `POST /api/entries` so entries drain under natural load.
- Operator auth (DEV-02) — argon2id verify of a shared passphrase, 12h server-side session in `operator_sessions`, httpOnly cookie, 5/min per-IP login rate limit. `/operator/login` + `/api/operator/{login,logout}`.
- `middleware.ts` gating `/operator/*` + `/api/draw` — 303 to login for pages, 401 JSON for APIs.
- `/operator` console — live entry count, outbox pending/delivered/failed counts, last-draw summary, and DRAW / REDRAW controls (client component posts to `/api/draw`, shows winner + committed/revealed seed prefixes).
- `POST /api/draw` — server-authoritative draw. 32-byte CSPRNG seed, sha256 commit, stored first; HMAC-SHA256(seed, entry_id) selection (lowest wins, unbiased across seeds, deterministic given seed); audit-chain hash chained off the previous draw's hash.
- 14 new unit tests (8 on draw engine incl. a 2000-trial statistical distribution smoke, 6 on payload builder).
### Fixed
- `/api/entries` outbox payload now carries `contact.entryConsent: true` + `entryConsentTosVersion` (Day-1 compliance gap).
- Relative redirect Location so Traefik-fronted 303s resolve to the public host instead of the internal container origin.
- ESLint `react/no-unescaped-entities` in `/filed/[id]` unblocking prod build.
## [0.2.0] - 2026-04-23
### Added
- Initial Supabase schema (migration `20260423130000_initial_schema.sql`): `entries`, `sharedo_outbox`, `draws`, `operator_sessions`, `event_counters`. All tables RLS-enabled per SUP-005 with deny-all default to anon; server-only mutations via service role (SUP-003, SUP-004).
- `generate_file_number(event_slug)` sequence function, `entry_count_for_event(event_slug)` public aggregate counter (SECURITY DEFINER), `winner_card_for_event(event_slug)` for post-reveal audience view.
- Unique constraint `entries(event_slug, email)` for email dedup with citext for case-insensitivity.
- Supabase typed clients (`src/lib/supabase/{server-client,browser-client,types.generated}.ts`) from `supabase gen types` (via Management API).
- Event configuration model — hardcoded Legal Tech Fest 2026 config with FormIO-compatible component schema (`src/lib/events/legaltechfest-2026.ts`) and date-range active-event resolver.
- FormIO-schema renderer supporting `textfield`, `email`, `textarea`, `select`, `checkbox`, `hidden` with inline labels + error slots.
- Form on `/` — Navy ground + reversed logo + Chronicle "File opening. Automated." headline + branded form panel with Citrus submit ("Open File").
- `POST /api/entries` — server-side validation, honeypot detection, in-memory per-IP rate limit (10/min), SHA-256 IP hashing with pepper, file-number allocation, audit-chain hash (prev-hash + canonical JSON), transactional entry + outbox insert, email dedup idempotency.
- `/filed/[id]` confirmation with File No. reveal, live client-side countdown to the draw, "Winner must be present" reminder.
- Structured JSON logger (`LOG-*`) with correlation IDs.
- Vitest configuration + 20 unit tests covering validation, canonical JSON + audit chain hash determinism, active-event resolver, rate limiter.
## [0.1.0] - 2026-04-23
### Added
- Initial scaffold: Next.js 15 (App Router) + TypeScript + Tailwind v4 per FEAT-001 design.md.
- Brand-consistent placeholder hero on `/` — Navy ground, reversed Alterspective logo top-left (LOGO-001, LOGO-003), Chronicle Display "File opening. Automated." headline, Citrus accent, triangle motif. Visually continuous with the printed booth poster so an early QR scan does not 404.
- Fonts served from `brand.alterspective.com.au` (Chronicle Display + Montserrat), hosted per brand guide.
- `/api/health` endpoint returning `{ status, version, commit, env }` per AIRUN-021 Phase 1.
- `/api/version` endpoint per VER-UI-*.
- `/release-notes` page renders `CHANGELOG.md` per VER-LOG-03.
- Version + environment visible in footer linking to `/release-notes` (VER-UI-02, VER-UI-03, VER-UI-07).
- Multi-stage Dockerfile with `HEALTHCHECK` directive, non-root runtime user, `SOURCE_COMMIT` build ARG per AIRUN-021 Lessons 2 + 4 + 5.
- CI workflow copied from `Principles/Web/standards/templates/ci-cd.yml`; lint + typecheck + test + release-on-main.
- `.env.example` documenting every runtime variable (no values).