cocottetech/@platform/codebase/@features/ai-copilot/docs/unified-inbox.screen.md
natalie 1b719e1fd7 chore(bootstrap): initial V4 commit
Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac
working tree at ~/Code/@projects/@cocottetech/. node_modules and build
artifacts excluded via .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:11:41 -07:00

6.4 KiB
Raw Blame History

Unified inbox · screen

Implementation breakdown of brief P's unified inbox view. The screen is reachable as a drawer from chat-home (a sibling to brief B's catalog — "inbox" added to the drawer roster) or as a deep-link from a notification.

Layout (iPhone)

┌────────────────────────────────────────┐
│  ←   Inbox                  ⋮   ⚙      │  ← top bar: back, filter chip, settings
├────────────────────────────────────────┤
│  [all] [warm] [cold] [flagged]         │  ← state filter row (horizontal scroll)
│  via: [any▾]   sort: [most recent ▾]   │  ← source filter + sort
├────────────────────────────────────────┤
│  • @felix · via Tryst · 11 min         │  ← prospect-rolled row
│    "Hey, thinking about Berlin..."     │
│    triage: warm · drafted reply        │
├────────────────────────────────────────┤
│  • +1 415 555 0142 · via SMS · 47 min  │  ← unknown sender; channel-explicit
│    "is this number still good?"        │
│    triage: cold · queued for review    │
├────────────────────────────────────────┤
│  • via Proton: myprivatedelights@…     │  ← per-mailbox source label
│    PrivateDelights verification reply  │
│    triage: system · auto-archived      │
├────────────────────────────────────────┤
│  • @felix · via OF DM · 2h             │  ← same prospect, different channel
│    "subbing again"                     │
│    threaded with Tryst row above ↑     │
└────────────────────────────────────────┘

Component table

Component Source Notes
SourceChip new (P + F F5d) Rounded-square chip with channel-tinted glyph; per brief F F5d geometry distinguishes channel from surface.
MailboxChip new (P) Sub-variant of SourceChip showing per-mailbox label for email rows ("Proton: myprivatedelights@…").
TriageBadge new (P + L) Inline tag: warm / cold / flagged / system / blocked. Plain register.
ProspectThread sibling to B3 Groups multiple channel rows by prospect_id once prospect-resolver (P4) catches up. Visual: thin vertical connector on the left edge.
InboxRow new (P) Row composition: SourceChip + sender + timestamp + body preview + TriageBadge.
FilterRow shared (B4) Horizontal scrollable chips. Same component as audit drawer filters.

States to render

  1. Empty — no inbound across any source. Hearth register:

    Quiet. She's tending the queues and will surface anything worth your time.

  2. Typical mix — 3080 rows across 46 sources. Default sort: most recent.

  3. All-source filtered — only one source active in via: filter. Other rows hidden.

  4. Prospect-grouped — same prospect across iMessage + OF + Tryst. Thin connector groups; tap a row to expand the cluster inline.

  5. Source-degraded — Tryst inbox stalled. Banner above the affected rows:

    Tryst inbox stalled — last fetched 47 min ago. Showing what we have.

  6. Per-source policy editor — long-press a source chip → bottom sheet showing per-source triage posture (auto-reply / draft-only / hands-off + cadence).

  7. Reply-as-different-channel confirm — Quinn opens a fan's email row, taps "Reply via iMessage" instead of "Reply via email":

    They emailed. You're replying via iMessage — that uses a different identifier they may not have. Continue / switch back to email.

  8. Auto-replied row — triage already sent. Row shows triage: auto-replied · 6 min ago and the body preview is the reply, not the inbound.

  9. Blocked sender — collapsed under a single card:

    5 blocked-prospect messages today. Review.

  10. Inbox loading initial fetch — skeleton rows.

Gestures

  • Swipe right on a row: opens reply composer in the appropriate channel.
  • Swipe left: archive (preserved in audit; triage knows you saw it).
  • Tap a row: opens the prospect drawer (brief B3) scoped to this conversation.
  • Long-press: multi-select for batch archive / batch route-to-Quinn.
  • Pinch / pull on a ProspectThread: expand to show every channel row in the cluster.

Per-source triage posture (settings sub-page)

Reached via top-bar settings gear. Per-source row:

iMessage          [ Auto-reply ▾ ]  cadence: instant
SMS               [ Draft-only ▾ ]  cadence: instant
Proton: hi@cocotte.maison
                  [ Draft-only ▾ ]  poll: every 5min
Proton: myprivatedelights@…
                  [ Auto-archive ▾ ]  poll: every 30min  (transactional)
Tryst DM          [ Hands-off ▾ ]  poll: every 1min
OF DM             [ Draft-only ▾ ]  poll: every 10min

personas.facets[channel_id].triage_policy is the canonical store; this UI is a friendlier editor over it.

Edge cases

  • Same prospect, two phone numbersprospect-resolver may take a vigil to merge. UI shows two rows; once merged, both collapse into one ProspectThread with a small "merged" indicator.
  • A Proton mailbox temporarily disconnected — surfaces an inline degradation banner (per brief M M2a); rows from that source greyed.
  • Outbound failure on reply — row flips to a pending retry state with the reply still visible; matches brief M M3 failure interrupt pattern.
  • A surface-DM that triage classified as blocked — never appears in the feed; subsumed under the "blocked-prospect messages today" card.
  • brief P — full design.
  • brief C — outbound counterpart (notifications).
  • brief I — triage decisions surface in audit + counter-actions.
  • brief K §K1 — prospect blocklist (drives the collapsed-blocked card).
  • brief F §F5d — channel geometry (rounded-square, not circle).