ligbox-ops-platform/specs/004-onboard-funnel-events/plan.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

4.4 KiB

Implementation Plan: Funil de Onboarding Completo (004)

Branch: 004-onboard-funnel-events | Date: 2026-06-08 | Spec: 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

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.

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/applyapplied.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)