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

67 lines
2.5 KiB
Markdown

# 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/` |