You are editing my Dealer Pulse FastAPI app. Goal: Add a simple inbound endpoint for Lia so Make.com can send customer WhatsApp-style messages for processing and logging. Keep it minimal but production-safe. Requirements: 1. Create a new module: app/lia_inbound.py 2. In that file, implement: - a Pydantic model: class LiaInbound(BaseModel): from_number: str body: str channel: str | None = "whatsapp" conversation_id: str | None = None - a Pydantic response model: class LiaReply(BaseModel): conversation_id: str mode: str status: str defer_until: date | None = None reply: str - a function: async def process_inbound_message(payload: LiaInbound) -> LiaReply: - Use asyncpg connection helpers already in app.db (get_conn etc). - If payload.conversation_id is provided: • Load that row from dp_conversations. Else: • Create a new dp_conversations row with: conversation_id = gen_random_uuid() customer_id = NULL for now status = 'active' defer_until = NULL defer_reason = NULL - Always insert the inbound message into dp_messages: • direction = 'inbound' • channel = payload.channel or 'whatsapp' • sender = payload.from_number • message_body = payload.body • template_key = NULL • mode = 'inbound' • ab_variant = NULL - Very simple logic for now: body_lower = payload.body.lower() CASE 1: customer defers (contains any of: "not right now", "maybe later", "not a good time", "couple of months"): • Update dp_conversations: status = 'paused' defer_until = current_date + interval '2 months' defer_reason = 'customer said not right now – default 2 month defer' • Set: mode = "defer" status = "paused" reply = ( "No problem at all, I completely understand.\n\n" "I’ll make a note to check back in a couple of months instead, " "and I won’t keep chasing you in the meantime.\n\n" "If you do want to look at options sooner, just drop me a quick message here.\n\n" "Thanks,\nLia\nLincoln Audi" ) CASE 2: hard stop / opt out (contains any of: "stop", "do not contact", "remove my details"): • Update dp_conversations: status = 'dnc' defer_until = NULL defer_reason = 'customer requested do not contact – hard opt out' • Set: mode = "dnc" status = "dnc" reply = ( "Of course, I’ll update your preferences now and won’t contact you about renewals again.\n\n" "If you ever change your mind or need anything for your Audi in future, " "you can still message me here any time and I’ll be happy to help.\n\n" "Lia\nLincoln Audi" ) DEFAULT: • Leave conversation status as-is (or 'active' if newly created) • mode = "general" • status = existing status • reply = ( "Thanks for your message.\n\n" "I’ve made a note of this. If you’d like, I can also arrange a quick visit " "to run through your options properly, or we can just keep things as they are.\n\n" "What would you prefer?\n\n" "Lia\nLincoln Audi" ) - Also insert Lia’s outbound reply into dp_messages with: • direction = 'outbound' • channel = 'whatsapp' • sender = 'lia' • message_body = reply • template_key = NULL for now • mode = mode • ab_variant = NULL - Return LiaReply with: • conversation_id (uuid as string) • mode • status • defer_until (as date or None) • reply text 3. Wire this into FastAPI: - In app/main.py: • import LiaInbound, LiaReply, and process_inbound_message from app.lia_inbound • Add a POST endpoint: @app.post("/api/lia/inbound", response_model=LiaReply) async def lia_inbound(payload: LiaInbound, request: Request): await require_auth(request) reply = await process_inbound_message(payload) return reply 4. Constraints: - Reuse existing db connection helpers from app.db, do not create a separate pool. - Handle errors with try/except and log them; raise HTTPException(status_code=500) on unexpected errors. - Do not expose stack traces to the client. - Do not modify any existing endpoints or secret handling. 5. After making changes: - Run the tests / reload the app to ensure it still starts cleanly. - Then do a quick manual test (internal) calling /api/lia/inbound with a JSON body that includes: { "from_number": "+447900000000", "body": "Not right now thanks", "channel": "whatsapp", "conversation_id": null } - Confirm that: • The endpoint returns 200 with a LiaReply JSON. • A new dp_conversations row exists (if conversation_id was null). • Two dp_messages rows exist: one inbound, one outbound. • Status and defer_until are set correctly for the defer case. Report back in the chat with a short summary of what you changed and the test result.