Filing-related entities in Dossier
Reference table mapping every concept across code (TypeScript), DB (PostgreSQL table), and UI (what the lawyer sees).
Entities
| Concept | TypeScript / Code | DB table | UI label | What it is |
|---|---|---|---|---|
| Schema | Schema |
schemas |
"Schema" (admin only); tenant UI is law-themed and never says "schema" | Named vocabulary of data point definitions. Has a ui config that shapes the client app per law type. |
| Form (leaf) | Form |
forms |
"Form" (e.g. "Form 101", "Schedule A/B") | A fillable PDF: fields, bindings (schema-key → field), validations. References a schema. |
| Form (composite / "package") | Form with children[] |
forms + form_children |
"Package" (admin); usually invisible to tenants | Same forms row — a form with children[] IS the package. No separate Group entity. Children referenced by key (alias) for use in expressions like $schedule_d.line1. |
| Case Form (working set) | CaseForm, CaseFormWithMeta |
case_forms |
The Forms tab list ("Forms attached to this case") | A form attached to a specific case, with a state lifecycle: scratch → drafting → queued → filed. Drives the readiness/checklist views. |
| Case | Case |
cases |
"Case" (a client matter) | Top-level container. Owns schema data, contacts, tasks, etc. Has references (case #, docket #) and dates. |
| Entry (data entry) | Entry |
entries |
"Data entry" / shown on the Data tab and Activity | A batch of schema-keyed values written at one moment. Append-only — replayed in timestamp order to reconstruct case state. Source-tagged (manual, intake, client-portal, import). Optionally linked to the attachment it came from (attachment_id). |
| Data Source | DataSource |
data_sources |
"Import source" (in Settings → Imports), "Pull data" button | Reusable recipe for importing external data into the schema (intake form, credit-report parser, Clio API mapping). Writes Entries when invoked. |
| Attachment | Attachment |
attachments |
"Document" / Documents tab | An uploaded supporting file on a case (pay stub, ID, credit-report PDF). Lives independently of any filing. |
| Filing (envelope) | Filing |
filings |
"Filing" — Filings tab | One row = one envelope submitted (or to be submitted) to court. Carries status (draft / filed / accepted / rejected), filed_at, snapshot_at (point-in-time cutoff for replay), court_reference (ECF #). |
| Filing → Form link | FilingForm (embedded as forms[] on Filing) |
filing_forms |
"Forms in this filing" section in the detail rail | Join row: which forms this envelope contains. Captures form_version at envelope-creation time. |
| Filing → Attachment link | FilingAttachment raw / FilingAttachmentSummary embedded as attachments[] on Filing |
filing_attachments |
"Attachments" section in the detail rail; required badge |
Join row: which uploaded attachments accompany this envelope. Has a required flag. |
| Snapshot (point-in-time view) | mergeEntriesValues(caseId, asOf) returns Record<string, unknown> |
derived (no table) — filings.snapshot_at is the cutoff |
"Data snapshot · drift" section; GET /filings/:id/snapshot |
The reconstructed merged values as of snapshot_at. There is no stored JSONB blob — replay is the source of truth. |
| Drift | DriftItem[] from computeDrift(filed, current) |
derived | "Changes since filing" badge in detail rail (label TBD) | Diff between snapshot values and current case values, key-by-key. |
| Activity entry | ActivityEntry |
activity |
Activity tab | Auto-generated audit log: case created, filing created/status changed/deleted, data imports, etc. |
API routes
| Route | What it does |
|---|---|
GET /api/cases/:id/filings |
List all filings (envelopes) on a case |
POST /api/cases/:id/filings |
Create a filing envelope { name, formIds[], attachmentIds? } |
PUT /api/cases/:id/filings/:filingId |
Update name / status / courtReference. Status transition to 'filed' stamps filed_at + snapshot_at to NOW(). |
DELETE /api/cases/:id/filings/:filingId |
Delete an envelope. case_forms.state='filed' is preserved. |
GET /api/cases/:id/filings/:filingId/snapshot |
Frozen merged values for the filing (404 if not yet filed) |
GET /api/cases/:id/filings/:filingId/drift |
Diff: snapshot values vs current values |
GET /api/cases/:id/activity |
Audit log for the case |
GET /api/filings/:id/export?format=pdf|zip |
Export the envelope as merged PDF or ZIP |
GET /api/filings/:id/preview/:formId |
Preview a single child form in the envelope |
Naming conflicts to know about
- "Form" covers both leaf PDFs and composite "packages" — there is no separate
Group/Packageentity. Composition is justform_childrenrows pointing form → form. - "Filed" is overloaded:
cases.status = 'filed'— the case has been filed with the court overall.case_forms.state = 'filed'— this specific form is part of an envelope that went out.filings.status = 'filed'— this envelope has been submitted.- When an envelope transitions to
'filed', it upserts each childcase_formsrow tostate='filed'.
What's not an entity (intentionally)
- No "packet" — old UI copy ("Packet · 1 form") was just visual grouping for the one-form-per-row world. Removed.
- No "Group" — composite forms are forms.
- No "Document" as a separate concept — the Documents tab is just the Attachments view with required-checklist filtering.
- No "Form version" entity — the table was dropped; we keep
filing_forms.form_versionas an int for future-proofing. Real form-edit-after-filing versioning will need this re-introduced. - No "Amendment" entity — deferred; future spec will add a "this filing supersedes filing X" link.
Engine concepts the lawyer should never see
These are back-of-house — hide them behind plain-English buttons or copy:
| Engine concept | Lawyer-facing surface |
|---|---|
DataSource |
"Pull data" button, "Import sources" in Settings |
Entry |
"Edit data" / Data tab cells |
Binding |
(never surfaced) |
Validation |
"Issues" / red badges on fields |
Schema |
(never surfaced — UI uses law terms instead) |
Drift |
"Changes since filing" |
Snapshot |
"Filed values" |
CaseForm.state |
"Drafting" / "Ready to file" / "Filed" status pills |
Source:
docs/form_entities.md