Document Types catalog UI — Settings → Matter Configuration
A firm needs to name the kinds of documents it works with — Contract, Affidavit, Court order — so the Documents pipeline (EPIC-1489) can classify uploads against a stable, firm-owned vocabulary. This Story ships the CRUD surface for that catalog. It is a copy of the Filing Types settings page with one structural difference: document types are firm-wide, not attached per matter-type, so there is no reference number and no per-matter-type attach step.
Why mirror Filing Types instead of inventing a page
Every settings catalog (Forums, Filing types, Proceeding types,
Participant labels) is the same shape: a
SettingsPageHeader + SettingsToolbar
(SegmentedFilter Live/Archived tabs + SettingsSearch)
+ a table with a row-actions menu + a create/edit Sheet +
a delete AlertDialog. Reinventing that chrome is the exact
drift the repo doctrine bans. Document types compose the same primitives
and the same data pattern (server-prefetch → hydrate → TanStack), so the
page reads identically to its siblings.
The one real difference: firm-wide, so no reference column
| Aspect | Filing types | Document types |
|---|---|---|
| Scope | attached per matter-type / practice area | firm-wide, shared across every matter |
| Reference number | FT-001 column | none — table is name / status / date / actions |
| Attach step | yes (matter-type picker) | omitted |
| Mutation path param | filing_type_id | document_type_id |
AI fields (Mode-2/3 fill & review) are EPIC-009 and live on documents, not on the document-type catalog — there are no AI columns to render here. This catalog is purely deterministic (Mode-1).
The data pattern (canonical, copied verbatim)
-
Archive / unarchive / delete are optimistic:
onMutateflipsavailability(or drops the row) in the list cache so the row jumps tabs instantly, reconciling on settle and rolling back on error — same as Filing types. -
The list query key
(
appListDocumentTypesQueryKey({ includeArchived: true })) is shared by the RSC prefetch and the client read, so hydration never refetches. -
HR-21: the gateway fetches as
unknownand runs every payload throughassertContract(documentType*Schema, …)fromsrc/gen— noas Tat the trust boundary.
Storybook-first leaf components stories shipped
Each leaf was storied before live wiring, mirroring the filing-types stories with mock fixtures (no Clerk, no gateway):
-
DocumentTypesTable— Default, With descriptions, Live, Archived tab, In use (delete disabled), Read only, Empty, Long text. -
DocumentTypeSheet— Add, Edit, Saving, With error.
The empty / zero-row state is a first-class story (and table branch), not an afterthought — the new-firm catalog is exactly the first real run.
i18n & tokens
-
New
DocumentTypesnamespace +SettingsNav.documentTypesadded to bothmessages/en.jsonandmessages/hi.json. No hardcoded display strings. -
No color literals — semantic tokens only (
var(--token)/ token-backed utilities). Color / hardcoded-copy scans clean on the new files. -
Nav item placed immediately after Filing types under
Matter configuration, with the
Filesglyph (sibling to Filing types'FileText).
Files
| File | Change |
|---|---|
src/lib/document-types/{types,gateway,presentation}.ts | new — gen-typed contracts + HR-21 gateway + date helper |
src/app/api/internal/document-types/** | new — list GET + delete + archive + unarchive BFF proxy routes |
src/app/[locale]/(workspace)/settings/matter-configuration/document-types/{page,actions}.tsx | new — RSC prefetch + create/edit server actions |
src/components/settings/document-types/** | new — list page, table, toolbar, sheet, delete dialog, hooks, fixtures, error + 2 stories |
src/lib/kubb-client.ts | /app/document-types* → /api/internal/document-types* mapping |
src/components/settings/settings-sidebar.tsx | nav item + section id + Files icon |
messages/{en,hi}.json | DocumentTypes namespace + nav label (both locales) |
tests/unit/document-types-contract.test.ts | new — boundary DTO + gateway contract tests (5 passing) |
Verification
pnpm tsc --noEmitcleanpnpm lint0 errors (one pre-existing avatar warning, unrelated)pnpm vitest run527 passing (incl. 5 new document-type contract tests)pnpm buildok — all 5 routes registered (page + 4 API)
Files changed
27 file(s), +1776 / -0 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +45 | -0 |
| messages/hi.json | Config | +45 | -0 |
| src/app/[locale]/(workspace)/settings/matter-configuration/document-types/actions.ts | App route | +105 | -0 |
| src/app/[locale]/(workspace)/settings/matter-configuration/document-types/page.tsx | App route | +59 | -0 |
| src/app/api/internal/document-types/[documentTypeId]/archive/route.ts | App route | +13 | -0 |
| src/app/api/internal/document-types/[documentTypeId]/route.ts | App route | +36 | -0 |
| src/app/api/internal/document-types/[documentTypeId]/unarchive/route.ts | App route | +13 | -0 |
| src/app/api/internal/document-types/route.ts | App route | +27 | -0 |
| src/components/settings/document-types/document-type-delete-dialog.tsx | Component | +50 | -0 |
| src/components/settings/document-types/document-type-sheet.stories.tsx | Component | +58 | -0 |
| src/components/settings/document-types/document-type-sheet.tsx | Component | +107 | -0 |
| src/components/settings/document-types/document-types-error.tsx | Component | +14 | -0 |
| src/components/settings/document-types/document-types-fixtures.ts | Component | +51 | -0 |
| src/components/settings/document-types/document-types-list-page.tsx | Component | +141 | -0 |
| src/components/settings/document-types/document-types-presentation.ts | Component | +34 | -0 |
| src/components/settings/document-types/document-types-table.stories.tsx | Component | +113 | -0 |
| src/components/settings/document-types/document-types-table.tsx | Component | +167 | -0 |
| src/components/settings/document-types/document-types-toolbar.tsx | Component | +55 | -0 |
| src/components/settings/document-types/document-types-types.ts | Component | +5 | -0 |
| src/components/settings/document-types/use-document-type-actions.ts | Component | +153 | -0 |
| src/components/settings/document-types/use-document-type-sheet.tsx | Component | +117 | -0 |
| src/components/settings/settings-sidebar.tsx | Component | +8 | -0 |
| src/lib/document-types/gateway.ts | Library | +156 | -0 |
| src/lib/document-types/presentation.ts | Library | +15 | -0 |
| src/lib/document-types/types.ts | Library | +14 | -0 |
| src/lib/kubb-client.ts | Library | +12 | -0 |
| tests/unit/document-types-contract.test.ts | Test | +163 | -0 |