feat(emails): log every POST /api/emails attempt (email_send_log, 7-day observability)

Merged
SW
4mo ago
+356-166

What

Records every POST /api/emails attempt — sent, send_failed, rejected (empty/malformed) — in email_send_log, so a send is debuggable days later without the ephemeral agent sandbox.

Why

The empty footer-only emails reached customers and we could not recover what the API received (malformed bodies swallowed, route logged nothing, sandbox ephemeral). This is the instrument that makes the rest of the issue measurable.

Change

  • lib/emails/logEmailAttempt.ts — best-effort writer (never throws), inserts the 5 settable columns: account_id, chat_id, status, resend_id, raw_body. Stores the full raw body (no truncation).
  • lib/emails/sendEmailHandler.ts — captures the raw body via request.clone() (validation still reads the original) and logs on every outcome; rejected attempts keep the raw body, so a malformed/empty send is visible after the fact.
  • lib/supabase/email_send_log/insertEmailSendLog.ts — typed insert.
  • types/database.types.ts — regenerated from the live schema (supabase gen types equivalent); adds the 7-column email_send_log (id, created_at, account_id, chat_id, status, resend_id, raw_body).

The table + RLS ship in the database repo — #37 (create) and #38 (drop error, enable RLS), both merged. Schema reviewed down to the minimal 7 columns (KISS).

Tests

logEmailAttempt unit (fields + full-body + swallow-errors) and sendEmailHandler (sent/rejected/send_failed log calls). Full lib/emails suite: 149 passing. tsc + lint clean.

Part of recoupable/chat#1829. Base main.

🤖 Generated with Claude Code