Opus finding
flipReceipt is invoked before recordEvent persistence error handling — but flipReceipt itself has no try/catch, so a DB error in flipReceipt produces a 500 with no friendly page
- apps/web/app/api/opt-in/route.ts:58-66
- apps/web/app/api/opt-in/route.ts:94-118
The route has a try/catch around recordEvent (with an explicit comment 'Flip already succeeded; surface success to the user but log the audit-row miss'). But the upstream flipReceipt call has no try/catch. If the DB is down, the user gets an unstyled Next.js 500 with no errorPage. Given the rest of the route invests heavily in friendly HTML error pages (Missing token, Invalid link, Link expired), this is a UX gap the file's own conventions argue against. Not data-loss because the flip didn't happen — but the user is left without instructions on what to do.
Recommendation
Wrap the flipReceipt call in a try/catch and render an errorPage (status 500 or 503) with the same email-fallback messaging used elsewhere.