Inbox
The Inbox is DayZero's unified notification feed. Every alert, approval request, anomaly, sync event, ledger change, and announcement that needs your attention lands here as a single row with a status, a topic, and a severity — so nothing gets lost across screens. Open it from the sidebar (it renders the Notifications view at /books/inbox), pick the scope you care about, and work the feed top to bottom.
Key capabilities
- One feed across every business you belong to, with a Me / Business / Firm scope switch (Firm is gated to firm staff by the backend)
- A real status workflow — Open / Snoozed / Done tabs backed by a
new → seen → resolved | dismissed | snoozedstate machine - Topic filter chips (anomaly, billing, AP approvals, Plaid, month-end, ledger, notes, email ingest, reconciliation, manual) with live server-side counts
- Severity chips (Info, Warning, Urgent); warning and urgent rows get a colored left border
- Pin important rows to the top of the Open tab
- Snooze with presets — 1 hour, 4 hours, Tomorrow 9am, 1 week — and the row reappears when the timer elapses
- Resolve or Dismiss (both terminal), plus Mark all seen to clear the unread dots in bulk
- A deep-link action button that jumps straight to the related record (bill, invoice, transaction, report, etc.)
- Live virtual rows (low cash, stale Plaid connection, etc.) merged into the feed and tagged "Live"
- A real-time Server-Sent Events stream that pushes new items instantly, with a 30-second poll as a backstop for the bell badge
- Multi-channel fan-out per topic: in-app always, Slack when a webhook is configured, email when the topic policy allows
- A bell badge that counts only Open (new + seen) items for your current scope
How it works
When something happens — a bill enters an approval gate, an anomaly is detected, a bank sync finishes — a publisher hands the event to the notification policy. The policy resolves who should be notified (the business owner, all business users, the per-tier approver, mentioned users, or firm staff) and which channels fire, then writes one row per recipient and fans out.
flowchart TD
event["Event (bill gate, anomaly, sync, mention)"] --> policy{"Audience + channel policy by topic"}
policy --> rows["Notification rows (recipient: user / business / firm)"]
rows --> feed["Inbox feed (/books/inbox)"]
rows -->|"Slack if enabled"| slack["Slack webhook"]
rows -->|"email per policy"| email["Email"]
feed --> stream["Live SSE stream + bell badge"]
feed --> act{"You act"}
act -->|"open / mark seen"| seen["Seen"]
act -->|"snooze"| snoozed["Snoozed (wakes later)"]
act -->|"resolve / dismiss"| done["Done (terminal)"]How to use it
- Open Inbox from the sidebar — the bell badge shows how many Open items wait on you.
- Use the Me / Business / Firm switch in the header to choose the audience slice. Me spans all your businesses; Business scopes to the active business; Firm shows the advisor feed.
- Switch between the Open, Snoozed, and Done tabs to focus on what's actionable now versus deferred or finished.
- Click severity chips (Info / Warning / Urgent) and topic chips to filter; chips show live counts and hide topics with zero items. Click Clear to reset.
- Click any row to open the detail panel on the right — a
newrow is auto-marked seen when you open it. - Use the row's action button (e.g. "Review bill") to jump to the underlying record.
- From the detail header, Pin, Snooze (pick a preset), Resolve, or Dismiss the item.
- In the Open tab, click Mark all seen to clear unread dots across the visible feed in one action.
Pro tips
- Stay in the Me scope for your personal triage; switch to Business or Firm only when you're working on someone else's behalf or doing a portfolio sweep.
- Snooze instead of dismiss for things you can't action yet — a dismissed row is terminal, but a snoozed row resurfaces in the Open tab when its timer elapses.
- Filter to Urgent severity first thing each morning — those are the rows the policy also escalates to Slack/email.
- Pin the one or two items you're actively working so they stay at the top of Open even as new rows arrive.
- "Live" rows are computed, not stored — dismissing one hides it for you specifically; it can reappear if the underlying condition (e.g. low cash) recurs.
- Tune per-topic noise in notification preferences rather than dismissing repeatedly — you can mute routine sync pings while keeping urgent reconnect alerts.
In-depth guide
Scopes and audience routing
Every notification is addressed to a recipient — a single user, a whole business, or an entire firm — and the read path unions across the three based on your memberships. The scope switch picks which slice you see:
- Me — everything addressed to you across all your businesses.
- Business — filtered to one business.
- Firm — the firm advisor feed (only firm staff can load it).
Who actually receives a row is decided per topic by the audience policy:
- Billing → the business owner (and firm owners).
- AP approvals → the per-tier approver (and the assigned advisor).
- Operational alerts (anomalies, Plaid health) → the owner plus the full firm staff bench.
Status lifecycle
Status replaces the old read/starred/archived flags with a single state machine. Open = new or seen; Done = resolved or dismissed.
| Status | Meaning | Tab | Next states |
|---|---|---|---|
new |
Just delivered, unread (blue dot) | Open | seen, snoozed, resolved, dismissed |
seen |
Opened or marked seen | Open | snoozed, resolved, dismissed |
snoozed |
Hidden until snoozed_until elapses |
Snoozed | seen (auto, when the timer wakes it) |
resolved |
Handled — terminal | Done | — |
dismissed |
Cleared without action — terminal | Done | — |
Severity
Severity drives visual urgency and, for some topics, whether email fires.
| Severity | Use | Visual |
|---|---|---|
info |
Routine / FYI | Muted chip, no row border |
warning |
Worth a look soon | Amber chip + amber left border |
urgent |
Needs action now | Red chip + red left border |
Topics
Topic answers "what domain is this about?" and powers the filter chips and per-topic counts. The chip row hides any topic with a zero count so it stays scannable.
| Topic | Examples |
|---|---|
billing |
Subscription/billing events |
ap_approval |
A bill entered an approval gate |
anomaly |
Unusual transaction or amount detected |
plaid / xero / quickbooks |
Bank/ledger connection health (reconnect needed) |
plaid_sync / xero_sync / quickbooks_sync |
Routine "+N records synced" pings |
subscription |
Recurring-spend budget threshold crossed |
month_end |
Month-end close milestones |
reconciliation |
Reconciliation prompts and results |
ledger |
Ledger changes (per-user, in-app only) |
notes |
Note/mention activity |
email_ingest |
A forwarded email was ingested |
manual |
A person-to-person or manually sent notification |
Channels and delivery
Each topic declares how it fans out. In-app (the Inbox) is the constant; Slack and email are conditional.
| Channel | Behavior |
|---|---|
| In-app | Always written to the feed |
| Slack | Sent when the firm has a webhook configured (if_enabled) |
Per topic — always (billing), if_urgent / if_high_severity (AP approvals, anomalies, reconnect prompts, budget overruns), or off (routine sync pings, ledger, email ingest) |
Delivery is best-effort: if Slack or email fails, the in-app row is still written, so the Inbox is the source of truth.
Email ingestion
- Forwarded documents (e.g. vendor invoices sent to your DayZero ingest address) raise the
email_ingesttopic so the business owner sees that something arrived and was processed. - By policy these are in-app only — no Slack or email — to avoid a notification echoing the email you just forwarded.
Linking to entities and action buttons
- Rows carry an optional polymorphic entity reference (
entity_type+entity_id) plus anaction_url/action_label. - When present, the detail panel renders the action button so one click takes you to the bill, invoice, transaction, or report the notification is about — no hunting required.
Live (virtual) notifications
- Some signals — low cash, a stale Plaid connection — are computed on every read rather than stored as durable rows.
- They appear inline tagged Live and merge into the feed for the business in context.
- Because they aren't persistent, dismissing one is recorded per user in a small dismissals table keyed to the signal — and the item can return if the condition recurs.
Real-time stream and the bell badge
- The feed subscribes to a Server-Sent Events stream that delivers new rows the instant they're published across any server or background worker, with heartbeats to keep the connection alive through proxies.
- If the real-time layer is unavailable, the stream stays idle and a 30-second poll keeps the bell badge's Open count correct.
- The badge counts only Open (
new+seen) items for your current scope.
Edge cases
- Selecting the Business scope with no active business shows a "no business selected" prompt instead of an empty feed.
- Mark all seen only affects
newrows currently in the list; it doesn't resolve or dismiss anything. - Terminal rows (
resolved,dismissed) won't transition again — reopening isn't supported, so prefer Snooze when you might need the item back. - Pinning and snoozing apply to durable rows only; Live rows can't be pinned or snoozed.
Start free and keep everything that needs you in one prioritized feed.