update: Major Overhaul to all subsystems

This commit is contained in:
2026-03-07 11:32:18 +02:00
parent 810e81b323
commit c62188fda6
107 changed files with 20414 additions and 929 deletions

81
.claude/crm-step-11.md Normal file
View File

@@ -0,0 +1,81 @@
# CRM Step 11 — Integration: WhatsApp Business API
## Context
Read `.claude/crm-build-plan.md` for full context and IMPORTANT NOTES.
Steps 0110 must be complete.
## Prerequisites (manual setup required before this step)
- A Meta Business account with WhatsApp Business API enabled
- A dedicated phone number registered to WhatsApp Business API (NOT a personal number)
- A Meta App with webhook configured to point to: `https://yourdomain.com/api/crm/whatsapp/webhook`
- The following values ready: `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_ACCESS_TOKEN`, `WHATSAPP_VERIFY_TOKEN`
## Task
Receive inbound WhatsApp messages via webhook and send outbound messages, all logged to crm_comms_log.
## Backend changes
### 1. Add to `backend/config.py`
```python
whatsapp_phone_number_id: str = ""
whatsapp_access_token: str = ""
whatsapp_verify_token: str = "change-me" # you set this in Meta webhook config
```
### 2. Create `backend/crm/whatsapp.py`
```python
async def send_whatsapp(to_phone: str, message: str) -> str:
"""
POST to https://graph.facebook.com/v19.0/{phone_number_id}/messages
Headers: Authorization: Bearer {access_token}
Body: { messaging_product: "whatsapp", to: to_phone, type: "text", text: { body: message } }
Returns the wamid (WhatsApp message ID).
"""
```
### 3. Add webhook + send endpoints to `backend/crm/router.py`
`GET /api/crm/whatsapp/webhook`
— Meta webhook verification. Check `hub.verify_token` == settings.whatsapp_verify_token.
Return `hub.challenge` if valid, else 403.
**No auth required on this endpoint.**
`POST /api/crm/whatsapp/webhook`
— Receive inbound message events from Meta.
**No auth required on this endpoint.**
Parse payload:
```
entry[0].changes[0].value.messages[0]
.from → sender phone number (e.g. "306974015758")
.id → wamid
.type → "text"
.text.body → message content
.timestamp → unix timestamp
```
For each message:
1. Look up customer by phone number in crm_customers contacts (where type=phone or whatsapp)
2. If found: create crm_comms_log entry (type=whatsapp, direction=inbound, ext_message_id=wamid)
3. If not found: still log it but with customer_id="unknown:{phone}"
`POST /api/crm/whatsapp/send`
Body: `{ customer_id, to_phone, message }`
Requires auth.
→ calls `send_whatsapp(...)`, creates outbound comms_log entry
## Frontend changes
### Update Comms tab in `CustomerDetail.jsx`
- WhatsApp entries: green background, WhatsApp icon
- "Send WhatsApp" button → modal with: to_phone (pre-filled from customer's whatsapp/phone contacts), message textarea
- On send: POST `/api/crm/whatsapp/send`
### Update `InboxPage.jsx`
- WhatsApp entries are already included (from crm_comms_log)
- Add type filter option for "WhatsApp"
## Notes
- Phone number format: Meta sends numbers without `+` (e.g. "306974015758"). Normalize when matching against customer contacts (strip `+` and spaces).
- Webhook payload can contain multiple entries and messages — iterate and handle each
- Rate limits: Meta free tier = 1000 conversations/month (a conversation = 24h window with a customer). More than enough.
- If whatsapp_phone_number_id is empty, the send endpoint returns 503. The webhook endpoint must always be available (it's a public endpoint).
- Media messages (images, docs): in this step, just log "Media message received" as body text. Full media download is a future enhancement.