# 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.