Files
hope-events/FEATURES.md
T
joshuaandClaude Opus 5.5 1516e104df Add rooms & groups allocation
Supervisors can split an event's named attendees into allocation sets
(rooms, small groups, buses) with capacity, gender and leader per group,
using a drag-and-drop board or auto-allocate (keep bookings together or
split them). Adds printable group and master lists (medical view
audited), the group on tickets and in My Events, messaging by group,
a "My groups" page for leaders, and an optional per-event gender
question for named attendees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:44:58 +02:00

503 lines
26 KiB
Markdown

# Hope Events — Feature Overview
A complete map of what the platform does, grouped by who uses it. For setup and
deployment see [README.md](./README.md); for the API see
[backend/API_DOCUMENTATION.md](./backend/API_DOCUMENTATION.md); for setting
defaults see [SETTINGS.md](./SETTINGS.md); for history see
[CHANGELOG.md](./CHANGELOG.md).
**Stack:** Next.js (React, Tailwind, shadcn/ui) frontend · Express + Prisma +
PostgreSQL backend · Yoco for card payments · SMTP for email · WAWP for
WhatsApp · PM2 for process management · optional Sentry for error monitoring.
---
## Contents
1. [Roles](#roles)
2. [Public site](#public-site)
3. [Events](#events)
4. [Registration](#registration)
5. [Payments, donations & refunds](#payments-donations--refunds)
6. [Tickets & check-in](#tickets--check-in)
7. [Attendee forms](#attendee-forms)
8. [Messaging & notifications](#messaging--notifications)
9. [User dashboard (My Events)](#user-dashboard-my-events)
10. [Staff tools](#staff-tools)
11. [Supervisor tools](#supervisor-tools)
12. [Admin tools](#admin-tools)
13. [Cashup & event costs](#cashup--event-costs)
14. [Reports](#reports)
15. [Site settings & setup wizard](#site-settings--setup-wizard)
16. [Accounts & security](#accounts--security)
17. [Help system](#help-system)
18. [Background jobs](#background-jobs)
19. [Operations](#operations)
20. [Page map](#page-map)
---
## Roles
Four roles, each including everything the roles below it can do:
| Role | Can do |
|------|--------|
| **User** | Browse events, register, pay, donate, view tickets, fill in forms, manage their own profile |
| **Staff** | Scan tickets, view/print event tickets, view registrations and form responses |
| **Supervisor** | Create and manage events, record payments/refunds, assign donations, at-the-door desk, manual registration, bulk email/WhatsApp, reports, site banner, self-service kiosk |
| **Admin** | Manage users and roles, all registrations, event costs and cashup (close/reopen events), audit log, site settings, WhatsApp connection, backups |
---
## Public site
- **Home page** — hero section with the organisation's name and branding, upcoming
and in-progress events, and a "Join Us" button (becomes "My Dashboard" when
logged in).
- **Events list** (`/events`) — event cards with picture, dates, location,
price, and a Register / Sold Out / Contact us button.
- **Event detail** (`/events/[id]`) — description, ticket options with
variant and early-bird pricing, low-stock and sold-out badges, downloadable
attachments, embedded Google Map with "Directions" link, and an
**Add to calendar** (`.ics`) button.
- **Short links** — events can have an alias (e.g. `/camp-2025`) that redirects
to the event. Only plausible aliases hit the database, so bot probes are
rejected cheaply.
- **Contact page** (`/contact`) — organisation email, phone, address and map.
- **Legal pages** — Terms of Use and Privacy Policy, filled from Site Settings.
- **Site banner** — a site-wide announcement bar set by supervisors.
- **Lockdown rules** (`/lockdown-rules`) — static rules page for the youth
lockdown event.
- **SEO** — `sitemap.xml` (every public page and event), `robots.txt`, and
Open Graph/Twitter link-preview metadata.
- **Theming** — brand colours, logo and favicon come from Site Settings.
---
## Events
Created and edited by supervisors through a 6-step wizard: **Basic Details →
Items & Pricing → Sections → Form → Visibility → Attachments**.
- **Basic details** — title, description, start/end dates, registration
deadline, picture (upload or URL), location (defaults to the org's address),
contact person.
- **Contact-only events** — for things like baptisms: shown publicly with a
"Contact us" popup instead of registration, with no tickets.
- **Ticket options** — multiple options per event (e.g. Adult, Child, Dinner,
T-shirt), each with a price and optional **stock limit**. One option is marked
as the main ticket, which is what gets checked in at the door.
- **Variants** — sub-types of an option (sizes, colours, Adult/Child/VIP), each
with an optional price override and its own stock limit.
- **Early-bird tiers** — deadline- and/or stock-limited cheaper prices per
option or variant. Prices are locked in per purchase ("tranches"), so buying
more later doesn't re-price what was already bought.
- **Sections** — named scan points (e.g. "Main hall", "Dinner") limited to
certain ticket options, so a scanner at that point only accepts those tickets.
- **Visibility** — active/inactive, hidden (reachable only by link), scheduled
go-live date, require login vs. allow guest registration, or no registration
at all.
- **Attachments** — downloadable files (maps, schedules, waivers) shown on the
event page.
- **Notify recipients** — choose which staff get registration/payment alerts and
the daily summary for the event.
- **Sold-out handling** — an event is sold out when every stock-limited option
is exhausted. "X remaining" badges appear at a threshold that scales with
capacity.
---
## Registration
- **Online registration** (`/register/[eventId]`) — pick options, variants and
quantities; see early-bird prices and stock warnings; fill in the event form.
- **Guest registration** — when an event doesn't require login, an inactive
account is created and an activation link is sent by email or WhatsApp.
- **Statuses** — Pending, Confirmed, Partially Paid, Paid, Cancelled.
- **Edit options** — users can add or change items on their registration
(not for past or closed events).
- **Self-cancellation** — allowed only before any payment; admins can cancel
any time.
- **Pricing refresh** — when an unpaid registration is viewed or paid, expired
early-bird prices are re-evaluated, and the user is warned if the total
changed.
- **Manual registration** (supervisor) — register someone on their behalf,
creating an account if needed. Includes a "Record Payment" tab.
- **Duplicate-account protection** — if an email and phone belong to two
different accounts, the registration is blocked instead of merging them.
- **Group tickets** — on events with "Named attendees" turned on, someone booking
several places can name each person (with optional email/phone). Each named person
gets their own ticket and their own attendee form; unnamed places share one ticket.
Tickets go all to the payer, or each to the person (falling back to the payer).
Attendees matching an existing account see their ticket in My Events. Names can be
added or changed later from My Events, and attendees can be sent a link to fill in
their own form. Available on the registration page, manual registration, At the
door and the kiosk.
- **Waitlist** — on events with a waitlist, sold-out tickets show "Join waitlist"
(on the event page, the register page and the event list). When places free up — a
cancellation, a smaller booking or a higher stock limit — the next person is
emailed/WhatsApped a claim link and the places are held for them (24 hours by
default) so nobody else can buy them. Unclaimed offers expire and move on; people
who asked for more than came free can be offered what's free or skipped. Claiming
works without logging in. People can leave from My Events.
- **Parental consent (youth events)** — on events that require it, every attendee
gives a date of birth; for anyone under 18, a parent or guardian gets an email and
a WhatsApp with a consent link. They read the event's consent text, optionally give
medical info, an emergency contact and photo consent, type their name to sign, and
give or decline. Tickets are issued but can't be checked in until consent is given
(supervisors can override, audited). Reminders go after 2 days, then every 3 days.
Medical details are encrypted and deleted a set number of days after the event.
- **Coupon codes** — percentage, fixed-amount or free (comp) codes, entered under
"Have a code?" on the registration page, in My Events (for unpaid registrations),
manual registration, At the door and the kiosk. Codes can be limited to events,
ticket options or variants, dates, total and per-person uses, a minimum quantity,
and specific people, roles or an email domain (restricted codes need a login).
Early-bird prices either stack or the better price wins. The discount is locked in
when applied and shows on invoices, receipts, emails and the Yoco checkout;
cancelling frees the use. Managed from Supervisor → Coupon codes.
- **Staff price** — a ticket option or variant can have a staff price that Staff and
above get automatically, without a code.
---
## Payments, donations & refunds
- **Online card payments via Yoco** — checkout for the full outstanding balance,
confirmed by a signed webhook.
- **Payment links** — supervisors can generate and send a Yoco link for any
amount (including partial).
- **Manual payments** — cash, card, EFT, voucher or other, recorded by staff.
Each payment records **who recorded it** as well as who it's for.
- **Refunds** — negative payments against an original payment, netted against
the original method.
- **Donations** — users can donate from their dashboard (`/dashboard/user/donate`).
Supervisors can **assign** a donation (fully or partly) to someone's
registration and **unassign** it later. Assignments are kept as separate
records, so the original donation never changes.
- **Yoco reconciliation** — imported Yoco transactions can be matched to a
registration, recorded as a donation (optionally choosing the donor), or
ignored.
- **Invoices & receipts** — branded PDFs: an invoice (itemised, early-bird
discount, balance due, pay-now link and QR code) and a payment receipt. Sent
automatically and re-sendable on demand by email or WhatsApp.
- **Method normalisation** — Apple Pay / Google Pay / checkout payments count as
"Card" in reports and user views.
---
## Tickets & check-in
- **Automatic tickets** — QR-coded tickets are generated when a registration is
fully paid (or free), and sent as a PDF by email and/or WhatsApp.
- **Quantity tickets** — one ticket can cover several people and be redeemed
partially (e.g. check in 2 of 3).
- **Named tickets** — group bookings can give each person their own ticket, shown
with their name on the PDF, the scanner and the staff ticket list.
- **QR scanner** — works in any mobile browser. A preview checks the ticket is
for the selected event/section, then a confirmation screen shows holder, type
and remaining quantity.
- **Check-in confirmation** — holders get an email/WhatsApp saying how many were
checked in and how many remain.
- **Scan stats** — recent scans and per-event scan counts.
- **Offline scanning** — while online, a staff member locks an event section (or the
whole event) to their device and downloads its tickets. They can then keep scanning
with no connection; scans are queued on the device and sync automatically when it's
back online (never redeeming more than is left). Only one device can hold a section,
and while it's locked nobody else can scan it, online or offline. Problems found
while syncing go into a report for a supervisor. Supervisors can force-release a
lost device. The scanner can be added to the home screen (PWA) and opens offline.
- **Printing** — A4 sheets (8 tickets per page) and A6 single tickets.
- **Resend** — send tickets to a different email/phone at the door.
---
## Attendee forms
- **Form builder** per event — field types: Yes/No, Text, Paragraph, Number,
Date, plus Statement and Heading blocks; required/optional, help text,
reordering. The whole form can be marked required.
- **Drafts** — partially filled forms are auto-saved.
- **Responses** — view, filter (event, user, past/inactive) and print one
response per A4 page. Supervisors can edit responses.
---
## Messaging & notifications
Every user picks a **notification preference**: Email, WhatsApp, or Both.
**Automatic notifications**
| Trigger | Goes to |
|---------|---------|
| Registration created / updated | Registrant (with invoice if unpaid) + event notify recipients |
| Payment recorded / donation applied / unassigned | Registrant (with receipt) + admins |
| Refund processed | Registrant + admins |
| Tickets generated | Registrant (ticket PDF) |
| Ticket checked in | Ticket holder |
| Daily summary, 07:00, for each live event that hasn't started yet | Registrations inbox + event notify recipients |
| Account registered, activation, login, password changed/reset, account closed | The account holder |
**Bulk messaging** (supervisor)
- **Email attendees** and **WhatsApp attendees** — filter by status or pick
specific attendees, preview, send now or schedule for later.
- **Placeholders** — `{{name}}`, `{{event.title}}`, `{{event.link}}`,
`{{event.start}}`, `{{balance}}`, and `{{payment.link}}` (a live Yoco link for each recipient's
outstanding balance).
- **Broadcasts** — ad-hoc email/WhatsApp to any users or addresses, not tied to
one event.
- **Automations** — schedule a sequence of lifecycle emails for an event
(pre-event, final reminder, thank-you, promo for another event).
- **Manage scheduled** — view, edit or delete queued jobs per channel. Sends
run in the background and are purged 24 h after sending.
**WhatsApp** is connected through the WAWP API: an admin links a number in
Site Settings → WhatsApp (QR code or pairing code), with status, restart and
logout controls. Disconnected sessions are recovered automatically.
---
## User dashboard (My Events)
- Registrations with status badges, event thumbnails, and Closed/Past/Inactive
tags. Past and closed events are hidden by default.
- Registration detail: itemised bill (early-bird lines grouped), payments,
**Invoice** and **Receipt** buttons, edit, cancel, **Make payment**.
- Upcoming events and tickets side by side, with bulk ticket email/WhatsApp.
- **Ticket transfer** — hand a ticket to someone else before the event (name plus
email/phone). They get a new ticket and QR code, and an inactive account with an
activation link if they're new. The old code stops working, and scanning it says it
was transferred, both online and in offline-mode sync reports. One place can be split
off a ticket covering several people. Billing stays with the payer. It's not allowed
once a ticket has been scanned, and it can be turned off per event (supervisors can
always transfer, from At the door → Tickets). On youth events the new holder needs
their own parental consent, and the previous holder's form answers are removed.
Every transfer is in the audit log.
- **Payment history** (`/dashboard/user/payments`) — paginated, with filters by
date, method and payment/refund.
- **Donate** page.
- **Forms** — complete outstanding attendee forms.
- **Profile & Security** — edit details and notification preference, change
password, see recent account activity (logins, password changes, device),
sign out everywhere, deactivate or delete my data.
---
## Staff tools
- **Staff dashboard** — scan stats and quick actions.
- **Ticket scanning** (`/dashboard/staff/ticket-scanning`) — camera QR scanner
with event and section filters.
- **Event tickets & printing** (`/dashboard/staff/event-tickets`) — list, search
and print an event's tickets.
---
## Supervisor tools
- **Dashboard** — KPIs (active events, revenue, donations, registrations,
tickets sold, each vs. the previous month), revenue trend chart, top events,
and recent scans. Tiles link to the matching report.
- **Manage events** — the 6-step event wizard, ticket options, variants,
sections, form and attachments.
- **At the door** — search by name/phone/ticket ID, walk-in registration,
payments, a **Check-In** tab for redeeming main tickets by quantity, and
ticket printing/resending.
- **Self-service kiosk** (`/self-service`) — a touchscreen page a supervisor
unlocks for an event, where visitors register themselves. Existing accounts
are matched by email/phone, and any change to their details needs
confirmation.
- **Manual registration** — register someone on their behalf and record their
payment.
- **Payments** — tabs for Payment, Refund, Donations (assign/unassign),
Reconcile (Yoco transactions), and Payment Link.
- **Coupon codes** (`/dashboard/supervisor/coupons`) — create, edit and turn off
discount codes, and see who used each one.
- **Rooms & groups** (`/dashboard/supervisor/allocations`):
- Per event, allocation sets such as "Rooms", "Small groups" or "Buses". Each set
has groups with an optional capacity, gender restriction and leader (staff).
- A drag-and-drop board, plus auto-allocate: fill evenly, respecting capacity and
gender, keeping bookings together or splitting them.
- Printable per-group and master lists. On youth events they can include medical
details, and viewing those is audited.
- The group can show on tickets and in My Events.
- Email and WhatsApp attendees can be filtered to one group.
- Leaders see their people under Staff → **My groups**.
- Works on named attendees. Events can ask each person's gender.
- **Offline scanning** (`/dashboard/supervisor/offline-scans`) — devices holding
offline locks (with force release) and sync reports to review.
- **Waitlist** (`/dashboard/supervisor/waitlist`) — the queue per event: offer a
place now, move people up or down, or remove them.
- **Parental consent** (`/dashboard/supervisor/consent`) — consent status per
attendee on youth events, resend (one or all pending), re-request after the
consent text changes, and a printable medical & emergency list (audited).
- **Email attendees / WhatsApp attendees** — bulk and scheduled messaging.
- **Forms** — view, filter, edit and print form responses.
- **Reports** — see [Reports](#reports).
- **Site banner** (`/set-banner`) — set the announcement bar.
---
## Admin tools
- **Admin dashboard** — same KPIs as supervisor, plus admin quick actions.
- **Manage users** — server-side search and filters (role, active), paging,
edit role and notification preference, revoke sessions, delete or
**anonymise** personal data.
- **Registrations** — all registrations, with filters (event, status, text),
status counts, revenue and outstanding totals, and per-registration options,
form answers and payments (with who recorded each one).
- **Cashup** — see below.
- **Audit log** (`/dashboard/admin/audit-log`) — who did what and when for
refunds, donation assign/unassign, manual registrations, staff
cancellations, event create/update/delete, settings changes, and coupon codes
(created, edited, turned off, applied or removed by staff).
- **Site settings** — see below.
---
## Cashup & event costs
- **Event costs** — once-off or per-item costs (optionally linked to a ticket
option), with a "paid from takings" method so cash on hand is correct.
- **Expected vs. actual** — expected takings per method (cash/card/EFT/other)
compared with actual amounts, with variance shown.
- **Cash denomination counts** — entered per staff member, at any time. The
event's actual cash is the sum of these counts.
- **Payment accountability by staff member** — what each person recorded, by
method, with live cash variance.
- **Close / quick close / reopen** an event — closing locks it from further
edits and hides it from the kiosk and user actions. Drafts are saved as you
go.
- **Report tab** — a read-only cashup summary, shown automatically once the
event is closed.
- **Cashup audit trail** — every close/reopen with totals and who did it.
---
## Reports
A full-width workspace with shared filters (events, date range with presets,
include past/inactive/closed) and a searchable grid of reports, each opening in
a viewer with its own filters, stat tiles and bar charts.
| Category | Reports |
|----------|---------|
| Financial | Payments between dates · Revenue summary (by method) · Revenue detailed · Finance report (revenue & costs, after discounts) · Profit report · Discounts (coupon codes) |
| Registration | Attendees per event (grouped by option) · Registration type counts · Master orders breakdown · Registration status breakdown (count by registration or ticket quantity) · Parental consent status · Medical & emergency list |
| Ticketing | Ticket usage summary |
| Donations | Donations breakdown (used / unused per event) |
| Cashup | Cashup reconciliation · Cashup audit trail |
**Export:** Print, branded PDF download, styled Excel (`.xlsx`) workbook,
Email (to yourself), or WhatsApp (the PDF to your own number). Dashboard tiles
deep-link into reports with `?report=&range=`.
---
## Site settings & setup wizard
**Setup wizard** (`/setup`) — on a fresh database, walks through organisation
details, the first admin account and branding. No manual seeding needed.
**Site Settings** (`/dashboard/admin/settings`) — stored in the database and
applied without a restart. Secrets are encrypted with AES-256-GCM.
| Tab | Contains |
|-----|----------|
| Organisation | Name, tagline, contact email/phone, address (with map link) |
| Branding | Primary/secondary/accent colours, logo, favicon, colours suggested from the logo, live website/email preview on desktop and mobile |
| Notifications | Registrations inbox and admin notification emails |
| Email | SMTP host/port/TLS/user/password/from, with a "Test connection" button |
| Legal | Operator, Information Officer, website, effective date for the Terms/Privacy pages |
| WhatsApp | WAWP credentials, connect a number, status/restart/logout |
| Backups | List, run now, download database backups |
See [SETTINGS.md](./SETTINGS.md) for the default of every setting.
---
## Accounts & security
- Register, log in, forgot/reset password, activate account (for accounts
created on someone's behalf).
- JWT authentication (HS256 pinned) with **session revocation** (token
versioning) — users can sign out everywhere, and admins can do it for any user.
- **Two-factor authentication** — a 6-digit login code by email or WhatsApp
(10-minute expiry, 5 attempts, resend), with "Trust this device for 30 days".
**Required for Admins and Supervisors**: their next login sends a code that turns
it on, and they can change the channel but not turn it off (skipped only when no
email or WhatsApp channel can deliver a code; `TWO_FACTOR_REQUIRED_ROLES=false`
is the emergency switch). Optional for everyone else from Profile & Security.
Admins can reset it for a locked-out user, and the kiosk asks for the code at
setup.
- **Login lockout** after repeated failed attempts, plus login rate limiting
(`TRUST_PROXY` to read real IPs behind a proxy).
- **Security event log** — logins, password changes and resets, with device
and IP.
- **Account closure** — deactivate, or anonymise personal data while keeping
financial records.
- **Upload hardening** — server-generated filenames, and uploads served with a
sandbox CSP and `nosniff`.
---
## Help system
A floating **"Need help?"** button on every page opens a page-specific guide
(tabs, quick links). Every page has dedicated content (`frontend/src/content/help/`),
falling back to a general guide.
---
## Background jobs
| Job | Schedule |
|-----|----------|
| Scheduled email/WhatsApp worker | Polls every 30 s (`SCHEDULED_EMAILS_INTERVAL_MS`) and purges sent jobs after 24 h |
| Daily event summary email | 07:00 daily |
| Waitlist: expire unclaimed offers, offer freed places | Every 10 minutes (`WAITLIST_JOB_ENABLED=false` to disable) |
| Parental consent reminders, and deleting medical details after events | 09:00 daily (`CONSENT_JOBS_ENABLED=false` to disable) |
| Database backup (`pg_dump`, gzipped, 14-day retention) | 02:00 daily (`BACKUP_ENABLED=false` to disable) |
| Temp file cleanup (files older than 7 days in `/temp`) | Daily |
---
## Operations
- **PM2** (`ecosystem.config.js`) runs backend and frontend, restarting either
one above 500 MB of memory.
- **Sentry** error monitoring when `SENTRY_DSN` / `NEXT_PUBLIC_SENTRY_DSN` are
set.
- Unhandled promise rejections are logged and don't crash the server.
- Backend status page (`/`) and built-in API docs page (`/docs`).
- Jest tests for early-bird tranche pricing and donation balances.
- Versioning via git tags and [CHANGELOG.md](./CHANGELOG.md).
---
## Page map
| Path | Who | What |
|------|-----|------|
| `/` | Public | Home |
| `/events`, `/events/[id]` | Public | Event list and detail |
| `/[alias]` | Public | Event short link |
| `/register/[eventId]` | Public / User | Registration |
| `/registration/success` | Public / User | Confirmation, form and pay |
| `/payment/success`, `/payment/failure`, `/payment/cancel` | Public | Yoco return pages |
| `/forms` | Public / User | Attendee forms |
| `/contact`, `/legal/terms`, `/legal/privacy`, `/lockdown-rules` | Public | Info pages |
| `/login`, `/register`, `/forgot-password`, `/reset-password`, `/activate-account` | Public | Accounts |
| `/setup` | First run | Setup wizard |
| `/consent/[token]` | Parent/guardian | Give or decline parental consent |
| `/waitlist/claim/[token]` | Public | Claim a waitlist place |
| `/self-service` | Supervisor-unlocked | Kiosk |
| `/set-banner` | Supervisor | Site banner |
| `/dashboard/user` (+ `/payments`, `/donate`, `/forms`, `/profile`, `/reset-password`) | User | My Events |
| `/dashboard/staff` (+ `/ticket-scanning`, `/event-tickets`) | Staff | Staff tools |
| `/dashboard/supervisor` (+ `/events`, `/event-options`, `/at-the-door`, `/manual`, `/manual-registration`, `/payments`, `/coupons`, `/waitlist`, `/consent`, `/offline-scans`, `/allocations`, `/email-attendees`, `/whatsapp-attendees`, `/forms`, `/reports`) | Supervisor | Supervisor tools |
| `/dashboard/admin` (+ `/users`, `/registrations`, `/forms`, `/cashup`, `/cashup/[id]`, `/audit-log`, `/settings`) | Admin | Admin tools |