# Tasks: Webhook VM112 → Ops Platform **Input**: [spec.md](./spec.md) · [plan.md](./plan.md) · [contracts/webhook-onboard.md](./contracts/webhook-onboard.md) **Prerequisites**: plan.md ✅ · spec.md ✅ · research.md ✅ · data-model.md ✅ ## Format: `[ID] [P?] [Story] Description` --- ## Phase 1: Setup **Purpose**: Preparar paths e configuração partilhada - [ ] T001 Confirmar VM122 API healthy: `curl http://10.10.10.122:8080/health` - [ ] T002 Confirmar VM112 portal healthy: `curl http://10.10.10.112:8090/api/onboarding/health` - [ ] T003 [P] Documentar secret actual em ambos `.env` (VM122 `WEBHOOK_SECRET`, VM112 `OPS_WEBHOOK_SECRET` a criar) - [ ] T004 [P] Criar `scripts/verify-webhook.sh` em `ligbox-ops-platform/scripts/` **Checkpoint**: Ambos serviços acessíveis na LAN --- ## Phase 2: Foundational — Ops Receptor (VM122) **Purpose**: Idempotência e tickets melhorados no receptor existente **⚠️ CRITICAL**: Completar antes do emissor portal - [ ] T005 [US1] Adicionar função `_is_duplicate_event(conn, event, session_id, domain)` em `api/app/main.py` (VM122 deploy path) - [ ] T006 [US1] Em `webhook_onboard`: skip INSERT ticket se duplicado; sempre INSERT webhook_events - [ ] T007 [US1] Melhorar subject ticket: `[{event}] {domain} — {email}` quando `data.email` presente - [ ] T008 [P] [US1] Rebuild e restart: `docker-compose -f docker-compose.mvp.yml up -d --build api` na VM122 - [ ] T009 [US1] Testar idempotência com curl duplicado (quickstart §2) **Checkpoint**: Receptor pronto para receber do portal --- ## Phase 3: User Story 1 — Ticket automático ao criar conta (P1) 🎯 MVP **Goal**: Portal emite `account.created` → ticket no Ops Desk - [ ] T010 [P] [US1] Adicionar campos `ops_webhook_url`, `ops_webhook_secret`, `ops_webhook_enabled` em `backend/app/config.py` (obsidian-infra path) - [ ] T011 [US1] Criar `backend/app/services/ops_webhook.py` com `emit_event()` + retry 3x (1s, 3s, 9s) + httpx timeout 5s - [ ] T012 [US1] Em `ops_webhook.py`: log warn via `activity_log` em falha; nunca raise - [ ] T013 [US1] Em `backend/app/routers/onboarding.py` `create_account`: obter `session_id` de `request.state` e chamar `ops_webhook.emit_event("account.created", ...)` via `BackgroundTasks` - [ ] T014 [US1] Payload `data`: `email`, `account_verified`, `needs_review`, `dns_mode`, `mail_aliases` - [ ] T015 [US1] Adicionar `.env` entries em VM112: `OPS_WEBHOOK_URL=http://10.10.10.122:8080/api/v1/webhooks/onboard` - [ ] T016 [US1] Deploy portal VM112 (rsync + restart backend) - [ ] T017 [US1] E2E: onboarding teste → verificar ticket em `GET /api/v1/desk/tickets` **Checkpoint**: MVP US1 completo e testável --- ## Phase 4: User Story 2 — Rastreio de sessão (P2) **Goal**: Eventos correlacionados por `session_id` - [ ] T018 [US2] Garantir `session_id` sempre enviado em `emit_event` (fallback `""` aceite pelo Ops) - [ ] T019 [US2] Adicionar endpoint `GET /api/v1/webhooks/events?session_id=` no Ops (opcional, consulta audit log) - [ ] T020 [US2] Testar 2 eventos mesma sessão — ambos em `webhook_events` **Checkpoint**: Sessão rastreável no Ops --- ## Phase 5: User Story 3 — Falha não bloqueia onboarding (P2) **Goal**: Portal resiliente com Ops offline - [ ] T021 [US3] Teste: parar API VM122, completar onboarding, confirmar resposta 200 ao cliente - [ ] T022 [US3] Verificar activity log portal contém warn de falha webhook - [ ] T023 [US3] Confirmar `OPS_WEBHOOK_ENABLED=false` desactiva envio sem erro **Checkpoint**: Resiliência validada --- ## Phase 6: User Story 4 — Eventos funil P3 (opcional) **Goal**: Visibilidade pipeline completo - [ ] T024 [P] [US4] Hook `domain.validated` em endpoint validate-domain do portal - [ ] T025 [P] [US4] Hook `dns.applied` em cloudflare apply - [ ] T026 [US4] Hook `onboarding.completed` / `onboarding.failed` nos pontos finais - [ ] T027 [US4] Ops: eventos não-ticket só INSERT webhook_events **Checkpoint**: Funil completo visível no Ops --- ## Phase 7: Polish & Docs - [ ] T028 [P] Actualizar `README.md` do ligbox-ops-platform com link para spec - [ ] T029 [P] Rotacionar `WEBHOOK_SECRET` para valor produção (não dev default) - [ ] T030 Executar `scripts/verify-security.sh` na VM122 pós-deploy - [ ] T031 Actualizar inventário VMs / backlog Obsidian com INT-2 concluído --- ## Dependencies ```text Phase 1 → Phase 2 → Phase 3 (MVP) → Phase 4, 5 (paralelo após Phase 3) → Phase 6 (opcional) → Phase 7 ``` ## MVP Scope (mínimo entregável) **T001–T017** — US1 completa: portal emite, ops recebe, ticket criado, idempotente.