Changelog

What we shipped, when. Newest first.

Coaching assistant and Video reviews in every plan, Club Insights for every club, automations that send once, and reminders on UK time

4 October 2026

Plans

  • Coaching assistant (drills, lesson plans and the smart planning helper) and Video reviews are now part of every AllSorted plan from Starter, like everything else in the £69 plan. Before, they needed the Pro plan, so a new club could not use them. Each club still switches them on in Settings when it wants them.

Club Insights

  • Club Insights is now set up for every club automatically, so owners and admins can run reports straight away. Before, each club had to be set up by hand first, and every other club saw "This club has not enabled the Club Insights trial yet". New clubs are set up as they join. A club that has been switched off keeps its choice.

Training pathways

  • Saving a change to a pathway no longer shows "An unexpected error occurred". Publishing or archiving a pathway, renaming or removing a stage, changing or removing a task, and cancelling a member's pathway all saved correctly, but the page said they had failed and did not update until you reloaded it. Now the page confirms the change and shows it straight away.

Assessments

  • The red, amber and green buttons now have their icon in the middle of the button. Before, each icon sat a little to the left. This applies everywhere you score: assessments, the register and examiner scoring.

Signing up and changing classes

  • Families can sign up again. A one-off session added from the register, like the two "Last Thursday" sessions, has no weekday, and the sign-up page crashed when it offered one as a class. The member's class editor (Members, then Billing, then edit the enrolled classes) crashed for every member for the same reason. One-off sessions are no longer offered as regular classes, on the sign-up page or in the class editor, because they only run once.
  • Anywhere a class's day is shown, a one-off session now says "One-off" instead of breaking the page, including the timetable's full list.
  • When a change to a member's classes can't be saved, you now see why. For example: a class is full on an upcoming date, the member isn't active, or a class is no longer running. Before, it said "An unexpected error occurred".
  • A member's class editor no longer offers classes that have ended. After a timetable change it listed the old classes next to the new ones, so it was easy to pick the wrong one. If a member is still in a class that has ended, it stays on their list marked "Ended", so you can see it and swap it for a new one.
  • On the register, "Add a lesson", then "Regular lesson", now also offers classes that ended in the last four weeks, with their end date shown. So if a class's end date was set too early, or you run one last session after a timetable change, you can run the real class and its register and attendance stay on it. Before, only a one-off session was possible, and that night's attendance ended up on the one-off.
  • Staff "Add member" and the website's join page no longer offer one-off sessions (like the "Last Thursday" sessions added from the register) as classes to join. A one-off session runs only once, so nobody can join it.
  • The family app no longer shows archived classes. An archived class has no end date, so the family's calendar ("What's On") showed it every week, next to their new classes. One-off sessions are left out too. Classes that have ended still show up to their last date.

Trial bookings

  • The trial booking page and the staff "Book a trial" window now list only classes that still run. After a timetable change they listed the old classes next to the new ones, with a Book button but no dates to choose. One-off sessions are no longer listed either.
  • The trial booking page now uses UK time. Before, it used the server's clock, which is an hour behind in summer, so the "book at least 2 hours before" cut-off was really 1 hour. Families could pick a slot that was then refused. Shortly after midnight, the first day offered is now today, not yesterday.

Reminders and calendars

  • Trial and event reminders set to "X hours before the start" now go at the right time all year. In summer (British Summer Time) they went an hour late, because the server read class times as UTC instead of UK time. So a "2 hours before" reminder for a 6pm class went at 5pm instead of 4pm, and a "1 hour before" reminder went as the class started. Winter times were already right. Reminders already scheduled keep their time.
  • Families who add the club calendar to their phone (the calendar link in the family app) now see classes and events at the right time. In summer every class showed an hour late.

Closures

  • Calendar, then "Add closure", now emails only the members of classes that really run that day, and only current members (active or new). Before, it emailed everyone on the list of any class on that weekday: classes that had ended or not started yet, paused members, and people who had left. This now matches Settings, then Closures. If AllSorted can't check who to tell, no emails are sent and you're told, so you can let members know another way.

Automations

  • An automation now sends its message once for each real event, even after you edit and republish it. Before, republishing an automation sent its first message again to everyone it had already messaged who was still in the same situation. On 4 October, families whose insurance had expired received the same "Insurance Expired" email twice, because the automation was edited the afternoon before and the nightly check reports every expired insurance again each night.
  • The message goes again only when something new happens: for example, insurance that has been renewed and then expires again, a new bill or a new booking. A message that never reached the family (refused by the email provider, or held back on purpose) can still be sent.
  • If you republish an automation while someone is part-way through its steps, the rest of their steps stop. Nobody gets its messages twice.
  • An "expiring soon" reminder step now stops at midnight UK time on the expiry date. Before, from midnight to 1am in summer it used the server's date, which was still the day before.

