How notifications travel
The architecture is opaque to most coaches, but understanding the plumbing helps when things look slow or weird.
The pipeline
[Coach edits event] → [worker writes audit_log row] ↓ [fanoutNotifications] ├── if change is "material" (time/location/coach-note/cancel/…) │ ├── if ≤48h: enqueue 'immediate' rows per family │ └── if >48h: enqueue 'digest' rows per family, │ scheduled for next 6pm club tz └── for each other coach with access + notify-on for this calendar: fire web push directly (no queue) ↓ [background sender, every 5 min] ├── for 'immediate' rows: │ ├── fire Telegram channel post (once per channel) │ ├── fire web push to every family subscription │ └── markSent — NO email └── for 'digest' rows (only at 6pm): └── one combined email per opted-in contactWhy ≤48h has no email
To keep inbox noise down. Phone push and Telegram channels cover the urgency case; email goes back to its useful role as a daily summary at end of day.
Why digests are at 6pm
It’s late enough that the day’s edits are usually done, and early enough that families still have time to react before the next morning. Club-tz-aware (America/Denver), so it always lands at 6pm local even under DST.
What if a family has push, Telegram, AND email enabled?
For a ≤48h change: push fires + Telegram posts + no email. They see the change three places (lock screen, Telegram channel, the in-app banner next time they open) but only get one phone buzz from push (Telegram has its own).
For a >48h change: just the daily digest email at 6pm. Family page banner is also there but doesn’t push.
What if a family has none of those?
They see changes the next time they open their family page (the “what’s changed since last visit” banner + the chat panel below). This is the no-notification baseline.
The 5-minute sender
A background sender runs every 5 minutes and pushes out anything queued up. So a ≤48h coach edit can wait up to 5 minutes for its push to fire. Most of the time it’s faster (median ~2.5 min latency).
The daily brief uses the same 5-minute sender
For each coach with a brief_time set, the sender checks if the
current club-tz HH:MM falls in the 5-min window from their target. If
yes, it fires the brief push. A “last sent” stamp on the coach row
prevents double-firing within the day.