Substrate changes that turn /inbox from approvals-only into the unified notification surface m asked for. - Migration 126: paliad.users.inbox_seen_at (high-watermark read cursor; pending approval_requests bypass it per design §3). - KnownProjectEventKinds gains note_created, our_side_changed, deadline_updated/deleted, deadlines_imported. New InboxProjectEventKinds curated subset (head's Q1=A lock). - InboxSystemView spans [approval_request, project_event]; defaults to past 30 days, newest first, row_action="inbox". - view_service.allowedProjectEventKinds drops *_approval_* audits when ApprovalRequest is also in spec.Sources (no double-count). - RunSpec resolves the caller's inbox_seen_at once and threads it through viewSpecBounds; runProjectEvents excludes self-authored events and rows older than the cursor when unread_only is set. Decided approval_requests follow the cursor; pending always survives. - ApprovalService.UnseenInboxCountForUser (unified badge count) + MarkInboxSeen + InboxSeenAt service methods. - GET /api/inbox/count returns the unified count; new POST /api/inbox/mark-all-seen advances the cursor (optional up_to=). Tests cover the InboxSystemView shape, the audit-dedup helper, the isApprovalAuditKind matcher, and the no-narrow-no-approvals nil path.
22 lines
1.0 KiB
SQL
22 lines
1.0 KiB
SQL
-- t-paliad-249 — /inbox overhaul, Slice A.
|
|
-- Add a per-user high-watermark read cursor for the inbox feed
|
|
-- (approval requests + curated project_events). The cursor advances
|
|
-- only when the user POSTs to /api/inbox/mark-all-seen. NULL means
|
|
-- "never visited" → every row counts as unread on first paint.
|
|
--
|
|
-- Note on the carve-out enforced in service code: pending
|
|
-- approval_requests count toward the inbox's unread state regardless
|
|
-- of this column. The cursor narrows the project_event source only,
|
|
-- so a stale cursor never buries a high-value pending approval.
|
|
--
|
|
-- Design ref: docs/design-inbox-overhaul-2026-05-25.md §3.
|
|
|
|
ALTER TABLE paliad.users
|
|
ADD COLUMN IF NOT EXISTS inbox_seen_at timestamptz NULL;
|
|
|
|
COMMENT ON COLUMN paliad.users.inbox_seen_at IS
|
|
'High-watermark cursor for the /inbox feed. project_events newer '
|
|
'than this timestamp are unread for the caller; NULL = never '
|
|
'visited (everything unread). Pending approval_requests bypass '
|
|
'this column and stay unread until decided.';
|