Filings tab: every document, one home
A matter's Filings tab now opens on three read-only registers for the matter's Main proceeding — Main Filings, Annexure Register, and Exhibit Register — switched by a segmented control. A document is a noun with one home: its annexure label and its exhibit number describe the same file. Privileged work-product is excluded by the backend JOIN (DR-2), so it can never surface in a tenderable register. Lawyer vocabulary on the surface throughout: Record, Annexure, Exhibit, Filing.
What shipped
/matters/[matterId]/filings renders the
FilingsTab against the synced contract (Story-1882):
appListMatterProceedingFilings,
appGetProceedingExhibitRegister, and
appListDocumentAnnexures. Reached from the matter
Worknav (Filings) and the matter subnav, mirroring the Record
sub-route.
The RSC server-prefetches Main Filings + Exhibit Register into a
per-request QueryClient, dehydrates, and
hydrates — the client reads through the generated TanStack
hooks off a warm cache (no first-paint spinner; ADR-095). Read-only,
so no mutations / no invalidation.
The Exhibit Register row shows the document, its
exhibit number (exhibitLabel), and the
party series as a display label + canonical token
chip (e.g. "Claimant" / initiating_party), plus the
marking lifecycle (Marked / Admitted / Rejected, DR-5).
A new firm with no filings, no markings, no annexures sees explicit
empty states — never a broken-looking blank. Each register also
has its own loading and error treatments. Verified in Storybook
(RegisterStates) and against the real contract types.
Scope decisions (locked with the issue author)
-
Main-proceeding-scoped, no selector. Filings + Exhibit
Register are proceeding-scoped; v1 scopes to the universal Main
proceeding (
isMain). A proceeding selector is a separate follow-up. -
Annexure Register stays per-parent-document. The
contract has no proceeding-level annexure enumeration and
FilingViewcarries no lead-document link, so the subtab is sourced from a?doc=<uuid>parent filing and shows an honest guidance state when none is selected.
Gated on pramaan-functions Story-1891
Two pieces of the brief are blocked on backend the synced contract does not yet expose — not faked here (HR-22):
| Brief item | Why deferred |
|---|---|
| Single-click exhibit renumber + duplicate-in-series 409 | No renumber write endpoint exists; the exhibit register is
read-only in src/gen. The Exhibit Register ships
read-only with the renumber affordance deferred (caption notes it). |
| Full two-identity row (annexure label beside the exhibit number) | DocumentExhibitMarkingView carries no
filing_label / parentDocumentId, so the
Annexure cell shows an em-dash. The exhibit identity + party render
today; the annexure half lands after #1891 + a codegen-sync. |
Trust boundary
New BFF proxies keep the browser on /api/internal/* only:
/matters/{id}/proceedings/{pid}/filings and
/exhibit-register (new proceedingProxyHandler),
plus /documents/{doc}/annexures (existing documents proxy).
Every gateway read parses the raw upstream through
assertContract against the generated schema before it
crosses back (HR-21). toBrowserRoute maps the new paths.
Verify
pnpm lint (0 errors),
tsc --noEmit (clean),
pnpm test (949 passing, incl. route-registry
freshness), and pnpm build (new routes
registered) all green. New surface matter.filings exported
and gen:routes committed; Filings i18n added to
both en and hi.
Files changed
24 file(s), +1121 / -7 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +58 | -2 |
| messages/hi.json | Config | +58 | -2 |
| src/app/[locale]/(workspace)/matters/[matterId]/filings/page.tsx | App route | +108 | -0 |
| src/app/api/internal/documents/[docId]/annexures/route.ts | App route | +4 | -0 |
| src/app/api/internal/matters/[matterId]/proceedings/[proceedingId]/exhibit-register/route.ts | App route | +4 | -0 |
| src/app/api/internal/matters/[matterId]/proceedings/[proceedingId]/filings/route.ts | App route | +4 | -0 |
| src/components/matters/filings/annexure-register-table.stories.tsx | Component | +29 | -0 |
| src/components/matters/filings/annexure-register-table.tsx | Component | +77 | -0 |
| src/components/matters/filings/exhibit-register-table.stories.tsx | Component | +33 | -0 |
| src/components/matters/filings/exhibit-register-table.tsx | Component | +87 | -0 |
| src/components/matters/filings/filings-fixtures.ts | Component | +131 | -0 |
| src/components/matters/filings/filings-tab.tsx | Component | +112 | -0 |
| src/components/matters/filings/main-filings-table.stories.tsx | Component | +29 | -0 |
| src/components/matters/filings/main-filings-table.tsx | Component | +65 | -0 |
| src/components/matters/filings/register-states.stories.tsx | Component | +51 | -0 |
| src/components/matters/filings/register-states.tsx | Component | +55 | -0 |
| src/components/matters/live-matter-shell.tsx | Component | +6 | -0 |
| src/components/matters/matter-subnav.tsx | Component | +1 | -0 |
| src/components/matters/matter-tabs.tsx | Component | +1 | -1 |
| src/lib/filings/gateway.ts | Library | +90 | -0 |
| src/lib/filings/presentation.ts | Library | +38 | -0 |
| src/lib/filings/route-helper.ts | Library | +55 | -0 |
| src/lib/kubb-client.ts | Library | +13 | -0 |
| src/lib/surface-registry/route-registry.ts | Library | +12 | -2 |