Site settings -> Webhooks: admins add https endpoints and choose event
types (registration created/paid/cancelled, payment received/refunded,
ticket checked in, account created, event published). Events are
noticed by a Prisma client extension so every write path is covered,
re-checked before sending, and delivered as signed JSON
(X-CrossEvents-Signature, HMAC-SHA256) with retries, a 30-day delivery
log, Send test and Resend. Public https addresses only; each endpoint
is added to the operator register; kids and volunteer tickets are never
sent. New `webhooks` job. Migration 20261028160000_webhooks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After asking for an update, a newer version coming out made the Licence
page claim the newer version was requested, with no way to ask for it.
Now it shows the version asked for, that a newer one is out, and "Ask
for X instead"; the banner shows again. Hub 1.5.0 moves the open request
on (`changed`); with an older Hub the site withdraws and asks again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pass sells a ticket at each of several events in a series for one
price. Supervisors set passes up on the Event series page (events and
ticket per event; fixed once sold). Buying on the series page registers
the buyer at every event at once with one checkout (free passes give
tickets straight away; Pay now if online payment isn't possible). The
price is split over the events in proportion to their normal prices:
each registration line is priced at its share and the webhook records
one Payment per event, so cashups stay per event. Pass registrations
aren't repriced, take no coupons and can't be edited. Migration
20261028150000_season_pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New report (Reports -> Other, or "Compare" on the Event series page):
each event in a series side by side, oldest first - registrations,
tickets, income (dashboard definition), people checked in (average per
session on multi-session events) and attendance rate, with the change
from the event before. Exports like the other reports; campus-scoped
staff see only their campuses' events. GET /api/series/:id/compare.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Group separate events (Camp 2025, Camp 2026) on a series page at
/series/<slug> with upcoming and past events. Events join a series from
the event editor (copies keep it); a series can span campuses. Event
pages show "Part of ..." and "Next in this series". Signed-in people can
follow a series; the new `series` job emails followers once when a new
event in it goes live, as News & announcements (opted-in only, with
unsubscribe). Follows are in the data export and removed on
anonymising. Migration 20261028140000_event_series.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Copy" on each event card opens the event editor filled in from that
event (campus, sessions, options, variants, early birds, sections, form,
recipients, feedback questions, certificates, reminders). "New start"
moves every date with it. Allocation groups and, for admins, planned
costs are copied by POST /api/events/:id/copy-from. Registrations,
coupons, attachments, kids check-in and volunteer roles are not copied.
Roadmap: event series and cloning ships as 1.47.0-1.47.3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Hub reads this file from main (Hub 1.4.1), so these show on sites' Licence
page without a new release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Client-facing release notes the Hub reads from git with the version tags, so
the latest version and its notes reach installs without touching the Hub.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Site settings -> Licence shows the release notes for every newer version from
the Hub; urgent (security/serious) updates are marked and can't be put off.
- Withdraw an update request (the provider is told through the Hub).
- "Not now" on the banner or Licence page hides update reminders until the
next version.
- Notices from the provider show as a dashboard banner for site admins and
supervisors, in their time window, and on the Licence page.
- New audit actions (migration), API docs, help, protocol doc, tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There's no Actions runner (no machine that can run Docker), so every push
left a run stuck on "Waiting". Tests and lint are run by hand before a
release, and releases are deployed with scripts/deploy.sh on the server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Serving roles per event or session, sign-ups and assigning with an overlap
check, swaps that happen on accept (notify recipients emailed), QR and manual
check-in (kids-room roles start rostered duty), optional free volunteer ticket,
day-before reminder job, hours served, privacy hooks. The kids check-in and
volunteer tickets are left out of public event pages and public registration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Admin -> Users 'Limit to campuses'; staff campus pickers, reports, dashboards
and audience picker follow the scope (useMyCampuses); scoped people pick one
of their campuses for new events, and church-wide / other campuses' events
open read-only; 'You work with ...' note; warning before turning campuses off
while staff are limited. e2e: scanner refusal naming the campus, scoped
events list and read-only editor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PUT /api/users/:id takes scopedCampusIds (supervisors/staff only, audited as
user_campus_scope_changed); GET returns scopedCampuses; the profile returns
campusScope (null when unscoped or campuses are off).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Events, payments, registrations, scan locks and tickets marked; list
controllers filtered (registrations, payments, tickets, scans, stats,
coupons, scheduled messages, form responses, funnel). Owner-or-staff routes
check staff against the record's event (ownerOk). Scanner names the campus
of another campus's ticket. Route test passes; unit tests for the rules.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Site settings -> Campuses tab; campus picker in the event editor; campus
filter and badges on the events list, public events page (remembered,
starts on home campus) and reports/dashboards; /campus/<slug> pages and
sitemap; home campus on the profile; "Everyone at a campus" in email and
WhatsApp broadcasts. Help, FEATURES, SETTINGS, API docs, protocol doc
(campusCount), handover and roadmap updated; campuses seeded for e2e.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Campus model, Event.campusId (null = all campuses), User.homeCampusId,
per-campus summary recipients; campuses_enabled setting (off by default)
- /api/campuses: public list and landing page, admin CRUD/order/archive,
"everyone at campus X" audience (home campus + optional 12-month registrants)
- Events: campus on create/update (audited when moved), ?campus= on the
public list (with church-wide events) and staff list; campus included
- Home campus on the profile; cleared when anonymising
- Overview stats ?campus= filter; campus summary recipients; campus on
ticket PDFs; heartbeat reports the real campus setting
- Migration also adds hub_update_requested, missing since 1.42.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the decisions: scoped staff view and scan "All campuses" events but
can't edit them; "everyone at campus X" is home campus plus optional recent
registrants; campus landing pages in 1.43.0. Later phases move up by one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PRODUCTION_PUBLIC_KEY is the key the production Hub serves at
/api/public-key, normalised to PEM, so installs no longer need
HUB_PUBLIC_KEY. Test covers the built-in key with the env var unset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1.41.3 and 1.42.0 / Hub 1.1.0 recorded; Multi-campus is now 1.43.0 and
later phases move up by one. Next steps: roll out update requests, build
the Hub public key in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Site settings -> Licence sends a signed update request to the Hub
(docs/hub-protocol.md 3a) instead of showing bash scripts/deploy.sh. Shows
"Update requested" until the site runs that version and hides the update
banner meanwhile. Audit-logged as hub_update_requested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Display text only: storage keys, slugs, the encryption salt, the repo URL
and applied migrations keep their old names so existing installs keep working.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>