Files
hope-events/docs/HANDOVER.md
T
joshuaandClaude Opus 5.5 4bc7dbc989
CI / Backend tests (push) Canceled after 0s
CI / Frontend lint, typecheck, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
CI / Deploy tagged release (push) Canceled after 0s
Bump to 1.37.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 15:05:01 +02:00

111 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Handover — where things stand and how to carry on
Last updated: 2026-10-23, after **1.37.1**. The plan itself is in
[ROADMAP-v2.md](./ROADMAP-v2.md) (decisions table at the end); the previous round of
features is in [FEATURES-ROUND-1.md](./FEATURES-ROUND-1.md).
## Done so far (road to 2.0)
| Version | What |
|---------|------|
| 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.1 | "Pay online" hidden when no provider is on or under R15; SnapScan/Zapper dropped from the roadmap |
| 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) |
## Next up
1. **1.37.2 — payment status checks** for notifications that never arrive (see the
roadmap's payment edge cases).
2. **1.38.0–1.39.0 — POPIA toolkit** (spec §3 in the roadmap).
3. **1.40.0 + Hub v1** — install/update tooling and the Hope Events Hub (separate repo
`joshua/hope-events-hub`).
## Working on this repo
- **Release routine:** branch `feat/<name>` → commit → bump with
`npm version X.Y.Z --no-git-tag-version` in `.`, `backend` and `frontend` → add the
`## [X.Y.Z] - date` heading under `[Unreleased]` in CHANGELOG.md → `git merge --no-ff`
into `main` → `git tag vX.Y.Z` → `git push origin main <branch> vX.Y.Z`. One minor
version per feature.
- **Changelog:** add entries to `[Unreleased]` as you go, in plain language.
- **Docs to keep in step:** CHANGELOG.md, FEATURES.md, README.md, SETTINGS.md,
backend/API_DOCUMENTATION.md, the `/docs` route list in `backend/src/index.js`, and
in-app help in `frontend/src/content/help/` (register new pages in `registry.ts`).
- **Prisma migrations:** `npx prisma migrate dev --create-only --name x` against a local
DB. Prisma 7 keeps adding an unrelated `_EventNotifyRecipients` primary-key/index
change — delete those two blocks from the generated SQL. It also rewrites the comment
in `migration_lock.toml`; `git checkout` that file back. New `AdminAuditAction` values
need a migration.
- **Server Node version:** the deployment notes install Node 20, so dependencies must
support Node 20 (that's why pg-boss is pinned to 10.x).
- **Pushing:** pushing from some shells fails with "Failed to authenticate user" (a stale
saved credential); pushing from your own terminal works.
## Tests
- Backend unit tests: `cd backend && npm test` (Jest).
- PayFast e2e (`e2e/payfast.spec.ts`) pays into a real PayFast sandbox account and is skipped
unless `E2E_PAYFAST_MERCHANT_ID`, `E2E_PAYFAST_MERCHANT_KEY` and `E2E_PAYFAST_PASSPHRASE` are
set (from the Sandbox dashboard). PayFast's documented public test merchant (10000100) no
longer accepts payments. ITNs can't reach localhost; they're covered by unit tests
(`backend/tests/payments.test.js`) — to try one for real, use a tunnel, a public
`BACKEND_URL` and `PAYFAST_SKIP_IP_CHECK=true`.
- End-to-end: `npm run test:e2e` from the repo root (first time: `npm install` and
`npx playwright install chromium`). They start their own backend (5100) and
frontend (3100) against `<your DATABASE_URL database>_e2e`, which is dropped and
re-seeded every run (`e2e/support/prepare-db.js`). The DB user must be able to
create databases. ~5 minutes in dev mode.
Locally, Playwright reuses servers already running on 5100/3100. If the run times out
waiting for the frontend (the home page returns 500 until the e2e backend is up), start
them yourself — `node e2e/support/prepare-db.js`, then the backend from `backend/`
with `PORT=5100`, the e2e `DATABASE_URL`, `JOBS_ENABLED=false`,
`TWO_FACTOR_REQUIRED_ROLES=false`, and `npx next dev -p 3100` from `frontend/` with
`NEXT_DIST_DIR=.next-e2e NEXT_PUBLIC_API_URL=http://localhost:5100` — then run
`npx playwright test`. Don't edit frontend files while it runs.
- **Careful with ad-hoc scripts against a dev/test database that has SMTP set up:**
registrations and check-ins send real email/WhatsApp. Use made-up `@test.local`
people only.
- CI: `.gitea/workflows/ci.yml` runs everything once a Gitea Actions runner is
registered (none yet). Tag deploys need the `DEPLOY_HOST`, `DEPLOY_USER`,
`DEPLOY_SSH_KEY` (+ optional `DEPLOY_PATH`) secrets.
## Where the multi-day code lives
- `backend/src/utils/sessions.js` — all session rules (dates, check-in window, late
pricing, pick sessions, capacity, grouping); unit tests in `backend/tests/sessions.test.js`.
- `backend/src/utils/certificates.js`, `sessionReminders.js`,
`controllers/attendanceController.js` (register + certificates API).
- `backend/src/jobs/index.js` — the background job registry.
- Frontend: `src/lib/sessions.ts`, `src/components/events/ScheduleEditor.tsx`,
`SessionPicker.tsx`, `SessionSchedule.tsx`, `src/app/dashboard/supervisor/attendance/`.
## Where the payment code lives
- `backend/src/payments/index.js` — the provider registry and the `PaymentProvider` interface
(documented at the top), provider on/off and order (AppSetting `payment_providers`), the R15
minimum, and `createCheckout`. Tests: `backend/tests/payments.test.js`.
- `backend/src/payments/providers/yoco.js` — Yoco: checkouts, webhook signature check, webhook
parsing. Keys/webhook admin stays in `utils/yoco.js` + `controllers/yocoController.js`.
- `backend/src/payments/webhook.js` — shared webhook processing (Payment with `provider`,
donation split, registration status, tickets, emails, `ProviderTransaction`).
- `backend/src/payments/checkouts.js` — registration checkouts (balance, part, + donation).
- **Adding a provider:** write `providers/<id>.js` with the same interface, add it to
`PROVIDERS` in `index.js`, mount `handleProviderWebhook('<id>')` at `/api/webhooks/<id>`
(`routes/webhookRoutes.js`), 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`.
## Known gaps / follow-ups
- At the door, per-session tickets are booked on new registrations only; editing an
existing registration leaves its booked sessions as they are (the backend refuses
changes to picked lines). "Add & charge" for a session at the scanner isn't built.
- Ticket scanning by camera isn't covered by the e2e tests (headless browsers have no
camera); scans are tested through the API.