ligbox-ops-platform/specs/017-vm112-domain-orchestration/spec.md
Ligbox Spec Hub edffd8b3c0 feat(desk): Serviços IaaS perf, Escopo OPS cards e blocklist UI (Spec 017/018)
Cache VM112/VM122 para lista e detalhe domínio, modal purge com loading animado,
cards Escopo OPS clicáveis (camada + Spec + navegação), blocklist visível na UI,
e documentação nas specs e anais de referência 20260625.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 18:53:57 +00:00

16 KiB
Raw Permalink Blame History

Feature Specification: Domínios VM112 — Purge & Histórico (017)

Criado: 2026-06-16
Actualizado: 2026-06-25 (performance modal + UX Escopo OPS + blocklist UI)
Solicitado por: Roger
Status: v1 + v2 concluídos · Fase 3 VM112 pendente
Prioridade: P1 (testes E2E + padrão de limpeza)
Sistema: Desk VM122 + Wizard VM112
Módulo: vm112-domains
UI purge: página Serviços (Spec 018)
UI histórico: Eventos → Histórico de purges


Resumo

Técnicos Admin (super_admin, ops_lead) executam purge completo de domínios VM112 (Carbonio, site, portal, Cloudflare, Traefik/SNI, registos Desk) a partir da página Serviços, com timeline ao vivo no drawer lateral.

v2 (2026-06-16): cada purge fica persistido em SQLite e consultável em Eventos → Histórico de purges — lista clicável + modal com timeline, utilizador e serviços removidos.

Uso inicial: limpar domínios de teste para reentrarem no wizard. Futuro: padrão de limpeza de dados por domínio.


Módulo Desk (Spec 015)

Campo Valor
id vm112-domains
label Domínios VM112
default_enabled true
nav_views (vazio — purge na página Serviços, histórico em Eventos)

RBAC

Acção Perfis
Executar purge (Serviços) super_admin, ops_lead + senha Root
Ver histórico de purges (Eventos) super_admin, ops_lead
Listar / detalhe job purge super_admin, ops_lead

Técnicos technician e noc não acedem.


UI — Serviços (Spec 018)

Tile E-mail Tenant → modal purge

  1. Resumo — domínio, mail host, admin portal, contas Carbonio, zona CF
  2. Infra — passos get_status() (Carbonio, DNS, SNI, Traefik)
  3. Contas — lista e-mails Carbonio
  4. Zona perigosa — Purge (Admin only)
    • Aviso irreversível
    • Confirmação: digitar domínio exacto
    • Campo senha Root (Desk)
    • Botão «Apagar domínio e todos os dados»
  5. Drawer lateral vm112-purge-drawer — timeline em tempo real durante execução

API Desk (VM122)

Método Path Descrição
GET /api/v1/vm112/domains?q= Lista domínios orquestrados (proxy VM112)
GET /api/v1/vm112/domains/{domain} Detalhe + infra status
POST /api/v1/vm112/domains/{domain}/purge/jobs Recomendado — purge async + polling
GET /api/v1/vm112/purge/jobs/{job_id} Estado / timeline do job
POST /api/v1/vm112/purge/jobs/{job_id}/recover Recuperar job após timeout UI
GET /api/v1/vm112/purge/jobs?limit=&offset= v2 — lista histórico persistido
POST /api/v1/vm112/domains/{domain}/purge/stream Purge SSE (legado Traefik)
POST /api/v1/vm112/domains/{domain}/purge Purge síncrono (legado)

Body purge:

{
  "confirm_domain": "iofficebooks.com",
  "root_password": "********"
}

Validações purge:

  1. user.role ∈ {super_admin, ops_lead}
  2. verify_password(root_password, hash do user root)
  3. confirm_domain === domínio (case-insensitive)
  4. Domínio ∉ blocklist (ligbox.com.br, etc.)
  5. Proxy VM112 POST /api/admin/domains/{domain}/purge com X-Api-Key

Pós-purge Desk: apagar audit_domains, tickets, assist_sessions, audit_checks, domain_console_scenarios com referência ao domínio. Preservar webhook_events e inserir marcador domain.purged (source=desk.purge).


API VM112

