What's new
More reliable scheduled communications
- Large scheduled SMS sends now continue across cron runs without waiting again
on—or re-texting—recipients whose delivery was already recorded. The gateway's 20-second pacing is retained for genuine provider attempts across the whole worker run.
- A broken recipient-data read is now settled with visible retry/backoff state,
allowing later scheduled jobs to continue instead of being blocked behind the oldest row.
- Attachment emails stop safely at the request budget and resume from their
remaining durable recipient rows on the next run.
- Personalised merge tags are now applied to scheduled email subjects as well
as bodies, including attachment sends.
- The minute worker again claims a bounded batch of ten jobs while preserving
per-provider pacing and releasing untouched claims before its deadline.
No SQL, environment variable or feature-flag change is required.
More reliable card, Link and Pay by Bank payments
- Card and Link are available together across Payment Element checkouts. Pay by
Bank remains limited to eligible GBP payments, while time-sensitive event places continue to exclude delayed bank settlement.
- Pro Shop payment webhooks now preserve Stripe's provider-event order. An old
processing delivery cannot overwrite a newer failure, but a genuinely later retry of the same payment can still continue normally.
- Payment reconciliation pages through its complete seven-day Stripe lifecycle
window instead of silently ignoring recent events after the first 600 rows.
- A late Stripe success against a cancelled or void invoice now creates durable
operator evidence instead of reviving the invoice or disappearing as a harmless zero-row update.
- Existing Stripe account recovery continues even when the optional Pay by Bank
capability request fails, with a clear retry message on return.
- Apply
supabase/_proposed/stripe-pro-shop-event-ordering-01.sql before
deploying this application revision. Existing code is compatible with the additive SQL; the new webhook intentionally retries until the authority is present.
A simpler event creation flow
- Club Setup → Event Types now opens new event types in a focused modal instead
of expanding a large form into the settings list. Existing event types still edit in place.
- New events now open with a neutral Create your event heading and an empty
event name, instead of assuming the event is a grading.
- The configured event-type choice is always shown, even when a club currently
has only one type. The picker explains which defaults the type supplies and links directly to Club Setup → Event Types to add or manage more choices.
- Event descriptions use the same searchable merge-tag picker as
Communications and Automations, so supported details can be inserted without memorising tag names.
- Start and finish times now use predictable hour and quarter-hour choices.
Single-day events can be entered as either a length or a finish time, with quick 30, 60 and 90 minute choices plus a clearable custom length. Choosing Finish time reveals its selector directly beneath that choice so it is not missed above the controls.
- Entering a positive cost automatically enables Requires payment. Early-bird
prices can be calculated with 5%, 10%, 15% or 20% shortcuts, and Public listing now explains where the event will appear.
- Booking requirements can now collect text, number, date, yes/no and dropdown
answers, with quick starts for membership, insurance, progression level, weight and date-of-birth details.
- Booking requirements now use one clear Add booking requirement action before
asking for the type. Clubs can then combine or repeat equipment lists, text information, signed declarations, questions and acknowledgements without choosing the same thing twice in succession.
- Clubs can add signed declarations using an exact declaration, typed signer
name, signer role and acceptance. No signature image or biometric mark is collected.
- Questions, declarations, checklists, waivers and booking information can be
prepared before the first save. They are validated by the server, copied independently to every repeated occurrence, and retained in the booking's immutable staff-visible history.
- Opening an event from Calendar → Day now leads with the event name, type,
status, date, time, location and price. Bookings, attendance, invites and revenue use the same responsive summary cards as the rest of the app; bookings and invites are separated into clear tabs with proper empty states, and reschedule/cancel actions sit in a contained action menu.
- Manage Event now follows the same event-summary design, adds clear booking,
attendance, invitation and capacity figures, and keeps invitation creation inside the Invites workspace. Invite-only and publicly listed events are labelled honestly, and the unusable tokenless Copy public URL action has been removed; secure member invitations continue to carry individual links.
- External Events now loads through a tenant-bound server snapshot with exact
entry totals, pagination and distinct unavailable, empty and filtered states. Search, dated views and counted status tabs make current, upcoming and past events easier to find without a wide mobile filter strip.
- New external events are explicitly saved as drafts. The accessible creation
dialog starts without assuming a competition format, treats a single day as the default and explains when a starter template could not be applied after the draft itself was safely saved.
- External-event creation now asks for an entry structure rather than exposing
martial-arts database terms. Attendance-only, individual, pair, team and mixed choices give different club types clearer starting points while existing saved events remain compatible.
- Apply
supabase/_proposed/event-booking-response-fields-01.sql before this
application release. No environment change is required.
Safer external-event setup and entries
- External events now remain genuinely private while they are drafts. Entry
links, staff entry creation and invitation issuing only become available after the event is explicitly opened.
- Registration deadlines are now enforced by the server, event and division
date/range errors are blocked before saving, and entrant ages are evaluated on the event date rather than the day the form is opened.
- Cancelling an external event must use the protected cancellation and refund
action; ordinary editing can no longer bypass that workflow.
- External document links accept only valid HTTP or HTTPS destinations. Used
invitation links can show the entry and payment outcome for their one bound student without exposing another entrant or club.
- The saved-event workspace now opens on a concise overview with readiness,
entries, payment and collected-value summaries. Setup, roster, entry-finance and organiser-finance controls follow their separate effective permissions; denied permissions no longer send member or roster details to the browser.
- Staff entry and public invitation journeys now guide people through entrant,
division and review steps, explain deadlines and refund terms, show autosave state, and keep pending payments recoverable without creating a second charge.
- Opening an event is now checked by the server as well as the screen: event
dates, registration deadline, entry options and all fee values must be valid. Completed and cancelled events are shown as terminal rather than suggesting that staff can reopen them.
- No SQL or environment change is required for these protections.
Programme-first External Events v2
- New external events are attached to one of the club's active programmes, so
basketball, football, cheer, martial arts and multi-programme clubs all begin from their own real membership rather than a sport-specific preset.
- Starter setups are now generic: attendance, individual and pair entry, team
tournament, judged routine, or a blank mixed setup. The programme's vertical changes the recommended order only; it never hides an option.
- Entry divisions are presented as neutral categories with an attendance,
individual, pair or team participation mode. Clubs choose whether the fee is charged once per registration or once per participant and can set exact roster bounds, music and supporting-document requirements.
- Staff and public entry journeys now validate every participant against the
event programme. Public links can select an individual or pair; team rosters remain staff-managed so a public token cannot enumerate the club's members.
- One canonical entry remains the invoice, settlement, cancellation and refund
identity. Normalised participant rows prevent the same member being entered twice in one category while preserving existing links, invoices and legacy event records.
- Apply
supabase/_proposed/external-events-v2-model-01.sql, then
supabase/_proposed/external-events-v2-authority-01.sql, before deploying the matching application revision. No environment flag is required.
Communication and audit reliability
- Immediate and queued automation deliveries now stop before contacting a
provider when the club identity or communication-secret read cannot be proved. A temporary database fault can no longer produce a partly blank club-branded message.
- Legacy event automation metadata can once again populate the supported
booking link and booking button tags. Only relative application paths and HTTP(S) destinations are accepted.
- The communications recipient snapshot now includes the real SMS opt-out
state, so the Opted out filter and recipient counts agree with the final SMS compliance gate.
- Monthly audit archiving now writes bounded, deterministic JSON parts followed
by a completion manifest. Partitions larger than 100,000 rows no longer wedge, and no source partition is dropped after a failed or incomplete archive.
- Apply
supabase/_proposed/comms-snapshot-sms-optout-01.sql with the matching
application release. It is safe to reapply and requires no environment flag.
Faster, steadier live data
- Recording an assessment from the register now keeps the assessment grid on
screen. The member who was edited stays current without the panel refreshing itself, while other open readers and browser tabs still receive the update.
- Register-day and member-profile snapshots now queue one fresh read when a
confirmed change arrives during an existing request. The older response is prevented from replacing the newer state.
- Club-wide attendance, insurance and renewal reports batch rapid member
updates into one authoritative refresh instead of reloading once per row.
- Admin attention totals and their preview now both exclude demo environments.
Successful admin states also use the established success styling, and a disabled secondary action no longer mutes the label for an otherwise active mixed form field.
- No SQL or environment change is required.