Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce25bf40b | ||
|
|
376b93a438 |
+45
-31
@@ -14,9 +14,6 @@ encrypted settings unreadable or break existing installs.
|
||||
|
||||
| Version | What |
|
||||
|---------|------|
|
||||
| 1.51.3 | **Express 5** (qs query parser and `req.body = {}` kept); scanner and at-the-door on v2 check-in; shared middleware answers v2-shaped on `/api/v2` (`legacyErrorsToV2`, `reason`); v1 `Deprecation` + `successor-version` headers (`src/v2/deprecation.ts`) |
|
||||
| 1.51.2 | **v2 accounts and check-in**: signup, login (+ code step), `PATCH /me`; check-in look-up and scan with `outcome`s. `src/services/auth.ts` (from userController) and `src/services/checkin.ts` (from ticketController); login/signup/profile pages on v2 |
|
||||
| 1.51.1 | **v2 registrations and payments**: register, get, cancel, checkout; create/cancel moved to `src/services/registrations.ts`, online checkout to `src/services/payments.ts` (v1 uses them too); typed frontend calls (`apiV2`, `npm run api:types`); register page, Pay now and My Events cancel on v2 |
|
||||
| 1.51.17 | **Security:** forgot-password and sign-in don't reveal whether an account exists (same answer, status and timing); forgot-password rate-limited |
|
||||
| 1.51.16 | **Incoming webhooks and message links on v2** — `src/v2/links.ts` (`/api/v2/webhooks/…`, one-click unsubscribe, 308s for old links); provider URLs and email links point at v2 |
|
||||
| 1.51.15 | **Privacy and admin on v2** — `resources/adminPrivacy.ts`; every frontend call on v2; impersonation end/log allowed on v2 while read-only |
|
||||
@@ -29,6 +26,11 @@ encrypted settings unreadable or break existing installs.
|
||||
| 1.51.8 | **Rest of event set-up on v2**: event in full, calendar, alias, ticket options and variants, attachments, sections, costs, image uploads — `src/services/eventDetails.ts`, `src/services/setup.ts`; frontend `fetchEvent()` and `lib/eventSetup.ts`; v2 `file` and `upload` routes |
|
||||
| 1.51.7 | **Setting events up on v2** (`/events/manage`, create, `PATCH`, deactivate, copy-from, notify-recipients) via `src/services/events.ts`; `fetchManagedEvents()` for every picker; **pg-boss 11** in schema `pgboss_v11` |
|
||||
| 1.51.6 | Command palette lists every report (from `ReportCatalog`) and every dashboard page (e2e drift check); exceljs → ExcelTS 10 (`@cj-tech-master/excelts`, no dependencies; e2e `e2e/excel.spec.ts`); backend `engines.node` >= 22 |
|
||||
| 1.51.5 | **Next.js 16** and React 19.3 (Turbopack), **ESLint 10** with Next 16's flat configs (`npm run lint` = `eslint src`); React Compiler-era rules as warnings for now; empty `middleware.ts` removed |
|
||||
| 1.51.4 | **Security and dependency updates**: Next.js 15.5.28, @sentry/nextjs, zod, multer, nodemailer and others for published advisories; minimum versions raised in package.json; cron-parser 5 |
|
||||
| 1.51.3 | **Express 5** (qs query parser and `req.body = {}` kept); scanner and at-the-door on v2 check-in; shared middleware answers v2-shaped on `/api/v2` (`legacyErrorsToV2`, `reason`); v1 `Deprecation` + `successor-version` headers (`src/v2/deprecation.ts`) |
|
||||
| 1.51.2 | **v2 accounts and check-in**: signup, login (+ code step), `PATCH /me`; check-in look-up and scan with `outcome`s. `src/services/auth.ts` (from userController) and `src/services/checkin.ts` (from ticketController); login/signup/profile pages on v2 |
|
||||
| 1.51.1 | **v2 registrations and payments**: register, get, cancel, checkout; create/cancel moved to `src/services/registrations.ts`, online checkout to `src/services/payments.ts` (v1 uses them too); typed frontend calls (`apiV2`, `npm run api:types`); register page, Pay now and My Events cancel on v2 |
|
||||
| 1.51.0 | **TypeScript backend + `/api/v2` foundations** (§14): tsconfig (`allowJs`), build to `dist/`, launcher `src/index.js` → `src/app.js`; v2 route declarations with zod → validation, response stripping and OpenAPI 3.1 at `/docs/v2`; first endpoints events, event, me, my registrations. Tests `tests/v2.test.ts`, e2e `e2e/api-v2.spec.ts` |
|
||||
| 1.50.2 | Searchable **event picker** (`components/shared/EventPicker.tsx`) on staff/supervisor pages and the kiosk; searchable reports events list; **How webhooks work** guide on Site settings → Webhooks (examples from `EVENT_TYPES[].example`). e2e `e2e/event-picker.spec.ts` |
|
||||
| 1.50.1 | Long lists: audit-log search/role filter/all actions and inclusive To date, data-request search and paging, webhook-delivery status filter and Load older, supervisor Payments loads only what it needs (`unpaid`, `userId`, `from`, `donations` filters). `components/shared/Pager.tsx`; e2e `e2e/long-lists.spec.ts` |
|
||||
@@ -44,9 +46,9 @@ encrypted settings unreadable or break existing installs.
|
||||
| 1.47.2 | **Series: year on year** report (§6 part 3): `GET /api/series/:id/compare` (`compareSeries` in `utils/series.js`), report `seriesComparison` in `ReportsV2`, "Compare" on the Event series page |
|
||||
| 1.47.1 | **Event series** (§6 part 2): Event series page, Series box on events, public `/series/<slug>`, "Next in this series", follow (News & announcements email from the `series` job when a new event goes live). Migration `20261028140000_event_series` |
|
||||
| 1.47.0 | **Copy an event** (§6 part 1): "Copy" opens the event editor filled in from the source (campus, sessions, options, tiers, sections, form, recipients, feedback, certificates); "New start" moves every date; allocation groups and (admins) costs copied by `POST /api/events/:id/copy-from`. No registrations, coupons, attachments, kids check-in or volunteer roles |
|
||||
| 1.46.0 | **Volunteer rosters** (§5): serving roles per event or session, anyone signs up (or supervisors assign), day-before reminders, "can't make it" swaps that happen on accept (notify recipients emailed), self check-in with the event's QR code or by staff, kids-room roles count as leaders on duty, free volunteer ticket off by default, roster sheet and hours served. Also fixes the 1.45.0 kids ticket being offered publicly |
|
||||
| 1.46.1 | Removed the Gitea CI workflow (no runner): test, lint and deploy by hand |
|
||||
| 1.46.2 | Licence page: what's new (from WHATS-NEW.md via the Hub), withdraw update request, "Not now", urgent updates, provider notices banner (Hub 1.4.0: releases from git tags, Notices page) |
|
||||
| 1.46.1 | Removed the Gitea CI workflow (no runner): test, lint and deploy by hand |
|
||||
| 1.46.0 | **Volunteer rosters** (§5): serving roles per event or session, anyone signs up (or supervisors assign), day-before reminders, "can't make it" swaps that happen on accept (notify recipients emailed), self check-in with the event's QR code or by staff, kids-room roles count as leaders on duty, free volunteer ticket off by default, roster sheet and hours served. Also fixes the 1.45.0 kids ticket being offered publicly |
|
||||
| 1.45.1 | Privacy notice (built-in text) and terms of use brought up to date with kids check-in, sessions, certificates, campuses, the Hub heartbeat and where data is stored. Installs with a published notice must publish a new version themselves |
|
||||
| 1.45.0 | **Kids check-in** (§4), fully digital: families/children/authorised adults kept between events (My account → Kids), staff desk with pickup codes and a "write on the sticker" panel, rooms with age ranges and ratios, room screen (on duty, call parent, alerts), check-out by code (wrong code alerts, override with reason), offline desk with reserved codes, attendance through a free kids ticket; 6-month retention rule for children |
|
||||
| 1.44.0 | **Campus-scoped staff** (§12 part 2): Admin → Users "Limit to campuses"; `utils/campusScope.js` on every staff/supervisor route (and owner-or-staff routes), lists filtered, scanner names the other campus, church-wide events view/scan/door-only for scoped staff; route test `tests/campusScopeRoutes.test.js` |
|
||||
@@ -60,10 +62,6 @@ encrypted settings unreadable or break existing installs.
|
||||
| 1.40.0 | POPIA toolkit part 3 — readiness checklist with score, retention policies + nightly `retention` job (inactive accounts anonymised after 5 years with a 30-day warning, on by default), breach register with notification drafts, children's/medical flag in the access log, `{retention}` in the notice |
|
||||
| 1.39.0 | POPIA toolkit part 2 — Admin → Privacy: privacy notice editor (built-in text as the start, placeholders, drafts, numbered versions, re-acceptance after login), operator register, consent log, access log; Information Officer on the contact page |
|
||||
| 1.38.0 | POPIA toolkit part 1 — Privacy page (news opt-in + history, download my data, correction and deletion requests), Event update vs News & announcements on every bulk send, unsubscribe links + one-click headers, WhatsApp STOP, one-time news question, Admin → Data requests, thorough anonymising |
|
||||
| 1.32.0 | Early-bird ribbon on event cards |
|
||||
| 1.33.0 | Multi-day events phase A — sessions, late joining + late pricing, per-session check-in, attendance register, session reminders, certificates (4 templates, verify page) |
|
||||
| 1.34.0 | Background jobs on pg-boss (admin Background jobs page), Playwright e2e tests, Gitea CI workflow, `scripts/deploy.sh` |
|
||||
| 1.35.0 | Multi-day events phase B — "pick sessions" (per-session tickets and prices, session capacity) |
|
||||
| 1.37.4 | Deploy script: no tag = latest main; per-install `ecosystem.config.js` out of git (`ecosystem.config.example.js`) |
|
||||
| 1.37.3 | Fix: the production build failed on unescaped quotes in a help text |
|
||||
| 1.37.2 | Payment status checks (PayFast transaction history; job every 15 min; Payments → Reconcile → Waiting for payment), PayFast Test connection |
|
||||
@@ -71,24 +69,37 @@ encrypted settings unreadable or break existing installs.
|
||||
| 1.37.0 | PayFast (signed form, ITN checks), `ProviderCheckout` with amount checks, the "Pay online" page (`/pay/<id>`) where payers choose a provider |
|
||||
| 1.36.0 | Payment provider interface (`backend/src/payments`) with Yoco behind it, `ProviderTransaction`, `Payment.provider`, Site settings → Payments (on/off and order per provider), R15 minimum |
|
||||
| 1.35.1 | Waitlist per session, session picker at the door, "All sessions" tickets let people tick sessions at one price; fixes (per-session stock limits, offline service worker serving stale scripts) |
|
||||
| 1.35.0 | Multi-day events phase B — "pick sessions" (per-session tickets and prices, session capacity) |
|
||||
| 1.34.0 | Background jobs on pg-boss (admin Background jobs page), Playwright e2e tests, Gitea CI workflow (removed in 1.46.1), `scripts/deploy.sh` |
|
||||
| 1.33.0 | Multi-day events phase A — sessions, late joining + late pricing, per-session check-in, attendance register, session reminders, certificates (4 templates, verify page) |
|
||||
| 1.32.0 | Early-bird ribbon on event cards |
|
||||
|
||||
## Next up
|
||||
|
||||
Hub 1.1.0 is deployed with update requests rolled out, and `scripts/install.sh` has been tried on
|
||||
a test server (both done 2026-10-28).
|
||||
|
||||
1. **2.0.0** — AI helpers, and v1 removed. Every endpoint is on v2 since 1.51.16. Keep
|
||||
answering the v1 webhook paths and the old links in sent messages (`src/v2/links.ts`) after
|
||||
v1 goes: providers and old emails still use them.
|
||||
2. **Servers run Node 24** (Joshua, 2026-10-29), so the backend may need Node 22+. Still to do:
|
||||
move from ExcelTS — deprecated in favour of `documonster` by the same author (pre-1.0 in Oct
|
||||
2026) — once documonster is stable. After 1.51.7 has run everywhere, the old `pgboss` schema
|
||||
can be dropped (`DROP SCHEMA pgboss CASCADE;`).
|
||||
Languages (Afrikaans, §10) are removed from scope (2026-10-28).
|
||||
2. AI rules decided 2026-10-29 (see §15 in the roadmap): the AI buttons show only when the
|
||||
licence's monthly cap is above R0, and are disabled (not hidden) once it's reached. The Hub
|
||||
charges the real cost plus a markup % (a default and a per-licence override) and counts the cap
|
||||
in charged rand. AI endpoints are `/api/v2` only.
|
||||
1. **2.0.0** — AI helpers (§15), v1 removed, a migration guide, and marketing site/docs for
|
||||
selling. Every endpoint is on v2 since 1.51.16. Keep answering the v1 webhook paths and the
|
||||
old links in sent messages (`src/v2/links.ts`) after v1 goes: providers and old emails still
|
||||
use them.
|
||||
2. **AI rules** (decided 2026-10-29, roadmap §15): the AI buttons show only when the licence's
|
||||
monthly cap is above R0, and are disabled (not hidden) once it's reached. The Hub charges the
|
||||
real cost plus a markup % (a default and a per-licence override) and counts the cap in charged
|
||||
rand. AI endpoints are `/api/v2` only. Check Claude Haiku 5.5's current prices before setting
|
||||
the markup and caps.
|
||||
3. **Clean-ups before or with 2.0:**
|
||||
- Turn the React Compiler lint rules back to errors (see [Next.js 16](#nextjs-16-1515)) — every
|
||||
screen is on v2 now, but they're still `warn` in `frontend/eslint.config.mjs`.
|
||||
- `node-fetch` is still listed in `backend/package.json` though nothing in `src/` uses it —
|
||||
remove it.
|
||||
- Password hashing upgrade with rehash-on-login (roadmap §14) isn't done: still `bcryptjs`.
|
||||
Decide whether it's in 2.0.
|
||||
4. **Later:** move from ExcelTS — deprecated in favour of `documonster` by the same author
|
||||
(pre-1.0 in Oct 2026) — once documonster is stable. After 1.51.7 has run everywhere, the old
|
||||
`pgboss` schema can be dropped (`DROP SCHEMA pgboss CASCADE;`).
|
||||
|
||||
Languages (Afrikaans, §10) and Wallet passes (§7) are removed from scope (2026-10-28).
|
||||
|
||||
## Working on this repo
|
||||
|
||||
@@ -176,8 +187,8 @@ a test server (both done 2026-10-28).
|
||||
up in its transaction history (`findPayments`); Yoco's Checkout API documents no lookup, so
|
||||
Yoco checkouts are "can't check". Tests: `backend/tests/paymentStatus.test.js`.
|
||||
- **Adding a provider:** write `providers/<id>.js` with the same interface, add it to
|
||||
`PROVIDERS` in `index.js`, mount `handleProviderWebhook('<id>')` at `/api/v2/webhooks/<id>` (in `src/v2/links.ts`; add the v1 path in `routes/webhookRoutes.js` only for providers already registered there)
|
||||
(`routes/webhookRoutes.js`), and give it a settings card in
|
||||
`PROVIDERS` in `index.js`, mount `handleProviderWebhook('<id>')` at `/api/v2/webhooks/<id>` (in `src/v2/links.ts`; add the v1 path in `routes/webhookRoutes.js` only for providers already registered there),
|
||||
and give it a settings card in
|
||||
`frontend/src/components/admin/PaymentsTab.tsx`. New providers start switched off.
|
||||
- `Payment.method` stays the wallet type (card, apple_pay…) because cashups bucket on it;
|
||||
the provider is `Payment.provider`.
|
||||
@@ -194,7 +205,8 @@ a test server (both done 2026-10-28).
|
||||
- Bulk sends: `broadcastController`, `whatsappBroadcastController`, and `emailEventAttendees` /
|
||||
`whatsappEventAttendees` in `eventController` take `kind`; scheduled payloads carry it.
|
||||
- WhatsApp STOP: `handleIncomingMessage` in `whatsappController.js` (WAWP `message` event on
|
||||
`/api/v2/webhooks/whatsapp?secret=…` — older set-ups use `/api/whatsapp/webhook`, which still works; secret in AppSetting `WAWP_WEBHOOK_SECRET`).
|
||||
`/api/v2/webhooks/whatsapp?secret=…` — older set-ups use `/api/whatsapp/webhook` or `/api/webhooks/whatsapp`, which run the same handler
|
||||
since 1.51.16; secret in AppSetting `WAWP_WEBHOOK_SECRET`).
|
||||
- Frontend: `app/dashboard/user/privacy`, `app/unsubscribe`, `app/dashboard/admin/data-requests`,
|
||||
`components/shared/NewsPrompt.tsx` (dashboard layout), `MessageKindPicker.tsx`.
|
||||
- **Anything new that stores personal data** must be added to `anonymiseUser` and
|
||||
@@ -467,7 +479,8 @@ a test server (both done 2026-10-28).
|
||||
- A list that grows for ever must page on the server (`page`/`limit`, `total`, `pages`) or load
|
||||
older items with a `before` cursor, and offer a search. `components/shared/Pager.tsx` renders
|
||||
"21–40 of 312 · Prev · Next". Already paged: users, registrations (Manage registrations), events,
|
||||
payments, audit log, consent/access logs, data requests, My payments.
|
||||
payments, audit log, consent/access logs, data requests, My payments. (Paths below are the v1
|
||||
names; each has a v2 successor in `SUCCESSORS`, `src/v2/deprecation.ts`.)
|
||||
- **Audit-log actions:** a new `AdminAuditAction` needs a label in `ACTION_LABELS`
|
||||
(`app/dashboard/admin/audit-log/page.tsx`) — the filter is built from that list.
|
||||
- **Still loading everything (fine for now, watch as installs grow):** user pickers that call
|
||||
@@ -548,8 +561,9 @@ a test server (both done 2026-10-28).
|
||||
- Turbopack for dev and build (the default). Lint with `npm run lint` / `npx eslint src` (`next lint`
|
||||
is gone). There's no middleware/proxy file — add `src/proxy.ts` (Next 16's name) only if needed.
|
||||
- **React Compiler lint rules are warnings, not errors** (`eslint.config.mjs`): 181 existing places,
|
||||
mostly `useEffect(() => { load(); }, [...])`. Fix them in a screen when it's moved onto v2
|
||||
(1.51.6 – 1.51.11), then turn the rules back to errors. Don't add new ones.
|
||||
mostly `useEffect(() => { load(); }, [...])`. The plan was to fix them as each screen moved onto
|
||||
v2; every screen is on v2 now (1.51.15) but the rules are still `warn` — fix what's left and turn
|
||||
them back to errors before or with 2.0. Don't add new ones.
|
||||
- `eslint-config-next` 16's bundled plugins (react, import, jsx-a11y) don't list ESLint 10 as a peer
|
||||
yet; they work, and npm notes the override. Revisit when they publish ESLint 10 support.
|
||||
|
||||
@@ -594,13 +608,14 @@ a test server (both done 2026-10-28).
|
||||
## Event picker and webhook guide (1.50.2)
|
||||
|
||||
- **Choosing an event:** use `EventPicker` (`components/shared/EventPicker.tsx`), not a `<select>`.
|
||||
Give it the whole list (`/api/events/all?includePast=true`); it opens on upcoming events, keeps
|
||||
Give it the whole list (`fetchManagedEvents(token, { past: true })`, v2 `GET /events/manage`
|
||||
since 1.51.7); it opens on upcoming events, keeps
|
||||
past ones behind "Show past events", and searches all of them. `emptyLabel` adds a clearable
|
||||
choice ("All events"), `graceHours` keeps just-ended events current (the scanner uses 12),
|
||||
`describe` adds detail per row, and `defaultEventId(events)` picks the next upcoming one. In e2e,
|
||||
`pickEvent(page, title)` from `e2e/fixtures.ts`.
|
||||
- `/api/events/all` still returns full events (options, form, sessions) — fine for a few hundred;
|
||||
a slim `?fields=` mode would help if a church gets into the thousands.
|
||||
- The managed events list still returns full events (options, form, sessions) — fine for a few
|
||||
hundred; a slim `?fields=` mode would help if a church gets into the thousands.
|
||||
- **Webhook examples:** a new webhook event type needs an entry in `EXAMPLES` in
|
||||
`utils/webhooks.js`; `tests/webhooks.test.js` fails if an example and `buildPayload` differ in
|
||||
shape.
|
||||
@@ -611,7 +626,6 @@ a test server (both done 2026-10-28).
|
||||
into WAWP (events `message` + `session.status`), and only for senders WhatsApp identifies by
|
||||
phone number — a sender known only by a "LID" is logged and ignored (they can still use the
|
||||
link in the message).
|
||||
- `/api/webhooks/whatsapp` runs the real WAWP handler since 1.51.16 (it was an empty stub).
|
||||
- There's no log of individual messages sent, so "Download my data" can't include "messages
|
||||
sent to you" yet.
|
||||
|
||||
|
||||
+40
-45
@@ -11,41 +11,35 @@ sold — trustworthy (POPIA), flexible (multi-day events, several payment
|
||||
providers), maintainable (tests, CI, typed backend, versioned API), and with
|
||||
**AI helpers** as the headline feature (§15).
|
||||
|
||||
**Status (2026-10-27):** all features in this document are approved. Shipped
|
||||
so far: 1.32.0 early-bird ribbon on event cards; 1.33.0 multi-day events
|
||||
phase A (sessions, late joining, per-session check-in, attendance register,
|
||||
reminders, certificates); 1.34.0 job queue (pg-boss), Playwright E2E tests, Gitea CI
|
||||
workflow (waiting for a runner) and deploy script; 1.35.0 multi-day events phase B
|
||||
(pick sessions, per-session capacity), with 1.35.1 adding the per-session waitlist, the session
|
||||
picker at the door and session choice on "All sessions" tickets; 1.36.0 payment provider interface
|
||||
(Yoco moved behind it, Site settings → Payments); 1.37.0 PayFast and the "Pay online" page;
|
||||
1.37.1 "Pay online" hidden when it can't be used; 1.37.2 payment status checks for missing
|
||||
notifications. SnapScan and Zapper are dropped — Yoco and PayFast are enough (2026-10-23);
|
||||
1.38.0 POPIA toolkit part 1 (privacy page, unsubscribe, WhatsApp STOP, data requests); 1.39.0 part 2 (privacy notice editor and versions, operator register, consent and access logs); 1.40.0 part 3 (retention policies and job, breach register, children’s-data flags, readiness page).
|
||||
1.41.0 the Hub connection (licence, heartbeat, read-only mode, `/health`, install script) with Hub 1.0.0 (`joshua/events-hub`);
|
||||
1.41.1–1.41.2 licence and job-time fixes; 1.41.3 renamed **Hope Events → Cross Events** (Hub 1.0.1:
|
||||
Cross Events Hub); 1.42.0 **Request update** button instead of the deploy command, with Hub 1.1.0
|
||||
(update requests); 1.42.1 the production Hub key built in. Later versions moved up by one
|
||||
(2026-10-27). Multi-campus is split in two — 1.43.0 campuses, 1.44.0 campus-scoped staff — so
|
||||
everything after moves up by one more (2026-10-27). 1.43.0 **campuses** shipped (settings, events
|
||||
per campus, public filter and campus pages, home campus, filters, campus broadcasts and summaries);
|
||||
1.44.0 **campus-scoped staff** shipped (Admin → Users "Limit to campuses", every staff route checked).
|
||||
Wallet passes are removed from scope (2026-10-28), so everything after volunteer rosters moves
|
||||
up by one. 1.45.0 **kids check-in** shipped (fully digital: pickup codes, sticker panel, rooms with
|
||||
ratios, offline desk). 1.46.0 **volunteer rosters** shipped (roles per event or session, sign-ups and
|
||||
assigning, swaps on accept, QR self check-in, kids-room roles on duty, optional volunteer ticket).
|
||||
Event series and cloning ships as 1.47.0–1.47.3 (2026-10-28); 1.47.0 **copy an event** and 1.47.1 **event series** (series page, Next in this series, follow) 1.47.2 **year-on-year
|
||||
report** and 1.47.3 **season passes** shipped — §6 is done. 1.48.0 **outbound webhooks** shipped. 1.49.0 **dashboard (Today, Waiting for you) and Ctrl+K palette**
|
||||
shipped; 1.49.1 **bulk actions** and 1.49.2 **saved filters** shipped — §9 is done. Languages
|
||||
(Afrikaans) are removed from scope (2026-10-28), so everything after moves up by one. 1.50.0 **accessibility
|
||||
pass** shipped. 1.50.1 **pagination and search on long lists** and 1.50.2 **event picker and webhook guide** shipped. 1.51.0 **TypeScript backend and `/api/v2`
|
||||
foundations**, 1.51.1 **v2 registrations and payments**, 1.51.2 **v2 accounts and check-in** and 1.51.3 **Express 5,
|
||||
scanner on v2, v1 deprecation headers** shipped. 1.51.4 **security and dependency updates**, 1.51.5 **Next.js 16** and 1.51.6 **the complete command palette and
|
||||
ExcelTS** , 1.51.7 **setting events up on v2, pg-boss 11** and 1.51.8 **the rest of event set-up on v2** and 1.51.9
|
||||
**series, passes, deals and campuses on v2** 1.51.10 **managing registrations on v2**, 1.51.11 **money on v2** and 1.51.12 **tickets and
|
||||
attendance on v2** 1.51.13 **kids and volunteers on v2**, 1.51.14 **people and messaging on v2** and 1.51.15
|
||||
**privacy and admin on v2** and 1.51.16 **incoming webhooks and links on v2** shipped — every
|
||||
endpoint is on v2. **Next: 2.0.0.**
|
||||
**Status (2026-10-30):** all features in this document are approved, and everything before 2.0.0
|
||||
has shipped (1.32.0 – 1.51.17). **Next: 2.0.0** — AI helpers (§15) and v1 removed. The full
|
||||
version list is in [HANDOVER.md](./HANDOVER.md) and the [build order](#suggested-build-order) below.
|
||||
|
||||
- **Multi-day events** (§1): 1.33.0 phase A (sessions, late joining, per-session check-in,
|
||||
attendance register, reminders, certificates); 1.35.0 phase B (pick sessions, per-session
|
||||
capacity); 1.35.1 per-session waitlist, session picker at the door.
|
||||
- **Platform:** 1.34.0 job queue (pg-boss), Playwright E2E tests and deploy script (the Gitea CI
|
||||
workflow was removed in 1.46.1 — no runner).
|
||||
- **Payments** (§2): 1.36.0 provider interface (Yoco behind it); 1.37.0 – 1.37.2 PayFast, "Pay
|
||||
online", payment status checks. SnapScan and Zapper dropped (2026-10-23).
|
||||
- **POPIA toolkit** (§3): 1.38.0 – 1.40.0.
|
||||
- **Hub** (§13): 1.41.0 connection (licence, heartbeat, read-only mode, `/health`, install
|
||||
script) with Hub 1.0.0; 1.41.3 renamed **Hope Events → Cross Events**; 1.42.0 **Request
|
||||
update** with Hub 1.1.0; 1.42.1 production Hub key built in.
|
||||
- **Multi-campus** (§12): 1.43.0 campuses; 1.44.0 campus-scoped staff.
|
||||
- **Kids check-in** (§4) 1.45.0; **volunteer rosters** (§5) 1.46.0.
|
||||
- **Event series and cloning** (§6): 1.47.0 copy an event, 1.47.1 series, 1.47.2 year-on-year
|
||||
report, 1.47.3 season passes.
|
||||
- **Outbound webhooks** (§8) 1.48.0.
|
||||
- **Dashboard, palette, bulk actions, saved filters** (§9): 1.49.0 – 1.49.2.
|
||||
- **Accessibility** (§11) 1.50.0; 1.50.1 long lists; 1.50.2 event picker and webhook guide.
|
||||
- **TypeScript backend and `/api/v2`** (§14): 1.51.0 – 1.51.3 foundations, registrations and
|
||||
payments, accounts and check-in, Express 5; 1.51.4 security and dependency updates; 1.51.5
|
||||
Next.js 16; 1.51.6 command palette and ExcelTS; 1.51.7 – 1.51.16 every remaining area on v2 —
|
||||
**every endpoint is on v2**.
|
||||
- 1.51.17 security fix: forgot password and sign-in don't reveal whether an account exists.
|
||||
|
||||
Removed from scope (2026-10-28): Wallet passes (§7) and languages (§10).
|
||||
|
||||
**Repositories:**
|
||||
|
||||
@@ -833,13 +827,13 @@ keep adding to.
|
||||
|
||||
| Item | What |
|
||||
|------|------|
|
||||
| CI (Gitea Actions) | Lint, typecheck, Jest, build on every push; deploy on tag |
|
||||
| Playwright E2E | Register → pay (sandbox) → ticket → scan → cashup; multi-day check-in; kiosk |
|
||||
| Job queue | Move `setInterval` jobs out of `index.js` into `pg-boss` (uses Postgres): retries, no double runs, job history in admin |
|
||||
| Split big controllers | `registrationController` (2.3k lines), `eventController`, `paymentController` → services by domain. Done **as each feature touches them**, not as a big-bang rewrite |
|
||||
| TypeScript backend | Incremental (`allowJs`), new code in TS first; share zod schemas/types with the frontend |
|
||||
| API v2 | `/api/v2` with consistent errors, pagination and an OpenAPI spec (replaces the hand-written API docs). `/api` (v1) kept during the transition |
|
||||
| Dependencies | Express 5, native `fetch` instead of `node-fetch`, password hashing upgrade with rehash-on-login |
|
||||
| ~~CI (Gitea Actions)~~ | Added in 1.34.0, **removed in 1.46.1** (no machine to run a runner): lint, tests and deploy are done by hand |
|
||||
| Playwright E2E ✅ | Register → pay (sandbox) → ticket → scan → cashup; multi-day check-in; kiosk (1.34.0) |
|
||||
| Job queue ✅ | Move `setInterval` jobs out of `index.js` into `pg-boss` (uses Postgres): retries, no double runs, job history in admin (1.34.0; pg-boss 11 in 1.51.7) |
|
||||
| Split big controllers | `registrationController` (2.3k lines), `eventController`, `paymentController` → services by domain. Done **as each feature touches them**, not as a big-bang rewrite. Partly done (1.51.1 – 1.51.10); the handlers behind `v1Route` are a 2.x clean-up |
|
||||
| TypeScript backend ✅ | Incremental (`allowJs`), new code in TS first; share zod schemas/types with the frontend (1.51.0) |
|
||||
| API v2 ✅ | `/api/v2` with consistent errors, pagination and an OpenAPI spec (replaces the hand-written API docs). `/api` (v1) kept during the transition; every endpoint on v2 since 1.51.16 |
|
||||
| Dependencies | Express 5 ✅ (1.51.3); native `fetch` ✅ (nothing uses `node-fetch` any more — it's still in `backend/package.json`, to remove); password hashing upgrade with rehash-on-login — **not done** (still `bcryptjs`), decide whether it's in 2.0 |
|
||||
|
||||
---
|
||||
|
||||
@@ -868,7 +862,8 @@ never saves, sends or publishes by itself.
|
||||
|
||||
- **One provider: Claude (Anthropic), model Claude Haiku 5.5** — the cheapest
|
||||
current model ($0.10 per million input tokens, $0.50 per million output, for
|
||||
prompts under 100K tokens; prices as of 2026-10). Good enough for drafting and
|
||||
prompts under 100K tokens; prices as of 2026-10 — **check them against Anthropic's pricing
|
||||
page before setting the markup and caps**). Good enough for drafting and
|
||||
summarising; a helper can move to a bigger model later if quality needs it.
|
||||
- **Rough cost:** a helper call is ~2,000–10,000 tokens in and ~500 out, so well under
|
||||
US$0.002 per click — about R1.50–R3 per thousand clicks. Fixed instructions are
|
||||
@@ -1004,7 +999,7 @@ income justify the hardware:
|
||||
|-------|---------|----------|-----|
|
||||
| 0 | 1.32.0 ✅ | **Early-bird ribbon** on event cards (shipped 2026-10-22) | Quick win |
|
||||
| 1 | 1.33.0 ✅ | **Multi-day events — phase A** (sessions, whole-course tickets, late joining + late pricing, per-session check-in with whole-day window, attendance register, optional reminders, certificates) | Requested first; touches registration/tickets/scanning, so it shapes later work |
|
||||
| 2 | 1.34.0 ✅ | CI + Playwright E2E + job queue | Safety net before the riskiest work (payments). Session reminders move to the queue |
|
||||
| 2 | 1.34.0 ✅ | CI (removed in 1.46.1) + Playwright E2E + job queue | Safety net before the riskiest work (payments). Session reminders move to the queue |
|
||||
| 3 | 1.35.0 ✅ | Multi-day events — phase B (pick sessions, per-session capacity) | Builds on phase A, now with E2E coverage |
|
||||
| 4 | 1.36.0 ✅ – 1.37.2 | Payment provider interface (Yoco moved behind it) → PayFast, then hiding "Pay online" when it can't be used and payment status checks (SnapScan and Zapper dropped) | Payment code gets split out of the big controller as part of this |
|
||||
| 5 | 1.38.0 ✅ 1.39.0 ✅ 1.40.0 ✅ | **POPIA toolkit** (1.38.0: user privacy centre, unsubscribe, WhatsApp STOP, data requests inbox; 1.39.0: privacy notice editor + versions, operator register, consent log, access log; 1.40.0: retention jobs, breach register, children’s-data flags, readiness page) | Main selling point; retention jobs use the job queue |
|
||||
@@ -1014,7 +1009,7 @@ income justify the hardware:
|
||||
| 9 | 1.47.0 ✅ – 1.47.3 ✅, 1.48.0 ✅ | Event series & cloning (1.47.0 clone, 1.47.1 series, 1.47.2 year-on-year reports, 1.47.3 season pass), Outbound webhooks (Wallet passes removed from scope) | Smaller, independent wins |
|
||||
| 10 | 1.49.0 ✅ – 1.49.2 ✅, 1.50.0 ✅, 1.50.1 ✅, 1.50.2 ✅ | Admin dashboard/Ctrl+K/bulk actions/saved filters, Accessibility pass, pagination and search on long lists, event picker and webhook guide (Afrikaans removed from scope) | Polish before the big release |
|
||||
| 11 | 1.51.0 ✅, 1.51.1 ✅, 1.51.2 ✅, 1.51.3 ✅ | TypeScript backend + OpenAPI + `/api/v2` alongside v1: 1.51.0 foundations (build, launcher, route declarations, errors, paging, OpenAPI at `/docs/v2`, first read endpoints); 1.51.1 registrations and payments as TS services, typed frontend calls; 1.51.2 check-in and accounts; 1.51.3 Express 5, the scanner on v2, v1 deprecation headers, v2-shaped shared middleware | The breaking-change groundwork |
|
||||
| 11b | 1.51.4 ✅ – 1.51.16 ✅ | **Every endpoint on v2 before 2.0** (decided 2026-10-29): 1.51.4 dependency audit and Node 24 LTS; 1.51.5 Next.js 16 and ESLint 10 (ESLint 9 is out of support); 1.51.6 the complete command palette and ExcelTS instead of exceljs; 1.51.7 setting events up (the staff list, create, change, deactivate, copy-from, notification recipients) and pg-boss 11; 1.51.8 the rest of event set-up (the event in full, ticket options and variants, attachments, sections, costs, uploads, calendar file, alias); 1.51.9 series, season passes, bundles, coupons and campuses; 1.51.10 managing registrations (the staff lists, status, at the door, bulk actions, items, coupons, attendees, attendee forms); 1.51.11 money, staff side (payments, cashup, provider transactions, waitlist, sponsorship, consent, form builder, feedback); 1.51.12 tickets and attendance, staff side (tickets, scan locks, attendance, allocations); 1.51.13 kids check-in and volunteer rosters; 1.51.14 people and messaging (users, WhatsApp, broadcasts, scheduled emails, automations, banner, saved filters, dashboard, stats, analytics, reports); 1.51.15 privacy and admin (privacy, admin, settings, setup, Hub, outbound webhooks, backups); 1.51.16 **incoming webhooks and links in sent messages**: Yoco, PayFast and WAWP webhooks and the links in emails and WhatsApp (unsubscribe, consent, ticket transfer, calendar feeds, waitlist offers) get v2 URLs — new messages and provider registrations use them, and the v1 paths keep answering (links by a 308 redirect to v2, provider webhooks handled by the same code, since providers may not follow a redirect on a POST). Each puts its area's endpoints on v2 (1.51.1 – 1.51.10 by moving the logic into TS services; from 1.51.11 by `v1Route`, which runs the v1 handler behind a v2 route — moving those handlers into TS services is a 2.x clean-up that doesn't change the API), its screens onto `apiV2`, and its v1 routes into `SUCCESSORS` | 2.0 can then remove v1 |
|
||||
| 11b | 1.51.4 ✅ – 1.51.16 ✅ | **Every endpoint on v2 before 2.0** (decided 2026-10-29): 1.51.4 dependency audit and Node 24 LTS; 1.51.5 Next.js 16 and ESLint 10 (ESLint 9 is out of support); 1.51.6 the complete command palette and ExcelTS instead of exceljs; 1.51.7 setting events up (the staff list, create, change, deactivate, copy-from, notification recipients) and pg-boss 11; 1.51.8 the rest of event set-up (the event in full, ticket options and variants, attachments, sections, costs, uploads, calendar file, alias); 1.51.9 series, season passes, bundles, coupons and campuses; 1.51.10 managing registrations (the staff lists, status, at the door, bulk actions, items, coupons, attendees, attendee forms); 1.51.11 money, staff side (payments, cashup, provider transactions, waitlist, sponsorship, consent, form builder, feedback); 1.51.12 tickets and attendance, staff side (tickets, scan locks, attendance, allocations); 1.51.13 kids check-in and volunteer rosters; 1.51.14 people and messaging (users, WhatsApp, broadcasts, scheduled emails, automations, banner, saved filters, dashboard, stats, analytics, reports); 1.51.15 privacy and admin (privacy, admin, settings, setup, Hub, outbound webhooks, backups); 1.51.16 **incoming webhooks and links in sent messages**: Yoco, PayFast and WAWP webhooks and the links in emails and WhatsApp (unsubscribe, consent, ticket transfer, calendar feeds, waitlist offers) get v2 URLs — new messages and provider registrations use them, and the v1 paths keep answering (links by a 308 redirect to v2, provider webhooks handled by the same code, since providers may not follow a redirect on a POST). Each puts its area's endpoints on v2 (1.51.1 – 1.51.10 by moving the logic into TS services; from 1.51.11 by `v1Route`, which runs the v1 handler behind a v2 route — moving those handlers into TS services is a 2.x clean-up that doesn't change the API), its screens onto `apiV2`, and its v1 routes into `SUCCESSORS`. Then 1.51.17, a security fix (forgot password and sign-in don't reveal accounts) | 2.0 can then remove v1 |
|
||||
| 12 | **2.0.0** | **AI helpers** (§15 — headline feature: draft an event, summarise reports and feedback, draft messages, improve text; through the Hub with a rand cap per licence), v1 removed (all of it is on v2 by then; the old webhook URLs and links already sent in messages keep forwarding to v2), migration guide, marketing site/docs for selling | The release. AI needs the Hub (phase 6) for the key, metering and caps |
|
||||
|
||||
Each phase should add matching help content (`frontend/src/content/help/`),
|
||||
|
||||
Reference in New Issue
Block a user