76 lines
2.8 KiB
Markdown
76 lines
2.8 KiB
Markdown
# WuzAPI Native Channel Implementation Plan (V2 - Strict V1 Specs)
|
|
|
|
## Goal
|
|
|
|
Implement WuzAPI as a native `Channel::Whatsapp` provider, adhering to strict V1 requirements: text-only, strong deduplication, and encrypted token storage.
|
|
|
|
## User Review Required
|
|
|
|
> [!IMPORTANT] > **Schema Change**: Adding `encrypted_wuzapi_user_token` and `encrypted_wuzapi_admin_token` (plus IVs) to `channel_whatsapp` to replace insecure JSONB storage.
|
|
|
|
> [!WARNING] > **V1 Scope**: Only `text` messages supported. Groups and self-messages are explicitly ignored.
|
|
|
|
## Proposed Changes
|
|
|
|
### Database
|
|
|
|
#### [NEW] Migration: Add Encrypted Tokens to Channel Whatsapp
|
|
|
|
- Add `encrypted_wuzapi_user_token` (string)
|
|
- Add `encrypted_wuzapi_user_token_iv` (string)
|
|
- Add `encrypted_wuzapi_admin_token` (string)
|
|
- Add `encrypted_wuzapi_admin_token_iv` (string)
|
|
- _Rationale_: Avoids storing sensitive tokens in `provider_config` (JSONB).
|
|
|
|
### Backend (Models)
|
|
|
|
#### [MODIFY] `app/models/channel/whatsapp.rb`
|
|
|
|
- Add `encrypts :wuzapi_user_token, :wuzapi_admin_token` (Rails 7+ encryption).
|
|
- Update `validate_provider_config` to check these new fields instead of JSONB.
|
|
|
|
### Backend (Services)
|
|
|
|
#### [NEW] `app/services/whatsapp/providers/wuzapi/payload_parser.rb`
|
|
|
|
- Implement class to strictly parse WuzAPI payload per contract:
|
|
- `external_id` <- `body.event.Info.ID`
|
|
- `from_me` <- `body.event.Info.IsFromMe`
|
|
- `wa_id` <- `body.event.Info.Sender` (parsed)
|
|
- `text` <- `body.event.Message.conversation`
|
|
- `timestamp` <- `body.event.Info.Timestamp`
|
|
|
|
#### [MODIFY] `app/services/whatsapp/incoming_message_wuzapi_service.rb`
|
|
|
|
- Integrate `PayloadParser`.
|
|
- Implement **Strong Dedupe**:
|
|
- Return early if `Message.exists?(source_id: external_id, inbox_id: inbox.id)`.
|
|
- Implement Loop Protection:
|
|
- Return early if `from_me` is true.
|
|
|
|
#### [MODIFY] `app/services/whatsapp/providers/wuzapi_service.rb` (Outbound)
|
|
|
|
- Update to use `channel.wuzapi_user_token` (decrypted) instead of `provider_config`.
|
|
- Ensure `send_message` handles errors gracefully.
|
|
|
|
### Security
|
|
|
|
- **Token Migration**: If any data exists (unlikely in prod yet), migrate from `provider_config` to encrypted columns.
|
|
|
|
## Verification Plan
|
|
|
|
### Automated Tests
|
|
|
|
- **Request Spec (`spec/requests/webhooks/whatsapp_controller_spec.rb`)**
|
|
- Verify WuzAPI payload submission creates a message.
|
|
- Verify duplicate payload does NOT create a second message (Idempotency).
|
|
- Verify `is_from_me: true` is ignored.
|
|
|
|
### Manual Verification
|
|
|
|
1. **Setup**: Create Inbox with WuzAPI, providing Token.
|
|
2. **Persistence**: Verify Token is stored in encrypted columns (checked via Rails Console).
|
|
3. **Inbound**: Send "Hello" from WhatsApp. Verify it appears in Chatwoot.
|
|
4. **Dedupe**: Replay the same webhook JSON. Verify no new message.
|
|
5. **Outbound**: Reply "World" from Chatwoot. Verify delivery to WhatsApp.
|