# Feature Specification: Webhook VM112 → Ops Platform

**Feature Branch**: `001-webhook-vm112-integration`

**Created**: 2026-06-08

**Status**: Draft

**Input**: User description: "Ligar o portal de onboarding VM112 (ibytera-mail-portal) à plataforma Ops VM122 via webhooks seguros, para que eventos de onboarding criem tickets e registo operacional automático no Support Desk."

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Ticket automático ao criar conta (Priority: P1)

Quando um cliente conclui a criação de conta de mail no portal de onboarding, a equipa de operações recebe automaticamente um ticket no Support Desk Ops com domínio, email criado e estado da verificação — sem intervenção manual.

**Why this priority**: É o evento de maior valor operacional; substitui o processo actual de monitorizar emails ou logs do portal para saber que um novo cliente entrou.

**Independent Test**: Simular conclusão de onboarding com conta verificada e confirmar que um ticket `open` aparece no desk Ops com subject contendo o domínio e evento `account.created`.

**Acceptance Scenarios**:

1. **Given** portal VM112 com onboarding concluído e conta Carbonio verificada, **When** o evento `account.created` é emitido, **Then** o Ops Desk regista um ticket aberto associado ao tenant VM112 com domínio e email no payload.
2. **Given** conta criada mas não verificada (`needs_review=true`), **When** o evento é emitido com flag de revisão, **Then** o ticket é criado com prioridade/indicador de revisão necessária.
3. **Given** secret de webhook válido, **When** o portal envia o evento, **Then** o Ops responde com confirmação de aceitação em menos de 5 segundos.

---

### User Story 2 - Rastreio de sessão de onboarding (Priority: P2)

A equipa ops consegue correlacionar todos os eventos de uma mesma sessão de onboarding (validação DNS, aplicação Cloudflare, criação de conta, falhas) através de um identificador de sessão partilhado.

**Why this priority**: Permite diagnóstico rápido quando um onboarding falha a meio — sem precisar cruzar logs manualmente entre portal e ops.

**Independent Test**: Enviar dois eventos com o mesmo `session_id` e confirmar que ambos ficam registados e consultáveis com essa chave.

**Acceptance Scenarios**:

1. **Given** uma sessão de onboarding activa, **When** múltiplos eventos são emitidos com o mesmo `session_id`, **Then** todos ficam associados à mesma sessão no registo de eventos Ops.
2. **Given** um evento sem `session_id`, **When** é recebido, **Then** o sistema aceita o evento mas marca a sessão como desconhecida (não rejeita).

---

### User Story 3 - Falha de webhook não bloqueia onboarding (Priority: P2)

Se a plataforma Ops estiver indisponível ou rejeitar temporariamente um evento, o cliente continua o fluxo de onboarding no portal sem erro visível — a equipa ops é notificada da falha por outro canal (log/alerta).

**Why this priority**: O portal de mail é crítico para o cliente; a integração ops é secundária e não pode interromper vendas/onboarding.

**Independent Test**: Com Ops API offline, completar onboarding no portal e verificar que o cliente recebe resposta de sucesso; portal regista falha de webhook nos seus logs.

**Acceptance Scenarios**:

1. **Given** Ops API indisponível, **When** portal tenta enviar webhook após criar conta, **Then** o portal conclui onboarding normalmente e regista falha de entrega no activity log.
2. **Given** secret inválido no portal, **When** webhook é enviado, **Then** Ops rejeita com erro de autenticação e portal regista falha sem expor o secret ao cliente.

---

### User Story 4 - Eventos de marcos do funil (Priority: P3)

Além da criação de conta, marcos importantes do funil (validação de domínio, DNS aplicado, onboarding completo, falha crítica) são reportados ao Ops para visibilidade do pipeline.

**Why this priority**: Visibilidade proactiva do funil; não bloqueia MVP se apenas `account.created` estiver implementado.

**Independent Test**: Emitir evento `onboarding.completed` e confirmar registo sem criação de ticket duplicado para o mesmo domínio/sessão.

**Acceptance Scenarios**:

1. **Given** domínio validado com sucesso, **When** evento `domain.validated` é emitido, **Then** fica registado no histórico de eventos Ops.
2. **Given** onboarding já reportado como `account.created`, **When** `onboarding.completed` chega para a mesma sessão, **Then** actualiza contexto do ticket existente ou adiciona nota — não cria ticket redundante.

---

### Edge Cases

