Work / Chitragupt / Wiki / Decisions
2026-08-10-inbox-wireframe-alignment
Decisioncanonicalverified 2026-08-10
DECISION.2026-08-10.INBOX-WIREFRAME-ALIGNMENTInbox React pages audited against all 3 wireframe variants; real gaps closed, one archetype scoped out
Decision
Audited the live Inbox implementation (apps/website/src/app/(app)/inbox/, apps/website/src/components/inbox/) against all wireframe variants under .context/designs/web/inbox/*.html — inbox-empty.html, inbox-populated.html, inbox-upgrade.html (the only 3 that exist; inbox.html, inbox-free.html, inbox-transfers.html, inbox-uploading.html, inbox-zip-expanding.html referenced by some .context/wiki/surfaces/inbox-*.md pages are mobile-only wireframes under .context/designs/mobile/app/inbox/ — those surface pages cite the wrong path, a pre-existing wiki-drift issue out of scope for this pass). Unlike the sibling Expense/Portfolio audit (2026-08-07-expense-portfolio-wireframe-alignment), Inbox's family-tier surface (/inbox/transfers) already existed and is real (listFamilyTransfers callable, acceptFamilyTransfer/denyFamilyTransfer, real PAN-match indicator) — no family-tier gap here.
Gaps found and fixed, component-for-component, with real derived data:
- Receipt-to-transaction linkage never surfaced in the UI.
apps/functions/src/inbox/link-evidence-to-ledger.ts(linkEvidenceToLedger, called frompersist-confirmed-document.ts) stamps a reallinked_ledger_entry_idon evidence-only docs (travel-receipt, utility-bill, motor-insurance-policy, generic-receipt) that matched a bank_debit/bank_credit row — per inbox-document-typesDOC.EVIDENCE-ONLY-NOTE/[[receipt-to-transaction-linkage]]. The website'sDocumentRecord/DocumentDetailtypes never read the field and no component rendered it. Added the field tostore/documents.ts, auseLedgerEntryhook tostore/ledger.ts, and a newLinkedTransactionNotecomponent rendered inDocConfirmedView's "Used by" section — real matched amount/date/merchant, not a placeholder. - Fabricated upload-progress numbers.
DocumentUploader.tsxshowed a hardcoded~${(remaining) * 12}s remainingcountdown and a static"—%"per-file progress, becauseapi/upload.tsused non-resumableuploadBytes(no progress events exist). Switched touploadBytesResumablewith a realstate_changedprogress callback threaded throughuploadFiles; the uploader now shows real byte-transferred percentages, no invented timing. - "Needs your action" main-panel shelf missing the "Expiring policy" archetype.
PILLAR.INBOX.NEEDS-ACTION.ARCHETYPESlists 5 archetypes (Locked · AIS/26AS mismatch · Uncategorised · Expiring policy renewal · OCR failure);NeedsActionShelf.tsxonly handled the first, third, and fifth (pure document-status archetypes). The expiring-policy archetype's data (temporal.valid_untilwithin 90 days) was already computed correctly but only in the sidebar's separate "Expiring in 90 days" shelf. HoistedisExpiringSoon/EXPIRING_WINDOW_MSout ofFolderTree.tsx(previously duplicated inline inFolderTree.tsxandDocumentList.tsx) into_bucket-helpers.tsas the single source of truth, and extendedisNeedsActionto optionally include expiring-soon docs so the main panel, sidebar shelf count, and?shelf=needs_actionfilter all agree. - Hardcoded, drifted doc-type counts.
InboxFreeUpgradeBanner.tsxandDocViewOnlyView.tsxboth said "23 more types" (28 total); the empty-state hint the wireframe specifies ("… 28 document types supported") didn't exist in the live empty state at all. The actualDOCUMENT_TYPESregistry has 43 entries. Replaced both hardcoded literals withObject.keys(DOCUMENT_TYPES).length-derived counts, and added the missing empty-state hint line toDocumentList.tsx's zero-doc state. - Dead buttons.
DocViewOnlyView.tsx's "Download" and "Delete" buttons (the free-tier single-doc page every Free-tier user hits before upgrading) had noonClickhandlers at all. Wired real handlers reusingfetchDocumentDownloadUrl/deleteDocumentfromapi/documents.ts, matching the pattern already used inDocConfirmedView.tsxandOpenOriginalButton.tsx. - Small fabricated/broken details.
InlineTick.tsxcomputed acolorvariable pertoneprop but never applied it (tick was always the same color regardless oftone="emerald"vs"blue") — fixed.DocConfirmedView.tsx's audit-trail line unconditionally claimed "no overrides" with no backend field tracking whether the user actually edited any parsed value before confirming — replaced with an accurate "Confirmed by you" status line instead of an unverified claim.
Scoped out, not fabricated: the wireframe's "AIS mismatch — AY 2026-27" needs-action archetype has no backend computation anywhere in the codebase — no job compares AIS entries against 26AS entries per TAN/section (the only reconciliation-adjacent work in the repo is _lib/reconcile-income-sources.ts, which is unrelated: it dedupes evidence-doc income against AIS, not AIS-vs-26AS). Building this needs new server-side logic (a per-AY diff over ledger_entries grouped by TAN/section), which is out of scope per this task's instruction not to build net-new backend computation. NeedsActionShelf.tsx intentionally omits this archetype rather than rendering a fake mismatch banner.
Why
Same rationale as the Expense/Portfolio pass: audit the live Inbox build against every wireframe variant that actually exists, close every gap with real data, and flag (rather than fake) anything that needs backend work not yet built.
Impact
apps/website/src/store/documents.ts,apps/website/src/store/ledger.ts—linked_ledger_entry_idfield +useLedgerEntryhook.apps/website/src/components/inbox/LinkedTransactionNote.tsx(new),DocConfirmedView.tsx,DocViewOnlyView.tsx,DocumentUploader.tsx,DocumentList.tsx,NeedsActionShelf.tsx,FolderTree.tsx,InboxFreeUpgradeBanner.tsx,InlineTick.tsx,_bucket-helpers.ts— the fixes above.apps/website/src/api/upload.ts—uploadBytesResumable+ progress callback.[[pillar-inbox]],[[inbox-document-types]]— no factual change, still accurate; not re-synced beyond this pass.- AIS/26AS mismatch reconciliation remains unbuilt — needs a new backend job before any Inbox UI can show it. Not a silent gap: it is simply absent from the "Needs your action" list rather than faked.
- Pre-existing wiki drift noted but not fixed in this pass:
.context/wiki/surfaces/inbox-free.md,inbox-folders-default.md,inbox-transfers.md,inbox-uploading.md,inbox-zip-expanding.mdcite website wireframe paths (inbox.html,inbox-free.html, etc.) that only exist under.context/designs/mobile/app/inbox/, not.context/designs/web/inbox/. A/wiki-lintpass is recommended to correct these citations or mark them mobile-only (Phase 8, out of V1 scope per 2026-05-30-v1-website-only).
Status
Active
Sources
- .context/designs/web/inbox/inbox-empty.html
- .context/designs/web/inbox/inbox.html
- .context/designs/web/inbox/inbox-locked.html
- 2026-08-07-expense-portfolio-wireframe-alignment — the sibling audit this follows the same methodology from
- .context/wiki/entities/inbox-document-types.md
- .context/wiki/entities/pillar-inbox.md
Every project of mine is written down like this.
Read the résumé