The Documents Register learns whose filing it is
The Record is the complete case picture — our filings and the opponent's and the court's, sitting in one register. Until now it showed what a filing is (filing type) and its state (draft / filed) — but never whose it is. A "Reply Affidavit · Filed" row read the same whether we filed it or the claimant did. This Story adds the missing axis: a Filing By column (filer + label + a coloured Side badge), and the ability to group and slice the whole register by Side and by Participant.
🛰️ Satellite — why "whose" is a first-class question
The stakes: counsel reading the Record all day asks three questions of every filing — what is it, where is it in its life, and who put it on the table. We answered the first two and left the third to memory and filename archaeology. "Show me everything the opposing side filed" or "everything from Vega Capital" required eyeballing a column that does not exist. For an adversarial record that is not a nicety; it is the difference between reading our case and reading the dispute.
The naive fix bolts a free-text "filed by" string onto each document and calls it done. It detonates the moment you want to filter: free text does not bucket ("Vega", "Vega Capital", "Vega Cap." are three parties to a computer), and it has no notion of side — the one axis counsel actually pivots on. The real fix recognises two distinct things: a participant (a real party with a stable name) and a side (a fixed, four-value structural axis relative to our client). Both are already on the wire — this Story renders them and makes them pivotable.
✈️ Airplane — one cell, two axes, the engine you already have
Think of the register as a filing cabinet where every document carries a routing slip. The slip names the filer ("Vega Capital"), their role in this proceeding ("Claimant"), and a coloured tab for the side of the room they sit on. The Filing By column is that slip; the coloured tab is the Side badge:
| Side | Badge | Meaning (relative to our client) |
|---|---|---|
ours | Ours | Our own client's filing. |
opposing | Opposing | The adversary's filing. |
court | Court/Tribunal | The neutral authority's filing (order, direction). |
others | Others | Any other party (e.g. a regulator). The default until classified. |
Crucially, the pivots are two axes, not one. "Side" buckets the whole record into Ours / Opposing / Court·Tribunal / Others; "Participant" buckets it by the individual filer. Both run through the exact view-state engine from Story-1510 (DOCS-VIEWENGINE) — the same grouping, slicing, counting, and sentinel machinery that already powers document-type and tag. This Story adds no new engine logic; it teaches the existing engine two new fields and renders them.
🔬 Microscope — the parts that earn their place
Why one display column but two group/slice axes
Counsel wants to see the filer, label, and side together in one
cell — that is one column, filingBy. But they want to
pivot on side or on participant independently. A single column
maps to a single group/slice field, so the cell column cannot carry both
pivots. The clean shape: filingBy is a normal display column
(sortable by filer name, not directly groupable), and the two pivots live
as axis fields — filingSide and
filingParticipant — that surface only in the Group-by /
Slice-by pickers and as group headers, never as their own table columns.
// columns.ts — axis fields are group/slice-only, not display columns
export const AXIS_FIELDS = [
{ key: "filingSide", groupable: true, sliceable: true, sortable: false, ... },
{ key: "filingParticipant", groupable: true, sliceable: true, sortable: false, ... },
];
// they join GROUP_FIELDS / SLICE_FIELDS and getColumn(), but NOT REGISTER_COLUMNS
Why Side is the only value the engine must localize
Every other group/slice value the engine emits is already display-ready: a
document type, a tag, a participant name are human strings from
data. Side is different — it is a fixed enum (ours /
opposing / court / others) that must
read as Ours · Opposing · Court/Tribunal · Others, and
correctly in Hindi. So the slice navigator and the group header
special-case only the filingSide axis, mapping the
token through DocumentsRegister.sideLabels.*. The participant
axis needs no such treatment — its value is the name itself.
Why four distinct tokens, never a hex literal
Side is a structural axis, so it earns four distinct, token-backed
hues: ours = green (our own), opposing = crimson
(the adversary — deliberately not the red reserved for the failed
status), court = the brand accent (neutral authority),
others = neutral paper chrome. All live in
presentation.ts as SIDE_TONE — no inline colour
ever touches a component.
Why "filed by" is a read-time derive, never stored
The filing lifecycle lives on the Filing, never the document (ADR-125).
FN-2 derives the filer from the linked Filing's
filed_by_participant_id → participant name + per-proceeding
label + side, and serves it on DocumentFilingLinkView.filedBy
(FiledByView in src/gen). The adapter maps that
straight onto the row; nothing about "whose" is stored on the document. A
row with no link, or a filing that names no filer, simply renders "—" and
falls into the No filer sentinel bucket.
filingType and
filingState columns exactly as they were and adds Filing By
alongside. The Record is where you see everything; the Filings tab
is where you edit. Both truths now coexist on the same row.
What shipped
| File | Change |
|---|---|
lib/documents/register/types.ts | RegisterDocument gains filingParticipant / filingParticipantLabel / filingSide; FieldKey gains filingBy / filingSide / filingParticipant; new no-filer sentinel. |
lib/documents/register/columns.ts | filingBy display column (after Filing state) + AXIS_FIELDS (Side, Participant) wired into GROUP_FIELDS / SLICE_FIELDS / getColumn / membership / sentinels. |
lib/documents/register/adapter.ts | Maps FN-2 filedBy (name + label + side) onto the row; null when unlinked / no filer. |
components/.../filing-side-badge.tsx | New FilingSideBadge primitive — four token-backed hues, localized label. |
components/.../register-cell.tsx | filingBy cell: filer name + label + Side badge ("—" when no filer). |
register-slice-navigator.tsx / register-group-header.tsx / register-table.tsx | Side-axis enum tokens localized in the slice rail and group headers (header receives the group field). |
view-popover/icons.ts | Glyphs for the three new fields (Stamp / Split / Users). |
messages/{en,hi}.json | columns.filingBy/filingSide/filingParticipant, sideLabels.*, sentinels.noFiler — both locales. |
| Stories & tests | filing-side-badge.stories (4 badges + all-sides), table "Grouped by Side / Participant", slice-nav "Slice by Side"; adapter + engine tests for the new derive and axes. |
Mode-1 honoured: no AI naming/classification. Tokens only — no hex/rgb
literals (verified). i18n en + hi at parity. Imports the generated
FiledByView / FilingSide from src/gen;
no codegen run (FN-1/FN-2 already merged + synced).
One-sentence recall
Filing By turns every Record row's routing slip — filer, label, and a coloured Side tab — into a first-class cell, and lets counsel pivot the whole record by Side or by Participant through the engine that already exists.
Files changed
18 file(s), +372 / -19 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +11 | -1 |
| messages/hi.json | Config | +11 | -1 |
| src/components/documents/register/filing-side-badge.stories.tsx | Component | +45 | -0 |
| src/components/documents/register/filing-side-badge.tsx | Component | +36 | -0 |
| src/components/documents/register/presentation.ts | Component | +36 | -0 |
| src/components/documents/register/register-cell.tsx | Component | +20 | -1 |
| src/components/documents/register/register-group-header.tsx | Component | +10 | -4 |
| src/components/documents/register/register-slice-navigator.stories.tsx | Component | +8 | -0 |
| src/components/documents/register/register-slice-navigator.tsx | Component | +11 | -4 |
| src/components/documents/register/register-table.stories.tsx | Component | +28 | -0 |
| src/components/documents/register/register-table.tsx | Component | +1 | -0 |
| src/components/documents/register/view-popover/icons.ts | Component | +6 | -0 |
| src/lib/documents/register/adapter.test.ts | Library | +21 | -0 |
| src/lib/documents/register/adapter.ts | Library | +5 | -0 |
| src/lib/documents/register/columns.ts | Library | +59 | -7 |
| src/lib/documents/register/fixtures.ts | Library | +16 | -0 |
| src/lib/documents/register/types.ts | Library | +23 | -1 |
| src/lib/documents/register/view-state.test.ts | Library | +25 | -0 |