# Managed WhatsApp Number Profiles

## Executive Summary

The managed WhatsApp layer now supports per-number AI behavior inside the same tenant.

This means a single tenant can connect multiple WhatsApp numbers and give each one its own:

- identity
- context
- tone
- rules
- goal
- human handoff guidance
- closing signature

The managed inbox now also exposes lightweight operational workflow per conversation:

- queue status
- owner label
- per-number operational summary cards
- combined filtering by number and queue state

The system applies these settings at the connected-number level and falls back to tenant-level defaults when a number-specific field is empty.

The dashboard also supports:

- filtering conversations by connected number
- showing which number each conversation belongs to
- editing the number profile through a modal opened only by `Editar perfil`

This document covers the current implementation, data model, API, dashboard flow, fallback rules, testing, and deployment considerations.

## Scope

This document describes the current implementation of:

- managed WhatsApp numbers
- number-level AI profile fields
- fallback to tenant defaults
- conversation filtering by `number_id`
- conversation workflow with `queue_status` and `assigned_to`
- per-number operational summary in the dashboard
- number profile editing through the dashboard modal

It does not describe future ideas such as:

- per-conversation personas
- departments or queues
- team-member accounts with real authentication
- advanced routing logic
- conditional prompt rules
- image, video, and document automation

## Product Behavior

### Why this exists

One tenant may operate multiple WhatsApp numbers with different business roles.

Examples:

- `Comercial`
- `Suporte`
- `Agendamento`

Each number may need a different:

- presentation
- style of speech
- objective
- boundary of responsibility

Without number-level configuration, every conversation would inherit the same tenant-wide prompt and behavior, which is too coarse for real operations.

### Current behavior

When a message arrives for a managed WhatsApp number:

1. the backend identifies the tenant
2. it identifies the connected number
3. it loads the number profile
4. it classifies the inbound content as text or audio
5. it fills empty number fields using tenant defaults when possible
6. it builds a structured prompt context for the AI
7. it generates the reply using the existing ChatAgent core when there is usable text

This keeps the current tenant model intact while allowing specialized behavior per connected number.

### Audio behavior

Managed WhatsApp now supports inbound audio messages in the operational inbox.

Current first-release behavior:

- text messages continue through the normal AI flow
- audio messages are stored as `message_type = audio`
- if a transcription is available, the transcription is used as the AI input
- if no transcription is available, the inbox still records the audio and the conversation is handed to human mode with a safe customer-facing fallback reply

This keeps audio from being silently dropped while avoiding fake AI understanding when the system has no usable text.

## Data Model

The number profile lives in `managed_whatsapp_numbers`.

### Table

File reference:

- [db.js](C:/Users/Administrator/Documents/api/db.js)

### Number profile fields

The following optional fields are stored per managed number:

- `identity_name`
- `context_description`
- `personality_tone`
- `behavior_rules`
- `primary_goal`
- `handoff_rules`
- `closing_signature`

These fields are created with empty-string defaults so existing installations remain compatible.

### Related entities

#### `managed_whatsapp_numbers`

Stores the connected number and its profile data.

Important fields:

- `id`
- `tenant_id`
- `label`
- `phone_jid`
- `status`
- the seven profile fields above

#### `managed_conversations`

Stores one conversation per tenant, number, and contact.

Important fields:

- `id`
- `tenant_id`
- `number_id`
- `contact_jid`
- `contact_name`
- `mode`
- `ai_status`
- `queue_status`
- `assigned_to`

#### `managed_messages`

Stores inbound and outbound managed messages.

Important fields:

- `tenant_id`
- `number_id`
- `conversation_id`
- `direction`
- `sender`
- `body`
- `message_type`
- `media_mime_type`
- `media_duration_seconds`
- `transcription_text`
- `transcription_status`
- `is_voice_note`

## Fallback Rules

The feature uses number-first configuration with tenant fallback.

### Effective profile resolution

The prompt context builder currently lives in:

- [managed-whatsapp-service.js](C:/Users/Administrator/Documents/api/managed-whatsapp-service.js)

It builds the effective profile using:

- number field when non-empty
- tenant default when applicable

### Current fallback behavior

- `identity_name` falls back to `tenant.name`
- number-specific text fields remain empty if the number does not define them
- the tenant base prompt is still appended as general context

### Prompt structure

The managed service turns the effective profile into a structured context block before calling the AI.

Current sections include:

- number identity
- number context
- tone/personality
- rules
- goal
- human escalation guidance
- closing signature
- tenant base context

This is intentionally more structured than concatenating one long free-form blob.

