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

6.2 KiB
Raw Blame History

Implementation Plan: Webhook VM112 → Ops Platform

Branch: 001-webhook-vm112-integration | Date: 2026-06-08 | Spec: spec.md

Input: Feature specification from /specs/001-webhook-vm112-integration/spec.md

Summary

Implementar integração LAN entre o portal de onboarding VM112 (ibytera-mail-portal) e a API Ops VM122 (ligbox-ops-platform). O portal emite webhooks autenticados após marcos do onboarding; o Ops regista eventos, cria tickets automaticamente e garante idempotência. Falhas de webhook são não-bloqueantes para o cliente.

Abordagem: módulo ops_webhook no portal (httpx + retry), extensão mínima do receptor existente em VM122 (idempotência + índice), secret partilhado via .env em ambas as VMs.

Technical Context

Language/Version: Python 3.11+ (portal VM112 Ubuntu 24.04; Ops VM122 Debian 12)

Primary Dependencies: FastAPI, httpx, pydantic-settings (portal); FastAPI, httpx, redis, sqlite3 (Ops — já deployados)

Storage: SQLite ops.db (VM122) — tabelas webhook_events, tickets existentes; sem alteração de schema obrigatória (índice lógico para idempotência)

Testing: curl manual + script scripts/verify-webhook.sh; teste portal com Ops offline

Target Platform: VM112 10.10.10.112:8090 → VM122 10.10.10.122:8080 (LAN only)

Project Type: Integração cross-VM (dois repositórios/deploy paths)

Performance Goals: Webhook entrega < 5s p95; não adicionar > 500ms ao tempo de resposta do portal

Constraints: LAN-only; secret em header X-Webhook-Secret; fail2ban inalterado; onboarding nunca bloqueado por falha Ops

Scale/Scope: ~1050 onboardings/dia; 4 tipos de evento MVP + 4 fase 2

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Princípio Status Notas
I. vmbr1 / LAN PASS Tráfego 112→122 na LAN 10.10.10.0/24 via vmbr4000
II. Interfaces Proxmox PASS Nenhuma alteração de rede
III. Anti-scan Hetzner PASS Sem novas regras NAT/iptables
IV. Mail vs Ops separation PASS Portal emite; Ops recebe — sem mail stack em 122
V. fail2ban PASS Sem alteração SSH
VI. pfSense API N/A Não usado nesta feature
VII. Spec-Driven PASS spec → plan em curso
VIII. Documentation PASS Artefactos em specs/001-*
IX. YAGNI PASS Sem novos serviços; extensão mínima

Post-design re-check: Nenhuma violação. Sem Complexity Tracking necessário.

Project Structure

Documentation (this feature)

specs/001-webhook-vm112-integration/
├── spec.md
├── plan.md              # este ficheiro
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── webhook-onboard.md
├── checklists/
│   └── requirements.md
└── tasks.md             # gerado por /speckit-tasks

Source Code (deploy targets)

# VM112 — /opt/ibytera-mail-portal/ (sync desde obsidian-infra/carbonio/ibytera-mail-portal/)
backend/app/
├── config.py                    # + ops_webhook_url, ops_webhook_secret, ops_webhook_enabled
├── services/
│   └── ops_webhook.py             # NOVO: emit_event(), retry logic
└── routers/
    └── onboarding.py              # chamar ops_webhook após account/create

# VM122 — /opt/ligbox-ops-platform/ (já deployado)
api/app/
└── main.py                        # + idempotência, índice dedup, log melhorado

Structure Decision: alterações mínimas em dois deploy paths existentes; código fonte versionado em obsidian-infra (portal) e workspace/projects/ligbox-ops-platform (ops).

Phase 0: Research Summary

Ver research.md — conclusões:

  1. Endpoint receptor MVP já funcional (POST /api/v1/webhooks/onboard)
  2. session_id disponível via header X-Onboarding-Session / request.state
  3. Portal não tem cliente webhook — criar ops_webhook.py
  4. Idempotência: lookup event+session_id+domain antes de INSERT ticket
  5. Secret dev ligbox-ops-dev-secret — rotacionar em produção

Phase 1: Design Artifacts

Artefacto Ficheiro Conteúdo
Data model data-model.md Payload, entidades, dedup key
API contract contracts/webhook-onboard.md Request/response, eventos
Quickstart quickstart.md Testes manuais e deploy

Implementation Phases

Phase A — Ops receptor (VM122) — ~1h

  1. Adicionar verificação idempotente em webhook_onboard
  2. Query webhook_events por (event_type, session_id, domain) antes de criar ticket
  3. Melhorar subject do ticket: [account.created] dominio.com — admin@dominio.com
  4. Log estruturado em falha 401

Phase B — Portal emissor (VM112) — ~2h

  1. config.py: ops_webhook_url, ops_webhook_secret, ops_webhook_enabled (default true)
  2. services/ops_webhook.py:
    • emit_event(event, domain, session_id, data, timeout=5)
    • Retry 3x: 1s, 3s, 9s backoff
    • Header X-Webhook-Secret
    • activity_log.warn em falha, nunca raise para o router
  3. onboarding.pycreate_account: após sucesso, chamar:
    ops_webhook.emit_event("account.created", domain, session_id, {...})
    

Phase C — Config + validação — ~30min

  1. .env VM112: OPS_WEBHOOK_URL=http://10.10.10.122:8080/api/v1/webhooks/onboard
  2. .env VM122: confirmar WEBHOOK_SECRET igual
  3. Script scripts/verify-webhook.sh no repo ops
  4. Teste E2E: criar conta teste → ticket no desk

Phase D — Eventos P3 (opcional, pós-MVP)

  • domain.validated em /validate-domain
  • dns.applied em /cloudflare/apply
  • onboarding.completed / onboarding.failed nos respectivos pontos

Risk & Mitigation

Risco Mitigação
Ops offline durante onboarding Retry + non-blocking; email admin continua
Secret exposto em log Nunca logar secret; só "auth failed"
Tickets duplicados Idempotência no receptor
Latência no portal Fire-and-forget async (BackgroundTasks FastAPI)

Complexity Tracking

Nenhuma violação da constitution — tabela vazia.