fix: webhook message insert uses wrong schema field names

When a WhatsApp message arrives, the webhook creates/updates the contact
and conversation fine (so the conversation appears in the Inbox), but
every message INSERT fails silently because the field names don't match
the messages table schema:

  Webhook wrote              Schema has
  -----------------          ----------
  user_id                    (doesn't exist)
  whatsapp_message_id        message_id
  direction: 'inbound'       sender_type ('customer' | 'agent' | 'bot')
  message_type               content_type
  media_type                 (doesn't exist)
  status: 'received'         status ('sending'|'sent'|'delivered'|'read'|'failed')
  timestamp                  created_at

The insert error was caught and logged with console.error but silently
swallowed — the conversation update succeeded (its fields were right),
so the Inbox showed the contact and last message text, but opening the
thread showed zero messages. The 24-hour session timer also read
"no customer messages ever" and immediately marked the session expired.

Fixes in src/app/api/whatsapp/webhook/route.ts:
- processMessage() — message insert now uses the correct schema columns:
    sender_type: 'customer'
    content_type: message.type
    message_id: message.id
    status: 'delivered'
    created_at: <ISO from Meta timestamp>
- handleStatusUpdate() — lookup uses message_id (not whatsapp_message_id)
  and no longer sets updated_at (column doesn't exist on messages).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arnas Donauskas 2026-04-16 21:03:08 +03:00
parent 82fc18e460
commit ffdf2d1c80
No known key found for this signature in database

View File

@ -184,13 +184,13 @@ async function handleStatusUpdate(status: {
timestamp: string
recipient_id: string
}) {
// The messages table schema uses `message_id` (not whatsapp_message_id)
// and has no `updated_at` column. Meta's status values (sent/delivered/
// read/failed) already match our CHECK constraint.
const { error } = await supabaseAdmin()
.from('messages')
.update({
status: status.status,
updated_at: new Date().toISOString(),
})
.eq('whatsapp_message_id', status.id)
.update({ status: status.status })
.eq('message_id', status.id)
if (error) {
console.error('Error updating message status:', error)
@ -227,18 +227,23 @@ async function processMessage(
)
if (!conversation) return
// Insert message
// Insert message — field names MUST match the messages table schema
// (see supabase/migrations/001_initial_schema.sql):
// conversation_id, sender_type, content_type, content_text,
// media_url, template_name, message_id, status, created_at
// `mediaType` is intentionally unused — the schema has no media_type
// column; the MIME type is only used to construct the proxy URL during
// parseMessageContent. Silence the unused-var warning:
void mediaType
const { error: msgError } = await supabaseAdmin().from('messages').insert({
conversation_id: conversation.id,
user_id: userId,
whatsapp_message_id: message.id,
direction: 'inbound',
message_type: message.type,
sender_type: 'customer',
content_type: message.type,
content_text: contentText,
media_url: mediaUrl,
media_type: mediaType,
status: 'received',
timestamp: new Date(parseInt(message.timestamp) * 1000).toISOString(),
message_id: message.id,
status: 'delivered',
created_at: new Date(parseInt(message.timestamp) * 1000).toISOString(),
})
if (msgError) {