## API

Managed WhatsApp routes are JWT-protected dashboard routes.

Primary file:

- [api.js](C:/Users/Administrator/Documents/api/api.js)

### Numbers

#### `GET /managed/whatsapp/numbers`

Returns the tenant's managed numbers, including the profile fields.

#### `POST /managed/whatsapp/numbers`

Creates a managed number.

The current flow primarily requires:

- `label`

Profile fields may also be accepted when needed.

#### `PUT /managed/whatsapp/numbers/:id`

Updates the number profile.

Supported request fields:

- `identity_name`
- `context_description`
- `personality_tone`
- `behavior_rules`
- `primary_goal`
- `handoff_rules`
- `closing_signature`

#### `POST /managed/whatsapp/numbers/:id/connect`

Starts the WhatsApp connection flow.

#### `POST /managed/whatsapp/numbers/:id/disconnect`

Disconnects the managed number.

#### `GET /managed/whatsapp/numbers/:id/qr`

Returns QR state for the connection flow.

#### `GET /managed/whatsapp/numbers/:id/status`

Returns the connection status of the number.

#### `DELETE /managed/whatsapp/numbers/:id`

Removes the managed number.

### Conversations

#### `GET /managed/whatsapp/conversations`

Lists the tenant's conversations.

Optional query:

- `number_id`

This enables dashboard filtering by connected number.

The conversation list also exposes number metadata for display:

- `number_label`
- `number_phone_jid`

It now also returns workflow metadata used by the inbox:

- `queue_status`
- `assigned_to`

#### `PUT /managed/whatsapp/conversations/:id/workflow`

Updates the lightweight operational workflow for one conversation.

Supported request fields:

- `queue_status`
- `assigned_to`

Allowed queue states:

- `open`
- `waiting_human`
- `waiting_customer`
- `closed`

#### `GET /managed/whatsapp/conversations/:id/messages`

Returns message history for one conversation.

#### `PUT /managed/whatsapp/conversations/:id/mode`

Changes conversation mode between:

- `ai`
- `human`

#### `POST /managed/whatsapp/conversations/:id/send`

Sends a manual human reply when the conversation is in human mode.

#### `GET /managed/whatsapp/overview`

Returns per-number operational counts for the dashboard summary cards.

Current counters:

- `total_conversations`
- `waiting_human`
- `waiting_customer`
- `open_count`
- `closed_count`

## Dashboard UX

Dashboard files:

- [frontend/dashboard.html](C:/Users/Administrator/Documents/api/frontend/dashboard.html)
- [frontend/js/dashboard.js](C:/Users/Administrator/Documents/api/frontend/js/dashboard.js)
- [frontend/css/style.css](C:/Users/Administrator/Documents/api/frontend/css/style.css)

### Numbers list

The WhatsApp section shows connected number cards with:

- label
- JID or session identity
- status badge
- optional profile preview chips
- connect / disconnect / edit / remove actions

### Profile editor modal

The number profile editor is implemented as a modal.

Important behavior:

- it is hidden by default
- it opens only via `Editar perfil`
- clicking the backdrop closes it
- pressing `Esc` closes it
- switching away from the WhatsApp tab closes it

This replaced the earlier inline card approach, which was too visually persistent and made the intent of editing feel ambiguous.

### Modal fields

The modal currently exposes:

- `Nome / identidade`
- `Personalidade / tom`
- `Contexto`
- `Regras`
- `Objetivo`
- `Escalada`
- `Assinatura / fechamento`

### Conversation list

The conversation panel shows:

- all conversations by default
- a filter by connected number
- a filter by queue state
- a discreet source label per conversation
- a visible queue badge
- the lightweight owner label when filled

The source label prefers:

- `label + phone`

If that would be too long, it falls back to:

- `label`

### Workflow controls

When an operator selects a conversation, the inbox now exposes:

- queue status selector
- owner input
- `Atualizar fila` action

This keeps operational organization in the same surface where takeover and manual replies already happen.

### Operational summary

Above the inbox, the dashboard now renders per-number summary cards with:

- total conversations
- waiting human count
- waiting customer count
- open count
- closed count

The goal is to make each connected number feel like an operable lane instead of only a connection object.

## Backend Flow

### Inbound AI flow

1. Baileys receives a message
2. the service resolves tenant and number
3. the service creates or updates the managed conversation
4. the inbound message is stored
5. if the conversation is in `ai` mode, the AI path runs
6. the effective number profile is built
7. the ChatAgent core generates the reply
8. the reply is sent back through the managed session
9. the outbound message is stored

