Every row the Dashboard can show, rendered rather than described. Grouped by how the row clears, because that is the thing the current screen hides: some rows fix themselves and some sit until dismissed, and today they look identical. Text and links are transcribed from home.service.ts and red-rules.ts, not written for this page.
Built ships today, exactly as drawn
On the wire the data exists, the UI does not use it
Proposed does not exist yet
Group 1 · Not working
Computed fresh on every load from live database state. Nobody dismisses these — they disappear when the thing is fixed. So the only CTA is one that takes you to where you fix it. Usually empty, and it looks alarming precisely because it usually is not there. home.service.ts:398-425
The bot cannot write replies at allBuiltThe model provider has refused every call since 09:12, five hours ago. Nothing has been answered on any channel since.Open Models
The Marina launch campaign is stuckBuiltIt sent 184 of 412 and stopped 20 minutes ago. The remaining 228 people have not been contacted.Open campaign
The Summer offer campaign is failing to sendBuilt31 sends failed in the last hour. Usually the template, the contact's consent, or the quality rating.Open campaign
The database is unreachableOn the wireFires as an alert today, but never reaches this list — it has no computed row, so the Dashboard cannot show it even while everything is down.Open Settings
The moderator is letting comments through uncheckedOn the wire14 comments in the last 30 minutes stayed public because the moderator could not decide. Same gap: an alert exists, a row does not.Open Activity
Defect this catalogue found. The first three rows also exist as notification kinds — red.campaign.stuck, red.campaign.failure_spike, red.llm. One stuck campaign therefore renders twice on today's Home, once self-clearing and once dismissible, side by side saying the same thing. Deduplicating on dedupKey in home.service.ts is the fix, and it is the same fold the fail-safe row already does at line 497.
Group 2 · Waiting for you
Also computed, also self-clearing — but this is routine queue work, not breakage, and it should never look like an emergency. It drains to zero as you work it. Count first, because the count is the decision. home.service.ts:428-509
The last row is the real fallback string in the code. It appears whenever a review kind is added without adding its sentence — the screen degrades to engineering vocabulary rather than breaking, which is right, but every kind should get its own line before it ships.
Group 3 · Told you about
Saved messages, written when an alert fired. These are the only rows a person dismisses, and the only ones that survive a restart. They can be stale — the thing may already be fixed and the row still sits here until cleared. red-rules.ts:69-173
Told you about7
WhatsApp webhooks silent for 74hBuiltThreshold is 6h. Check the Meta subscription, the connection, and the server. · 2 days agoOpen
Redis is unreachableBuiltQueues for webhooks, campaigns and reminders are not being processed. · 6 hours agoOpen
Moderator failing safe: 14 comments left unmoderated in 30mBuiltThe moderator could not decide, so those comments stayed public with no review item. · 20 minutes agoOpen
Yesterday's summaryBuiltThe daily digest. Nothing is wrong; it is a report. · 09:00
The dashed “Open” buttons are the point.alert-evaluator.service.ts:98 already stores data: {href}, and the API already returns the whole row — the link is on the wire right now. The web type just never declared data, so today a critical alert's only affordance is to make it go away. Declaring one field turns every one of these into an actionable row.
Every kind of CTA a row can carry
Two exist. The rest are proposals, each answering a row that currently has no honest action.
NavigateBuiltGo to where the thing is fixed. Every computed row has exactly one. Never mutates anything.Open Models
Dismiss, and dismiss allBuiltNotifications only. Optimistic — the row goes at once, one quiet retry behind it, and it comes back with a notice if the server refused. “Dismiss all” appears at two or more.
Navigate from a notificationOn the wireZero backend work. The href is stored and returned; the client type omits it.Open
Resolve hereProposedThe queue rows are counts of items that each need one decision. Sending you to a list to click one thing is the long way round.Review 3
Try againProposedThe failed-comment rows are failed Graph calls. The honest action for a failed call is to retry it — today it navigates to a list that cannot retry either. The one CTA here that needs a new endpoint.Try again
SnoozeProposedDifferent from dismiss, because it comes back. A silence alert for a channel you already know about is what trains people to ignore the list.Snooze
Stop telling me thisOn the wirealerting-config.ts already supports seeded muted channels and labels — the WhatsApp mute was applied by editing that config. There is no UI for it anywhere.Mute
UndoProposedA dismissed notification cannot be recovered from the UI. CONVENTIONS §1.4 says undo beats confirm.Undo
When a group is empty
Three groups, three different empties. None of them is a single “all clear”.
Not working — empty is the normal state
Nothing is brokenEverything the bot needs is answering.
Waiting for you — empty means you are done
Your queue is clearNothing is waiting on a decision from you.
Told you about — empty means you cleared it
Nothing newAlerts you have not read yet show up here.
Nothing anywhere, and nothing connected yet
No channel is connectedConnect WhatsApp, Instagram or Facebook and this fills in on its own.