Cases in depth

Files route by identifier: a matching identifier joins the existing case, otherwise a new case is atomically created. Extraction never overwrites your manual edits, and every case carries a read-time activity timeline.

Updated 8 min read
Diagram of two documents flying along dotted arcs into a single dossier folder whose tab carries a padlock seal, with a third document queued behind a gate
Fig. 01Same identifier, same case. The padlock is the workspace's identifier lock: at most one case may claim a value, so every later file with that identifier files itself into the winner.

How files route to cases

Every case has a top-level Identifier. The workspace enforces uniqueness: at most one case per (workspace, identifier value) pair, backed by an atomic Firestore lock. Every ingestion channel (Gmail, Drive, manual upload) runs the same routing:

  1. Identifier extracted, lock found → file attaches to the existing case.
  2. Identifier extracted, no lock → atomically claim the lock, create a new case, attach the file.
  3. No identifier surfaced → create a new case with an auto-generated ID, attach the file.

The atomic claim makes step 2 race-safe: two parallel ingests of one identifier can't produce two cases (one wins the lock, the other attaches to it).

Auto-promote: a case created without an identifier (manual placeholder or no-identifier ingest) carries a generated ID and shows a muted auto tag next to it. It auto-promotes the moment a later extraction surfaces a clean value. If that value is already claimed, the promote is skipped and the auto ID stays, so resolve the collision by editing either case's identifier.

Rename: open the case, choose Edit case (header menu), change the Case ID field at the top of the edit form, then click Save changes. The rename atomically releases the old lock and claims the new one. If another case owns the new value, a prompt appears: Merge folds this case into that one (files move, this case deleted), or Rename uses the next free variant (e.g. E-9 (2)). Cancel keeps you editing.

When a file lands on the wrong case

Routing reads an identifier and acts on it. If that read comes back empty, or comes back with something that looks right but isn't (EO8123 where the document says E08123), the file starts a brand new case instead of joining the one it belongs to. Nothing flags this at the time, because from the app's point of view the routing succeeded: it read a value and made a case for it.

This matters most in a multi-document process. If document 2 lands somewhere else, the values it carried never reach the real case, so document 3 has nothing to build on.

Ask the assistant to check it. Open the case that looks wrong and say something like "re-read the ID on this file". It reads the identifier again from wherever your template takes it, the document itself or the delivering email, and tells you where the file should have gone. Nothing moves until you say so.

Three things it can find:

  • Another case owns that identifier. The file moves there, bringing its extracted values with it.
  • Nobody owns it and this case holds only that file. The file is already in the right place and the case is just named wrong, so it renames the case.
  • Nobody owns it and this case holds other files too. The file is carved out into its own case.

If a document failed because it is genuinely unusual, tell the assistant how to read it when you ask: "re-read the ID, the project number is after the second dash". That applies to this file only. When the same instruction would help every document of that type, put it on the template's ID field instead so future documents route correctly on arrival.

What happens to the case left behind. When a move empties a case that only ever existed because of the bad routing, it is deleted, so your dashboard doesn't fill with empty duplicates. A case is only deleted when it has nothing of its own: no other files, no notes, no teammates added, no documents generated from it, and no fields you edited by hand. Anything else is kept and the assistant tells you which ones and why.

What happens when a second file arrives

Extraction runs on that one new file against its matched template; results write to case.data field by field. There's no cross-file diffing. The write rules:

  • Latest extraction wins per field: the newest value replaces the prior one. No "longer string wins," no similarity check.
  • Empty extractions can't blank populated fields: null/undefined/empty for a field that already has a value is skipped, and the previous value stays.
  • Manual edits are sticky. Any pencil-edit (or chat-agent correction) is recorded as an _overrides entry. Every re-extraction, automatic or manual, skips overridden fields, so the app never silently undoes a worker's correction. You can tell a field is protected because its provenance tag flips to User Input (a pencil). Click the clock icon on the row to see what the value was before, who changed it, when, and the document the original came from. Editing a field is permanent in one sense worth knowing: once you have set a value by hand, later extractions will not touch that field again, and typing the old value back in does not hand it back to extraction.
  • Dates normalize at write time to US MM/DD/YYYY; free text like "TBD" falls through unchanged.
  • Batch (repeating-row) fields write as a whole: the latest array replaces the previous one. No row-level concatenation; to accumulate line items across invoices, use a separate case or merge by hand.
A merge in action
Old fileVendor='Acme Supply', Due=2026-04-01
New fileVendor='Acme Supply Co.', Due=2026-04-15
After re-extractionVendor='Acme Supply Co.' (overwritten), Due=2026-04-15 (overwritten)