Member requests

  • Families are no longer offered "Keep as now (no change)" on club requests. On 4 October a family kept a class that had ended with the old timetable, which left the member with no class at all. Families now always choose their membership and classes. If someone isn't carrying on, make them a leaver instead.
  • A request's member list (open a request, then its numbers) now marks anyone who has since left the club or been paused, with "Left the club" or "Paused".
  • You can take a member off a request straight from that list: press "Withdraw" next to any question still waiting for them or for your review. If members have left the club, "Withdraw everyone who has left" takes them all off the request in one go. Their families see "Withdrawn by the club" and the reason you give.

Faster pages, a clean portal sign-out, a tidier Member requests page and fewer spinners

3 October 2026

Faster pages

  • AllSorted's servers now run in Dublin, next to its database, instead of in Washington DC in the USA. Before, every page asked the database several questions, and each question crossed the Atlantic and back, so just checking you were signed in took up to three quarters of a second per request. Now those questions stay in Ireland, so pages should fill in noticeably faster. Nothing else changes, and your data stays where it was.

Family portal

  • Logging out of the family portal, or a portal session running out, now goes straight to the portal login page. Since the 2 October update the page could get stuck: it asked the club for the family's details again and again, several times a second, and never reached the login page.
  • The same applies to staff using "Stop" after viewing the portal as a family: the tab now goes straight back to Members.
  • Why it happened: clearing the page's saved data now also refreshes what is on screen (that change fixed staff lists stuck on "Loading..."). When the reason for clearing was "you are signed out", the refresh asked again, was told "signed out" again, and started over. Now, once a page is leaving its session it clears its data without asking again, and only the first "signed out" answer sends it to the login page. Switching club or refreshing permissions still refreshes the screen as before.

Member requests

  • The number of member requests waiting for your review now shows as soon as you open the menu. Before, the count only started loading when the menu opened, so you had to wait for it. It now loads with the page, and checks again each time you open the menu.
  • Outstanding requests are now one line each: the request's name, how many were sent and when, how many have not replied or are overdue, the reply-by date, and how many are waiting for your review. Click a request to open it and see its details, buttons and counts.

Courses and training pathways

  • Courses now shows for clubs that have switched it on. Since July, Courses has been part of every AllSorted plan, but one setup step was missed, so it stayed hidden even when it was switched on. Clubs that have not switched Courses on see no change.
  • Training pathways had the same missed step and is fixed the same way: it now shows for clubs that have switched it on.

Moving between pages

  • The small spinner next to a menu link now only appears when a page takes a moment to open. Quick page changes show nothing, so you no longer see it on every click. This applies to the staff menus and the family portal menus.

AI features

  • Communications drafting and smart planning now use OpenAI's GPT-6 Luna, the newest model of its kind. It costs about half as much per word as the one before. Past records keep the model they used.
  • Club Insights moves to GPT-6 Luna through its recorded quality review, so the reason for the choice is kept with it.
  • Club Insights is now on as standard for club owners and admins, with nothing to switch on. An emergency off setting still exists for AllSorted, but it is never needed day to day.
  • The writing helper in Communications and the activity helper in smart planning are now on for every club too. There is no longer a club-by-club switch to turn them on. Each person still needs the right permission, and the demo club still can't save anything.
  • Message translation in the family app is on as standard as well. Each club still has to agree to it first, because family messages are private.

Requirement dates, safer joining, family pricing, a steadier register and member requests

2 October 2026

