- Retention policies (Admin -> Privacy -> Retention) applied by a nightly
`retention` job: inactive accounts anonymised after 5 years with a
30-day warning (on by default; never staff roles or people with an
upcoming registration), form answers, login history, payer details in
payment notifications, audit/access logs
- User.lastLoginAt (set on login, backfilled) and inactivityWarnedAt
- Breach register (SecurityBreach) with drafts for the people affected
and the Information Regulator
- Readiness checklist with a score
- Children's/medical flag in the access log; {retention} placeholder in
the privacy notice
- Unit tests (retention.test.js), e2e (privacy-retention.spec.ts); docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012mt6TCv85T9VKRq3cV7rXq
- Privacy page: news opt-in per channel with history, download my data
(JSON + PDF), correction and deletion requests
- Bulk messages are an Event update or News & announcements; news only
reaches people who opted in, with unsubscribe links, one-click
List-Unsubscribe headers and "Reply STOP" on WhatsApp
- WhatsApp STOP via WAWP's message webhook, checked against a secret in
the webhook URL
- Sign-up opt-in box; existing accounts kept opted in and asked once
- Admin -> Data requests with 30-day due dates and a daily reminder job
- Deleting an account is a request; anonymising now covers attendees,
form answers, consent details, payer details in provider payloads, etc.
- Unit tests (privacy.test.js) and e2e (privacy.spec.ts); docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012mt6TCv85T9VKRq3cV7rXq
- Waitlist per session: entries for pick-sessions tickets name a session;
offers use that session's free places, never run past its start, and
claim links tick it. Held offers count towards session capacity.
- At the door: the Select items pop-up has the session picker, with
today's session preselected for new attendees.
- On pick-sessions events every ticket shows the session list straight
away. "All sessions" tickets record the ticked sessions
(RegistrationOption.sessionIds) at one price; scanning, attendance,
certificates, reminders and capacity follow them.
- Fix: per-session stock limits weren't enforced (takenCount filtered
WaitlistEntry by a sessionId column that didn't exist, and the error
was swallowed), and the public event page lost its stock info.
- Fix: editing a door registration with picked sessions couldn't be saved.
- Fix: the offline-scanning service worker served /_next/static cache-first
forever, so dev browsers that had opened the scanner ran stale code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Event wizard: how people book (whole course / pick sessions), capacity
per session and per-option session mode. Session picker on the public
registration page, Manual registration and the kiosk; at the door points
to Manual registration. Register, tickets and My Events handle picked
sessions. Adds docs/ROADMAP-v2.md and docs/HANDOVER.md so work can carry
on from another machine, and a pick-sessions e2e test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Timed jobs move from in-process timers to a job registry run by pg-boss:
once per schedule across processes, retries, run history, cron schedules
in the church timezone, and an admin Background jobs page with Run now.
Playwright end-to-end tests run against their own seeded database. A
Gitea Actions workflow runs backend tests, frontend checks and the e2e
tests, and deploys v* tags with scripts/deploy.sh once secrets are set.
Also fixes the at-the-door check-in count for multi-day tickets.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>