Actualiza dns-viewer, exec/rollback, fichas VM112/122/123, API Console proxy, token interno wizard e verify script para evitar drift documental. Co-authored-by: Cursor <cursoragent@cursor.com>
180 lines
7.4 KiB
Markdown
180 lines
7.4 KiB
Markdown
# Spec 037 — DNS multi-conta Cloudflare + BYO + Registrador
|
||
|
||
**Criado:** 2026-06-22
|
||
**Solicitado por:** Roger
|
||
**Status:** 🔄 Em implementação (Fase A activa · B/C/D em construção)
|
||
**Prioridade:** P1
|
||
**VM:** 112 (wizard API `:8090`)
|
||
**Relacionado:** [004 cloudflare-zone-provision](../004-onboard-funnel-events/cloudflare-zone-provision.md) · 025 · 017 · **[dns-viewer.md](./dns-viewer.md)** · [035 §5.5](../035-ligbox-mail-bundles-foss-openpanel/domain-manager-console-ui.md)
|
||
|
||
---
|
||
|
||
## Resumo
|
||
|
||
O passo DNS do onboarding usa **três contas Cloudflare gerenciadas pela Ligbox** (ligit, itecnologys, ibytera). O wizard:
|
||
|
||
1. **Se a zona já existe** numa das 3 contas → aplica apontamentos com o token dessa conta.
|
||
2. **Se o cliente escolhe «Cloudflare Ligbox»** e a zona **ainda não existe** → o wizard **cria a zona do cliente** na conta Ligbox correcta (`provision-zone`), depois aplica MX/SPF/etc.
|
||
3. **Se o cliente não quer DNS na Ligbox** → BYO (token CF dele) ou registrador externo.
|
||
|
||
**Política:** não importar domínios alheios nem criar zonas fora do fluxo wizard; **sim** criar a zona **do cliente** na CF gerenciada pela Ligbox quando esse for o caminho escolhido.
|
||
|
||
**Evolução (Roger 2026-06-22):** cada cliente novo terá **conta Cloudflare dedicada** — e-mail inicial `proj_{id}@ligbox.com.br`, dados do domínio do cliente; após go-live, convidar gestor `admin@dominio`. Ver [client-cf-account-lifecycle.md](./client-cf-account-lifecycle.md).
|
||
|
||
**Identidade projeto (Roger 2026-06-22):** o agente **cria** `proj_{id}@ligbox.com.br` no Carbonio, **entrega senha** ao cliente e referencia em CF, DNS, registry e webhooks. Ver [project-email-identity.md](./project-email-identity.md).
|
||
|
||
---
|
||
|
||
## Três contas Ligbox (pré-cadastro)
|
||
|
||
| ID interno | E-mail admin (referência) | Ficheiro token (VM112) | `account_id` CF |
|
||
|------------|---------------------------|-------------------------|-----------------|
|
||
| `ligit` | admin@ligit.com.br | `secrets/cloudflare-ligit.token` | _configurar_ |
|
||
| `itecnologys` | admin@itecnologys.com | `secrets/cloudflare-itecnologys.token` | _configurar_ |
|
||
| `ibytera` | ibytera@gmail.com | `secrets/cloudflare-ibytera.token` | _configurar_ |
|
||
|
||
Catálogo: `deploy/vm112-wizard/dns-accounts.yaml` (não commitar tokens).
|
||
|
||
Conta **legacy** `cloudflare.token` + `cloudflare_account_id` em `config.py` → migrar para `ibytera` ou deprecar após cutover.
|
||
|
||
---
|
||
|
||
## Fluxo decisão (passo DNS)
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[POST validate-domain] --> B[GET /dns/resolve/{domain}]
|
||
B --> C{Zona já existe em conta Ligbox?}
|
||
C -->|sim| D[apply na conta encontrada]
|
||
C -->|não| E{Cliente escolhe caminho}
|
||
E -->|Cloudflare Ligbox| F[provision-zone: cria zona do cliente na conta default]
|
||
F --> G[apply apontamentos]
|
||
E -->|BYO| H[connect-custom + apply]
|
||
E -->|Registrador| I[instructions + verify manual]
|
||
D --> V[GET dns/verify]
|
||
G --> V
|
||
H --> V
|
||
I --> V
|
||
V --> J[account/create]
|
||
```
|
||
|
||
### Regra «zona do cliente na CF Ligbox»
|
||
|
||
- **Existente:** probe `ligit → itecnologys → ibytera`; usa a conta onde a zona já está.
|
||
- **Nova (wizard):** `POST provision-zone` cria `cliente.com.br` na conta `default_provision_account` (yaml, hoje `ibytera`) — **só** quando o utilizador escolhe Cloudflare Ligbox.
|
||
- **Nunca:** criar zona sem escolha explícita Ligbox; nunca BYO/registrador criar em conta Ligbox.
|
||
|
||
---
|
||
|
||
## Endpoints novos / alterados
|
||
|
||
| Método | Path | Descrição |
|
||
|--------|------|-----------|
|
||
| GET | `/api/onboarding/dns/resolve/{domain}` | Procura zona nas 3 contas; devolve `matched_account`, `zone_id`, `paths_available` |
|
||
| POST | `/api/onboarding/dns/cloudflare/connect-custom` | Valida token BYO + zona; guarda em vault sessão |
|
||
| POST | `/api/onboarding/dns/cloudflare/apply` | **Alterado:** usa conta resolvida, BYO, ou body `account_id` |
|
||
| POST | `/api/onboarding/dns/cloudflare/provision-zone` | **Cria zona do cliente** na CF Ligbox (conta default ou existente) — só caminho Ligbox |
|
||
|
||
### Response `dns/resolve`
|
||
|
||
```json
|
||
{
|
||
"domain": "cliente.com.br",
|
||
"matched": true,
|
||
"account_id": "ligit",
|
||
"account_label": "Ligbox Ligit (admin@ligit.com.br)",
|
||
"zone_id": "…",
|
||
"zone_status": "active",
|
||
"dns_mode": "ligbox_cf_ligit",
|
||
"paths_available": ["apply_ligbox", "byo", "external"]
|
||
}
|
||
```
|
||
|
||
Se `matched: false` (zona nova):
|
||
|
||
```json
|
||
{
|
||
"matched": false,
|
||
"can_provision_ligbox": true,
|
||
"provision_account_id": "ibytera",
|
||
"paths_available": ["provision_ligbox", "byo", "external"],
|
||
"message": "Domínio novo — pode criar zona na Cloudflare gerenciada pela Ligbox ou usar BYO/registrador."
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## BYO Cloudflare (cliente)
|
||
|
||
1. Cliente cola **API Token** (scope: DNS Edit + Zone Read **só na zona**).
|
||
2. `verify_token()` + `get_zone_by_name(domain)`.
|
||
3. Token em vault (`/var/lib/.../dns_tokens/{session_hash}`), TTL 7 dias pós-onboard.
|
||
4. `apply` com `CloudflareDNS(token=customer_token)`.
|
||
5. Purge Spec 017 **não** apaga zona BYO — só registos criados por nós (futuro: tracking).
|
||
|
||
---
|
||
|
||
## Registrador / DNS externo
|
||
|
||
Sem mudança funcional core: `GET /dns/instructions/{domain}` + verificação `dns_verify`.
|
||
|
||
Fase 2: adapters EPP/API (Gandi, GoDaddy, Registro.br homologado).
|
||
|
||
---
|
||
|
||
## DNS Viewer (read-only) — Spec 037-DNS-VIEWER
|
||
|
||
Painel unificado para **exibir** apontamentos (staff Desk + gerente Console) **sem editar** na UI.
|
||
|
||
| Caminho wizard | O viewer mostra |
|
||
|----------------|-----------------|
|
||
| **Cloudflare Ligbox** | Registos **planeados** (pré-NS) ou **aplicados** (pós-apply) + NS CF |
|
||
| **BYO / Registrador / externo** | DNS **actual** (público + instructions) — **não** preview Ligbox |
|
||
|
||
Documento completo: **[dns-viewer.md](./dns-viewer.md)** — endpoints, links editar, fases V0–V4.
|
||
|
||
**Estado deploy (2026-06-25):** V1–V3 produção (VM122/123) · commit `038fb8f` · V4 wizard patches prontos · deploy VM112 pendente.
|
||
|
||
---
|
||
|
||
## Código
|
||
|
||
| Caminho monorepo | Deploy VM112 |
|
||
|------------------|--------------|
|
||
| `projects/wizard/backend/app/services/dns_account_registry.py` | `/opt/ligbox-wizard/backend/app/services/` |
|
||
| `deploy/vm112-wizard/dns-accounts.yaml` | `/opt/ligbox-wizard/dns-accounts.yaml` |
|
||
| `deploy/vm112-wizard/dns-accounts.yaml.example` | exemplo versionado |
|
||
|
||
---
|
||
|
||
## Critérios de aceitação (Fase 1)
|
||
|
||
1. Domínio existente na conta `ibytera` → `resolve` retorna `matched` + `apply` OK.
|
||
2. Domínio **novo** + caminho Ligbox → `provision-zone` cria zona na conta default + `apply` OK.
|
||
3. BYO com token válido → `apply` na conta do cliente.
|
||
4. Caminho registrador → sem `provision-zone` Ligbox.
|
||
5. Tokens em `secrets/` — nunca no Git.
|
||
|
||
---
|
||
|
||
## Decisões Roger (2026-06-22, corrigido)
|
||
|
||
| # | Regra |
|
||
|---|--------|
|
||
| 1 | Não importar domínios alheios nas contas Ligbox |
|
||
| 2 | **Sim** criar zona **do cliente** na CF gerenciada Ligbox via wizard (escolha explícita) |
|
||
| 3 | Conta para zona nova: `default_provision_account` no yaml (hoje `ibytera`) |
|
||
| 4 | BYO / registrador = DNS fora das contas Ligbox |
|
||
|
||
---
|
||
|
||
## Fase 2 — Conta CF dedicada por cliente
|
||
|
||
Ver [client-cf-account-lifecycle.md](./client-cf-account-lifecycle.md):
|
||
|
||
| Fase | E-mail Cloudflare | Quando |
|
||
|------|-------------------|--------|
|
||
| A — Onboarding | `proj_{id}@ligbox.com.br` | Criação conta + zona |
|
||
| B — Handoff | `admin@{dominio_cliente}` convidado como gestor | DNS + email + infra OK |
|
||
|
||
**Orquestração agentica (edge):** [cf-agents-sdk-architecture.md](./cf-agents-sdk-architecture.md) — Cloudflare Agents SDK (Durable Objects, multi-agent, human-in-the-loop) + roster Spec 029 A0–A7.
|