17 KiB
SPEC — Integração Validação Admin Domínios Virtuais (Wizard VM112 + Desk VM122)
Versão: 1.0
Data: 2026-06-12
Autor: Roger / Cursor DevOps
Estado: 📋 PLANEAMENTO (correcção VM112 ✅ concluída)
Depende de: SPEC-CORRECAO-ADMIN-DOMINIOS-VIRTUAIS.md
1. Objectivo
Integrar a validação e provisionamento admin Carbonio (porta :6071, redirect /admin, certs SSL) no:
- Wizard VM112 (
/opt/ligbox-wizard/) — onboarding automático por domínio virtual - VM122 Ligbox Ops (
ligbox-ops-platform) — Desk, tickets, timeline, auditoria
Problema actual: validação admin existe em scripts offline (admin-login-check/) mas não no wizard API nem no Desk.
2. Contexto — dois conceitos de «admin»
| Conceito | URL | Onde vive hoje |
|---|---|---|
| Painel delegado wizard | https://onboard.ligbox.com.br/admin |
SPA DomainAdmin.jsx + /api/domain-admin/* |
| Carbonio Admin Console | https://mail.{dominio}/admin → :6071/static/login/ |
nginx VM112 + Carbonio auth |
Esta spec trata exclusivamente do Carbonio Admin Console por domínio virtual.
3. Estado actual vs alvo
3.1 Wizard — infrastructure.py (6 checks hoje)
| ID actual | O que valida | Admin? |
|---|---|---|
carbonio_domain |
zmprov domínio existe | ❌ |
dns_mail |
MX/A públicos | ❌ |
haproxy_sni |
SNI CT114 | ❌ |
traefik_router |
Router Traefik :443 | ❌ |
cert_san |
LE mail-vm112-multi (webmail) |
❌ (não :6071) |
webmail_https |
GET :443 | ❌ |
3.2 Novos checks admin (4 adicionais)
| ID novo | Label | O que valida | Severidade |
|---|---|---|---|
admin_redirect_443 |
Admin redirect :443 | GET /admin → 302 Location :6071/static/login/ |
P1 |
admin_cert_6071 |
Cert SSL admin :6071 | CN/SAN = mail.{dominio} no cert nginx :6071 |
P1 |
admin_login_6071 |
Admin login :6071 | E4 /zx/login/supported JSON 200; E6 config OK |
P1 |
admin_block_nginx |
Bloco nginx admin | server block :6071 existe (admin ou .custom) |
P2 |
3.3 Estado alvo — 10 checks infra
carbonio_domain → dns_mail → haproxy_sni → traefik_router → cert_san → webmail_https
→ admin_block_nginx → admin_redirect_443 → admin_cert_6071 → admin_login_6071
ready: true quando todos P1 OK (P2 = warning, não bloqueia onboarding).
4. Wizard VM112 — desenho técnico
4.1 Novo módulo Python
Ficheiro: /opt/ligbox-wizard/backend/app/services/admin_domain_validation.py
# Funções principais (interface proposta)
def check_admin_redirect(mail_host: str) -> StepResult
def check_admin_cert_sni(mail_host: str) -> StepResult
def check_admin_login_flow(mail_host: str) -> StepResult
def check_admin_nginx_block(mail_host: str) -> StepResult
def provision_admin_infra(domain: str, mail_aliases: list[str] | None) -> ProvisionResult
Implementação interna:
| Check | Método |
|---|---|
admin_redirect_443 |
httpx HEAD https://{mail_host}/admin → Location contém :6071/static/login/ |
admin_cert_6071 |
openssl s_client -connect 127.0.0.1:6071 -servername {host} ou leitura nginx ssl_certificate |
admin_login_6071 |
Subprocess node check-admin-login-flow.mjs --host {mail_host} ou reimplementar E4/E6 em Python |
admin_block_nginx |
grep server block em carbonio.admin + .custom |
4.2 Alterações em infrastructure.py
get_status() — adicionar 4 steps após webmail_https:
steps.append(check_admin_block_nginx(all_hosts))
steps.append(check_admin_redirect_443(all_hosts))
steps.append(check_admin_cert_6071(all_hosts))
steps.append(check_admin_login_6071(all_hosts))
Payload de resposta (exemplo):
{
"domain": "iofficebooks.com",
"mail_host": "mail.iofficebooks.com",
"steps": [
{"id": "admin_redirect_443", "ok": true, "message": "302 → :6071/static/login/"},
{"id": "admin_cert_6071", "ok": true, "message": "CN=mail.iofficebooks.com"},
{"id": "admin_login_6071", "ok": true, "message": "E4 JSON 200, E6 domain OK"},
{"id": "admin_block_nginx", "ok": true, "message": "bloco :6071 presente"}
],
"admin_ready": true
}
provision() — novo step admin_infra após cert_san:
def do_admin_infra() -> str:
# 1. sync-traefik-admin-certs.sh (se domínio usa cert Traefik)
# 2. apply-admin-nginx-overrides.py --reload
# 3. re-validar admin_redirect + admin_cert + admin_login
Ordem provision completa:
domain_site_layout → haproxy_sni → traefik_router → cert_san → admin_infra → (re-check all)
4.3 API routes (sem breaking changes)
| Método | Route | Alteração |
|---|---|---|
| GET | /api/onboarding/infrastructure/status/{domain} |
+4 steps admin |
| POST | /api/onboarding/infrastructure/provision?step=admin_infra |
Novo step |
| POST | /api/onboarding/infrastructure/provision |
Inclui admin_infra no fluxo completo |
4.4 Frontend wizard (App.jsx / WizardProcessHub)
UI — secção «Infraestrutura admin» no painel de progresso:
| Step UI | Ícone OK | Ícone fail | Acção |
|---|---|---|---|
Redirect /admin |
✅ | ⚠️ | «Abrir admin» link |
| Certificado :6071 | ✅ | ❌ | «Sincronizar cert» botão |
| Login admin | ✅ | ❌ | «Diagnosticar» → activity log |
| Bloco nginx | ✅ | ⚠️ | automático |
Link pós-onboarding (Passo Concluído):
Admin do domínio: https://mail.{dominio}/admin
(credenciais: admin@{dominio})
4.5 Activity log — mensagens
[infra] admin_redirect_443: OK — 302 → mail.iofficebooks.com:6071/static/login/
[infra] admin_cert_6071: FAIL — CN=mail.diarissima.com (esperado mail.iofficebooks.com)
[infra] admin_infra: sync Traefik certs + apply nginx overrides
[infra] admin_login_6071: OK — E4/E6 validados
4.6 Configuração (.env / config.py)
# Novos settings
admin_check_scripts_dir: str = "/opt/ligbox-deploy/scripts/admin-login-check"
admin_nginx_apply_script: str = ".../apply-admin-nginx-overrides.py"
admin_traefik_sync_script: str = ".../sync-traefik-admin-certs.sh"
admin_canonical_url: str = "https://mail.ligbox.com.br:6071/static/login/"
4.7 Hook em POST /account/create
Após criar conta e auto-provision infra existente:
# onboarding.py — após provision infra
infra = infrastructure.provision(domain, mail_aliases=aliases)
if not infra["status"].get("admin_ready"):
activity_log.warn(f"Admin infra incompleto: {domain}", source="infra")
# Não bloquear cliente — emitir webhook infra.partial
ops_webhook.emit("infra.synced", domain, session_id, data={
"steps": infra["status"]["steps"],
"admin_ready": infra["status"].get("admin_ready"),
"admin_url": f"https://mail.{domain}/admin",
})
5. VM122 Desk — desenho técnico
5.1 VM122 actual
| Componente | Path | Estado |
|---|---|---|
| API | ligbox-ops-platform/api/app/main.py |
✅ running |
| Desk UI | frontend/ → desk.ligbox.com.br |
✅ |
| Webhook ingest | POST /api/v1/webhooks/onboard |
✅ |
| SQLite | tenants, tickets, webhook_events | ✅ |
5.2 Novos eventos webhook (extend contract 001 + 004)
| Event | Emissor | Quando | Cria ticket? |
|---|---|---|---|
infra.synced |
VM112 wizard | Após provision infra completo | Nota em ticket existente |
admin.validation.failed |
VM112 wizard | admin_ready=false pós-provision | Sim (prioridade média) |
admin.cert.expiring |
VM122 cron/worker | Cert :6071 < 14 dias | Sim (prioridade baixa) |
Payload infra.synced (extendido):
{
"event": "infra.synced",
"domain": "iofficebooks.com",
"session_id": "sess-abc123",
"data": {
"mail_host": "mail.iofficebooks.com",
"admin_ready": true,
"admin_url": "https://mail.iofficebooks.com/admin",
"admin_url_canonical": "https://mail.ligbox.com.br:6071/static/login/",
"steps": [
{"id": "admin_redirect_443", "ok": true},
{"id": "admin_cert_6071", "ok": true},
{"id": "admin_login_6071", "ok": true}
],
"provisioned_at": "2026-06-12T18:52:00Z"
}
}
Payload admin.validation.failed:
{
"event": "admin.validation.failed",
"domain": "betinplace.com",
"session_id": "sess-xyz",
"data": {
"failed_steps": ["admin_cert_6071"],
"messages": ["CN mismatch: expected mail.betinplace.com"],
"suggested_action": "Run sync-traefik-admin-certs.sh + apply-admin-nginx-overrides.py --reload"
}
}
5.3 VM122 — alterações API
Ficheiro: api/app/routers/webhooks.py (ou equivalente)
# Novos handlers
EVENT_HANDLERS = {
...
"infra.synced": handle_infra_synced, # update ticket + timeline
"admin.validation.failed": handle_admin_fail, # create ticket priority=medium
}
Ficheiro: api/app/routers/desk.py — extend ticket detail
# GET /api/v1/desk/tickets/{id}
# + admin_status block quando domain conhecido:
{
"admin_status": {
"ready": true,
"url": "https://mail.iofficebooks.com/admin",
"last_check": "2026-06-12T18:52:00Z",
"failed_steps": []
}
}
5.4 VM122 — novo endpoint auditoria admin
GET /api/v1/infra/admin-status/{domain}
Resposta: proxy para VM112 GET /api/onboarding/infrastructure/status/{domain} filtrando steps admin, ou VM122 armazena último infra.synced.
Uso Desk: widget «Admin domínio» no detalhe do ticket.
5.5 VM122 Desk UI — telas
Tela 1: Ticket detalhe — secção «Admin domínio»
┌─────────────────────────────────────────────────┐
│ Admin Carbonio — iofficebooks.com │
├─────────────────────────────────────────────────┤
│ URL: https://mail.iofficebooks.com/admin [↗] │
│ Redirect :443 ✅ 302 → :6071 │
│ Cert :6071 ✅ CN=mail.iofficebooks.com │
│ Login E4/E6 ✅ │
│ Última validação: 2026-06-12 18:52 UTC │
│ [Re-validar agora] [Abrir admin] │
└─────────────────────────────────────────────────┘
Tela 2: Dashboard Ops — widget «Admin domínios»
| Domínio | Admin OK | Cert :6071 | Último check |
|---|---|---|---|
| iofficebooks.com | ✅ | ✅ | 12/06 18:52 |
| betinplace.com | ✅ | ✅ | 12/06 18:52 |
| novo-cliente.com | ❌ | ❌ | — |
Fonte: agregação webhook_events tipo infra.synced + admin.validation.failed.
Tela 3: Runbook Desk — «Admin ERR_CERT»
Passos automáticos sugeridos (link para runbook):
- Verificar Traefik tem cert para
mail.{dominio} - Correr
sync-traefik-admin-certs.sh - Correr
apply-admin-nginx-overrides.py --reload - Re-validar via wizard ou script E1–E8
5.6 Processos Desk Support
Processo 1: Onboarding novo domínio (automático)
sequenceDiagram
participant C as Cliente
participant W as Wizard VM112
participant C114 as Traefik CT114
participant V112 as Carbonio VM112
participant O as Ops VM122 Desk
C->>W: validate-domain + create account
W->>C114: provision SNI + router + cert :443
W->>V112: cert_san + admin_infra
Note over V112: sync Traefik certs + nginx overrides
W->>W: validate admin_redirect + cert + login
alt admin_ready=true
W->>O: webhook infra.synced (admin_ready=true)
O->>O: timeline + nota ticket
else admin_ready=false
W->>O: webhook admin.validation.failed
O->>O: ticket prioridade média + runbook
end
W->>C: onboarding.completed + link /admin
Processo 2: Ticket manual «Admin não abre»
| Passo | Actor | Acção |
|---|---|---|
| 1 | NOC | Cliente reporta ERR_CERT ou 504 em mail.X/admin |
| 2 | Desk | Abrir ticket; campo domínio preenchido |
| 3 | Desk | GET /api/v1/infra/admin-status/{domain} |
| 4 | Técnico | Se cert fail → sync Traefik + apply overrides |
| 5 | Técnico | Se redirect fail → apply-admin-nginx-overrides.py |
| 6 | Técnico | Se NAT fail → verificar pfSense :6071 → VM112 |
| 7 | Desk | Re-validar; fechar ticket com evidência curl |
Processo 3: Renovação cert (preventivo)
| Trigger | Acção |
|---|---|
| Traefik renova LE (CT114) | Cron VM112: sync-traefik-admin-certs.sh semanal |
| Cert < 14 dias | VM122 emite admin.cert.expiring → ticket low priority |
| zmproxyconfgen executado | Obrigatório zmproxyconfgen-ligbox |
Processo 4: Novo domínio virtual (pós-onboarding)
Quando ops adiciona domínio manualmente (zmprov cd):
- Correr wizard
infrastructure/provision?domain=X(ou script CLI) - Inclui step
admin_infraautomaticamente - Desk recebe
infra.syncedouadmin.validation.failed
6. Wire VM112 → VM122 (pré-requisitos)
6.1 Completar ops_webhook.py (VM112)
Ficheiro: /opt/ligbox-wizard/backend/app/services/ops_webhook.py
Adicionar em config.py:
ops_webhook_enabled: bool = False
ops_webhook_url: str = "http://10.10.10.122:8080/api/v1/webhooks/onboard"
ops_webhook_secret: str = ""
Montar em main.py: routers assist se necessário.
6.2 Secret partilhado
VM112 .env:
OPS_WEBHOOK_SECRET=<same-as-VM122-WEBHOOK_SECRET>
OPS_WEBHOOK_ENABLED=true
VM122 .env:
WEBHOOK_SECRET=<shared>
7. Plano de implementação (fases)
Fase 1 — Wizard backend (P1) — ~2-3 dias
| Task | Ficheiro | Esforço |
|---|---|---|
Criar admin_domain_validation.py |
services/ | M |
Integrar 4 checks em infrastructure.get_status() |
infrastructure.py | S |
Step admin_infra em provision() |
infrastructure.py | M |
| Config settings | config.py | S |
| Testes unitários checks | tests/ | M |
Fase 2 — Wizard frontend (P1) — ~1-2 dias
| Task | Ficheiro | Esforço |
|---|---|---|
| UI steps admin no ProcessHub | frontend/ | M |
| Link admin pós-onboarding | App.jsx | S |
| Botão «Sincronizar admin» | frontend/ | S |
Fase 3 — Webhooks VM112→VM122 (P1) — ~1-2 dias
| Task | Ficheiro | Esforço |
|---|---|---|
| Settings ops_webhook | config.py, .env | S |
Emit infra.synced extendido |
onboarding.py | S |
Emit admin.validation.failed |
onboarding.py | S |
| Handlers VM122 | api/app/ | M |
Fase 4 — Desk UI admin widget (P2) — ~2-3 dias
| Task | Ficheiro | Esforço |
|---|---|---|
| Secção admin no ticket detail | frontend-desk/ | M |
| Widget dashboard domínios | frontend-desk/ | M |
| Endpoint proxy admin-status | api/app/ | S |
| Runbook ERR_CERT na UI | docs/ | S |
Fase 5 — Automação ops (P2) — ~1 dia
| Task | Esforço |
|---|---|
| Cron sync Traefik certs semanal | S |
| Alert cert expiring → VM122 | M |
| Documentar zmproxyconfgen-ligbox em runbook Desk | S |
Total estimado: 7-11 dias dev.
8. Critérios de aceitação integração
Wizard
GET infrastructure/status/{domain}inclui 4 steps adminPOST infrastructure/provisionexecutaadmin_infraautomaticamente- UI mostra estado admin no ProcessHub
- Link
mail.{dominio}/adminno passo Concluído - Novo domínio onboarding → admin_ready=true sem intervenção manual
VM122 Desk
infra.syncedaparece na timeline do ticketadmin.validation.failedcria ticket com runbook- Widget «Admin domínio» no detalhe do ticket
- Dashboard lista domínios com status admin
- Técnico consegue re-validar via API sem SSH
Ops
- Cron sync certs Traefik documentado e activo
- Runbook Desk para ERR_CERT / 504 / redirect
- zmproxyconfgen-ligbox referenciado em procedimento padrão
9. Referências
| Documento | Conteúdo |
|---|---|
SPEC-CORRECAO-ADMIN-DOMINIOS-VIRTUAIS.md |
Correcção implementada VM112 |
SPEC-ADMIN-DOMINIO-BLINDAGEM-NGINX.md |
Blindagem nginx |
SPEC-CARBONIO-ADMIN-LOGIN-FLOW-VALIDATION.md |
Fluxo E1–E8 |
ligbox-ops-platform/specs/001-webhook-vm112-integration/ |
Webhook MVP |
ligbox-ops-platform/specs/004-onboard-funnel-events/ |
Funil onboarding |
ligbox-ops-platform/specs/009-ops-audit-overview/ |
Audit scorecard |
10. Sincronização documentação
| Destino | Caminho |
|---|---|
| VM112 | /opt/ligbox-deploy/docs/SPEC-INTEGRACAO-ADMIN-WIZARD-VM122-DESK.md |
| Obsidian | /root/obsidian-infra/carbonio/carbonio-server/docs/ |
| VM122 | /root/obsidian-infra/ligbox-ops-platform/specs/010-admin-domain-validation/ |
| GitHub | itecnologys/ibytera-mail-portal + ligbox-ops-platform |
Roger — planeamento integração Wizard + Desk — 2026-06-12