Behaviour: INSERT into dp_messages (conversation_id, message_body, sender, direction, channel, template_key, mode, ab_variant) Let created_at and updated_at use the defaults (do not override unless needed). Then: Use this helper in: The inbound webhook that handles CUSTOMER messages sender='customer', direction='inbound', channel='whatsapp' The LIA reply path (e.g., /api/lia/inbound, /api/lia/outbound, /api/lia/nudge) sender='lia', direction='outbound' The manager reply endpoint above sender='manager', direction='outbound' DNC guard for sending messages In any endpoint that triggers an outbound message (LIA or manager), before sending: Fetch dp_conversations.status for that conversation_id If status == 'dnc': DO NOT send an outbound message Return an HTTP 409 or similar with a clear JSON error: { "error": "Conversation is DNC; no further messages allowed." } This applies to: /api/lia/outbound /api/lia/nudge Any campaign senders Manager reply endpoint should probably also respect DNC (you can still allow a one-off "we've removed you" message if required, but that’s optional). Wiring into the existing LIA pipeline Wherever the URE / LIA pipeline runs (likely in /api/lia/inbound): After URE classification, you should have: tier (string) appointment_intent (string) updated soft_no_count and confusion_count (based on T4/T5/T6 behaviour) any needs_human_review flag (from confusion or policy triggers) After computing these: Call the conversation state helper to update status. Call the appointment status helper to update appointment_status. Use log_message to record the customer’s inbound message and LIA’s outbound reply. ──────────────────────────────── IMPLEMENTATION EXPECTATIONS Use existing db access pattern (get_db, asyncpg, or Supabase client) consistently with current code. Respect type hints and async patterns already in the project. Do NOT invent new tables or columns. Do NOT change existing column types. Keep functions focused and reusable (helpers in services/, endpoints in routes/). ──────────────────────────────── WHEN YOU ARE DONE Reply with a concise summary like: Files created: app/services/conversation_state.py app/services/appointment_state.py app/services/message_log.py Files modified: : added status + appointment updates in inbound pipeline : added /api/conversations/{id}/escalate endpoint : added /api/conversations/{id}/manager_reply endpoint : wired log_message into inbound/outbound/manager flows How it works: Brief description of when status changes to paused/dnc Brief description of appointment_status transitions Confirmation that dp_messages logs all messages. Make all edits now.