Work / Chitragupt / Wiki / Concepts
user-identity-entry
Conceptcanonicalverified 2026-07-17
CONCEPT.USER-IDENTITY-ENTRYUser → Identity → Document → Entry
Summary
Every parsed fact in chitragupt lives on one chain — a Firebase user owns one "self" identity plus many entity identities (banks, brokers, employers, insurers, loans, properties, retirement accounts, businesses, conditions, ID docs); every uploaded document points to one identity; every parsed entry inherits that identity plus a bucket + a strict-enum entry type.
Why it matters
Before this model, three collides masqueraded as one: the login owner's PAN lived on users/{uid} root; entities lived in accounts/; the matcher's per-doc identity_extracted snapshot lived on every documents/{docId} but never rolled up. Every callable that read PAN had two code paths, mappers emitted free-form entry_type strings that shipped silent-orphan bugs before a contract test caught them, and the Inbox folder tree grouped by a fourth ad-hoc taxonomy. Collapsing to one chain removes all four sources of drift.
Chitragupt is upload-only (upload-only · no-manual-entry) — the parser is the only writer of facts. Every fact therefore needs a single stable home: which user, which identity, which document produced it, which bucket it belongs to. That is what this concept enforces.
Implications
- Exactly one identity per user has
type: "self"(deterministic id"self"). It holds the login owner's PAN, DOB, full name, and residential status.users/{uid}never stores those fields again. Self is the only hand-editable identity — the user edits it on Settings › People & accounts (backed byupsertIdentitywithid = "self"). - Every entity identity lives under one of the 12 top-level buckets documented in identity-buckets. No new bucket without an ADR.
- Entity identities are upload-only — a non-self identity is minted only as a side-effect of the parser calling
ensureAcceptedIdentityduring document ingestion, per 2026-07-17-identity-creation-is-upload-only. There is no "+ Add bank / Add employer / …" affordance in the UI. Settings › People & accounts renders non-self identities read-only, with a Delete affordance guarded by a document-count precondition (delete blocked if any doc still references the identity — otherwise the FK dangles and every rollup loses those docs). - Every document has
identity_id(the entity it came from — or"self"for docs like 26AS/AIS/ITR-V),bucket(denormalised for fast Inbox queries), andabout_self(default true — false only when the doc is about an entity, not the taxpayer). - Every ledger entry has
identity_id,bucket, and anentry_typefrom the strict enum in ledger-entry-types. Free-form entry_type is forbidden. - Multi-person households use Pro Family (multiple Firebase logins with independent DPDP consent — family-workspace). No "dependent-without-login" model exists.
- The matcher (
parser/identity-matcher.ts) matches extracted attributes (PAN, TAN, IFSC, account_last4, folio, client_id, …) against allusers/{uid}/identities/*in one query. On mismatch the doc goes topending_identity_confirmation— a single status that replaced the priorpending_owner_confirmation | pending_family_transfer | pending_entity_confirmationtriad. User accepts (grows the identities), transfers to a family member (existing two-sided flow), or rejects. - Every recompute — tax review, expense review, portfolio review, capital gains — reads from ledger entries filtered by identity_id + AY / FY. Tax review sources login-owner PAN from
identities/self, never fromusers/{uid}. - CA share scope becomes
identity_ids[](notaccount_ids[]). Rules enforce the scope at the read.
Related
- identity-buckets — the 12 top-level Inbox buckets and their allowed identity_types
- identity-types — the ~31 identity_type variants with their required matcher attributes
- ledger-entry-types — the strict enum of every fact a mapper can emit, grouped by bucket
- upload-only — the principle that makes this chain load-bearing
- no-manual-entry — sibling invariant; the parser is the only writer
- family-workspace — the only multi-person model (Pro Family)
- 2026-07-11-user-identity-entry-model — the ADR that established this chain
- 2026-07-17-identity-creation-is-upload-only — the follow-on ADR that closes the "Add identity" affordance
- inbox-document-types — every parser + its natural bucket + expected identity_type
- inbox-folder-taxonomy — superseded by identity-buckets
Sources
- .context/wiki/concepts/* § "User → Identity → Document → Entry"
packages/shared/src/schemas/identity.tsapps/functions/src/parser/identity-matcher.ts
Every project of mine is written down like this.
Read the résumé