Método Path Auth
GET /api/admin/domains X-Api-Key — resposta inclui cached, cache_age_sec (2026-06-25)
GET /api/admin/domains/{domain} X-Api-Key
POST /api/admin/domains/{domain}/purge X-Api-Key
GET /api/admin/domains/purge-jobs/{job_id} X-Api-Key (memória, efémero)

Cache listagem domínios (2026-06-25)

Problema: list_orchestrated_domains() chamava zmprov gad em cada GET /api/admin/domains (~5s) — gargalo da página Serviços IaaS no Desk (Spec 018).

Implementação VM112 (deploy/vm112-wizard/perf-domains-list-20260625/):

Cache TTL Chave Invalidação
Lista Carbonio (gad) 90s gad_all_domains zmprov cd, zmprov dd, purge concluído
Lista orquestrada montada 60s orchestrated_domains_list idem
Detalhe domínio (purge modal) 120s domain_detail:{domain} purge / dd / cd
Infra checks (get_status) 90s infra_status:{domain} idem
Contas (zmprov gaa) 45s accounts_list:{domain} purge contas / dd

Optimizações modal purge (2026-06-25): get_domain_detail() executa gaa + infra + Cloudflare em paralelo (ThreadPoolExecutor). 1.º hit ~16s → 2.º hit ~0,04s.

Ficheiros: carbonio_cache.py, carbonio.list_all_domains(), domain_orchestration.get_domain_detail(), infrastructure.get_status() cache.

Desk VM122 mantém cache proxy adicional 60s (VM112_DOMAINS_CACHE_TTL) — ver Spec 018 § Performance.


Purge VM112 (ordem):

  1. Apagar contas Carbonio (zmprov da)
  2. Apagar domínio Carbonio (zmprov dd)
  3. Remover portal users com planned_corporate_email no domínio
  4. Apagar /opt/ligbox-sites/domains/{domain}/
  5. Apagar zona Cloudflare (se existir na conta Ibytera)
  6. Remover mail.{domain} do SNI + routers Traefik (CT114)
  7. Apagar logs sessão JSONL com referência ao domínio

Fase 2 — Jobs async + polling (implementado)

POST /api/v1/vm112/domains/{domain}/purge/jobs inicia thread em background.
UI faz polling GET /api/v1/vm112/purge/jobs/{id} a cada 2s.

Motivo: SSE longo falhava via Traefik (504 / Failed to fetch ~6079s).
Fix nginx Desk: proxy_read_timeout 600s em frontend/nginx.conf.

Persistência SQLite (vm112_purge_jobs) criada nesta fase — base para v2.


Fase 2 — SSE (implementado, legado)

POST /api/v1/vm112/domains/{domain}/purge/stream · text/event-stream

type Conteúdo
step { label, at, status, detail }
heartbeat { elapsed } — cada 5s
error purge falhou
done { desk, vm112, domain }

Ordem: validação → VM112 (heartbeat) → passos VM112 → passos Desk → concluído.


v2 — Histórico de purges (implementado 2026-06-16)

Problema resolvido

Antes Depois
Timeline só ao vivo no drawer Histórico persistente no Desk
Dados em SQLite sem UI Lista + modal de detalhe
VM112 jobs em memória (efémero) Fonte de verdade: VM122 ops.db
Purges «desapareciam» ao fechar modal Consulta por domínio, data, utilizador

Nota: purges antes da persistência (ex.: betinsport.com) não aparecem no histórico.

UI — Eventos

  • Aba Webhooks (existente)
  • Aba Histórico de purges (Admin only)
  • Lista: Job ID, domínio, status, utilizador, resumo Desk, data, duração VM112
  • Clique na linha → modal com:
    1. Cabeçalho (domínio, status, utilizador, data, job id)
    2. Removido no Desk — webhook_events, tickets, audit_domains, assist_sessions, audit_checks
    3. Removido na VM112 — Carbonio, portal, site, Cloudflare, Traefik
    4. Timeline completa (timeline_json)

Persistência

Campo Valor
Base /var/lib/ligbox-ops-platform/ops.db (Docker: /data/ops.db)
Tabela vm112_purge_jobs
Colunas timeline_json, desk_json, vm112_json, by_user, status, created_at

Ficheiros v2

Ficheiro Alteração
api/app/vm112_purge_jobs.py list_jobs(), schema, persistência
api/app/vm112_domains_routes.py GET /purge/jobs
frontend/assets/app.js renderPurgeHistory(), modal, aba Eventos
frontend/index.html Toolbar Eventos + purge-history-modal
frontend/assets/styles.css Estilos lista/modal

