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>
369 lines
16 KiB
Markdown
369 lines
16 KiB
Markdown
# 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](./spec.md) · [004 cloudflare-zone-provision](../004-onboard-funnel-events/cloudflare-zone-provision.md) · [009](../009-ops-audit-overview/spec.md) · [028](../028-openpanel-ce-ligbox-reengineering/DNS53_OPENPANEL_PORTA53.md) · [035 §5.5](../035-ligbox-mail-bundles-foss-openpanel/domain-manager-console-ui.md) · [027 RBAC](../027-desk-rbac-function-matrix/spec.md)
|
|
|
|
---
|
|
|
|
## 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:
|
|
|
|
1. **Lista completa read-only** (tipo, nome, conteúdo, TTL, função)
|
|
2. **Origem do DNS** (Cloudflare Ligbox · BYO · OpenPanel BIND · registrador externo · resolução pública)
|
|
3. **Link «Editar aqui»** para a consola correcta (Cloudflare, OpenPanel, registrador)
|
|
4. **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`**.
|
|
|
|
```mermaid
|
|
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)
|
|
|
|
```http
|
|
GET /api/v1/dns/viewer/{domain}
|
|
Authorization: Bearer <JWT staff ou domain-admin>
|
|
Query: ?include_public=true&include_planned=true
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"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):**
|
|
|
|
```http
|
|
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](../028-openpanel-ce-ligbox-reengineering/DNS53_OPENPANEL_PORTA53.md).
|
|
|
|
---
|
|
|
|
## 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](../035-ligbox-mail-bundles-foss-openpanel/domain-manager-console-ui.md#55-domínio--dns-dns-viewer).
|
|
|
|
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:
|
|
|
|
1. Entitlements domínio activo
|
|
2. Sessão onboarding em curso
|
|
3. `GET dns/resolve/{domain}`
|
|
4. 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
|
|
|
|
1. Staff abre domínio email Ligbox no Desk → vê **≥ MX, SPF, DKIM, DMARC, A mail** com origem «CF Ligbox».
|
|
2. Domínio **externo** (registrador) → viewer mostra **NS actuais** + registos **públicos** (`dig`), **não** preview Ligbox.
|
|
3. Domínio **Ligbox pré-NS** → viewer mostra **planned_records** + NS Cloudflare a configurar.
|
|
4. Botão «Editar na Cloudflare» visible para `ops_lead` → abre zona correcta (conta ibytera/ligit/itecnologys).
|
|
5. **Nenhum** botão «Guardar» / «Apagar registo» no viewer.
|
|
6. Gerente em `/admin` vê mesma tabela (domínio próprio) — Spec 035.
|
|
7. OpenPanel zone (Fase V2): registos BIND listados + link OpenPanel.
|
|
8. 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](./spec.md) | Fluxo decisão DNS wizard |
|
|
| [cloudflare-zone-provision.md](../004-onboard-funnel-events/cloudflare-zone-provision.md) | provision-zone / apply |
|
|
| [domain-manager-console-ui.md §5.5](../035-ligbox-mail-bundles-foss-openpanel/domain-manager-console-ui.md) | UI gerente |
|
|
| [009 spec](../009-ops-audit-overview/spec.md) | Checks públicos |
|
|
| [027 spec](../027-desk-rbac-function-matrix/spec.md) | Deep-links CF / OP |
|
|
| [DNS-VIEWER-ROLLBACK](./deploy/DNS-VIEWER-ROLLBACK.md) | 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](./deploy/DNS-VIEWER-EXEC-20260625.md) | Checklist deploy, ficheiros, validação |
|
|
| [deploy/DNS-VIEWER-ROLLBACK.md](./deploy/DNS-VIEWER-ROLLBACK.md) | Rollback por fase (Desk / Wizard / Console) |
|
|
| [deploy/scripts/preflight-dns-viewer.sh](./deploy/scripts/preflight-dns-viewer.sh) | Backup VM122 (+ `--wizard` / `--console`) |
|
|
| [deploy/scripts/verify-dns-viewer.sh](./deploy/scripts/verify-dns-viewer.sh) | Smoke test pós-deploy ou pós-rollback |
|
|
| [deploy/scripts/rollback-dns-viewer.sh](./deploy/scripts/rollback-dns-viewer.sh) | Rollback automatizado VM122 |
|
|
|
|
### Feature flag VM122
|
|
|
|
```bash
|
|
DNS_VIEWER_ENABLED=1 # viewer activo
|
|
DNS_VIEWER_ENABLED=0 # fallback legado /dns/cloudflare/records + UI V0
|
|
```
|
|
|
|
### Tag git recomendada
|
|
|
|
```bash
|
|
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.
|