Sys-Originated Communications
At a glance
Sys-originated communications across the whole platform: a broadcast composer reaching tenants/roles/custom segments, a banner template+activation library, a release-notes publisher, a sys operator inbox for replies, a per-operator test-send gate that expires after 30 minutes, and a 1:1 DM tool with rate-limit and user opt-out.
How it works
When sys needs to talk to people on the platform, it does so through this surface and nowhere else. The broadcast composer can target all tenants, selected tenants, selected roles, or a custom filter, and dispatches over three channels: in-app banner, email through SendGrid in 10 000-recipient batches at 100 rps, and push through FCM/Expo in 100-recipient batches. Test-send is mandatory and per-operator: `/send` returns `412 SysBroadcastTestSendRequired` unless the current operator has a `test_sent_at` within the last 30 minutes, so a handover always forces a fresh test before a real send goes out.
The banner library separates `SysBannerTemplate` (reusable: maintenance, incident, feature) from `SysBannerActivation` rows that bind a template to a start/end window and a tenant/role audience; the admin and app consume them through `GET /me/banners`. Release-notes publisher lets sys author a `SysReleaseNote` with internal context plus a customer-safe public version, dispatch by channel, and link to the release in F21.18. The sys operator inbox routes broadcast replies and inbound support mail through the SendGrid Inbound webhook into `SysSupportInboxMessage` rows; assign and close workflows surface in `sys/comms/inbox`.
The 1:1 DM endpoint at `POST /sys/users/{id}/messages` is the proactive sys-to-user channel for any single-recipient communication: the operator picks channels (email/push/in-app), provides a reason of at least 10 characters, and clears fresh-auth. Rate limit is five DMs per operator per user per 24 hours, a self-test-send is mandatory before real delivery, and users can opt out per channel through `/me/communications`. Every channel write — broadcast, banner, release-note, DM — produces an audit row with metadata, so an operator can prove later who sent what to whom.
Key capabilities
- Broadcast composer: all/selected tenants, roles, or custom filter; in-app + email + push
- SendGrid 10k-recipient batches at 100 rps; FCM/Expo 100-recipient batches
- Per-operator test-send gate expiring after 30 minutes (`412 SysBroadcastTestSendRequired`)
- Banner library: reusable `SysBannerTemplate` plus `SysBannerActivation` windows
- Release-notes publisher with internal + customer-safe versions
- Sys operator inbox via SendGrid Inbound for broadcast replies and support mail
- 1:1 DM tool with reason, fresh-auth, 5/operator/user/24h rate limit, and user opt-out
In practice
A planned database migration needs a 30-minute maintenance window. The operator opens the broadcast composer, picks `all tenants`, selects in-app banner + email, drafts copy, and clicks `Test send`. Her own test inbox receives both.
Within 30 minutes she clicks `Send`; the gate passes, the email batch ships at 100 rps, and the in-app banner activates from a `SysBannerActivation`. A user replies asking when the window starts; the reply lands in the sys operator inbox, she assigns it to herself, sends a 1:1 DM with the start time, and closes the thread. Every step is audited.
Features in this subsystem
6| ID | Status | Features |
|---|---|---|
| F21.12.01 | Shipped | Broadcast composer — reach all tenants, selected tenants, selected roles, or a custom filter. Channels: in-app banner, email (SendGrid batch, 10 k/batch, 100 rps), push (FCM/Expo, 100/batch). Test-send mandatory ≤ 30 min before /send. ✅ PL-T132 |
| F21.12.02 | Shipped | Banner library — reusable SysBannerTemplate (maintenance, incident, feature) spawned into SysBannerActivation rows with start/end windows and tenant/role audience. Consumed by admin/app via GET /me/banners. Implemented (PL-T132) |
| F21.12.03 | Shipped | Release-notes publisher — SysReleaseNote with internal \ external visibility, sections, linked PR URLs. Public subset exposed at /public/changelog and rendered on www/ via Changelog.astro. | Implemented (PL-T132) |
| F21.12.04 | Shipped | Sys operator inbox — SendGrid-inbound webhook routes broadcast replies + inbound support mail to SysSupportInboxMessage. Assign/close workflow surfaced in sys/comms/inbox. ✅ PL-T132 |
| F21.12.05 | Shipped | Test-send gate — /send returns 412 SysBroadcastTestSendRequired unless the current operator has a test_sent_at ≤ 30 min old. Gate is per-operator so handovers force a fresh test-send. Implemented (PL-T132) |
| F21.12.06 | Shipped | 1:1 direct message to user — POST /sys/users/{id}/messages for proactive sys-to-user DM (channels: email/push/in-app). Fresh-auth + reason (≥ 10 chars) gate, rate-limit 5 DM/operator/user/24 h, mandatory self-test-send before real delivery, user opt-out via GET PUT /me/notifications/preferences.dm_muted. Opt-out suppresses channels (recorded in receipt). Every send audited as sys.user.direct_message.{test_send,sent,failed}. | ✅ PL-T148 |