Skip to content

T 110


uid: T-110 title: Records page β€” restore WOPC list after the T-089 migration + drop the All tab status: done area: accounting-records created: 2026-06-24 updated: 2026-06-24 related: T-089, I-011


Why

Two Records-page tab problems the owner reported on 2026-06-24, fixed in one PR:

  1. The WOPCs tab showed nothing. A previous change reshaped how WOPC documents are stored β€” it moved the "created" timestamp and the reference number out of the top level and into a WOPC.* group (T-089, the WOPC doc-shape restructure, done 2026-06-24). But the code that lists WOPCs for the Records page still asked Firestore to "sort by the top-level createdAt" β€” and Firestore silently drops every document that doesn't have the field you sort by. After the migration no WOPC has a top-level createdAt, so the list came back empty even though all 34 WOPCs are still there. (See I-011 for the symptom record.)
  2. The "All" tab was misleading. It combined WOPCs + project invoices + coaching invoices but never included receipts or bank statements, so it was never actually "all documents." The owner asked to drop it.

Verified (live Firestore, tebs-epl)

  • 34 WOPCs exist: payees/JC/wopc/* (33) + payees/JN/wopc/* (1).
  • 0 / 34 carry a top-level createdAt; it now lives at WOPC.created.at. The reference number likewise moved to WOPC.refNumber (top-level referenceNumber is gone; the doc id is the storage form, e.g. ERL-WOPC|2024-001).
  • So getAllWOPCs' .orderBy('createdAt','desc') matched nothing β†’ empty tab.

What changed

  • lib/wopc.server.ts β€” getAllWOPCs + getWOPCsForPayee:
  • Dropped .orderBy('createdAt', 'desc') from the Firestore query (it was the silent filter). The subcollection is now read unordered so every doc comes back.
  • Reconstruct the display referenceNumber from WOPC.refNumber (fallback: the doc id via toDisplayFormat) and surface it at the top level of the returned object, so the Records serializer + CSV export (which read w.referenceNumber) keep working unchanged.
  • Sort in memory by the bucketed WOPC.created.at (via the canonical getCreated accessor in lib/wopcDocShape). The old in-memory sort read the now-absent top-level createdAt, so it was a silent no-op too.
  • components/records/RecordsApp.tsx β€” removed the all tab, its now-dead allRows / allColumns / totalCount, the orphaned WOPC_STATUS_COLOR / WOPC_STATUS_LABEL maps and the AnyRow type; added a ?tab=all β†’ wopcs deep-link remap so stale links land on a real tab.

Why it's built this way

  • Reconstruct the ref number at the seam (getAllWOPCs) instead of rewriting every downstream consumer. The Records serializer reads w.referenceNumber in ~6 places (row key, Drive lookups, CSV links). Normalising once where the docs are loaded keeps the blast radius to one function and avoids touching the serializer / CSV / detail-drawer paths that already work via toView.
  • Read unordered + sort in memory rather than .orderBy('WOPC.created.at'): there are only ~34 WOPCs across 2 payees, so the in-memory sort is trivial and needs no composite index, and it tolerates the handful of legacy docs whose timestamp shape differs.

Decision log

2026-06-24 β€” opened + fixed

  • βœ… Attestation (Records (Infrastructure)): read AGENTS.md; scope-scanned the board by scope β€” T-089 is the migration (done); this is the read-path regression it left in the Records list, which no existing task covers. The All-tab drop is a sibling owner request landing in the same PR.
  • Source: Records (Infrastructure) Β· https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
  • Proposed by: the owner. Approved by: the owner (verbatim, 2026-06-24):

    "I have recently restructured the fields in WOPCs and I think that's probably why the WOPC tab on the Records page is now showing no WOPCs at all… Can you help me look into it?" "Let's proceed to fix the WOPC…" "…I'd rather that we drop the All tab once and for all as I don't think I'll ever look at mixed type of documents in a single tab anyways"

  • Commit: 6dfb0a1d on branch claude/records-wopc-empty-drop-all-tab β†’ PR to main (branch policy 2026-06-24: main 🟒 / nightly πŸ”΄ β†’ merge to main only).
  • Verification: root cause proven against live Firestore (0/34 WOPCs have top-level createdAt). Could not run tsc in-sandbox (no node_modules); the change is a small, self-contained edit using the existing lib/wopcDocShape accessors already used by the Records serializer. Owner to confirm the WOPC tab populates after deploy.
  • Blast radius: getAllWOPCs feeds the Records WOPC tab + its CSV export; getWOPCsForPayee feeds payee-scoped WOPC reads. Both now return the bucketed-shape WOPCs. No change to the WOPC write path, the signing flow, or toView. The All-tab removal touches only RecordsApp.tsx (the per-type tabs are unchanged). The Coaching Invoices tab is not addressed here β€” it's empty for a different reason (see I-012).