Entrega read-only de apontamentos DNS (Cloudflare, OpenPanel BIND, público) no Desk e Console /admin/dominio, com spec, scripts de rollback e patches VM112 para painel lateral no passo DNS do onboarding (deploy wizard pendente). Co-authored-by: Cursor <cursoragent@cursor.com>
16 KiB
Spec 037-DNS-VIEWER — Painel DNS read-only unificado
Criado: 2026-06-25
Solicitado por: Roger
Status: 📋 Especificado — implementação Fase 1 parcial (Desk CF only)
Prioridade: P1
Depende de: spec.md · 004 cloudflare-zone-provision · 009 · 028 · 035 §5.5 · 027 RBAC
1. Objectivo
Permitir que staff Ligbox e gerente de domínio vejam todos os apontamentos DNS relevantes para um domínio — sem alterar registos na UI — com:
- Lista completa read-only (tipo, nome, conteúdo, TTL, função)
- Origem do DNS (Cloudflare Ligbox · BYO · OpenPanel BIND · registrador externo · resolução pública)
- Link «Editar aqui» para a consola correcta (Cloudflare, OpenPanel, registrador)
- Regra wizard: se o cliente escolhe trazer DNS para Ligbox → mostrar o que será / foi aplicado; caso contrário → mostrar onde o DNS está no momento da operação
Fora de scope: PATCH/POST/DELETE de registos no Desk ou Console — edição só via deep-link externo.
2. Problema actual (Roger 2026-06-25)
| Superfície | O que existe hoje | Lacuna |
|---|---|---|
| Desk Overview → modal domínio | Tabela CF via GET /api/v1/dns/cloudflare/records |
Só Cloudflare; sem OpenPanel; sem link editar |
| Desk Serviços IaaS | Resumo zona CF | Sem tabela de registos |
| Wizard passo DNS | Modos Ligbox/BYO/Registrador (037) | Cliente vê passos; staff não tem painel unificado |
| OpenPanel BIND | Zonas em openpanel_dns VM123 |
Zero UI Desk/Console — operador não sabe apontamentos |
Console /admin §5.5 |
MX/NS status (mock) | Sem lista completa |
3. Regra de produto — caminho Ligbox vs externo
Esta regra obrigatória aplica-se em Wizard, Desk e Console /admin.
flowchart TD
A[Domínio + sessão onboarding] --> B{dns_mode escolhido?}
B -->|ligbox_cf_*| C[Modo PLANEADO / APLICADO]
B -->|byo_cf| D[Modo BYO — zona cliente CF]
B -->|external / registrador| E[Modo ACTUAL — DNS público]
B -->|openpanel_bind| F[Modo OPENPANEL — zona BIND VM123]
C --> C1[Mostrar NS Cloudflare Ligbox]
C --> C2[Mostrar mail_dns_records preview]
C --> C3[Após apply: registos CF reais]
C --> C4[Link: Cloudflare conta Ligbox]
D --> D1[Mostrar registos zona BYO via token vault]
D --> D2[Link: dash.cloudflare.com zona cliente]
E --> E1[GET dns/instructions — o que falta colar]
E --> E2[GET dns/verify + dig público 009]
E --> E3[NS actuais no registrador]
E --> E4[Link: registrador ou painel CF cliente]
F --> F1[Listar zona BIND OpenPanel]
F --> F2[Link: OpenPanel DNS UI]
3.1 Tabela de decisão UI
dns_mode (persistido) |
Badge UI | Fonte de dados | O que mostrar |
|---|---|---|---|
ligbox_cf_ligit / itecnologys / ibytera |
DNS Ligbox | CF API conta Ligbox + mail_dns_records() |
Registos aplicados; se pré-NS → preview + NS a configurar |
ligbox_cf_provision_pending |
DNS Ligbox (aguarda NS) | provision-zone + preview |
NS Cloudflare + tabela «será aplicado após NS» |
byo_cf |
Cloudflare cliente | Token BYO vault + CF API | Registos actuais na zona BYO |
external / registrar |
DNS externo | dns/instructions + dig público |
Estado actual + instruções manuais |
openpanel_bind |
OpenPanel BIND | OpenAdmin API / zone file VM123 | Registos autoritativos :53 Ligbox |
unknown |
A determinar | dns/resolve + NS lookup |
NS actuais + sugestão de caminho |
3.2 Texto UX (gerente / staff)
| Modo | Mensagem principal |
|---|---|
| Ligbox (pré-apply) | «Estes apontamentos serão configurados na Cloudflare Ligbox quando confirmar o passo DNS.» |
| Ligbox (pós-apply) | «Apontamentos activos na Cloudflare Ligbox.» |
| Externo | «O domínio usa DNS fora da Ligbox. Abaixo: o que está publicamente resolvido agora.» |
| OpenPanel | «Zona servida pelo DNS Ligbox (OpenPanel) em 95.216.14.162.» |
4. Fontes de dados (backend)
4.1 Matriz de providers
| Provider ID | Quando usar | API / método | Edit link template |
|---|---|---|---|
cf_ligbox |
Zona numa conta Ligbox (037) | CF API token conta + zone_id |
https://dash.cloudflare.com/{account_id}/{zone_name}/dns |
cf_byo |
BYO wizard | Token vault sessão / entitlements | https://dash.cloudflare.com/ (zona cliente) |
openpanel_bind |
Subdomínio/site bundle OP | OpenAdmin GET /api/domains/{domain}/dns ou rndc/zone export |
https://openpanel.ligbox.com.br/domains/{domain}/dns |
public_resolver |
Sempre (fallback / externo) | dig + dns/verify VM112 |
— |
planned_ligbox |
Ligbox antes de apply | mail_dns_records(domain) wizard |
— (preview only) |
4.2 Endpoint unificado (novo — Desk + Console)
GET /api/v1/dns/viewer/{domain}
Authorization: Bearer <JWT staff ou domain-admin>
Query: ?include_public=true&include_planned=true
Response:
{
"domain": "empresa.com.br",
"dns_mode": "ligbox_cf_ibytera",
"mode_label": "Cloudflare Ligbox (ibytera)",
"display_mode": "applied",
"authoritative_source": "cf_ligbox",
"nameservers": {
"current_public": ["ns1.registro.br", "ns2.registro.br"],
"ligbox_cloudflare": ["ada.ns.cloudflare.com", "bob.ns.cloudflare.com"],
"match_ligbox": false
},
"records": [
{
"source": "cf_ligbox",
"status": "applied",
"type": "MX",
"name": "empresa.com.br",
"content": "mail.empresa.com.br",
"priority": 10,
"ttl": 3600,
"purpose": "mx",
"email_related": true
}
],
"planned_records": [],
"public_checks": {
"mx": { "ok": true, "values": ["10 mail.empresa.com.br"] },
"spf": { "ok": true },
"dkim": { "ok": false, "hint": "TXT _domainkey ausente" },
"dmarc": { "ok": true }
},
"edit_links": [
{
"label": "Editar na Cloudflare (Ligbox)",
"provider": "cf_ligbox",
"url": "https://dash.cloudflare.com/…/empresa.com.br/dns",
"roles": ["super_admin", "ops_lead", "devops", "seo"]
}
],
"instructions": null,
"errors": []
}
Variante wizard (sessão cliente — sem staff JWT):
GET /api/onboarding/dns/viewer/{domain}
Header: X-Onboarding-Session: {session}
Reutiliza mesma shape; filtra edit_links vazios para cliente; mostra planned_records quando display_mode=planned.
4.3 Endpoints existentes reutilizados
| Endpoint | Papel no viewer |
|---|---|
GET /api/onboarding/dns/resolve/{domain} |
Detectar dns_mode + conta CF |
GET /api/onboarding/dns/instructions/{domain} |
Modo externo — o que colar |
GET /api/onboarding/dns/verify/{domain} |
Checks públicos |
GET /api/onboarding/dns/portal-onboarding/{domain} |
NS + passos registrador |
GET /api/v1/dns/cloudflare/records |
Legado Desk — migrar para viewer |
| Spec 009 audit | public_checks MX/SPF/DKIM/DMARC |
4.4 OpenPanel BIND (Fase 2 viewer)
| Método | Descrição |
|---|---|
| Desk proxy | GET /api/v1/dns/openpanel/records?domain= |
| Backend | Bridge VM123 → OpenAdmin list records |
| Fallback | SSH docker exec openpanel_dns zone dump (read-only) |
Ver 028 DNS53.
5. Superfícies UI
5.1 Desk VM122 (staff)
| Local | Componente | RBAC |
|---|---|---|
| Overview → modal tenant → clicar domínio | Secção «DNS do domínio» (substitui só-CF) | cloudflare_dns.read + roles 027 |
| Serviços IaaS → modal domínio | Mesma secção embed | idem |
| Chamado / ticket domínio | Tab DNS read-only | technician+ |
Wireframe Desk:
┌─ DNS — empresa.com.br ────────────────────────────────────────┐
│ [DNS Ligbox ▼] Zona activa · 14 registos · 6 e-mail │
│ NS públicos: ns1.registro.br … ⚠ ainda não apontam CF Ligbox │
├───────────────────────────────────────────────────────────────┤
│ Função │ Nome │ Tipo │ Conteúdo │ Origem │ Estado │
│ MX │ @ │ MX │ mail… │ CF Lig │ ✅ aplicado │
│ SPF │ @ │ TXT │ v=spf1… │ CF Lig │ ✅ aplicado │
├───────────────────────────────────────────────────────────────┤
│ Checks públicos (dig): MX ✅ SPF ✅ DKIM ⚠ DMARC ✅ │
├───────────────────────────────────────────────────────────────┤
│ [Editar na Cloudflare ↗] [Verificação avançada] [Actualizar]│
└───────────────────────────────────────────────────────────────┘
5.2 Console gerente /admin (Spec 035)
Secção Domínio & DNS — ver domain-manager-console-ui.md §5.5.
Gerente vê read-only + link externo se tiver permissão (BYO: link CF cliente; Ligbox: mensagem «contacte suporte» ou link help).
5.3 Wizard passo DNS (cliente)
| Estado wizard | Painel lateral viewer |
|---|---|
| Escolheu Ligbox | Preview planned_records + NS |
| Escolheu BYO | Registos actuais BYO + diff vs mail |
| Escolheu Registrador | instructions + verify |
6. Links «Editar aqui» (deep-link)
| Provider | Quem vê o botão | URL | Mecanismo |
|---|---|---|---|
| Cloudflare Ligbox | staff super_admin, ops_lead, devops, seo |
dash.cloudflare.com | Conta + zone_id de dns/resolve |
| Cloudflare BYO | gerente (zona dele) + staff | dash.cloudflare.com | Zona BYO |
| OpenPanel | staff + gerente hub | openpanel.ligbox.com.br | Autologin bridge 027 |
| Registrador externo | gerente | URL detectada ou genérica | instructions.registrar_url |
| Registro.br | gerente BR | https://registro.br | Manual |
Desk: botão abre nova tab — nunca iframe CF (CSP).
Implementação Fase 1: só link CF Ligbox (conta conhecida). Fase 2: OpenPanel autologin.
7. RBAC (Spec 027)
| Acção | Roles |
|---|---|
dns.viewer.read — ver painel |
super_admin, ops_lead, technician, noc, seo, devops, developer |
| Ver link Cloudflare Ligbox | super_admin, ops_lead, devops, seo |
| Ver link OpenPanel | super_admin, ops_lead, sales_admin, sales_support, seo |
Gerente domínio /admin |
Só domínio próprio; sem CF Ligbox interna |
| Agente A2/A3 (Desk) | Lê viewer API — sugere fixes, não edita |
Formalizar permissão dns.viewer.read em data-model.md 027 (backlog).
8. Persistência dns_mode
Gravar em:
| Store | Campo |
|---|---|
| Wizard sessão onboarding | session.dns_mode, session.cf_account_id |
bundle_entitlements (035) |
dns_mode, dns_provider, cf_zone_id |
Desk billing_accounts / tenant meta |
espelho read-only |
Resolver ordem:
- Entitlements domínio activo
- Sessão onboarding em curso
GET dns/resolve/{domain}- NS lookup público →
unknown
9. Fases de implementação
| Fase | Entregável | Estado |
|---|---|---|
| V0 | Desk CF only (cloudflare_dns.py) |
✅ Parcial |
| V1 | GET /api/v1/dns/viewer/{domain} — CF + public + planned |
✅ VM122 2026-06-25 |
| V1b | Desk UI unificada (dns-viewer.js) |
✅ VM122 2026-06-25 |
| V2 | OpenPanel BIND records no viewer | ✅ VM122 2026-06-25 |
| V3 | Console /admin/dominio |
✅ VM123 2026-06-25 |
| V4 | Wizard painel lateral + diff planned vs actual | 📋 |
10. Critérios de aceitação
- Staff abre domínio email Ligbox no Desk → vê ≥ MX, SPF, DKIM, DMARC, A mail com origem «CF Ligbox».
- Domínio externo (registrador) → viewer mostra NS actuais + registos públicos (
dig), não preview Ligbox. - Domínio Ligbox pré-NS → viewer mostra planned_records + NS Cloudflare a configurar.
- Botão «Editar na Cloudflare» visible para
ops_lead→ abre zona correcta (conta ibytera/ligit/itecnologys). - Nenhum botão «Guardar» / «Apagar registo» no viewer.
- Gerente em
/adminvê mesma tabela (domínio próprio) — Spec 035. - OpenPanel zone (Fase V2): registos BIND listados + link OpenPanel.
- API responde ≤3s (cache 60s por domínio OK).
11. Código (alvo monorepo)
| Caminho | Função |
|---|---|
projects/ops-desk/api/app/dns_viewer.py |
Orquestrador providers |
projects/ops-desk/api/app/cloudflare_dns.py |
Provider CF (existente) |
projects/ops-desk/api/app/openpanel_dns.py |
Provider BIND (novo) |
projects/wizard/backend/app/services/dns_viewer.py |
Wizard session variant |
projects/ops-desk/frontend/assets/dns-viewer.js |
Componente partilhado Desk |
projects/console/frontend/.../DnsSection.tsx |
Console /admin |
12. Documentos relacionados
| Doc | Relação |
|---|---|
| spec.md | Fluxo decisão DNS wizard |
| cloudflare-zone-provision.md | provision-zone / apply |
| domain-manager-console-ui.md §5.5 | UI gerente |
| 009 spec | Checks públicos |
| 027 spec | Deep-links CF / OP |
| DNS-VIEWER-ROLLBACK | Rollback e feature flag |
13. Decisões Roger (2026-06-25)
| # | Decisão |
|---|---|
| D1 | Viewer é read-only — edição só via link externo |
| D2 | Caminho Ligbox → mostrar planned/applied Ligbox; externo → mostrar actual público |
| D3 | OpenPanel BIND deve aparecer no viewer (Fase V2) — gap operacional actual |
| D4 | Um endpoint unificado dns/viewer — não proliferar modais CF-only |
| D5 | Mesmo componente visual Desk + Console /admin (design system 035) |
14. Versionamento e rollback
Obrigatório antes de cada deploy V1+: backup + tag git + feature flag.
| Documento | Função |
|---|---|
| deploy/DNS-VIEWER-EXEC-20260625.md | Checklist deploy, ficheiros, validação |
| deploy/DNS-VIEWER-ROLLBACK.md | Rollback por fase (Desk / Wizard / Console) |
| deploy/scripts/preflight-dns-viewer.sh | Backup VM122 (+ --wizard / --console) |
| deploy/scripts/verify-dns-viewer.sh | Smoke test pós-deploy ou pós-rollback |
| deploy/scripts/rollback-dns-viewer.sh | Rollback automatizado VM122 |
Feature flag VM122
DNS_VIEWER_ENABLED=1 # viewer activo
DNS_VIEWER_ENABLED=0 # fallback legado /dns/cloudflare/records + UI V0
Tag git recomendada
git tag -a dns-viewer-pre-v1-YYYYMMDD -m "Antes DNS Viewer V1"
Endpoint legado (mantido até cutover)
GET /api/v1/dns/cloudflare/records — não remover enquanto rollback não estiver validado em produção ≥7 dias.