154 lines
4.7 KiB
Markdown
154 lines
4.7 KiB
Markdown
# Spec 025 — Onboarding contínuo (sem gaps)
|
||
|
||
**Criado:** 2026-06-17 · **Roger**
|
||
**Sistema:** Wizard VM112 + Desk VM122 + Traefik CT114 + Carbonio VM112
|
||
**Prioridade:** P0
|
||
**Relacionado:** Spec 012 (ticket/lead), Spec 017 (purge), Spec 022 (ACCOUNT_EXISTS ops)
|
||
|
||
---
|
||
|
||
## Problema
|
||
|
||
O wizard trata cada passo como linear e «virgem». Na prática o cliente (ou um técnico) pode:
|
||
|
||
- Abandonar no meio e voltar dias depois
|
||
- Ter conta já criada no Carbonio mas portal/Traefik/DNS incompletos
|
||
- Receber `ACCOUNT_EXISTS` no passo 3 e ficar **bloqueado** sem caminho
|
||
|
||
O Desk Spec 022 resolve o caso **para técnicos**; o cliente no wizard continua preso.
|
||
|
||
---
|
||
|
||
## Princípio — «Estado real, não passo cego»
|
||
|
||
Cada etapa consulta o **estado efectivo** no servidor antes de mostrar UI ou falhar:
|
||
|
||
| Camada | Fonte de verdade | Acção se já feito |
|
||
|--------|-------------------|-------------------|
|
||
| Domínio Carbonio | `domain_exists` | Avançar |
|
||
| DNS mail | `dns_verify` | Mostrar OK + continuar |
|
||
| Conta admin | `account_exists` + `domain_registry` | **Reconciliar** (não falhar) |
|
||
| Portal admin | `is_portal_admin` | Registar se em falta |
|
||
| Webmail gate | Traefik dynamic | `sync_webmail_gate` |
|
||
| Infra completa | `infrastructure.get_status` | Painel «pendente» com checklist |
|
||
|
||
**Regra de ouro:** `POST /account/create` é **idempotente** — conta existente → reconciliação + passos pós-criação, HTTP 200 com `reconciled: true`.
|
||
|
||
---
|
||
|
||
## Fluxo alvo (cliente)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[Domínio] --> B[DNS]
|
||
B --> C{Dados conta}
|
||
C -->|não existe| D[Confirmar + criar]
|
||
C -->|já existe| E[Continuar activação]
|
||
D --> F[Reconciliar pós-criação]
|
||
E --> F
|
||
F --> G{Infra OK?}
|
||
G -->|sim| H[Concluído — webmail]
|
||
G -->|não| I[Checklist infra + polling]
|
||
I --> H
|
||
```
|
||
|
||
### Passo 2 (UI)
|
||
|
||
- Consultar `GET /onboarding/account/status?domain=&local_part=`
|
||
- Se `exists: true` → banner **«Conta já existe — vamos concluir a activação»** (não «NÃO existe»)
|
||
- Botão: **«Continuar activação →»** em vez de só «Rever e criar»
|
||
|
||
### Passo 3 (UI)
|
||
|
||
- Se conta existe → **«Continuar activação»** (mesmo endpoint, reconcilia)
|
||
- Opcional: actualizar senha via `zmprov sp` se utilizador confirmou nova senha
|
||
|
||
### Erros que **não** bloqueiam
|
||
|
||
| Situação | Comportamento |
|
||
|----------|---------------|
|
||
| ACCOUNT_EXISTS | Reconciliar → 200 |
|
||
| DNS incompleto | Passo 4 com `finishPendingInfra` (já existe) |
|
||
| Traefik/LE pendente | Polling infra + guia no card Resumo |
|
||
| API lenta (>30s) | Timeout frontend 120s + mensagem clara (feito VM122) |
|
||
|
||
### Erros que **bloqueiam** (com saída clara)
|
||
|
||
| Situação | Comportamento |
|
||
|----------|---------------|
|
||
| Domínio inválido / blacklist | Mensagem + voltar passo 1 |
|
||
| Carbonio indisponível (OOM) | «Servidor ocupado — tente em 2 min» + webhook ops |
|
||
| Senha < 8 chars | Validação local |
|
||
|
||
---
|
||
|
||
## API VM112 (novo / alterado)
|
||
|
||
### `GET /onboarding/account/status`
|
||
|
||
```json
|
||
{
|
||
"email": "admin@exemplo.com",
|
||
"exists": true,
|
||
"portal_admin": true,
|
||
"domain_registered": true
|
||
}
|
||
```
|
||
|
||
### `POST /onboarding/account/create` (idempotente)
|
||
|
||
Resposta quando conta já existia:
|
||
|
||
```json
|
||
{
|
||
"email": "admin@exemplo.com",
|
||
"reconciled": true,
|
||
"account_verified": true,
|
||
"needs_review": false,
|
||
"infrastructure": { "ready": false, "steps": [...] }
|
||
}
|
||
```
|
||
|
||
Webhook: `account.reconciled` (novo) ou `account.created` com `reconciled: true`.
|
||
|
||
---
|
||
|
||
## Desk / Ops (sem duplicar Spec 022)
|
||
|
||
| Evento | Desk |
|
||
|--------|------|
|
||
| `account.reconciled` | Nota no ticket — «Cliente retomou conta existente» |
|
||
| `onboarding.failed` + ACCOUNT_EXISTS | Spec 022 — só se reconciliação **impossível** (conta órfã de outro email) |
|
||
| `onboarding.completed` + infra não ready | Ticket mantém `crm_track: infra_pending` |
|
||
|
||
---
|
||
|
||
## Fases de entrega
|
||
|
||
### Fase 1 — P0 (esta spec, 2026-06-17)
|
||
|
||
- [x] Spec documentada
|
||
- [ ] Backend: idempotência `create_account` + `GET account/status`
|
||
- [ ] Frontend: banners dinâmicos passos 2–3
|
||
- [ ] Deploy VM112 + smoke `exuberanti.com.br`
|
||
|
||
### Fase 2 — Resiliência
|
||
|
||
- [ ] Sessão wizard: ao reabrir URL, `resume` consulta estado e salta passos feitos
|
||
- [ ] VM112 RAM → 16 GB (Proxmox)
|
||
- [ ] Validação Traefik YAML (router sem `rule` = build fail)
|
||
|
||
### Fase 3 — Processo comercial completo
|
||
|
||
- [ ] Spec 012 abandonos → lead
|
||
- [ ] Spec 023 billing no Desk
|
||
- [ ] Wizard dedicado VM124 (Spec 018 fase 3)
|
||
|
||
---
|
||
|
||
## Critério de aceite (exuberanti.com.br)
|
||
|
||
1. Cliente com `teste001@exuberanti.com.br` já no Carbonio abre wizard no passo 2 → vê «conta já existe»
|
||
2. Clica «Continuar activação» → passo 4 sem erro 400
|
||
3. Portal admin registado; gate Traefik sincronizado
|
||
4. Ticket Desk recebe evento; Bloqueios Carbonio **não** aparece para este caso
|