SRS: UC_6.2.2 — Flow 24: Notification Matrix
| BA in Charge | Date Created | Version | Document References |
|---|---|---|---|
| BA Team | 2026-09-06 | v1 | Zapier Integration V7.pdf; UC_4.1.3 BR_4.1.3.2–BR_4.1.3.5; UC_6.1.2 BR_6.1.2.6 |
UC_6.2.2 — Flow 24: Notification Matrix
This UC owns Flow 24's 4-channel broadcast engine: receiving the
Alert_Level/Widget_State/Widget_Short_Text/Notification_Severity/Message_Textpayload from the Middleware Hub (constructed by UC_6.1.2BR_6.1.2.6at each overnight milestone) and fanning it out to Discord, Slack#risk-ops, the DashboardNOTIFICATIONWebSocket event, and the DashboardMARKET_STATUS_UPDATEWebSocket event — including server-side[Asset_Class]/[Symbol]placeholder replacement inMessage_Textbefore dispatch. The Alert Level → Widget State/Text/Severity mapping table, the tie-breaking rule for simultaneous webhooks, the motion/severity visual mapping, and the DST handling are already fully specified in UC_4.1.3BR_4.1.3.2–BR_4.1.3.5and are cross-referenced here, not duplicated — this UC owns the broadcast/dispatch mechanism (the 4 channels + placeholder replacement), UC_4.1.3 owns the resulting widget's consumption of that broadcast. This UC is unaffected by CHR_67 — Flow 24's trigger is the Node.js Dynamic Timekeeper (UC_6.1.1), a separate provider/mechanism from Flow 23's Finnhub news feed, per CHR_67's explicit "Not Affected" note.
1. Overview
| Field | Content |
|---|---|
| ID | UC_6.2.2 |
| Use Case | Flow 24 — Overnight Margin & Swap Monitor (Broadcast): 4-channel notification fan-out + placeholder replacement |
| Description | On receiving a webhook from the Middleware Hub's Dynamic Timekeeper — payload:Asset_Class, Symbol (nullable), Alert_Level, Widget_State, Widget_Short_Text, Notification_Severity, Message_Text — Flow 24 replaces any [Asset_Class]/[Symbol] tokens in Message_Text server-side, then dispatches to 4 channels in parallel: (1) Discord Global Alert using Message_Text, (2) Slack #risk-ops Internal Alert using Message_Text, (3) Dashboard NOTIFICATION WebSocket event using Notification_Severity + Message_Text to populate the Notification Center, (4) Dashboard MARKET_STATUS_UPDATE WebSocket event using Widget_State + Widget_Short_Text to populate the Market Status Widget. The Node.js middleware is the timeline authority: because asset classes/symbols close or halt at different times (holiday shifts, market-specific structure), webhooks fire independently per asset-class/symbol configuration as each approaches its window — this UC does not batch or coalesce them. |
| Zapier Flow | Flow 24 — Overnight Margin & Swap Monitor (Broadcast) |
| Zapier Table | —(consumes the payload constructed by UC_6.1.2 BR_6.1.2.6; does not read Table A/B/C directly) |
| 3rd Party | Discord · Slack (#risk-ops) · Dashboard WebSocket (NOTIFICATION, MARKET_STATUS_UPDATE events — consumed by UC_4.1.3 Market Status Widget and UC_4.7.1 Notification Center) |
No wireframe of its own — this UC is the broadcast mechanism. The consuming UIs are UC_4.1.3 (Market Status Widget) and UC_4.7.1 (Notification Center), both already fully specified.
2. Trigger
Event-driven — a webhook from the Middleware Hub's Node.js Dynamic Timekeeper arrives at this flow whenever UC_6.1.2 constructs a payload for one of the 8 designated Alert_Level milestones (Warning_60, Warning_30, Warning_10, Lockout_Active, Enforcement_Complete, Halt_Active, Halt_Cleared, Session_Open) for a specific asset class/symbol configuration. Each asset class/symbol's milestones fire independently on their own timeline — this UC has no batching window and reacts to each webhook individually.
3. Pre-conditions
| ID | Condition |
|---|---|
| P-1 | UC_6.1.2 has constructed and dispatched a valid Flow 24 payload for the asset class/symbol in question — this UC has nothing to broadcast otherwise. |
| P-2 | The payload'sAlert_Level is one of the 8 values mapped by UC_4.1.3 BR_4.1.3.2 — this UC does not define behavior for an unrecognized Alert_Level value (see Exceptional Flow Exc-1). |
| P-3 | Discord, Slack, and the Dashboard WebSocket gateway are reachable for the 4-channel dispatch. |
4. Post-conditions
All 4 channels — successful dispatch
- Discord receives the Global Alert with fully-resolved
Message_Text(no unresolved[Asset_Class]/[Symbol]tokens). - Slack
#risk-opsreceives the Internal Alert with the same resolvedMessage_Text. - The Dashboard Notification Center (UC_4.7.1) receives a
NOTIFICATIONWebSocket event carryingNotification_Severity+Message_Text. - The Dashboard Market Status Widget (UC_4.1.3) receives a
MARKET_STATUS_UPDATEWebSocket event carryingWidget_State+Widget_Short_Text.
5. Basic Flow
- Receive webhook. Flow 24 receives a payload from the Middleware Hub:
Asset_Class,Symbol(nullable),Alert_Level,Widget_State,Widget_Short_Text,Notification_Severity,Message_Text. See BR_6.2.2.1. - Resolve placeholders. Any
[Asset_Class]or[Symbol]token insideMessage_Textis replaced server-side with the payload's actualAsset_Class/Symbolvalues before any channel dispatch. See BR_6.2.2.2. - Dispatch — Discord. Send a Global Alert to Discord using the resolved
Message_Text. - Dispatch — Slack. Send an Internal Alert to Slack
#risk-opsusing the resolvedMessage_Text. - Dispatch — Dashboard
NOTIFICATIONevent. Push aNOTIFICATIONWebSocket event to the Dashboard, carryingNotification_Severityand the resolvedMessage_Text, to populate the Notification Center (UC_4.7.1). - Dispatch — Dashboard
MARKET_STATUS_UPDATEevent. Push aMARKET_STATUS_UPDATEWebSocket event to the Dashboard, carryingWidget_StateandWidget_Short_Text, to populate the Market Status Widget (UC_4.1.3BR_4.1.3.2). See BR_6.2.2.3. - Independent per-asset-class/symbol firing. Because each asset class/symbol has its own timeline (per UC_6.1.1's independent timeline threads), steps 1-6 repeat independently whenever any configuration's milestone is reached — there is no cross-asset-class batching or coalescing. If two webhooks arrive at effectively the same time, UC_4.1.3
BR_4.1.3.3's tie-breaking rule governs display prioritization on the consuming widget — this UC dispatches both regardless of arrival order. See BR_6.2.2.4.
6. Alternative Flows
-
Alt-1 —
Symbolis null (asset-class-level milestone, not symbol-specific).- Context: some milestones (e.g.
Session_Openfor an entire asset class) do not target one specific symbol. [Symbol]tokens simply do not appear in thatMessage_Texttemplate; step 2's replacement has nothing to substitute forSymboland proceeds normally using only[Asset_Class].
- Context: some milestones (e.g.
7. Exceptional Flows
-
Exc-1 — Payload's
Alert_Leveldoes not match any of the 8 values UC_4.1.3BR_4.1.3.2maps.- The malformed/unrecognized payload is logged as an error; this UC does not continue with dispatch to any of the 4 channels.
8. Business Rules
BR_6.2.2.1: Flow 24 payload structure
The Middleware Hub webhook payload consumed by this UC has the following structure:
| Field | Type | Notes |
|---|---|---|
Asset_Class | String | — |
Symbol | String, Nullable | Null for asset-class-level milestones (seeAlternative Flow Alt-1) |
Alert_Level | String | One of:Warning_60, Warning_30, Warning_10, Lockout_Active, Enforcement_Complete, Halt_Active, Halt_Cleared, Session_Open |
Widget_State | String | One of:Open, Lockout, Closed, Halted — mapping per UC_4.1.3 BR_4.1.3.2 |
Widget_Short_Text | String, max 15 chars | e.g."Close in 10m" — mapping per BR_4.1.3.2 |
Notification_Severity | String | One of:INFO, WARN, CRITICAL — mapping per BR_4.1.3.2; visual/motion mapping per BR_4.1.3.4 |
Message_Text | String | Full copy text, may contain[Asset_Class]/[Symbol] tokens (see BR_6.2.2.2) |
This UC does not itself define the Alert_Level → Widget_State/Widget_Short_Text/Notification_Severity mapping — that table, the tie-breaking rule for simultaneous webhooks, the motion/severity visual mapping, and the DST handling that produces the correct milestone timestamps are all owned by UC_4.1.3 BR_4.1.3.2–BR_4.1.3.5 and are consumed here as given, not restated.
(Source: Zapier Integration V7.pdf §Flow 24, lines 2241-2255)
BR_6.2.2.2: Server-side placeholder replacement
Message_Text may contain [Asset_Class] and/or [Symbol] tokens (e.g. "[Symbol] has entered its scheduled intraday maintenance pause"). These tokens are replaced server-side, using the payload's own Asset_Class/Symbol values, before dispatch to any of the 4 channels (BR_6.2.2.3). No channel — Discord, Slack, or either Dashboard WebSocket event — ever receives an unresolved token; the frontend performs no placeholder substitution of its own (consistent with UC_4.1.3 BR_4.1.3.2's note that the widget only consumes Widget_State/Widget_Short_Text, not the full copy text — the copy text substitution is entirely this UC's responsibility).
(Source: Zapier Integration V7.pdf §Flow 24, lines 2263-2268 — "Message text tokens such as [Symbol] are replaced server-side before execution")
BR_6.2.2.3: 4-channel parallel dispatch
On receiving a valid payload, this UC dispatches to all 4 channels: (1) Discord Global Alert using Message_Text, (2) Slack #risk-ops Internal Alert using Message_Text, (3) Dashboard NOTIFICATION WebSocket event using Notification_Severity + Message_Text, (4) Dashboard MARKET_STATUS_UPDATE WebSocket event using Widget_State + Widget_Short_Text. These 4 dispatches are independent of one another (see Exceptional Flow Exc-2) — this UC does not require all 4 to succeed before considering the webhook processed.
(Source: Zapier Integration V7.pdf §Flow 24, lines 2256-2262 — "Action 1" through "Action 4")
BR_6.2.2.4: Independent per-asset-class/symbol timeline — no batching
The Node.js middleware acts as the core timeline authority, calculating dynamic, asset-specific market milestones from the master reference schedule database (UC_6.1.1). Because asset classes or individual symbols close or halt at different times — due to holiday calendar shifts or market-specific structures — webhooks are triggered independently for each specific configuration as it approaches its window. This UC does not coalesce or batch multiple asset classes' milestones into a single dispatch, even if their timestamps happen to coincide; each fires and is broadcast on its own. Display-side prioritization when two updates land at the same widget slot is UC_4.1.3 BR_4.1.3.3's concern, not this UC's.
(Source: Zapier Integration V7.pdf §Flow 24, lines 2263-2269 — "Operational Control Logic")
9. Update History
| Date | Version | Section | Change From | Change To | Source |
|---|---|---|---|---|---|
| 2026-09-06 | v1 | All (new) | UC_6.2.2 not yet written | Initial SRS for UC_6.2.2, covering Flow 24's 4-channel broadcast engine and server-side placeholder replacement, cross-referencing (not duplicating) UC_4.1.3's Alert Level mapping table/tie-break/motion/DST rules | Zapier Integration V7.pdf lines 2241-2269; UC_4.1.3 BR_4.1.3.2–BR_4.1.3.5; UC_6.1.2 BR_6.1.2.6 |
| 2026-09-15 | v1 | Exceptional Flows (Exc-1, Exc-2); §9-10 removed | Exc-1 was flagged⚠️ [ASSUMPTION — pending client confirmation], describing an unrecognized Alert_Level as logged + a Sev-1 alert fired to Slack #risk-ops, still broadcasting an error signal; Exc-2 (channel unreachable) was also flagged as an open assumption; NFRs (old §9) and Acceptance Criteria (old §10) sections present | Exc-1 simplified: an unrecognizedAlert_Level is logged as an error and dispatch does not continue to any of the 4 channels — no Sev-1/Slack alert branch. Exc-2 kept as a confirmed assumption (not rewritten) — each of the 4 channel dispatches remains independent/non-blocking, per-channel failure does not block the other 3. NFRs and Acceptance Criteria sections removed; Update History renumbered to §9 | User instruction (BA session), 2026-09-15 |