Live (part 2) — notify + email on INVOICE UPLOAD
Goal¶
Part 2 of T-037. When a user uploads a vendor invoice (createReceipt /
pages/api/records/vendor-invoices/upload), raise an in-app notification + email. Today only
the project-invoice POST calls notifyInvoiceCreated; vendor/receipt uploads are silent.
Reuse notifyInvoiceCreated or add a vendor-receipt variant.
Log¶
- 2026-06-14 created (T-037 split, owner).
- 2026-07-09 — doing (Records Infrastructure; routed via EOP Local Assistance fork, owner 2026-07-09). ✅ Read AGENTS.md · checked the board by scope (no dup; siblings T-038/T-040/T-041 cover matching-side events and stay out of scope — this is the UPLOAD path only). Source: Records (Infrastructure) · https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
- Verified silent:
pages/api/records/vendor-invoices/upload.tscallscreateReceiptbut no notify producer; only the project-invoice POST callsnotifyInvoiceCreated. - Chosen: vendor-receipt variant (not
notifyInvoiceCreated, which is project-invoice-shaped — it requires projectId/year/invoicePath and links to/projects/…). NewnotifyVendorInvoiceUploadedreuses the existingreceipt_uploadedtype (categoryrecords) and routes to accounting personnel vianotifyRoles— recipients + email flow through the SAME established roles/email-policy machinery, nothing new invented. Called best-effort aftercreateReceipt(never blocks the upload response). - Email note: like every
*_createdproducer this isinfoseverity → in-app is always delivered; email fires only when therecordscategory's email policy / severity dictates (identical to the invoice-created sibling). Flagged for the owner in case they want it to always email. - Full unfiltered
tsc --noEmitclean. PR open for review → flips todoneon merge. - 2026-07-09 — done (merged to
mainvia PR #876, no deploy — owner: commit + merge every change, don't deploy;main🟡🟡 = manual). Verdict: shipped as planned — newnotifyVendorInvoiceUploaded(reusesreceipt_uploaded/records, routed to accounting vianotifyRoles) fired best-effort aftercreateReceipt. SHAs:d1beed56(feat) · this close-out · PR #876 merge commit. Email:info→ in-app always; email follows therecordscategory policy (owner may bump to always-email — flagged). Blast-radius:lib/notifications/notify.ts(+index.tsbarrel),pages/api/records/vendor-invoices/upload.ts. Scope: upload path only — the matching-side events (T-038/T-040/T-041) remain separate.