Critérios de aceitação v2

  1. Admin vê aba «Histórico de purges» em Eventos.
  2. Lista mostra purges com status, utilizador, data e resumo Desk.
  3. Clique abre modal com timeline completa e contagens por serviço.
  4. Badges correctos: done, error, running, queued.
  5. technician / noc não vêem a aba.

Consulta manual (SSH VM122)

sqlite3 /var/lib/ligbox-ops-platform/ops.db \
  "SELECT id, domain, status, by_user, created_at FROM vm112_purge_jobs ORDER BY created_at DESC;"
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://desk.ligbox.com.br/api/v1/vm112/purge/jobs/57845ca1c5c64b53"

Extensão — Spec 026 (purge Traefik validation)

Validação YAML + smoke onboard pós-remoção Traefik (CT114). Incidente 2026-06-19: dynamic.yml inválido após purge → 404 global no onboard.

Spec dedicada: specs/026-purge-traefik-validation/spec.md


Extensão — Spec 032 (purge autorização extra)

Domínios em PURGE_EXTRA_AUTH_DOMAINS (ex.: myvexx.com) exigem código de autorização gerado pelo root em Infra (senha Root), além da validação purge normal.

Camada Regra
Blocklist ligbox.com.br, itecnologys.com — purge proibido
Extra auth Código único + senha Root
Normal Senha Root (Spec 017 v1)

Spec dedicada: specs/032-purge-domain-extra-auth/spec.md
UI geração: Infraestrutura → «Códigos autorização purge»
UI consumo: Serviços → modal purge (campo código)


Fase 3 — VM112 passos em tempo real (pendente)

VM112 (/opt/ligbox-wizard) emitir passos individuais durante execução (Carbonio, CF, Traefik) em vez de bloco único + heartbeat. Alterações no wizard, não só no Desk.


Critérios de aceitação (v1)

  1. Admin executa purge a partir de Serviços.
  2. Purge com senha root errada → erro na timeline.
  3. Purge com domínio confirmado errado → HTTP 400.
  4. Após purge, domínio ausente em Carbonio, ligbox-sites e Desk.
  5. Drawer mostra progresso ao vivo; job persiste em SQLite.

Fora de escopo

  • Purge parcial (só contas, só DNS)
  • Scheduler de limpeza automática
  • Export CSV/PDF do histórico
  • Filtro por domínio/data na lista de histórico
  • Retenção automática / purge de jobs antigos
  • Link directo Serviços → histórico do domínio

Conclusão (2026-06-16)

A Spec 017 cobre o ciclo completo de purge de domínio VM112:

Fase Entrega Estado
v1 Purge completo via Serviços + validação Root
Fase 2 Jobs async, polling, persistência SQLite
Fase 2 SSE Timeline drawer (legado)
v2 Histórico em Eventos — lista + modal audit trail
032 Códigos autorização extra (myvexx.com) — Infra + Serviços
026 Validação Traefik pós-purge
Fase 3 Passos VM112 em tempo real no wizard

Purges registados (exemplo): myvexx.com, diarissima.com, ibytera.com — visíveis em Eventos → Histórico de purges.

Próximo passo natural: Fase 3 no wizard VM112; depois filtros/export no histórico se necessário.


Incidente 2026-06-25 — Auditor 404 + purge timeout (Roger)

Sintomas reportados

# UI Mensagem Domínio / ref
1 Eventos → Auditor de Eventos Erro: Not Found webhook · 291 (domain.purged, cenario-demo.ops.ligbox.com.br)
2 Eventos → Histórico de purges badge ERRO, VM112 timed out (33s), Desk 0 eplacebets.com · job 84a78c85d6b6490c

Diagnóstico

Erro Causa raiz Impacto real
Auditor 404 Modal chamava detalhe inexistente (GET /webhooks/events/{id} ausente); evento 291 estava OK em SQLite Purge cenario-demo concluído — falha só de visualização
Purge timed out httpx poll VM112 com timeout 60s → excepção timed out; job marcado error antes da fase Desk; recover não actuava em jobs error eplacebets.com pode ter ficado parcial na VM112; Desk não limpo

Correções (2026-06-25)