To force a re-extraction without losing edits: open the file from the case detail's Documents section and pick Re-extract from the review modal's kebab (...) menu, or Update case (saves your inputs and re-reads the file when the run is stale, no new document) or Autofill (extract and generate) on the template's item. Override-protected fields stay; everything else takes the new values.

Consolidating two cases

Auto-detected (primary). When an orphan case (no readable identifier) holds a document carrying the real ID, run an ID-capturing template on it (any template with an identifier field configured to extract the case ID from the document). If the extracted ID belongs to another case, a merge banner appears at the top of the orphan case detail: "This document's ID [X] belongs to an existing case. Merge this case's documents into [X] and delete this one?" Click Merge: the orphan's files re-attach to the matching case (normal upload path, so the rules above re-apply) and the orphan is deleted, and you land on the survivor. If the ID is unclaimed, the orphan simply auto-promotes (no banner).

Manual (fallback). When neither case carries a shared extractable ID:

1Download the stray file2Open the surviving case3Edit case4Upload the fileDelete the duplicate case

In Edit case (the duplicate's menu, after downloading the stray file via the Download button in its preview), the Upload File section takes a Source File; click Upload to Case. Then delete the duplicate via Delete case from its menu; the confirm dialog warns deletion is permanent, so move everything you need first. The survivor re-extracts the uploaded file like any other arrival, so the merge rules above apply.

Moving one misrouted file

Merging folds whole cases together. When just a single file landed on the wrong case, move that one file instead of merging. Two places offer it:

  • From the activity timeline. Open the case and find the file in the timeline. The line under it reads Matched on EQ25998 (what the identifier read as when the file arrived) or No ID read. Click the pencil to correct the identifier. If the corrected value belongs to another case, the app shows a note ("Does not match this case. Matches case EQ17774.") with a Move file there button; if no case carries that value yet, it offers Move to new case. Nothing is created until you confirm.
  • From the Documents section. Each file's menu carries Move to another case (search for the destination by identifier) and Start a new case from this file (prefilled with the file's read identifier; leave it blank for a generated ID). The moved file keeps its extracted values.

The moved file leaves a File moved out entry on the old case and a File moved in entry on the new one, so the trail stays auditable on both sides.

The activity timeline

Each case has a chronological timeline (most recent first), derived at read time from several Firestore sources (case notes, form submissions, PDF generations, file store, template runs, the dataHistory map, and the activity subcollection), not one canonical collection. That is why editing a note rewrites the source rather than creating a new event. Entry types: Notes, added by workers in the single-editor composer (no tabs): free text, an optional event date, and paperclip attachments (images, PDFs, other media); edited notes show an Edited badge and keep an edit history so earlier text, attachments, or event date can be reviewed. Form submissions capture a client's template answers from the portal or a shared form link (workers don't fill forms from this composer). Generations preserve the template, output file, and a snapshot of the input values used. Signed documents read "Signed · N electronic signatures", save the stamped PDF to the case's Files, and keep an immutable signing record (who signed, when, the consent agreed to, and tamper-evident hashes of the file): an electronic signature, not a notarized or legally-binding one. Template runs can show field-level diffs when the same template runs more than once. System events cover file ingested, field updated, case created, collaborator added/removed, mailbox move (e.g. "Moved to Confirmations by automation: Confirmation of Award"), identifier renamed, file moved between cases, file identifier corrected, and a general catch-all.

Dates and calendar: entries land on their creation day; a note with an event date lands on that date instead, useful for follow-ups, calls, site visits, due dates, or reminders. Click a date for View in calendar (the in-app Calendar view) or Download .ics (a standard calendar file you open in Google, Apple, or Outlook); the Calendar view also has a bulk Export .ics that bundles every date showing under the current filters. The app does not push events to Google Calendar over the API. Copy distinguishes staff from clients: "Riley was assigned to this case" vs "client@example.com was given client access to this case".

Category visibility: entries referencing a file carry that file's category; any entry whose category a viewer can't see is hidden, enforced at the data layer, not UI-only. A restricted viewer still sees the case exists, just not activity about files they can't access. If a collaborator says an entry is missing, check its file category first.

Deleting: notes you manage can be deleted (if a note was tied to structured case changes, you may be asked whether to undo those too). Everything else on the timeline is a permanent record and has no delete: file ingestion, field updates, template runs, case creation, and the rest describe what actually happened to the case, so they stay. To add a note, scroll to the Activity section, type in the composer, optionally attach via the paperclip or set an event date with the calendar icon, then click Add Note.

Type at least 2 characters to search.
We use cookies to keep you signed in and improve the product. See our Cookie Policy.
Manage preferences