PR: #535: feat(matter): Triage tab v1 — list, one-tap resolve, provenance, history, badge [Story-2128] by @ankitmaheshwari-com
View PR →

Files changed

17 file(s), +952 / -15 lines

Path Role + -
messages/en.jsonConfig+35-0
messages/hi.jsonConfig+35-0
src/app/[locale]/(workspace)/matters/[matterId]/inbox/page.tsxApp route+59-9
src/app/api/internal/inbox/items/[itemId]/resolve/route.tsApp route+43-0
src/app/api/internal/matters/[matterId]/inbox/route.tsApp route+52-0
src/app/api/internal/matters/[matterId]/inbox/summary/route.tsApp route+32-0
src/components/matter-detail/inbox/inbox-fixtures.tsComponent+95-0
src/components/matter-detail/inbox/inbox-item-row.stories.tsxComponent+68-0
src/components/matter-detail/inbox/inbox-item-row.tsxComponent+142-0
src/components/matter-detail/inbox/inbox-list.stories.tsxComponent+57-0
src/components/matter-detail/inbox/inbox-list.tsxComponent+35-0
src/components/matter-detail/inbox/matter-inbox-page.tsxComponent+129-0
src/components/matter-detail/inbox/presentation.tsComponent+62-0
src/components/matters/matter-shell-chrome.tsxComponent+10-4
src/lib/inbox/gateway.tsLibrary+67-0
src/lib/kubb-client.tsLibrary+29-0
src/lib/surface-registry/route-registry.tsLibrary+2-2

Story-2128: IB-5 Triage tab v1

The matter's Triage tab — /matters/[matterId]/inbox — is where counsel clears the matter's HITL queue: the items an agent or pipeline paused on because a human must decide before work proceeds. This Story turns the placeholder route into the real surface described by the inbox RFD (pramaan-functions docs/notes/rfd-inbox-hitl-rail.md §7, row IB-5) and lights the Worknav badge. It is app-lane only: the contracts (IB-2) already landed in src/gen via codegen-sync #2138; this Story consumes them.

What landed — the surface

Data path — the forum pattern, end to end

Every read follows the canonical server-prefetch → hydrate → TanStack path (settings/AGENTS.md), and every write is optimistic.

LayerWhat it does
page.tsx (RSC) Prefetches the open list + the summary into a per-request QueryClient, dehydrates, wraps the client page in HydrationBoundary. A list 5xx degrades to an inline CatalogLoadError retry, not a shell crash.
matter-inbox-page.tsx (client) Reads with useAppListMatterInbox, resolves with useAppResolveInboxItem. Sorts client-side with the blocking-first comparator so order holds after cache edits.
Optimistic resolve onMutate snapshots the open-list cache and drops the resolved row immediately (the row slides out via AnimatedList); onError restores the snapshot; onSettled invalidates the list + summary to reconcile with server truth and refresh the badge.
BFF proxy Three /api/internal/* routes (list, summary, resolve) plus toBrowserRoute mappings, so the browser only ever talks to /api/internal. Each route validates and delegates to inboxGateway, which parses every upstream response through assertContract (HR-21).

What landed — Storybook (verify-first)

Reuse over reinvention

SegmentedFilter, StatusBadge, AnimatedList/AnimatedListRow, PrimaryButton, Button, and SettingsLoading are all existing shared primitives. Colors are token-backed (crimson accent, amber High chip via StatusBadge tone="pending", --cream provenance panel); no literals. Copy is fully i18n'd under the new MatterInbox namespace in both en and hi.

Honest seams (v1 sketch, per §7)

Verification

Staging note: the acceptance criterion "every wired type resolvable end-to-end on staging" is a runtime check against the live IB-2 backend once seeded inbox items exist for a matter; the app seam is contract-parsed at every trust boundary and verified green in Storybook + the full local suite.