67 lines
2.5 KiB
Markdown
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/` |
|