ligbox-ops-platform/specs/012-abandoned-onboarding-lead/spec.md
Ligbox Spec Hub 3a2c64834b Initial import: ligbox-ops-platform + specs + LAPTOP + obsidian merge (CT130)
Source: VM122 /opt + obsidian-infra + LAPTOP
Hub: CT130 spec-hub 10.10.10.130
2026-06-19 17:26:41 +00:00

236 lines
7.8 KiB
Markdown

# Feature Specification: Onboarding Abandonado → Lead CRM (012)
**Criado:** 2026-06-10
**Solicitado por:** Roger
**Status:** 📋 **Draft — decisões fechadas, pronta para plano**
**Prioridade:** **P1**
**Depende de:** Spec 001 (webhooks VM112), Spec 010 (ticket cedo + assist), Spec 007 (alertas — fase B)
**API alvo:** `0.9.1-onboard-ticket` (VM122) + VM112 wizard + CRM TBD
---
## Resumo
Cada sessão de onboarding no wizard VM112 gera **um ticket no Desk** no momento em que o cliente preenche e-mail/senha e clica **«Criar conta agora»** (`onboarding.started` com `step: create_account`). Esse ticket acompanha **todas as etapas** do funil.
Se o cliente **abandonar** o processo ou ficar **parado muitas horas** sem concluir, o mesmo registro é **promovido a Lead** no CRM — base para outreach proativo via chat (canal a estudar: IP, tablet SEO, widget web, etc.).
**Princípio:** não duplicar ticket nem lead — **um registro, uma jornada**.
---
## Decisões confirmadas (Roger — 2026-06-10)
| # | Pergunta | Decisão |
|---|----------|---------|
| 1 | Quando criar ticket? | No clique **«Criar servidor/conta»** — webhook `onboarding.started` com `email` |
| 2 | Precisa pedir suporte? | **Não** — ticket sempre, independente de escalada |
| 3 | Etapas no ticket? | **Sim**`funnel_notes` + backfill de `domain.validated` e `dns.applied` |
| 4 | Abandono | Ticket `open` + sessão stale → **Lead CRM** (Spec 012) |
| 5 | Outreach | Chat proativo com cliente — **dispositivo/canal TBD** |
| 6 | OTRS | Fora de escopo — Spec 011 futura |
---
## Fluxo VM112 → Desk (implementado 2026-06-10)
```mermaid
sequenceDiagram
participant C as Cliente
participant W as Wizard VM112
participant D as Desk VM122
C->>W: Valida domínio
W->>D: domain.validated
C->>W: Aplica DNS
W->>D: dns.applied
C->>W: E-mail + senha + Criar conta
W->>D: onboarding.started (email, step=create_account)
Note over D: Cria ticket + backfill etapas anteriores
W->>W: zmprov create account
W->>D: account.created
W->>D: infra.synced / onboarding.completed
Note over D: Notas no mesmo ticket
```
**Alteração VM112:** `onboarding.started` **removido** de `validate-domain`; **adicionado** em `POST /onboarding/account/create`.
---
## Estados `crm_track` (payload ticket)
| Valor | Significado | Gatilho |
|-------|-------------|---------|
| `onboarding` | Cliente comprometeu-se (criar conta) | `onboarding.started` |
| `onboarding_completed` | Funil concluído | `onboarding.completed` |
| `lead` | Abandonado / stale — candidato CRM | Job Spec 012 (futuro) |
| `lead_contacted` | Outreach iniciado | Chat Spec 012 |
| `lead_converted` | Voltou e concluiu ou fechou venda | Manual / webhook |
| `lead_lost` | Sem resposta após N tentativas | Manual / regra |
---
## Detecção de abandono
### Critérios (MVP)
| Critério | Valor default | Configurável |
|----------|---------------|--------------|
| Tempo sem evento | **24h** | `ONBOARD_STALE_HOURS` |
| Etapa máxima | < `completed` | — |
| Ticket status | `open` ou `escalated` (não `assisting`) | — |
| `crm_track` | `onboarding` (não já `lead`) | — |
### O que **não** é abandono
- Sessão `completed` ou `failed`
- Ticket em `assisting` (técnico activo)
- Ticket `closed` / `resolved` manualmente
### Job proposto (VM122 worker)
```
A cada 15 min:
1. Listar sessões stale no funil (já calculado em _funnel_summary)
2. Para cada sessão com ticket_id e crm_track=onboarding:
- PATCH ticket payload: crm_track=lead, lead_detected_at=now
- Opcional: push ops_lead (Spec 007)
- Enfileirar outreach (Spec 012 Fase B)
```
---
## Outreach / Chat (Fase B — canal TBD)
Roger vai estudar ferramenta para identificar e contactar o visitante:
| Opção | Prós | Contras |
|-------|------|---------|
| Widget chat web (Crisp, Tawk, Chatwoot) | E-mail + sessão browser | Precisa embed no wizard |
| Tablet SEO / dispositivo loja | Presencial | Escopo físico |
| IP + WHOIS / enrichment | Automático | Baixa precisão, LGPD |
| E-mail do ticket | Já temos `account_email` | Só após «criar conta» |
**MVP Fase A:** ops contacta manualmente via e-mail/telefone do ticket.
**MVP Fase B:** integrar canal escolhido + log em `lead_outreach_log`.
---
## Integração CRM
### Campos mínimos do Lead
| Campo | Origem |
|-------|--------|
| `session_id` | VM112 cookie |
| `domain` | Webhook |
| `email` | `onboarding.started` / `account.created` |
| `funnel_stage` | Última etapa conhecida |
| `last_event_at` | Funil Desk |
| `ticket_id` | Desk SQLite |
| `desk_ticket_url` | `https://desk.ligbox.com.br/#ticket/{id}` |
### Destino CRM (TBD)
- **Odoo CRM** (API key Roger já disponível no ambiente)
- Ou export CSV / webhook genérico
**Regra:** `ticket_id` é a chave de idempotência — não criar lead duplicado.
---
## API / Data model (VM122)
### Alterações em `tickets.payload`
```json
{
"crm_track": "onboarding",
"funnel_notes": [
{"event": "domain.validated", "at": "...", "backfilled": true},
{"event": "dns.applied", "at": "...", "backfilled": true},
{"event": "account.created", "at": "...", "data": {"email": "..."}}
],
"account_email": "admin@dominio.com",
"onboarding_outcome": null,
"lead_detected_at": null,
"lead_outreach": []
}
```
### Endpoints novos (propostos)
| Método | Endpoint | Auth | Descrição |
|--------|----------|------|-----------|
| GET | `/api/v1/crm/leads` | JWT ops_lead+ | Lista tickets `crm_track=lead` |
| POST | `/api/v1/crm/leads/{ticket_id}/contact` | JWT | Regista tentativa outreach |
| POST | `/api/v1/crm/leads/{ticket_id}/promote` | JWT | Força lead manualmente |
| POST | `/api/v1/crm/leads/sync` | internal token | Job stale → lead |
---
## User stories
### US-1 — Ticket no compromisso
Como ops lead, quero um ticket quando o cliente clica «Criar conta», para ver a jornada mesmo sem pedido de suporte.
**Critério:** `onboarding.started` com `step=create_account``ticket_created=true`, assunto `[onboarding] domínio — email`.
### US-2 — Etapas completas no ticket
Como técnico, quero ver no ticket as etapas anteriores (domínio, DNS) e posteriores (conta, infra, concluído).
**Critério:** `funnel_notes` contém ≥3 eventos após funil completo; backfill marca `backfilled: true`.
### US-3 — Abandono vira Lead
Como ops lead, quero que sessões paradas 24h sem concluir apareçam como Leads para recuperação.
**Critério:** job marca `crm_track=lead`; lista `/api/v1/crm/leads` retorna o ticket.
### US-4 — Outreach rastreável
Como técnico, quero registar cada contacto ao lead (chat, e-mail, telefone) no ticket.
**Critério:** `POST .../contact` append em `lead_outreach[]`.
---
## RBAC
| Acção | super_admin | ops_lead | technician | noc |
|-------|-------------|----------|------------|-----|
| Ver leads | ✅ | ✅ | ✅ | ❌ |
| Contactar lead | ✅ | ✅ | ✅ | ❌ |
| Promover manual | ✅ | ✅ | ❌ | ❌ |
| Sync CRM externo | ✅ | ✅ | ❌ | ❌ |
---
## Fases de entrega
| Fase | Entrega | Estado |
|------|---------|--------|
| **A** | Ticket no `onboarding.started` (criar conta) + backfill + VM112 alinhado | ✅ 2026-06-10 |
| **B** | Job stale → `crm_track=lead` + UI lista Leads no Desk | ✅ 2026-06-10 |
| **C** | Outreach log + push ops_lead (007) | 📋 |
| **D** | Sync Odoo CRM / canal chat escolhido | 📋 |
---
## Fora de escopo
- Criar ticket só na validação de domínio (removido)
- Múltiplos tickets por sessão
- Chatbot com IA
- Spec 011 OTRS
---
## Referências
- `specs/010-desk-assist-takeover/spec.md` — assistência humana
- `specs/007-mobile-push-notifications/spec.md` — alerta funil travado
- VM112: `/opt/ibytera-mail-portal/backend/app/routers/onboarding.py`
- VM122: `api/app/main.py``TICKET_EVENTS_BY_SOURCE`, `_backfill_funnel_notes`