Member requirements

  • A new member no longer gets an "expired" requirement the day after they join. Each requirement now has a "When someone joins" choice in Settings → Member requirements:
  • "Leave blank until we record it": the member shows "Not recorded yet". AllSorted sends no bill and no reminder, and never blocks them, until staff save a date. New requirements, and requirements that renew a year at a time, start with this choice.
  • "Due when they join": due on the day they join. This is only for people who join from the day you choose it. Anyone who is already a member shows "Not recorded yet" until you save a date. A requirement renewed on one club renewal day (for example every 1 September) keeps this choice for everyone, as it works today, and Settings says so.
  • "Covered for a year from when they join": their first expiry is one year after they joined. This needs an expiry date, so a requirement without dates only offers the first two choices.
  • Members who already have a date keep it.
  • A requirement without an expiry date no longer sends a new bill and a new reminder every night to a member who was never renewed. It stays due from the day it was first billed until they are renewed.
  • The register and the member's page show a quiet "Not recorded yet" for a missing date. It never blocks anyone. Everyone taking a register still sees who is blocked; the list of dates not recorded yet is shown only to staff who can see member requirements.
  • Staff can clear a wrong date back to "Not recorded yet" from the member's requirement card. It is saved in the audit log. It can't be cleared while a payment for that date is waiting, while a payment link is open, or for 7 days after a family started paying online (a payment can still finish after its link has run out). The message says what is happening and from which day the date can be cleared, or you can save the right date in Edit details straight away. After 7 days an unfinished payment no longer blocks it. If such a payment does finish later, the member's card shows "A payment for … is waiting": save that date again in Edit details, then press Process renewal. A date that came from a payment can't be cleared at all. The dialog says what happens next, for example that it will be due again on the next renewal day.
  • In "Edit details", leaving the expiry date blank clears it the same way, with the same checks. A date more than 5 years away asks "Are you sure?" first.
  • The Action Centre shows one item for each requirement with dates still to record, for example "4 members have no Taekwondo insurance recorded yet", with a button to the list of those members. It closes by itself when none are left.
  • Families can't start paying online for a requirement whose date isn't recorded yet, unless "Due when they join" applies to them. The portal says the club manages it. A payment they had already started can still be finished.
  • Settings no longer shows "Valid for (days)". Renewals use the one-year rule, and the saved number is left alone.

Insurance shown as "Not recorded yet"

  • A member with no insurance date shows a grey "Not recorded yet", never a red "No Insurance": on the Members list, in Communications, on the register, on the Grading page, and on the event and grading day pages.
  • An insurance date that ended yesterday now always shows "Expired" (in summer time it could show "Expiring soon" for a day).
  • An "Expired" insurance filter never includes a member with no date. That includes scheduled messages, which use the same filter. There is a new "Not recorded" choice in the insurance filters.
  • The older insurance reminders never call a missing insurance date "expired". A reminder already waiting for someone with no date is held back.

Renewing a requirement

  • When staff mark a requirement renewed (or process a renewal a family paid for online), they now choose the new date: "1 year from the current expiry date" (only while that date hasn't passed), "1 year from today", or "Pick a date" (after today and no more than 5 years ahead). The box shows the exact date before you confirm, for example "Valid until 1 September 2027".
  • A requirement renewed on one club renewal day offers "The next renewal day" instead of "1 year from today", and picks it for you once the date has passed.
  • A picked date earlier than the member's current cover is allowed, but the box says "This is earlier than their current cover" and asks you to tick before you confirm.
  • Renewing early no longer loses time. Before, a rolling renewal restarted from today, and a fixed-date renewal before its renewal day kept the same expiry.
  • Renewing uses the club's own day, so just after midnight it is already the new day. If something changes while the box is open, it reloads and shows the new choices. The nightly requirements run uses the club's day too.

Joining with no classes to pick

  • When every class in a programme has ended and the next ones aren't on the timetable yet, the joining form now says "Classes for Little Tigers aren't ready yet. You can still finish joining, and the club will tell you which class to come to." Families can still finish joining; the club adds their class later. The message has draft translations in every portal language.
  • Before an enrolment link goes out, staff now see a clear warning when the family won't find a class to pick: "There are no classes new members can join in Little Tigers right now (the last one ended on 26 September). The family can still finish joining, and you'll need to add their class later." It shows in the Send enrolment form and household link dialogs, and as a check before sending or resending from Trials & Enrolments, the invites list and the register. Staff can always carry on, and a slow check never holds them up: after 3 seconds the link goes out without the warning (a resent link's email never waits for it). If a link is for a programme the joining form can't offer at all, the warning says so.
  • Archiving a class, or saving an end date or settings that stop new members joining it, now warns first when it leaves the programme with no class to join: "After this change, new members can't join any class in Little Tigers. 3 enrolment links that can choose Little Tigers are still open. Families can still finish joining, and you'll need to add their class later." A future end date says "From 19 December, …". Staff can carry on, and after 3 seconds the change goes ahead without the warning.
  • The Action Centre now shows "Little Tigers has no classes new members can join" for a programme that is in use (it has members, or an open enrolment link made for it) when none of its classes can be joined. The button opens the timetable, and the item closes itself once a class can be joined again. Tidying the timetable (archiving the class that ended) keeps it the same item; the next gap, next term, is a new one. A programme with no members and no links of its own stays quiet.
  • Proof that joining never fails without a class: route tests for preparing and finishing with no class, and a database rehearsal (npm run db:rehearse-enrollment-safety, a run-owned copy of the test database) that prepares and finishes a pay-later and a paid enrolment with no class while the programme's only class has ended. The member simply has no class until the club adds one.
  • The joining form, its class list, the website join page, staff Add member and the staff warnings all use one rule for which classes a new member can join (not archived, a regular class, not ended, open to beginners). The website join page no longer offers bookable sessions as classes to join. Staff Add member no longer offers classes that have ended, and shows when a class starts or ends.

When a family can't start paying

  • If a family can't start paying to join (for example the club's card payments are switched off, Stripe is unreachable, the link has run out or the price changed), AllSorted now records the reason on that enrolment and tells the family in plain words, with a Try again button. Staff taking payment at the desk see what to fix. Recording the reason never changes the enrolment or any money.
  • Staff then see an Action Centre item, with no money in it: "A family couldn't pay to join Little Tigers on 29 September 2026: Stripe isn't letting your club take card payments right now". The button opens payment settings or the enrolment, and the item closes itself once the family starts paying. When the problem is with the club's own payments (not set up, card payments switched off, or Stripe unreachable or refusing), it is one item however many families it stops: "3 families couldn't pay to join Little Tigers, the latest on 30 September 2026: …".
  • Opening the joining page again while a bank payment is still going through (or after it went through) is normal: the family now sees "Your payment is still going through" and is asked not to pay again, and nothing is recorded for staff.