### Human takeover flow

1. the operator clicks `Assumir conversa`
2. the conversation mode becomes `human`
3. the queue state becomes operationally meaningful instead of only changing `mode`
4. the operator may assign an owner label such as `Joao` or `Equipe Comercial`
5. new inbound messages are still stored
6. AI replies are paused
7. a human can reply manually through the dashboard
8. the operator can later click `Devolver para IA`

## Workflow state transitions

Current first-pass workflow states:

- `open`
- `waiting_human`
- `waiting_customer`
- `closed`

Expected transition rules in this release:

1. switching to human mode should move the conversation into a human-action state
2. sending a manual reply should move the conversation to `waiting_customer`
3. new inbound contact messages should reopen or reprioritize the conversation depending on current mode
4. operators can override the queue state manually through the dashboard

This is intentionally lightweight. It is not a full SLA or routing engine.
3. new inbound messages are still stored
4. AI replies are paused
5. a human can reply manually through the dashboard
6. the operator can later click `Devolver para IA`

## Testing

Relevant tests live in:

- [tests/db.test.js](C:/Users/Administrator/Documents/api/tests/db.test.js)
- [tests/api.integration.test.js](C:/Users/Administrator/Documents/api/tests/api.integration.test.js)
- [tests/managed-whatsapp-service.test.js](C:/Users/Administrator/Documents/api/tests/managed-whatsapp-service.test.js)
- [tests/frontend-snippets.test.js](C:/Users/Administrator/Documents/api/tests/frontend-snippets.test.js)

### Covered behaviors

Current automated coverage includes:

- persistence of the new number profile fields
- tenant-safe read and update behavior
- filtering conversations by `number_id`
- exposing number metadata in conversation listings
- workflow route and workflow metadata exposure
- dashboard filters by queue state
- queue badges and owner controls in the selected conversation panel
- overview integration hooks for per-number operational summary
- prompt-context fallback behavior
- dashboard presence of the managed WhatsApp controls
- modal-based profile editing hooks in the frontend

### Validation command

Local validation:

```bash
npm test
```

## Deployment Notes

Managed WhatsApp deployments must preserve stateful runtime data.

Do not overwrite:

- `.env`
- `.sessions`
- `data/` (including `chatagent.sqlite*`)
- `openai-oauth-data*/` when the same deployment also carries ChatGPT OAuth sessions

The current ChatGPT runtime does not use `.browser-data`; that directory belongs to the
legacy Playwright path. DeepSeek browser state, when enabled, remains separate.

The general safe deploy helper is `deploy-safe.sh`. Legacy Python helpers still exist
under `scripts/`, but they are not the source of truth for the current Docker Compose deployment.

Operational procedures are documented in [runbook.md](./runbook.md).

The deploy flow currently performs:

1. remote backup
2. file upload while excluding sensitive state
3. remote test run
4. service restart
5. health verification with retry

## Troubleshooting

### The profile editor appears without explicit intent

Expected behavior now:

- the editor should not appear inline in the page
- it should open only from `Editar perfil`

If this regresses, inspect:

- modal markup in `frontend/dashboard.html`
- modal state helpers in `frontend/js/dashboard.js`
- frontend snippet coverage in `tests/frontend-snippets.test.js`

### The number profile does not affect replies

Check:

- whether the fields were saved on the correct managed number
- whether the conversation belongs to that `number_id`
- whether the service is building the prompt context through `buildManagedProfileContext`

### Filtering by number does not work

Check:

- query handling in `/managed/whatsapp/conversations`
- `number_id` propagation in the frontend filter
- SQL filtering in `db.listManagedConversations`

### Queue status looks inconsistent

Check:

- automatic transition rules in the managed service and API handlers
- the workflow update route `PUT /managed/whatsapp/conversations/:id/workflow`
- whether the frontend refreshed both the conversation list and `/managed/whatsapp/overview`

## Decision Notes

Current implementation decisions:

- configuration lives on the connected number, not on the conversation
- the number uses fallback to tenant defaults
- the conversation list shows everything by default
- the number source is visible but visually discreet
- the profile editor uses a modal instead of an inline card
- the modal opens only from the explicit `Editar perfil` action
- operational ownership is plain text for now, not a user account relation
- the first release keeps only four queue states to avoid premature complexity

## Suggested Next Documentation

If the project keeps evolving in this direction, the next useful docs would be:

1. an operator guide for the dashboard
2. an admin/deploy runbook for the VPS
3. a dedicated architecture doc for managed session lifecycle and reconnection