- Portal envia evento duplicado (retry ou duplo clique): Ops deve ser idempotente — mesmo evento+domínio+sessão não cria tickets duplicados.
- Domínio com caracteres especiais ou subdomínios: normalização consistente (lowercase, strip).
- Payload grande (múltiplos aliases mail): truncar ou resumir no ticket, payload completo no registo de eventos.
- VM122 reiniciada durante envio: portal re-tenta até 3 vezes com intervalo crescente.
- Secret rotacionado: ambos os lados devem suportar janela de transição (secret antigo + novo) durante deploy.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: O portal VM112 DEVE emitir webhook `account.created` automaticamente após conclusão bem-sucedida de `POST /account/create` (independentemente de `needs_review`).
- **FR-002**: Cada webhook DEVE incluir: `event`, `domain`, `session_id`, e `data` com pelo menos `email`, `account_verified`, `needs_review`.
- **FR-003**: O portal DEVE autenticar webhooks com secret partilhado transmitido em header dedicado (não em query string).
- **FR-004**: A plataforma Ops DEVE validar o secret antes de processar qualquer payload; pedidos sem secret válido DEVEM ser rejeitados.
- **FR-005**: A plataforma Ops DEVE criar ticket Support Desk para evento `account.created` associado ao tenant VM112 (id=1).
- **FR-006**: A plataforma Ops DEVE persistir todos os eventos recebidos num registo de auditoria consultável.
- **FR-007**: O portal NÃO DEVE bloquear nem alterar a resposta ao cliente se o webhook falhar — falhas DEVEM ser registadas no activity log do portal.
- **FR-008**: O portal DEVE implementar retry automático (mínimo 3 tentativas, backoff) para falhas de rede ou timeout.
- **FR-009**: A comunicação DEVE ocorrer exclusivamente na LAN (`10.10.10.112` → `10.10.10.122`) — sem exposição do endpoint webhook à internet.
- **FR-010**: O secret de webhook em produção DEVE ser diferente do valor de desenvolvimento default.
- **FR-011**: Eventos P3 (`domain.validated`, `dns.applied`, `onboarding.completed`, `onboarding.failed`) DEVEM ser suportados pelo receptor Ops mesmo que o emissor portal os implemente em fase posterior.
- **FR-012**: Duplicatas do mesmo evento (mesmo `event` + `session_id` + `domain`) NÃO DEVEM criar tickets adicionais.

### Key Entities

- **Webhook Event**: Tipo de evento, origem (vm112-onboard), payload JSON, timestamp UTC.
- **Support Ticket**: Subject derivado do evento, status (`open`/`closed`), tenant_id, payload de referência.
- **Onboarding Session**: Identificador de sessão do portal; correlaciona múltiplos eventos do mesmo fluxo.
- **Tenant**: VM112 registada como `onboarding_portal` com IP `10.10.10.112`.

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: 100% dos onboardings com conta criada geram ticket no Ops Desk em menos de 10 segundos após conclusão (com Ops disponível).
- **SC-002**: 0% de interrupções no fluxo de onboarding do cliente causadas por falha de webhook (medido em testes com Ops offline).
- **SC-003**: Equipa ops consegue identificar domínio, email e estado de verificação de um novo cliente consultando apenas o ticket — sem aceder ao portal VM112.
- **SC-004**: Eventos duplicados (3 retries do mesmo evento) resultam em exactamente 1 ticket por combinação evento+sessão+domínio.
- **SC-005**: Tempo de diagnóstico de falha de integração reduzido: activity log do portal + registo de eventos Ops permitem identificar falha em menos de 2 minutos.

## Assumptions

- VM112 portal corre em `10.10.10.112:8090` e VM122 Ops API em `10.10.10.122:8080` — ambos acessíveis na LAN.
- O endpoint receptor `/api/v1/webhooks/onboard` já existe no MVP VM122 e aceita o formato `WebhookPayload`.
- O `session_id` do portal já está disponível no contexto de request do onboarding (cookie/header existente).
- Notificações por email (admin@itecnologys.com) continuam activas — webhook é canal **adicional**, não substituto.
- Rotação de secret será feita manualmente em deploy coordenado (portal + ops simultâneo).
- Traefik/router público `ops.ligbox.com.br` fica fora de scope desta feature — apenas LAN.
- Idempotência no Ops pode usar combinação `event_type + session_id + domain` como chave natural.

## Dependencies

- Constitution Ligbox v1.0.0 (separação VM112/122, fail2ban, LAN-only).
- MVP Ops API deployado em VM122 (`/opt/ligbox-ops-platform/`).
- Portal ibytera-mail-portal deployado em VM112 (`/opt/ibytera-mail-portal/` ou equivalente).
- Secret partilhado configurado em `.env` de ambas as VMs.

## Out of Scope

- UI Support Desk completa (apenas criação automática de tickets).
- Webhook inbound de outros sistemas (Cloudflare, pfSense, PMG).
- Exposição pública do endpoint webhook via Traefik.
- Sincronização bidirecional (Ops → Portal).
- Notificações push (ntfy/Slack) — fase posterior.
