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 Case cases "Case" (a client matter) Top-level container. Owns schema data, contacts, tasks, etc. Has references (case #, docket #) and dates. Always has ≥1 filing — the active draft (most-recent status='draft') is the live workspace.
Case field override CaseFieldOverride case_field_overrides Hidden — surfaced only as the value showing in a field that has been pinned at case level Per-(case, form, field) PDF-field override. Case-wide live source for drafts; every filing on the case sees it unless a filing_forms.draft_overrides pin shadows it. Folded into filing_forms.snapshot (alongside the live binding-resolved values) at file-time.
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 Filing filings "Filing" — Court → Filings A workspace within a case. The active draft is where new form work happens; other filings are filed envelopes. Carries status (draft / filed / accepted / rejected), filed_at, snapshot_at, 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 filing contains. Carries draft_overrides JSONB (live per-filing field pins on drafts) and snapshot JSONB (frozen full resolved-field map captured at file-time — every PDF field bound on the form).
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 a filing.
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/filings/:filingId/override-map Per-(form, field) override map for a draft filing (case-level + draft pins, merged)
POST /api/cases/:id/filings/:filingId/resolve Stateless resolve preview — body carries an in-memory override map, server returns the resolved field values
POST /api/cases/:id/draft/commit Flush the Forms-tab edit buffer. Dispatches each edit to case-data (entries) / case-fields (case_field_overrides) / filing-override (filing_forms.draft_overrides).
GET /api/cases/:id/reference-bundle Reference tables (REF_LOOKUP — Census median income, IRS standards) shipped to the client so resolve runs in-browser.
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

The legacy PUT /api/cases/:id/forms/:formId/fields/:fieldKey keystroke endpoint and the useCaseOverridesDraft client hook are gone. The Form lens writes through /draft/commit, not on every keystroke.


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.
    • filings.status = 'filed' — this envelope has been submitted.
    • When a filing transitions to 'filed', snapshotOverridesForFiling runs the cross-form resolver and writes the full resolved-field map per form into filing_forms.snapshot, also clearing draft_overrides.

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 "Case Form" — there is no case_forms table. Forms attach to filings via filing_forms. The "what forms is this case working on" question is answered by the active draft filing's filing_forms rows.
  • 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"
filings.status "Drafting" / "Ready to file" / "Filed" status pills
case_field_overrides, filing_forms.draft_overrides (never surfaced as terms — both manifest as values that diverge from the schema, optionally tagged with a "pinned" affordance)
Source: docs/form_entities.md