Camada Alteração
API GET /api/v1/webhooks/events/{event_id} — detalhe para Auditor
API purge VM112_PURGE_HTTP_TIMEOUT=300 (env); poll tolerante a falhas transitórias; auto-recuperação se domínio já ausente na VM112
Jobs recover_job actua em status error; _execute_job tenta recuperação automática pós-timeout
UI Eventos Linhas clicáveis → modal Auditor de Eventos; render dedicado domain.purged; filtro origem Purge
UI Histórico Labels Desk actualizados (domain.purged preserva histórico); botão Recuperar purge em jobs com erro

Ficheiros

Ficheiro Alteração
api/app/main.py GET /webhooks/events/{id}
api/app/vm112_domains.py timeout 300s, poll resiliente, recover pós-timeout
api/app/vm112_purge_jobs.py recover em error, auto-recover
frontend/index.html event-auditor-modal, filtro Purge
frontend/assets/app.js Auditor, purge desk labels, botão recover

Validação pós-deploy

# Evento 291 — deve retornar domain.purged (HTTP 200)
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://desk.ligbox.com.br/api/v1/webhooks/events/291"

# Recuperar job eplacebets se VM112 já limpou
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  "https://desk.ligbox.com.br/api/v1/vm112/purge/jobs/84a78c85d6b6490c/recover"

Resultado esperado

  1. Clicar evento 291 → modal mostra utilizador, ferramenta, domínio e payload (sem 404).
  2. Job 84a78c85d6b6490cRecuperar purge conclui fase Desk se eplacebets.com já não existir na VM112; senão repetir purge após fix de timeout.
  3. Novos purges longos (Carbonio) não falham aos ~3360s por timeout HTTP do poll.

Resultado pós-deploy (2026-06-25, VM122)

Verificação Resultado
GET /webhooks/events/291 domain.purged · desk.purge
eplacebets.com na VM112 ausente (purge VM112 efectivo)
Job 84a78c85d6b6490c recover status=done, Desk limpo, marcador domain.purged inserido
Job posterior e238c1efb7c24d92 já estava done (retry manual anterior)

UI Serviços — loading, blocklist, Escopo OPS (2026-06-25)

Melhorias UX na página Serviços IaaS (Spec 018) sem alterar regras de purge.

Blocklist — apresentação

Domínio API purge_blocked UI lista clientes UI modal purge
ligbox.com.br true badge 🔒 (tooltip) formulário desactivado
itecnologys.com true idem idem
restantes false senha Root + confirmação

Constante Desk: PURGE_BLOCKLIST em vm112_domains.py — espelhada no frontend (servicos.js) para badges imediatos antes do detalhe API.

Painel Escopo OPS: banner vermelho quando cliente seleccionado ∈ blocklist, listando domínios protegidos.

Modal «Gerir» — loading animado

Enquanto GET /api/v1/vm112/domains/{domain} corre (~1015s cold):

Elemento Comportamento
Skeleton Dados da lista clientes (admin portal, Carbonio, site)
Barra progresso Indeterminada (CSS vm112-load-bar)
Etapas Rotação Carbonio → Infra CT114 → Cloudflare
Botão purge Spinner + «A carregar…» desactivado
A11y aria-busy, aria-live="polite"

Escopo OPS — cards clicáveis

Ver Spec 018 § Coluna Escopo OPS (mapa completo camada → Spec → destino).

Navegação cross-módulo: window.DeskNavigate.go(view, opts) em app.js.

Ficheiros (2026-06-25 UX)

Ficheiro Alteração
frontend/assets/servicos.js OPS_SCOPES enriquecido, navigateScope, blocklist UI, loading modal
frontend/assets/styles.css .vm112-load-*, .servicos-scope-*, alinhamento lista clientes
frontend/assets/app.js DeskNavigate
frontend/index.html cache bust ?v=20260625align1

Versão deploy VM122 (2026-06-25)

# Frontend (sem rebuild — docker cp)
docker cp servicos.js ligbox-ops-platform_frontend_1:/usr/share/nginx/html/assets/
docker cp styles.css ligbox-ops-platform_frontend_1:/usr/share/nginx/html/assets/
docker cp app.js ligbox-ops-platform_frontend_1:/usr/share/nginx/html/assets/
docker cp index.html ligbox-ops-platform_frontend_1:/usr/share/nginx/html/