ligbox-ops-platform/specs/001-webhook-vm112-integration/research.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

2.5 KiB

Research: Webhook VM112 → Ops Platform

Date: 2026-06-08
Feature: 001-webhook-vm112-integration

R1 — Estado do receptor Ops (VM122)

Decisão: Reutilizar endpoint MVP existente; estender com idempotência.

Evidência:

  • GET /health{"status":"ok","service":"ligbox-ops-api","version":"0.1.0-mvp"}
  • POST /api/v1/webhooks/onboard aceita WebhookPayload + header X-Webhook-Secret
  • Tabelas webhook_events, tickets já criadas em init_db()
  • Tenant VM112 pré-registado (id=1)

Alternativas rejeitadas:

  • Novo microserviço webhook → YAGNI, endpoint já existe
  • Redis pub/sub directo → menos auditável que HTTP + SQLite

R2 — Estado do emissor Portal (VM112)

Decisão: Novo módulo ops_webhook.py; hook em create_account.

Evidência:

  • Portal health: http://10.10.10.112:8090/api/onboarding/health OK
  • create_account retorna sem webhook actual
  • session_id via X-Onboarding-Session header (deps.bind_onboarding_session)
  • Notificações email existem (notifications.py) — webhook é canal adicional

Alternativas rejeitadas:

  • Polling Ops → VM122 worker já faz poll health; não substitui eventos push
  • ntfy como substituto → fora de scope; ops desk precisa tickets

R3 — Autenticação

Decisão: Header X-Webhook-Secret partilhado; mesmo padrão do MVP.

Evidência: Receptor já valida x_webhook_secret != WEBHOOK_SECRET → 401

Produção: Gerar secret forte (openssl rand -hex 32); configurar em ambos .env no mesmo deploy.

R4 — Idempotência

Decisão: Chave natural (event_type, session_id, domain) — consultar webhook_events antes de INSERT ticket.

Alternativas rejeitadas:

  • UUID por evento no portal → mais complexo; session_id já existe
  • UNIQUE constraint DB → requer migration; lookup é suficiente para MVP volume

R5 — Non-blocking

Decisão: BackgroundTasks do FastAPI no portal para emitir webhook após response preparada, OU try/except inline com timeout curto (5s).

Preferência: BackgroundTasks — zero impacto na latência percebida pelo cliente.

R6 — Rede

Decisão: URL fixa LAN http://10.10.10.122:8080 — sem Traefik nesta fase.

Constitution: LAN-only ; API bindada a 10.10.10.122 no docker-compose

R7 — Código fonte

VM Path deploy Path fonte (versionar)
112 /opt/ibytera-mail-portal/ obsidian-infra/carbonio/ibytera-mail-portal/
122 /opt/ligbox-ops-platform/ workspace/projects/ligbox-ops-platform/