Tracks the app that was already in place (capture, treatment, outreach, WhatsApp integration, server, frontend, tests, docs) so future feature work can branch and use isolated worktrees.
6.6 KiB
WhatsApp Verification and Manual Send Design
Goal
Make the visible manual phone field the authoritative send destination and distinguish a syntactically valid telephone from a number confirmed by WhatsApp.
Constraints
- Work only in
MAQUINA COMERCIAL PESSOAL. - Keep the RFB telephone value as source data; do not claim it is a WhatsApp account without a real lookup.
- Verify numbers on demand. Do not scan the full RFB lead base.
- Automatic outreach may use only numbers with a persisted successful verification.
- Brazilian mobile variants with and without the ninth digit represent the same opt-out identity.
- A send timeout is an unknown delivery outcome, not proof of failure.
Data Model
Add a whatsapp_number_verifications cache keyed by the normalized requested phone number. Each record stores:
numero: digits submitted for verification.status:confirmado,nao_cadastrado, orerro_temporario.numero_resolvido: number returned in the registered WhatsApp JID, when confirmed.variante:exata,sem_nono_digito, orcom_nono_digito, when confirmed.erro: temporary lookup error text, otherwise empty.checked_at: lookup timestamp.
No row for any equivalent variant means nao_consultado. Lead queries inspect all equivalent variants and use the most recent cached result. This sparse cache avoids updating every lead and allows repeated or equivalent lead phone values to reuse evidence.
telefone_valido keeps its existing meaning: the value has a valid Brazilian DDI, DDD, and phone shape. It must not be renamed in storage or treated as WhatsApp verification.
Number Identity
Move Brazilian variant generation to a provider-independent phone utility shared by WhatsApp resolution and opt-out persistence. For a valid Brazilian mobile number, the utility returns the exact number first and then the equivalent with or without the ninth digit.
Opt-out lookup checks all equivalent variants. Adding an opt-out removes conflicting equivalent records and stores one normalized representation. Removing an opt-out removes all equivalent records. This closes both route-time and queue-time bypasses.
Manual Send Flow
- The browser submits
numero,mensagem, and optionalleadId. - The server validates that the optional lead exists, but uses it only for template context, product metadata, and send history linkage.
- The server always validates and sends to
body.numero. It never substituteslead.whatsapp. - WhatsApp resolution checks the exact number and its Brazilian equivalent under a bounded timeout.
- A successful lookup or definite non-registration updates the verification cache.
- If the submitted number is equivalent to the selected lead's stored phone, the cached result describes that lead phone. An unrelated edited destination remains a separate phone-level result and does not relabel the stored lead phone.
- The send reservation rechecks opt-out and daily limit inside the serialized send queue.
- A successful
sendMessagereturns the provider message ID and resolved destination for normal ACK tracking.
The visible destination is therefore authoritative even while the selected lead continues to provide variables such as company and city.
Automatic Outreach Flow
Automatic candidate selection matches each stored lead number against all equivalent cached variants and includes it only when the most recent matching state is confirmado. Syntactic telefone_valido = 1 remains required but is not sufficient.
Numbers in nao_consultado, nao_cadastrado, or erro_temporario are skipped. The batch does not perform implicit bulk verification.
Timeouts and Errors
onWhatsApphas a configurable bounded timeout. Timeout produceserro_temporario, HTTP 504 for an explicit check, and no definitive registration claim.sendMessagehas a separate configurable bounded timeout.- When
sendMessagetimes out after the send reservation, the local send becomesdesconhecido. The API returns an accepted-style warning that the message may have been sent and instructs the operator not to resend without checking the phone. - A definite non-registration returns HTTP 422 and stores
nao_cadastrado. - Other pre-send provider failures remain errors and are persisted through the existing send finalization path.
The underlying provider promise is observed after a timeout to avoid unhandled rejection, but a late result does not trigger an automatic retry.
User Interface
- Replace labels that infer WhatsApp from
telefone_validowithTelefone valido,Com telefone, orSem telefone. - Show a separate WhatsApp state in lead details:
Nao consultado,Confirmado,Nao cadastrado, orErro temporario. - The treatment table phone column is labeled
Telefone. - The search placeholder refers to telephone rather than WhatsApp.
- Selecting a lead fills context and its phone, but later edits remain authoritative.
- Add a visible action to clear selected lead context without clearing the typed destination or message.
- While the settings dialog is open, connection polling continues in every state. Transitional states poll faster than stable states.
API Behavior
POST /api/whatsapp/check-number accepts numero and optional leadId. It returns the persisted state, resolved number, variant, and timestamp. A lead ID is validation/context only; the checked number always comes from numero.
Lead list and detail responses expose a derived whatsapp_status, whatsapp_numero_resolvido, and whatsapp_checked_at from the cache for the lead's stored phone.
Existing outreach status and ACK APIs remain compatible.
Testing
Automated regressions must prove:
- An edited manual number wins over the selected lead's stored phone.
- The selected lead still supplies template variables and
lead_idhistory. - Missing or invalid leads and destinations retain explicit errors.
- Verification persists confirmed, non-registered, and temporary-error states.
- An unrelated edited destination does not alter the selected lead's derived status.
- Automatic outreach selects only confirmed numbers.
- Either Brazilian variant triggers the same opt-out in manual and queued sends.
- Lookup timeout returns a temporary result without sending.
- Send timeout records an unknown outcome and warns against retry.
- UI copy no longer represents syntactic phone validity as WhatsApp confirmation.
- Polling continues after
READYand selected lead context can be cleared.
Run focused tests after each change, then the complete Node test suite and dependency audit. Perform a browser-level manual send-flow check without sending an uncontrolled real message.