Dossier · Internal docs
Internal · Filing Entities Map

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: scratchdraftingqueuedfiled. 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 / Package entity. Composition is just form_children rows 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 child case_forms row to state='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_version as 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