126 lines
4.4 KiB
Markdown
126 lines
4.4 KiB
Markdown
# Implementation Plan: Funil de Onboarding Completo (004)
|
|
|
|
**Branch**: `004-onboard-funnel-events` | **Date**: 2026-06-08 | **Spec**: [spec.md](./spec.md)
|
|
|
|
## Summary
|
|
|
|
Completar o funil VM112 → VM122: portal emite 6 tipos de evento adicionais; Ops agrega por `session_id`, expõe API de funil/timeline, e UI Dashboard mostra pipeline activo. Continuação directa da Phase D da feature 001.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: Python 3.11+ (portal VM112, Ops VM122)
|
|
|
|
**Primary Dependencies**: FastAPI, httpx, sqlite3, vanilla JS (frontend existente)
|
|
|
|
**Storage**: SQLite — novas tabelas opcionais `onboard_sessions` (cache funil) ou query agregada sobre `webhook_events` + `tickets.payload`
|
|
|
|
**Testing**: `scripts/verify-funnel-webhook.sh` + E2E wizard staging
|
|
|
|
**Target Platform**: VM112 `:8090` → VM122 `:8080` LAN
|
|
|
|
**Performance Goals**: Widget funil < 500ms; emissão webhook não adiciona > 200ms perceived latency
|
|
|
|
**Constraints**: Non-blocking portal; idempotência; LAN-only
|
|
|
|
## Constitution Check
|
|
|
|
| Princípio | Status |
|
|
|-----------|--------|
|
|
| IV. Mail vs Ops | ✅ PASS |
|
|
| VII. Spec-Driven | ✅ PASS |
|
|
| IX. YAGNI | ✅ PASS — reutilizar `webhook_events`, sem Postgres |
|
|
|
|
## Project Structure
|
|
|
|
```text
|
|
specs/004-onboard-funnel-events/
|
|
├── spec.md
|
|
├── plan.md
|
|
├── research.md
|
|
├── contracts/webhook-funnel-events.md
|
|
├── checklists/requirements.md
|
|
└── tasks.md
|
|
|
|
# VM112
|
|
backend/app/routers/onboarding.py # hooks emit_event em 5 endpoints
|
|
backend/app/services/ops_webhook.py # (sem alteração estrutural)
|
|
|
|
# VM122
|
|
api/app/main.py # funnel + timeline endpoints; ticket enrichment
|
|
frontend/assets/app.js # widget funil + timeline ticket
|
|
frontend/assets/styles.css # estilos funil
|
|
scripts/verify-funnel-webhook.sh # teste simulado multi-evento
|
|
```
|
|
|
|
## Phase 0: Research Summary
|
|
|
|
Ver [research.md](./research.md).
|
|
|
|
## Phase 1: Design
|
|
|
|
### Mapeamento evento → hook portal
|
|
|
|
| Evento | Endpoint / momento |
|
|
|--------|-------------------|
|
|
| `onboarding.started` | `POST /validate-domain` — 1ª vez por sessão |
|
|
| `domain.validated` | `POST /validate-domain` — sucesso |
|
|
| `dns.applied` | `POST /dns/cloudflare/apply` — `applied.length > 0` |
|
|
| `account.created` | `POST /account/create` — ✅ já existe |
|
|
| `infra.synced` | após `infrastructure.provision` OK em create_account |
|
|
| `onboarding.completed` | fim de create_account (antes do return) |
|
|
| `onboarding.failed` | except CarbonioError / HTTP 400 críticos |
|
|
|
|
### API Ops (novos endpoints)
|
|
|
|
```
|
|
GET /api/v1/onboard/funnel
|
|
→ { stages: { started: N, domain_validated: N, ... }, active_sessions: [...] }
|
|
|
|
GET /api/v1/onboard/sessions/{session_id}/timeline
|
|
→ { session_id, domain, events: [{ event_type, created_at, data }] }
|
|
|
|
GET /api/v1/desk/tickets/{id} (extend)
|
|
→ + timeline: [...] (eventos mesma session_id do ticket)
|
|
```
|
|
|
|
### Lógica ticket
|
|
|
|
- `_process_ingress` / `webhook_onboard`: após insert evento, se ticket existente para `session_id`, append nota timeline (JSON em payload ou tabela `ticket_events`).
|
|
- `onboarding.completed`: PATCH interno ticket → tag/note `ready_for_ops`.
|
|
- `TICKET_EVENTS`: manter `account.created`, `onboarding.failed`; outros só timeline.
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase A — Ops API funil (~2h)
|
|
|
|
1. Função `_session_timeline(session_id)` query `webhook_events`
|
|
2. Função `_funnel_summary()` — agrega última fase por sessão (48h)
|
|
3. Endpoints GET funnel + timeline
|
|
4. Enriquecer `get_ticket` com timeline
|
|
5. Actualizar `TICKET_EVENTS_BY_SOURCE` se necessário
|
|
|
|
### Phase B — Portal emissor (~2h)
|
|
|
|
1. Helper `_emit_once(session_id, event, ...)` com flag in-memory ou check activity log (preferir idempotência no Ops)
|
|
2. Hooks nos 5 pontos do router onboarding
|
|
3. `onboarding.failed` no except de create_account
|
|
|
|
### Phase C — UI Desk (~2h)
|
|
|
|
1. Dashboard: card funil com barras/contadores por fase
|
|
2. Ticket detail: secção timeline vertical
|
|
3. Link sessão → filtro eventos
|
|
|
|
### Phase D — Validação (~1h)
|
|
|
|
1. Script verify-funnel-webhook.sh
|
|
2. Deploy VM112 + VM122
|
|
3. Teste wizard domínio teste
|
|
|
|
## Risk & Mitigation
|
|
|
|
| Risco | Mitigação |
|
|
|-------|-----------|
|
|
| Eventos duplicados validate-domain | Idempotência Ops + emit started só 1x via cache sessão portal |
|
|
| Payload grande | Truncar data no ticket; payload completo em webhook_events |
|
|
| Funil lento com muitos eventos | Limitar active_sessions a 50; índice SQL em session_id (JSON extract ou coluna denormalizada fase 2) |
|