A safety net for joining payments

  • Every 15 minutes AllSorted now checks enrolment payments that started more than 15 minutes ago (up to 10 days) and haven't finished. It only reads from Stripe. A payment that went through finishes the enrolment exactly as Stripe's own message would have, so a family is never added twice or charged twice. Bank payments still being processed, and payments waiting at 3-D Secure or the bank, are left alone and looked at again. A payment that failed or was never made before the link ran out is recorded as not paid. It looks at the payments it checked longest ago first, so payments that stay unfinished for days (a slow bank payment, a link the family hasn't used yet) can't stop it reaching the others.
  • When a family has paid but their enrolment can't finish (for example a class they chose is full, or their link ran out before it finished), staff who can see payments get an Action Centre item: "A family paid £69.00 to join Little Tigers on 29 September 2026, but their enrolment didn't finish", with the reason and a link to the enrolment. Stripe keeps retrying for up to 3 days and the family can try again, so it may still finish by itself; the item then closes itself. Before refunding the family or adding them by hand, staff cancel their enrolment link (a new "Cancel their link" button on the enrolments page, which asks first; it waits while a payment for the link may still be going through), so a later retry can't add them as well: once a link is cancelled, a late payment message only puts the enrolment up for a refund review (proved on a copy of the database by npm run db:rehearse-enrollment-safety, which also shows that without the cancel the retry would enrol them). A short hiccup (for example two finishing steps running at the same moment) only becomes an item if it is still stuck 15 minutes later.
  • A payment that was refunded or disputed before the enrolment finished is never used to join: Stripe's message (and its retries) and the safety net check the payment first, and the family's page refuses it once it has been found (and checks again for an enrolment waiting for review). Staff get their own item for it: "A family's £69.00 payment to join Little Tigers on 29 September 2026 was refunded or disputed before their enrolment finished", which stays open until someone has checked it. The family is asked to contact the club. A refund that failed or was cancelled (the money stayed with the club) doesn't count, and a payment Stripe's message describes without its charge is looked up again before anyone is asked to check it.
  • The enrolments page has a new "Enrolments that need a look" list: families who paid but whose enrolment didn't finish, who couldn't start paying, whose payment didn't go through or who started paying and haven't finished. Each one says why in plain words and what to do next. Staff who send enrolment links or who can see payments can open it; amounts show only for staff who can see payments. The Action Centre items open the page on the right enrolment.
  • The 15-minute payment recovery job now gives its three parts 40 seconds (joining payments), 160 seconds (renewal payments) and 40 seconds (renewal baskets): 4 of its 5 minutes, so it always has time to write its log. Where Stripe isn't set up, the joining part reports "not set up" instead of failing.
  • Release note: no SQL is needed. The two new item kinds are listed in the Action Centre's check after (_verify/action-centre-bundle-p-postflight.sql). Before the deploy that ships the safety net, the owner runs the read-only census in docs/ops/stripe-webhook-configuration-2026-09-10.md ("Before the release"): counts of what the net will act on first.

Family pricing

  • A family's household page now says, in plain words, which family-discount rule the club uses, for example "Family discount: each membership on its own. Change this in Settings → Memberships → Household pricing", with a link there. It also says when a different rule is already scheduled.
  • When the club's rule is "Within each membership" and counting everyone in the family together ("Highest standard price first") would really lower this family's bill, it adds a gentle hint that says by how much: "Want the family discount to count across memberships? Choose 'Highest standard price first'. It would save this family £3.00 a month." It is worked out by the same pricing as the totals on the page (the same prices, household cap and VAT), which counts people, not memberships: one child on two memberships is the 1st person on both either way, so their family never sees the hint. It only counts the bills AllSorted collects: a membership the club collects itself (for example during the Xero handover) is left out, just as billing leaves it out, so the saving shown is exactly the change to AllSorted's bills. It never suggests a rule that would make any bill dearer. Nothing about how anything is priced has changed.

Collect-from date

  • A club that has never chosen its collect-from date gets the club's real date (today) when AllSorted first collects for it, or when it first connects Direct Debits. A billing job run by hand for an earlier date no longer saves that earlier date as the club's collect-from date, so older bills are never collected automatically before the club has chosen.
  • Late-bill checks that no longer need anything (the bill was paid, cancelled or credited) now close for clubs with more than 500 open checks too: AllSorted looks at them all, 500 at a time, within the time each run has, and carries on with the rest next time. A billing run never spends past its own time limit on them, and saving the collect-from date spends at most about 3 seconds on them, so a big club's save doesn't keep you waiting.
  • Collecting a bill by Direct Debit from a family's page now asks first exactly when AllSorted wouldn't collect it automatically. Before, it didn't read the club's collect-from date at all, so it never asked. Now it asks for a bill due before the collect-from date; while no date has been chosen yet, for a bill due before today ("Your club hasn't chosen a collect-from date yet, so AllSorted only collects bills due from today automatically"); and for a bill with no due date, whatever the setting (AllSorted never collects one automatically, so a club that collects every bill is still asked about it). A late bill still waiting for its check is refused until someone checks it on the family's household page, as before: unless a collect-from date is saved (which hides that check while the bill is before it, so the question says so), saying yes to the question never skips the check.
  • In Settings → Payments, a club that hasn't chosen a collect-from date can now choose to collect every unpaid bill straight away ("Collect every bill"). As with clearing a date, AllSorted first says how many older unpaid bills that would let it collect, and saves only when you confirm.

Text and Telegram messages

  • When the SMS gateway or Telegram sends AllSorted the same message again with a small, harmless change (for example the sender renamed their Telegram account while the message waited, or the gateway added an empty field), AllSorted now recognises it as the same message instead of refusing it for ever. A message finished before this change can't be checked against its first delivery, so a changed resend of it is still treated as the same message, and is counted for someone to check ("Didn't match 24h"). A stuck Telegram message no longer holds back the club's later ones. A genuinely different message under the same id is still never acted on: Telegram is now told it arrived, so the club's later messages aren't held back, and it is recorded for someone to check (Admin Health → Messaging, "Didn't match 24h"); the SMS gateway is still told no.

Register

  • While a day's register loads, the class list no longer shows classes that have ended, have not started yet or are archived, only for them to vanish a moment later. Classes added for just that day appear as soon as the day has loaded. The same rule applies to the "Add a regular lesson" list and to the class the register remembers from last time.
  • The register keeps working for clubs with a long history. It used to load every class the club had ever had, and stopped with an error after 500. It now loads the current timetable and recent classes, and older classes still appear on their own dates, under the right programme. If a club ever has more than 1,000 regular classes, "Add a regular lesson" says that only the first 1,000 are listed.

Syllabus covered

  • "On the mat" now shows the levels of everyone marked Present or Late, including people added to the class from another programme (it uses their level in this class's programme) and trial students (shown as the first level).
  • A skill that appears in several grades shows once, for example "Pattern 1 · White, Yellow and Orange belts". One tick covers it for the grades of the people on the mat, so nothing is recorded for a grade nobody there holds. If nobody on the mat holds any of them (for example in "Class syllabus"), the tick covers every grade listed, and the row says which ("Tick covers White, Yellow and Orange belts"). "Cover the rest" adds the other grades, and "Tick one grade" lets you tick or clear a single grade. Unticking clears all of them. If only some grades are covered, the row says so ("Covered for White Belt only").
  • Ticks show straight away and save in the background. Quick ticks are saved together in one go. Nothing locks or blanks while saving, or when someone is marked present or added. If a save fails, that row goes back to how it was and says "Couldn't save. Tap to try again". If another coach changed an item at the same moment, only that row says so ("Someone else changed this just now"), and your other ticks are saved again once the list has refreshed (unless you have changed them since). If the class is no longer on for that date, the rows say so and nothing is sent again.
  • Screen readers hear what each tick will do ("Mark covered" or "Clear"), and which grades and syllabus it is for.
  • Search also finds tag names, and tag buttons under the search box filter the list. Only your club's own tags appear.

Member requests

  • Sending a request is now one step. While you fill in the form, a summary updates by itself a moment after each change: who gets the request, who is left out and why, and the email check. There is no "Check choices" button any more. Create switches on as soon as the summary matches what is on screen, and AllSorted checks everything again when you press it.
  • The reasons are shown straight away, one line per member (for example "Already has a membership request open, or an accepted change that hasn't started yet"), instead of being folded away.
  • A membership request must now offer at least one plan, so nobody is asked only to keep the plan they have. A member who is already on the only plan you picked is left out of the membership question and the summary says why.
  • No class question is sent to a member whose accepted class change hasn't started yet (their answer would have been refused). You can replace that change instead.
  • Replace instead of skip: a member who already has an earlier request is listed with what it was and when it was sent. Tick "Replace Sam's earlier request" (or "Replace all"). This works if the family hasn't answered yet, has answered and is waiting for you, or has accepted a change that hasn't started. For an accepted change you see, for example, "Sam accepted Black Belt Club from 1 November 2026. Replacing cancels that change." A change that has already started can't be replaced. When you press Create, the old request is withdrawn and the new one is created together, so nobody ends up with neither. The family gets one email: the new request, saying who it is for and what is still open, for example "For Sam, this replaces the earlier request from 20 September 2026." A staff-only record of what was replaced is kept.
  • Replacing withdraws the earlier request, so only staff who can review member requests see Replace. Others see why.
  • If the earlier request also changes something the new one doesn't ask about (for example their classes, when the new request is about membership only), it can't be replaced. The summary says "Sam's earlier request also changes their classes. To replace it, ask about classes in this request too, or withdraw the earlier request first." Nothing is lost by accident.
  • Create stays off when a member you ticked to replace would get nothing from the new request, or when a family is answering right now (press Check again in a moment). If AllSorted refuses because something changed, the summary updates straight away.
  • Replacing a whole request from the household page follows the same rules.
  • If two published automations both send the new-request email, the email check now says so: "Families will get 2 emails because 2 automations send this."
  • The review window has Previous and Next buttons at the top, with "2 of 9", so you can move between families in the queue. Approve all is unchanged.
  • The long "Upcoming" list of scheduled class changes is now a button, "Upcoming accepted changes (12)". It opens a list of every accepted change that hasn't started yet, membership-only ones too: who, what changes and from which date. You can search by name, show more, and use Return for changes or Withdraw from there. "Needs attention" stays on the page.
  • One email per family: when two or more members of a family answer the same request one at a time (membership only, classes only, or both), the family gets one email for that sitting. AllSorted waits up to 10 minutes while others in the request are still answering. When you approve several members of one family within a few minutes, the family gets one approval email listing each member (this replaces "one approval email per member"). Declines work the same way, with each member's reason. Families waiting like this never hold up other emails.
  • The staff list of requests no longer shows requests that families start themselves; those are handled in the review queue.
  • Status: Local only. Needs the SQL below; until it is applied, sending works as before (with the new summary) and Replace is not offered.

Families asking to change lessons or membership

  • A new club setting in Member Requests: "Let families ask to change their lessons or membership". It is off for every club until staff with permission to manage member requests turn it on. While it is off, families see nothing new and nothing can be started.
  • When it is on, the Actions page in the family portal has a "Change lessons or membership" part under "Ask the club for a change". For each member it shows what they can do now: ask for a change, carry on with a change they started, wait for the club, or when they can ask again.
  • A family can ask for one change for each member each month (the club's calendar month). A request that is started, waiting or approved counts. One the club declined, the family cancelled, that was withdrawn, or that went out of date does not.
  • The family chooses the new membership and classes on the same screen the club's own requests use, then sends it. Nothing changes until staff approve it in Member Requests. Staff see who sent it ("Sent by"), and that it starts at the member's next bill.
  • An approved change starts on the member's next bill date, so nothing is billed backwards and a bill that is already made never changes. Bills are made a few days before their date, so the family sees: "If the club agrees before that bill is made, the change starts then. If not, it starts at the bill after."
  • A family can cancel a request before sending it. A request they started but didn't send goes out of date once its date has passed or the bill for that date has been made (so the family is only ever shown, and can only send, the date the change will really start). It then closes by itself within a few minutes, with no message, so it never stops the member being asked by the club. Asking again starts a fresh request for the new date straight away. A request the club sent back for changes is never closed this way: the family sees the club's reason ("The club has returned these choices for you to check"), then can ask again or cancel it.
  • A family request is always sent as one answer with the membership and the classes together. A membership-only or classes-only send is refused in plain words, so a member is never left waiting on half a request.
  • A family is only offered memberships the club's billing allows for them on that date, checked plan by plan exactly as the change is checked when they choose it (for example, a family price cap that covers one plan, while the family already has that plan billed on another day, takes just that plan away). When only the club can change a member's membership (it has a special price, it is paid by card subscription, or every other plan is ruled out that way), the family is told why in plain words and can still ask to change classes: the request then offers their current membership only.
  • With the setting off (every club today), the Actions page only looks for requests a family had already started, instead of working out every member's options on each visit, and its two parts load at the same time.
  • If the member leaves or is paused, an open request is withdrawn automatically and the family gets the same short message as for other requests.
  • In Member Requests, a family's request shows on its review card as "Family request: change lessons or membership", and once it is approved, in "Upcoming accepted changes" (marked "asked for by the family"). It is not listed with the requests the club sends, and it is not offered in the automation request filters, so it never uses up those lists.

Answering the club's membership and class requests

  • When the club asks about membership and classes, each member now has a choice: "Change membership or classes", or "Keep as now (no change)". A family can change one member and leave another as they are, and send without picking a plan for everyone.
  • "Keep as now" is offered on every kind of club request: membership and classes, membership only ("Change membership" or "Keep as now"), and classes only ("Change classes" or "Keep as now"), for one member or for each member when several answer together. It works even when the member's current plan is no longer on sale. The household card only mentions keeping when someone on it can keep.
  • "Keep as now" is saved straight away, even in clubs that check answers first. It doesn't go to the staff review list, nothing is scheduled and nothing new is billed. It never stops the club sending that member a new request later. It isn't offered for a request the family started themselves (they can cancel it), for a paused member's return offer, or for a member with no membership yet.
  • Picking exactly what a member has now (the same membership, the same classes, or both) counts as "Keep as now" too: it is recorded at once, not sent for review and not scheduled as a change.
  • A request about membership and classes together is answered as one: sending just the membership (or just the classes) is refused in plain words, so nothing is left half answered.
  • Staff see "Kept as now" in the request's member list (including under Completed). Trying to withdraw a kept answer says plainly there is nothing to withdraw. A kept answer keeps the history of that answer, such as an earlier "returned for changes" and the club's reason.
  • The family page only shows "Keep as now" once the database update below is in place; before that the page stays as it was.
  • When the club asks several members about membership only, or about classes only, the family now answers everyone on one card and sends it once. Everything is saved together or not at all, and the family gets one message about it. A request for just one member works as before.

Release requirements

  • Apply requirement-join-start-01 before final readiness: _verify/requirement-join-start-preflight.sql → _proposed/requirement-join-start-01.sql → _verify/requirement-join-start-postflight.sql. Until it is applied, every requirement behaves as "Leave blank until we record it" and the choice can't be changed. It changes no member's dates, creates no bills and sends nothing. Final readiness now requires it.
  • Apply requirement-renewal-choice-01 before final readiness: _verify/requirement-renewal-choice-preflight.sql → _proposed/requirement-renewal-choice-01.sql → _verify/requirement-renewal-choice-postflight.sql. It adds the new renewal step beside the current one, which the app in use today keeps calling until the deploy. The new app needs it: without it, renewing says it isn't available and changes nothing. Final readiness now requires it.
  • The read-only owner check docs/database/requirement-dates-new-starters-check-2026-10-02.sql (the same file as ~/Downloads/AllSorted-check-requirement-dates-new-starters.sql) counts which requirements gave new starters a date within 7 days of joining, and which choice each will start with.
  • New additive SQL provider-webhook-receipt-stable-identity-01 (after webhook-claim-stable-identity-01, before readiness): preflight, apply, postflight, as listed in docs/ops/kata-membership-owner-sql-2026-09-25.md (step 39d2). Readiness was regenerated to require it, so use the readiness copy from this branch or later. The app works before and after it is applied (it falls back to the old receipt check until then).
  • Apply syllabus-lesson-coverage-04-groups (after syllabus-lesson-coverage-03-replay) and register-setup-current-lessons-01, each with its check before and check after, before final readiness. The regenerated readiness check requires both. They add read and save functions only: no table, permission or data change, and nothing is sent.
  • Until they are applied (for example on a preview), the register falls back safely: one row per grade, one save per item, no tag buttons, and the older full class list.
  • New additive SQL member-request-replace-07 (after member-request-withdrawal-delivery-06, step 39.7, before readiness): _verify/member-request-replace-preflight.sql → _proposed/member-request-replace-07.sql → _verify/member-request-replace-postflight.sql. It adds read and request functions only (no table, permission on a table, or data change) and sends nothing by itself. Readiness was regenerated to require it, so use the readiness copy from this branch or later. Before it is applied the app falls back to the current request functions and offers no Replace.
  • Part B only (the branch claude/portal-change-requests): apply portal-family-change-requests-01 after the three portal family-details units and before final readiness: _verify/portal-family-change-requests-preflight.sql → _proposed/portal-family-change-requests-01.sql → _verify/portal-family-change-requests-postflight.sql (step 39a.4 in docs/ops/kata-membership-owner-sql-2026-09-25.md), at a quiet time: until it finishes (usually under a second) saving member requests waits, and reading request batches and request settings pauses briefly while their new columns are added; it stops with nothing changed if it waits more than 5 seconds. Readiness was regenerated to require it. Until it is applied the new parts stay hidden, the staff setting is not shown, and the member request job closes nothing. Turning the setting on is the owner's choice per club, after the October change.
  • Same branch: apply member-request-family-answers-01 after portal-family-change-requests-01 and before final readiness: _verify/member-request-family-answers-preflight.sql → _proposed/member-request-family-answers-01.sql → _verify/member-request-family-answers-postflight.sql (step 39a.5), at a quiet time (it replaces two checks on member requests). Readiness was regenerated to require it. Without it, "Keep as now" is not shown; the shared membership-only and classes-only cards still save each member's answer one by one (not together, and without the single message); changing membership and classes together still works.

Reliable conflict responses

1 October 2026

Reliability

  • A save that loses its claim or encounters a changed record returns a conflict promptly. Billing and membership checks continue to reject the same invalid requests, without repeatedly retrying them at the database API.

Release requirements

  • Use the corrected pending SQL units and their matching checks from the final release copy. Already-installed renewal follow-up claims have a separate additive correction, requirement-renewal-side-effect-conflicts-02, after the renewals basket checks and before final readiness. Applying the correction does not process renewals, create charges or send messages.
  • Existing runtime authorities also need the additive postgrest-business-conflicts-01 correction after the release units. Install the Xero and platform-referral companions only where their prerequisite chains exist; an installed chain must pass its matching correction and postflight before readiness. These changes preserve prices, permissions, locks and genuine database serialization handling.
  • The final readiness check now pins the conflict response definitions as well as their permissions. Earlier passing checks do not prove this release's corrected SQL is installed. The complete local release check and source-matched database rehearsals have passed. Current PR CI, production checks and SQL application remain with the owner.

Xero contact confirmation stability

30 September 2026

Accounting

  • Bulk Xero contact confirmations now stay open while the match list refreshes. Starting the next action no longer risks having its confirmation closed by the previous action's delayed completion.

Release verification

  • CI now exercises public enrolment preparation, completion and retry through the real route and database, including one suppressed automation delivery. The rehearsal uses an explicitly owned temporary database and API, refuses shared or remote targets, and does not read application environment files. No additional production SQL or setting is required by this test change.
  • The owner SQL handoff now checks existing automation prerequisites before beginning the release sequence: installed RPCs, template-snapshot authority, retained inbox source identifiers, and eleven historical delivery columns. The new delivery probe reads catalogue metadata only; a failure requires review, not reapplying an old installation. These checks do not send messages or prove live delivery.

Security

  • Updated Next.js and its matching lint configuration to 16.3.8, with patched brace expansion, DOMPurify and URI parsing dependencies. This addresses newly reported upstream advisories without adding audit exceptions. No database or environment change is required for these dependency updates.