Membership pricing, capacity and timetable changeovers
2 September 2026What's new
Settings are clearer on tablets and long forms
- Annual Requirements are now called Member Requirements throughout the
settings, staff and member views, reflecting that clubs can track insurance, registrations, qualifications and other checks—not only annual renewals.
- Member Type actions no longer wrap awkwardly at tablet widths, and shared
confirmation dialogs now keep every close and footer action at least 44px tall for reliable touch use.
- Trial Settings show a sticky unsaved-changes action after an edit, so club
staff can save a long programme form without scrolling back to the top.
Video Review limits now match each membership
- Clubs can set a default number of Video Review submissions per member each
Monday-to-Sunday week, or choose unlimited submissions.
- Each membership can exclude Video Reviews, inherit the club default, set its
own limit from one to 100, or allow unlimited submissions. When more than one current included membership covers a member, the highest allowance applies.
- Weekly places are reserved safely before an upload begins, including when a
member has several tabs open. Cancelling an unfinished upload releases its place; a submitted video continues to count if it is later withdrawn or deleted.
- Final submission creation and upload-intent consumption now settle together,
so a temporary database failure cannot use an upload token without creating the matching review.
Deployment note
- Apply and verify
video-review-weekly-quota-01.sqlbefore deploying the
matching application code. The routes fail closed if its service-only authorities are unavailable. No environment variable or feature-flag change is required.
Family pricing now grows with the household
- Membership plans can add consecutive family-price tiers beyond the second
and third member. The last configured tier continues to later family members, so clubs do not need to predict a maximum household size.
- A fixed family price now consistently means the final price charged for that
member. Existing plans that stored the older amount-off format remain compatible and are converted when opened for editing.
- Clubs can optionally cap the membership total for one household agreement in
one full billing period. Partial periods reduce both the membership charges and the cap by the same proportion. The cap is applied before an agreement-specific override; other memberships, events, courses, requirements and invoice fees remain outside it.
- Family members with the same link time are ordered deterministically, keeping
their price-tier positions stable between invoice runs and member views.
- Member profiles now derive family position from the same agreement coverage
union as invoice generation, including additional and junction-only plan links. Database read failures show as unavailable rather than as an empty family or a missing membership.
- The household headline is labelled as plan base rates, rather than claiming a
monthly invoice total before family pricing, caps, frequencies and overrides have been applied.
Deployment note
- Apply
membership-plan-family-pricing-01.sqland confirm its postflight
before deploying application code, because plan reads and writes name the new household_cap_pence column.
Timetable changeovers
- Classes can now have optional inclusive start and end dates, so clubs can prepare a replacement timetable before the old one finishes without showing both schedules on the same day.
- Calendar, register fallback, dashboard, trials, portal session booking, lesson-capacity forecasting and attendance-break analysis use the same date-window rule. Existing classes with no dates remain ongoing.
- Changing a class window is refused when it would hide a future trial or portal session booking; those bookings must be moved or cancelled first.
- Future-start classes remain available for advance joining, while ended classes are removed from public choices and cannot issue waitlist offers. Pending stale offer deliveries are suppressed without sending a message.
- Closure previews, trial-pause expansion, member next-session cards and momentum calculations now observe the same inclusive window.
- Deployment is SQL-first: apply and verify
lesson-date-windows-01.sqlbefore deploying the application code. This foundation does not schedule future roster assignments or membership choices.
Plan places are protected during membership changes
- Club owners can set an optional member capacity on each membership plan and
define the minimum and maximum number of regular classes members should pick.
- The member portal shows live places remaining. A full plan cannot be selected,
and clubs may optionally let the household join or leave its waiting list.
- Capacity counts people rather than billing agreements. Current members and
accepted future changes reserve places; choices awaiting staff review are shown separately as demand and reserve a place only when approved.
- The capacity rule is enforced at the database boundary for staff, imports,
enrolment and portal changes. Concurrent requests for the final place have one durable winner instead of allowing the plan to be oversubscribed.
- Capacity coverage, household-plan links and legacy student-plan links are now
required to belong to the same club. Direct signed-in writes to the coverage junction have been retired; guarded server authorities retain write access.
Deployment note
- Run
membership-plan-capacity-preflight.sqland require all three tenant
mismatch counts to be zero before applying membership-plan-capacity-01.sql. This migration must be applied before deploying the capacity application code.
Future membership and class choices are easier to review
- Members can explicitly apply a membership or regular-class change now, or
choose a future date, and their submitted receipt keeps the selected plan, classes and effective date visible.
- A membership can validly allow zero to 100 regular classes. Lesson-only
requests use the member's real current or scheduled plan and the same class bounds whether the change is immediate or scheduled.
- Staff review shows the current and requested plan and classes, including
class day, time, effective date and the selected plan's capacity position.
- Scheduled changes are split into attention and upcoming lists with paging.
Only retryable failures can be retried; terminal failures direct staff to review the member and issue a fresh request.
- Membership plan editing now includes an ordered waiting-list view. It never
changes a membership or creates a charge automatically; staff contact the household and send a fresh member request when a place is available.
Confirmed future class choices now reserve real places
- A member's accepted future class choice now shares one dated capacity rule
with portal session bookings, class waiting-list claims and staff/import roster changes. Concurrent attempts for the last place have one winner.
- The saved change is tied to the exact household membership and pending plan
state that the member confirmed. If that state later changes, the automatic update stops and asks staff to review it instead of applying an obsolete choice.
- Staff can cancel or rebase a stopped future class change with a required
reason and a before/after audit record. Classes with confirmed future places cannot be archived, shortened or reduced below those commitments first.
- Future class submissions and approvals now serialise against membership
expiry, cancellation and plan changes. A concurrent membership change wins cleanly rather than leaving an obsolete capacity reservation.
- The Member Requests control centre now exposes those recovery actions with a
current-versus-revised class preview. Completed and cancelled changes remain available in paged history, and memberships that allow zero regular classes can be corrected to an empty future roster without a false validation error.
- Due changes are claimed in recoverable leases and shared fairly between
clubs. The scheduled worker drains a bounded number of pages, reports the remaining backlog and fails visibly when work needs attention.
Changeover demand is visible before places are committed
- A read-only capacity forecast for each Member Request campaign separates the
current roster, confirmed future or held places, choices awaiting staff review and waiting-list demand for every offered membership and class.
- Remaining places still come from the same dated plan and lesson authorities
that enforce the final place. The report does not reserve a place or turn an unanswered choice into demand.
- Full choices and choices where review or waiting-list demand could use every
remaining place are clearly identified. Large class lists are loaded in bounded pages, and a failed census is shown as unavailable rather than as an empty or healthy result.
Deployment note
- Apply and verify
portal-future-lesson-rosters-02.sql, then
portal-future-lesson-rosters-03.sql, after portal-future-lesson-rosters-01.sql and before deploying the application code. The upgrades refuse ambiguous duplicate live schedules, backfill the exact membership snapshot for valid unit-01 work already waiting and add the service-only recovery preview.
- Apply and verify
changeover-capacity-forecast-01.sqlafter the future-roster
unit. Its application route fails closed as not ready until the read authority is present.
Member requests can be checked before they are sent
- Staff now preview the exact selected members and deduplicated households,
the actions that will be created, existing requests that will be skipped and the effective-date bounds before creating a member-action campaign.
- Membership requests offer only the compatible plans deliberately selected by
staff. Each household's current membership remains available as an explicit keep-current choice, and every option is stored as an immutable versioned snapshot so later plan edits cannot silently change what the member saw.
- A successful creation remains visible with its confirmed membership,
household-details, regular-class and skipped counts instead of closing the dialog before staff can verify the result.
Deployment note
- Follow
CHANGEOVER-CONTROL-CENTRE-SQL-CHECKLIST.mdas one SQL-first
sequence. Capacity and lesson-date-window authorities precede the campaign readiness unit; the future-roster units and member-request eligibility roll-forward have their own required postflights. Do not deploy the matching callers after only the older portal member-request units. Until the complete sequence is verified, every new path fails closed.
Changeover work is recoverable and easier to operate
- The Member Requests screen now prioritises changes awaiting staff approval,
keeps scheduled class changes split into upcoming, attention and history, and shows the staff reason recorded for a cancellation or correction.
- Staff can update or cancel a confirmed future class choice without changing
today's roster. Recovery rechecks the member, membership dates, active plan, programme, club lens, class dates and capacity before accepting a revision.
- Campaign previews and creation now use the same effective-date and programme
rules. Plans ending before the change, inactive members and classes outside their date window are safely excluded.
- Large histories and forecasts page independently. A failed page keeps the
already-loaded information visible and reports the affected section instead of presenting a false empty result.
- The changeover evidence now covers mixed households and programmes, the exact
12-choice limit, creation races, plan/lesson drift and future-roster terminal history.
Deployment note
- This is one SQL-first release unit. Follow
docs/rollout/CHANGEOVER-CONTROL-CENTRE-SQL-CHECKLIST.md and require every preflight and postflight to pass before deploying application code. No new environment variable is required, and automatic expiry generation remains a per-club owner decision.
Member changeover dialogs are ready for repeatable responsive QA
- Every deep-linked Settings section now exposes its section name as the page
heading to assistive technology, matching the Settings home and group views.
- Opening a confirmation dialog from a row menu now keeps keyboard focus in
the dialog instead of returning it to the closed menu's trigger.
- Forms opened in a dialog now keep their intended first field focused, while
confirmations without an initial field focus the close control. Closing either returns keyboard focus to the control that opened it.
- Trial Settings now gives its colour picker and editable hex value distinct
names for screen-reader and voice-control users.
- Trial journeys no longer accept a blank booking-button label; any legacy
blank value safely falls back to “Book trial”.
- Requirement setup now connects every visible field label to its control and
names the member-type selector as one group, improving keyboard, screen-reader and voice-control navigation without changing the form layout.
- Requirement lists now switch to readable action cards at tablet widths, so
the final status and row actions no longer sit beyond the visible Settings workspace beside its navigation rail.
- Assistive technology can now identify each member's selection control by the
member name, while the compact mobile action remains unchanged.
- The five member-request and future-roster dialogs now have isolated local QA
fixtures for desktop, tablet and phone. They use a run-owned club and staff session, stop before any consequential submit and require zero fixture residue before their evidence can count.
- The remaining owner lifecycle, suspended billing, platform administration and
household Portal views now share one repeatable local evidence campaign. It verifies a live isolated app, real local auth states and desktop/tablet/phone results, then removes the run-owned clubs, sessions and audit activity before those observations can count.
- Release evidence now displays the earliest expiry across both ordinary
fixtures and the authenticated lifecycle campaign, so its human-readable reuse deadline cannot outlast any evidence that contributes to the result.
SMS replies now reach the club's Telegram owners reliably
- A signed inbound SMS reply is forwarded to every enabled Telegram
owner/admin recipient for that same club. Each recipient has a durable key derived from the provider receipt, so a webhook replay or partial fan-out cannot notify the same person twice.
- The separate SMS-only forwarding chat has retired from Settings. Telegram
reply recipients are now managed in Club Details, keeping one recipient list for owner notifications instead of two lists that could drift apart.
- The message screen no longer labels a quiet gateway phone as “offline”. It
reports recent activity, no recent gateway update, a queued backlog or an unavailable status using only evidence the database can prove.
- Failed gateway-health reads now show as unavailable instead of presenting
zero queued messages as though the read succeeded.
SMS reply rollout note
- No SQL or new environment variable is required. Before relying on reply
forwarding, confirm the club has inbound SMS enabled, a unique webhook signing key, a connected Telegram bot and at least one enabled owner/admin Telegram recipient. The provider's webhook registration remains an external setup check; Allsorted does not infer it from a lack of message traffic.