update: Major Overhault to all subsystems
This commit is contained in:
81
.claude/crm-step-11.md
Normal file
81
.claude/crm-step-11.md
Normal 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 01–10 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.
|
||||
Reference in New Issue
Block a user