feat(migrations): create email_send_log table
Merged
SW
4mo ago+30+30+01234567890123456789-0-0-0123456789
What
Adds email_send_log — a durable record of every POST /api/emails attempt (sent / send_failed / rejected), so a send is debuggable several days back without the ephemeral agent sandbox.
Why
Empty footer-only "Message from Recoup" emails reached customers and we could not recover what the API received (malformed bodies swallowed, route logged nothing, sandbox ephemeral). This table captures it.
Design (KISS — reviewed twice)
Append-only; loose ids, no FKs (like error_logs). 7 columns:
id, created_at, account_id, chat_id, status, resend_id. raw_body (full — bounded by the platform request-size limit), error + (created_at DESC) / (account_id) indexes.
chat_idonly (TEXT, matchingchats.id).chats.session_idreaches the session andsessions.account_idthe account, so a separatesession_idcolumn would be redundant — andsession_idisn't in the/api/emailscontract anyway, so dropping it avoids extending that contract.account_iddenormalized (free at the API; the main query dimension).- Dropped earlier
to_count / subject / html_length / text_length(derivable fromraw_body). - Resend delivery lifecycle (delivered/bounced/opened) is a deliberate future concern — a separate
email_eventstable keyed offresend_id, not more columns here. (A retention/purge job forraw_body(the real size/PII control, since we keep the full body now) and achat_idindex for the verify-the-send lookup are follow-ups alongside that work.)
Pairs with
- recoupable/api#731 —
logEmailAttemptwrites this table. This migration lands first; then #731's code is reconciled to match (chat_id, drop the 4 fields) before it merges.
Part of recoupable/chat#1829.
🤖 Generated with Claude Code
Summary by CodeRabbit
- New Features
- Email send attempts are now recorded with delivery status, sender, chat reference, timestamps, and related message details.
- Added faster lookup support for recent entries and sender-based views.