Overview
AllSquads sends notifications via three channels: in-app (push/bell), email, and SMS. Players, coaches, and club admins each receive role-specific notifications. All notification preferences are configurable per user.
Email coverage is broad (~84 distinct templates) and spans authentication, welcome drips, bookings, court hire, subscriptions (lifecycle and pause/resume), credits, payments, payouts, invites, products, reviews, lesson offers, admin/legal, and marketing.
Channel matrix (rework, 2026-08-02, M1 bounce — Alex's GOVERNING ruling). Trigger: a live prod SMS read "Your All Comers Pickle Sesh class will be taken by Luca Katsamakis from now on." with no date, time, or club — sent for a routine coach reassignment. A first pass built to a SUPERSEDED relay of Alex's ruling that kept rescheduling on SMS; M1 bounced it. Alex's GOVERNING ruling, verbatim: "coach swaps don't need any email/in-app, except for a private lesson perhaps. cancellations get SMS, reminders get email and in-app. rescheduling gets in-app/email."
| Event family | SMS | In-app | |
|---|---|---|---|
| Cancellations (9 types — session/booking/subscription/court-hire cancelled, or a cash/credit refund tied to one) | ✅ | ✅ | ✅ |
| Reminders (24h/1h class reminders, court-hire series occurrence reminder) | — | ✅ | ✅ |
| Reschedules (class date changed, session rescheduled, booking moved, court hire rescheduled) | — | ✅ | ✅ |
| Coach swaps — GROUP class (per-session replacement, class-level reassignment) | — | — | — (suppressed entirely) |
| Coach swaps — PRIVATE LESSON | — | ✅ | ✅ |
Booking emails name the session you booked, and every session the booking covers (2026-09-04; Alex ruling). A booking email's Date and Time always describe the SESSION being attended — never the day the booking was made, and never a different session of the same class. A booking that covers more than one session lists every one of them, each with its own date, rather than showing the first and dropping the rest. This applies to the player's booking confirmation and to the club/coach "New Booking Received" email alike. The subject line deliberately does NOT carry a date; the body is where the dates live.
Why it is written down: a club received a "New Booking Received" email dated a fortnight before the session actually booked, for a session they knew was full, and reasonably read it as a phantom booking. The email was describing the class's next upcoming session instead of the one the player had bought.
This SUPERSEDES both the earlier "SMS on any booking change" policy and the first rework pass's "cancellations + rescheduling" SMS list. Every surviving cancellation SMS body must carry enough detail (class/court + date/time where one applies + club/venue) to be useful on its own — see the ≤160-character single-SMS-segment budget note below.
Player Notifications
| Event | In-App | SMS | |
|---|---|---|---|
| Booking confirmed | ✅ | ✅ | — |
| Booking cancelled (by player) | ✅ | ✅ | — |
| Booking cancelled (credits issued) | ✅ | ✅ | Optional |
| Booking refunded (Stripe — admin override) | ✅ | ✅ | Optional |
| Booking partially cancelled | ✅ | ✅ | Optional |
| Session cancelled by coach/club | ✅ | ✅ | Optional |
| Court hire booking confirmed | ✅ | ✅ | — |
| Court hire booking cancelled | ✅ | ✅ | Optional |
| Court hire series — occurrence reminder | ✅ | ✅ | — (reminder) |
| Court hire series — occurrence skipped | ✅ | ✅ | Optional |
| Court hire series — cancelled by coach | ✅ | ✅ | Optional |
| Private lesson booking pending approval | ✅ | ✅ | — |
| Private lesson approved | ✅ | ✅ | — |
| Private lesson declined | ✅ | ✅ | — |
| Private lesson request auto-cancelled (no coach response in time) | ✅ | ✅ | Optional |
| Alternative time suggested (private lesson) | ✅ | ✅ | — |
| Session reminder — 24 hours before | ✅ | ✅ | — (reminder) |
| Session reminder — 1 hour before | ✅ | — | — (reminder) |
| Session rescheduled | ✅ | ✅ | — (reschedule, not a cancellation) |
| Court hire rescheduled (booking moved to a new slot) | ✅ | ✅ | — (rework) |
| Class date changed | ✅ | ✅ | — (rework) |
| Booking moved to a different session | ✅ | ✅ | — (rework) |
| Coach change for upcoming session (replacement player) | GROUP: — · PRIVATE LESSON: ✅ | GROUP: — · PRIVATE LESSON: ✅ | — (never — coach swaps aren't a cancellation) |
| Coach changed on a class | GROUP: — · PRIVATE LESSON: ✅ | GROUP: — · PRIVATE LESSON: ✅ | — (the reported-bug type; never SMS) |
| Waitlist spot available | ✅ | ✅ | — |
| Payment confirmed | ✅ | ✅ | — |
| Payment failed | ✅ | ✅ | — |
| Credits issued | ✅ | ✅ | — |
| Credits expiring soon | ✅ | ✅ | — |
| Subscription cancelled | ✅ | ✅ | Optional |
| Subscription paused | ✅ | ✅ | — (lifecycle change, not a cancellation) |
| Subscription pause confirmed | ✅ | ✅ | — |
| Subscription resuming soon | ✅ | ✅ | — |
| Subscription pause — pre-resume reminder | ✅ | ✅ | — (reminder) |
| Subscription resume outcome | ✅ | ✅ | — |
| Auto-renew charge processed | ✅ | ✅ | — |
| Auto-renew charge failed | ✅ | ✅ | — |
| New message from coach or club | ✅ | ✅ | — |
| Group chat message | ✅ | Optional | — |
Legacy migrated group channels are notification-suppressed (2026-08-20): group channels imported from v1 that were never mapped to a class, segment, or club (type='group' with no target_kind) do NOT send message notifications or emails at all — one post to such a channel previously emailed every bulk-imported member (up to 340 people). Posts to these channels remain visible in-app to their members; DMs, class channels, segment channels and club announcements are unaffected. Each legacy channel will be individually mapped to its real class or archived.
Messages tab is organised, not just chronological (2026-08-20): Announcements always sit together in one section at the top. A class or lesson group chat that nobody has posted to yet stays hidden from players/members until the coach who set it up posts the first message (the coach always sees it so they can post that first message; club/coach staff always see it too) — it's never deleted, it just reappears the moment it has content. Conversations imported from before go-live are grouped into a collapsed "Earlier / imported" section rather than mixed in with current chats — nothing is ever deleted, just tucked away until you open it. Everything else is sorted by most recent activity.
| Review prompt (after attendance) | ✅ | ✅ | — |
|---|
Waitlist — strictly first-come, first-served (2026-07-19; ADR-042): when a spot opens, "Waitlist spot available" fires to the waitlisted player(s). There is no time-based expiry, no offer hold, and no sequential offer-to-next-player queue — a prior "Waitlist spot expired (no action taken)" row here described machinery that was never built (see also docs/02-core-flows.md "Auto-remove / offer expiry: NONE"). A 24h expiry + FIFO cascade job was built against this stale doc line without approval and was reverted the same day.
Losing the race (2026-07-20; Alex ruling Option B+C): a notified row is not a terminal state. If a different player's booking consumes the spot first, the loser's row resets from notified back to waiting, so they remain eligible for the next spot-open notification instead of being silently and permanently excluded. Re-joining the waitlist also resets a stuck notified row as a safety net. This does not add an expiry/hold/offer-queue — it only prevents a lost race from being a dead end.
Player SMS coverage (canonical, 9 types — rework, 2026-08-02)
Player-facing SMS is sent ONLY for cancellations — see the channel matrix in the Overview above. Reminders and rescheduling are email + in-app only (moved OFF SMS in this rework — a first pass had kept rescheduling on SMS against a superseded relay of Alex's ruling). Every other player event (booking-confirmed, court-hire-confirmed, player-initiated cancellations, waitlist notices, coach reassignment, subscription pause/resume lifecycle changes) is intentionally excluded — these are covered by in-app and email instead.
Every SMS body below carries the class/court name + the specific date and/or time + club/venue (or, for event-level types with no single session date — a rejected pending booking, a Stripe cash refund, a recurring court-hire series cancel, a subscription's effective date — the class + club/venue anchor at minimum). No SMS body ever emits a bare "has changed" / "from now on" with no identifying context (the defect in the reported prod SMS). Every cancellation SMS body is also capped at 160 characters (a single GSM-7 SMS segment — Alex: "≤160 so it's one SMS message") via a shared composer that shortens the date/time format and drops the coach/admin-typed cancellation reason (unbounded free text) and secondary credit/pack detail from the SMS specifically; the full detail still reaches email + in-app.
Cancellations (the complete SMS list):
- session_cancelled
- booking_cancelled_refund
- booking_partial_cancelled
- court_hire_cancelled
- court_hire_series_cancelled_by_coach
- court_hire_series_occurrence_skipped
- stripe_refund_issued (admin Stripe override; distinct from booking_cancelled_refund which is credits-issued)
- subscription_cancelled
- private_lesson_request_auto_cancelled (no coach response within the request window)
Moved to email + in-app only in this rework (rescheduling — was SMS-eligible under the first, superseded rework pass): class_date_changed, session_rescheduled, booking_moved_player, court_hire_rescheduled.
Moved to email + in-app only as of the first rework pass (previously SMS-eligible under the superseded earlier "any booking change" policy): reminder_24h, reminder_1h, court_hire_series_occurrence_reminder, waitlist_spot, subscription_paused, subscription_resuming_soon, subscription_pause_confirmed, subscription_pause_pre_resume_reminder, subscription_resume_outcome.
Never SMS, and suppressed on EVERY channel for a GROUP class (email + in-app too) in this rework — coach_changed_player and coach_session_replacement_player (the reported-bug type). A PRIVATE LESSON keeps these on email + in-app (never SMS, matching every other type in this list). The class/session's squad_type/schedule_type determines which applies.
Coach Notifications
Coaches receive notifications via in-app and email. SMS is reserved for the player-facing event types listed in the canonical SMS coverage section above.
| Event | In-App | |
|---|---|---|
| New booking (own class) | ✅ | ✅ |
| Booking cancelled (player) | ✅ | ✅ |
| Private lesson booking request | ✅ | ✅ |
| Private lesson cancelled (player) | ✅ | ✅ |
| New review received | ✅ | ✅ |
| Session reminder (own session) — 24 hours | ✅ | ✅ |
| Replaced on a session by club admin | ✅ | ✅ |
| Assigned as replacement coach on a session | ✅ | ✅ |
| New message from player | ✅ | ✅ |
| Payout processed | ✅ | ✅ |
| Payout failed | ✅ | ✅ |
| Stripe Connect approved | ✅ | ✅ |
| Class capacity reached | ✅ | ✅ |
Club Admin Notifications
Club admins receive notifications via in-app and email. SMS is reserved for player-facing event types (see canonical SMS coverage section).
| Event | In-App | |
|---|---|---|
| New booking (any class) | ✅ | Optional |
| Booking cancelled | ✅ | Optional |
| New private lesson request | ✅ | ✅ |
| Court hire booking made | ✅ | Optional |
| Court hire booking cancelled | ✅ | Optional |
| New review received | ✅ | ✅ |
| New contact added | ✅ | — |
| Membership expiring (contact) | ✅ | ✅ |
| Credits issued (by system) | ✅ | Optional |
| Payout processed | ✅ | ✅ |
| Payout failed | ✅ | ✅ |
| Stripe Connect approved | ✅ | ✅ |
| Class capacity reached | ✅ | ✅ |
| Scheduling conflict detected | ✅ | ✅ |
| New message from player | ✅ | ✅ |
| AI agent escalation (unresolved enquiry) | ✅ | ✅ |
Email Coverage
AllSquads ships ~84 distinct email templates across the following categories:
- Authentication and password
- Welcome drips for player, coach, and club roles (day 2, 3, and 5 touchpoints)
- Bookings (confirmation, cancellation, partial cancellation, refund, moved-player)
- Coach changes (replacement coach, coach changed on a class)
- Court hire (single bookings and recurring series)
- Subscription lifecycle (cancellation, paused, pause confirmed, resuming soon, pre-resume reminder, resume outcome)
- Credits (issued, expiring, redeemed)
- Payments and payouts (success, failed, processed)
- Invites (coach invite, club invite, accepted)
- Products (purchase, refund)
- Reviews and lesson offers
- Admin and legal notices
- Marketing campaigns
Specific templates can be enabled or disabled per user via notification preferences (see below).
Notification Preferences
Configuring preferences
All users manage notification preferences in Dashboard > Settings > Notifications. Each notification type can be toggled on or off per channel (in-app, email, SMS).
Coach/club email toggles — what each controls
The Settings > Notification preferences panel exposes two coach-side email toggles. Both default ON for new accounts.
- "New booking received" — fires the email when a player completes a booking (paid or pending) on one of your classes. Backend event:
new_booking_received. Includes manual bookings created by an admin, regular Stripe-paid bookings, annual subscription renewals. - "Booking cancellation" — fires the email when a confirmed booking is cancelled by either the player or by you. Backend events:
booking_cancelled_by_player,booking_cancelled_refund,booking_partial_cancelled,session_cancelled(all four map to the samebooking_cancelledpreference category).
Two former toggles ("Payment received" + "New player joined") were removed because no backend event existed to gate. Coach-side payment notifications are bundled into the "New booking received" email (most bookings are paid at booking time). Payouts are always-sent transactional and not user-toggleable. There is no platform-side "new player joined this club" event — players appear in your contacts the first time they book.
Per-club notification preferences
Players who follow or are members of multiple clubs can set per-club preferences in Dashboard > Profile > Notifications > "Per-club preferences". For each club a player can independently mute marketing broadcasts, class announcements, and waitlist notifications without affecting bookings/payment notifications, which always go through. The backend notify() dispatcher checks the per-club preference table before sending email or SMS so muted users receive nothing for that club.
SMS notifications
SMS notifications require a verified mobile number in the user's profile. Standard SMS rates may apply depending on the user's carrier. SMS is optional for most notification types and is off by default.
Email frequency
For high-volume events (e.g., individual bookings on a large class), club admins can switch from per-booking emails to a daily digest to reduce inbox volume.
Notification Content Standards
Booking confirmation (player)
Contains: class name, session date and time, full venue address (street, suburb, state, postcode — not just the suburb; 2026-07-30), coach name, participant name, booking reference, payment amount, cancellation policy summary, link to booking in dashboard. The full address applies to every booking-confirmation path (one-off, casual-recurring subscription renewal, annual subscription, session-pack redemption, free-trial, club-approval, manual add, court hire) so the player always knows exactly where to go — profile/explore/search cards intentionally show only suburb + state for browsing (see ADR-008's amendments).
Session reminder (player)
Contains: class name, session date and time, full venue address (street, suburb, state, postcode), coach name, what to bring (if configured), link to booking. Court-hire's equivalent recurring-series occurrence reminder carries the same full address.
Waitlist spot opened / booking payment link (player)
Contains: class name, session date and time, full venue address, spots remaining (waitlist) or amount due (payment link), a book-now / pay-now link. Every court-hire email (confirmed, new booking, cancelled, rescheduled, series invite, payment link) carries the same full address as its class-booking equivalent.
Coach reassignment (player + coach)
Per-session and class-level coach-change emails (coach_session_replacement_player, coach_changed_player, and the new-coach/original-coach counterparts) carry the full venue address, resolved from the class's linked venue — not read off sessions, which has no location column.
Rework (2026-08-02): the two PLAYER-facing types above (coach_session_replacement_player, coach_changed_player) are suppressed entirely — no email, no in-app, no SMS — when the class is a GROUP class. A PRIVATE LESSON keeps them on email + in-app (never SMS). The coach-facing counterparts (original coach told they were replaced; new coach told they were assigned) are unaffected and fire regardless of class type.
Booking cancellation (player)
Contains: class name, cancelled session date, reason (if provided), refund outcome (credit amount and expiry, or no refund), link to credit balance.
Private lesson request (coach)
Contains: player name, requested date and time, duration, lesson type, player notes, approve/decline action links.
Payout notification (coach/club)
Contains: payout amount, period covered, number of transactions, link to payout report.
AI agent escalation (club admin)
Contains: channel (website chat / email / WhatsApp), player name or identifier, conversation summary, link to full conversation in Messages tab.
Marketing SMS Broadcasts — not available
Marketing SMS broadcast campaigns are OFF on all tiers and not offered to any club or coach (the add-on purchase model was removed; the feature is deferred until a future paid plan re-introduces it). There is no SMS Campaigns surface in the dashboard today.
Transactional / operational SMS (booking confirmations, reminders, cancellation notices) is a separate feature with its own tier rules and is unaffected by this — see the notification-type sections above and 20-pricing-tiers.md for which tiers include transactional SMS.