# Research: 004-onboard-funnel-events **Date**: 2026-06-08 ## Decisões ### R1 — Agregação funil: query vs tabela cache **Decisão**: MVP query sobre `webhook_events` (JSON `payload.session_id`). **Rationale**: YAGNI — volume baixo (~50 eventos/dia). Tabela `onboard_sessions` só se performance degradar. ### R2 — Ordem de fases **Decisão**: Último evento conhecido define `current_stage`; ordem fixa enum. **Rationale**: Eventos podem chegar fora de ordem (retries); timestamp resolve timeline, enum resolve funil. ### R3 — onboarding.started vs domain.validated **Decisão**: Ambos em `validate-domain` — `started` só se primeira visita da sessão (Redis key `ops:started:{session_id}` TTL 48h no portal ou check activity log). **Alternativa rejeitada**: Só `domain.validated` — perde métrica de conversão início. ### R4 — Ticket timeline storage **Decisão**: Query join events por `session_id` extraído de `tickets.payload` — sem nova tabela MVP. ### R5 — infra.synced timing **Decisão**: Emitir após `infrastructure.provision` success block em create_account, antes de `onboarding.completed`. **Nota**: Se infra falhar (warn only), emitir `infra.synced` com `data.success=false` ou omitir — spec: omitir se falhou, `onboarding.completed` inclui `infra_status` em data. ## Hook points confirmados (VM112 onboarding.py) | Linha ~ | Função | Evento | |---------|--------|--------| | 130 | validate_domain | started + domain.validated | | 388 | apply_cloudflare_dns | dns.applied | | 524 | create_account | account.created (existente) | | 519 | create_account infra OK | infra.synced | | 515 | create_account final | onboarding.completed | | 462 | create_account except | onboarding.failed | ## Referências - `specs/001-webhook-vm112-integration/spec.md` User Story 4 (P3) - `specs/001-webhook-vm112-integration/plan.md` Phase D - CHAT BRUTO VM122 — expectativa dashboard vs MVP