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>
149 lines
5.6 KiB
Markdown
149 lines
5.6 KiB
Markdown
# Anexo 037-B — Conta Cloudflare por cliente (e-mail proj + handoff gestor)
|
|
|
|
**Parent:** [spec.md](./spec.md) · Spec **037**
|
|
**Solicitado por:** Roger · **2026-06-22**
|
|
**Status:** 📋 Regra definida — implementação Fase 2
|
|
|
|
---
|
|
|
|
## Regra de negócio (Roger)
|
|
|
|
Novos clientes que escolhem **vir para Cloudflare gerenciada pela Ligbox** recebem uma **conta Cloudflare dedicada** (não zona partilhada nas contas mãe ligit/itecnologys/ibytera a longo prazo).
|
|
|
|
### Fase A — Onboarding (conta sob controlo Ligbox)
|
|
|
|
| Campo | Valor |
|
|
|-------|--------|
|
|
| **E-mail titular / membro inicial** | `proj_{id}@ligbox.com.br` (ex.: `proj_005@ligbox.com.br`) |
|
|
| **Nome da conta CF** | Dados do **domínio do cliente** (ex.: `Empresa XYZ — empresa.com.br`) |
|
|
| **Zona DNS** | `cliente.com.br` criada **nesta** conta |
|
|
| **Gestão** | Ligbox opera via API token / membro admin Ligbox |
|
|
|
|
O `proj_{id}` vem do **ID de projeto/onboarding** (sequencial ou UUID curto no wizard / Ops Desk).
|
|
|
|
### Fase B — Handoff (conta estável)
|
|
|
|
Quando a conta estiver **setada e a funcionar** (DNS verificado + conta email Carbonio criada + infra OK):
|
|
|
|
1. **Convidar** `admin@{dominio_cliente}` (ou e-mail indicado no wizard) como **gestor** na conta Cloudflare.
|
|
2. Role sugerida: **Administrator** (ou custom com Zone DNS + Read mínimo se preferirem).
|
|
3. Manter `proj_{id}@ligbox.com.br` como membro técnico Ligbox (não remover até handoff confirmado).
|
|
4. Registar em `domain_registry`: `cf_account_id`, `cf_member_client_email`, `handoff_status`.
|
|
|
|
Opcional futuro: **promover** e-mail do cliente a owner principal e rebaixar `proj_*` a read-only — depende da política Cloudflare Tenant.
|
|
|
|
---
|
|
|
|
## Fluxo wizard (alvo Fase 2)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant W as Wizard VM112
|
|
participant CF as Cloudflare API
|
|
participant M as Mail ligbox.com.br
|
|
participant C as Cliente
|
|
|
|
W->>W: Gera project_id (ex. 005)
|
|
W->>M: Cria proj_005@ligbox.com.br + senha
|
|
W->>C: Entrega credenciais projeto (wizard)
|
|
W->>CF: POST /accounts (name=cliente.com.br)
|
|
Note over CF: Membro inicial proj_005@ligbox.com.br
|
|
W->>CF: POST /zones (account_id novo)
|
|
W->>CF: upsert MX/SPF/DMARC
|
|
W->>C: NS no registrador
|
|
C->>C: Propaga DNS
|
|
W->>W: dns/verify OK + account/create OK
|
|
W->>CF: POST /accounts/{id}/members (admin@cliente.com.br)
|
|
CF->>C: Convite gestor
|
|
W->>M: Notifica ops + cliente
|
|
```
|
|
|
|
---
|
|
|
|
## Relação com Fase 1 (actual)
|
|
|
|
| Fase 1 (hoje) | Fase 2 (regra Roger) |
|
|
|---------------|----------------------|
|
|
| Zona nova em conta partilhada `ibytera` | Conta CF **nova por cliente** |
|
|
| Token único conta mãe | Token scoped por `cf_account_id` cliente |
|
|
| Sem `proj_*@ligbox.com.br` | E-mail projeto Ligbox como membro inicial |
|
|
| Sem handoff gestor | Convite `admin@dominio` pós-go-live |
|
|
|
|
**Transição:** Fase 1 mantém-se até Tenant API / tokens prontos; novos clientes premium ou flag `dedicated_cf_account: true` usam Fase 2.
|
|
|
|
---
|
|
|
|
## Pré-requisitos técnicos
|
|
|
|
### 1. E-mails `proj_*@ligbox.com.br`
|
|
|
|
- O **agente Ligbox cria caixa real** no Carbonio (`ligbox.com.br`) via `project_identity.provision_project_email()`.
|
|
- Entrega **senha** ao cliente no wizard (uma vez) — ver [project-email-identity.md](./project-email-identity.md).
|
|
- Padrão: `proj_{project_id:03d}@ligbox.com.br`.
|
|
- Referenciado em: CF member, `domain_registry`, webhooks DNS, `activity_log`.
|
|
|
|
### 2. API Cloudflare
|
|
|
|
| Operação | Endpoint | Permissão |
|
|
|----------|----------|-----------|
|
|
| Criar conta | `POST /accounts` | **Tenant admin** (organização Ligbox) |
|
|
| Criar zona | `POST /zones` | Account Zone Edit na conta nova |
|
|
| Convidar gestor | `POST /accounts/{id}/members` | Account User Management |
|
|
| Abuse contact | `settings.abuse_contact_email` | Pode ser `admin@cliente.com.br` desde Fase A |
|
|
|
|
> `POST /accounts` está limitado a **tenant admins**. Se Ligbox ainda não tiver Tenant, alternativa interina: zonas na conta mãe (Fase 1) até activar Tenant.
|
|
|
|
### 3. Registo interno (VM112)
|
|
|
|
Ficheiro ou DB por domínio (`/var/lib/ligbox-wizard/cf_client_accounts/{domain}.json`):
|
|
|
|
```json
|
|
{
|
|
"domain": "empresa.com.br",
|
|
"project_id": "005",
|
|
"ligbox_email": "proj_005@ligbox.com.br",
|
|
"cloudflare_account_id": "…",
|
|
"cloudflare_account_name": "Empresa XYZ — empresa.com.br",
|
|
"zone_id": "…",
|
|
"client_manager_email": null,
|
|
"handoff_status": "pending",
|
|
"created_at": "2026-06-22T12:00:00Z",
|
|
"handoff_at": null
|
|
}
|
|
```
|
|
|
|
### 4. Gatilho handoff
|
|
|
|
Automático quando **todos** verdadeiros:
|
|
|
|
- `GET /dns/verify/{domain}` → `ready: true`
|
|
- `POST /account/create` → sucesso
|
|
- `infrastructure.ready` (se aplicável)
|
|
|
|
Então: `POST /dns/cloudflare/handoff-manager` com `{ domain, manager_email: "admin@empresa.com.br" }`.
|
|
|
|
---
|
|
|
|
## Endpoints planeados (Fase 2)
|
|
|
|
| Método | Path | Descrição |
|
|
|--------|------|-----------|
|
|
| POST | `/dns/cloudflare/provision-client-account` | Cria conta CF + zona + registo `proj_*` |
|
|
| POST | `/dns/cloudflare/handoff-manager` | Convida gestor do domínio cliente |
|
|
| GET | `/dns/cloudflare/client-account/{domain}` | Estado handoff (ops) |
|
|
|
|
---
|
|
|
|
## Critérios de aceitação (Fase 2)
|
|
|
|
1. Cliente novo → conta CF com nome do domínio e membro `proj_{id}@ligbox.com.br`.
|
|
2. Zona + apontamentos mail na **conta do cliente**, não na mãe ibytera.
|
|
3. Após go-live → convite `admin@cliente.com.br` enviado e registado.
|
|
4. `proj_*` permanece acessível à Ligbox para suporte.
|
|
5. BYO / registrador **não** passam por este fluxo.
|
|
|
|
---
|
|
|
|
## Pergunta em aberto (Roger)
|
|
|
|
**Formato do `project_id`:** sequencial `005` (`proj_005@`) ou slug do domínio (`proj_empresa-com-br@`)? Recomendação: **sequencial numérico** — mais limpo e alinhado ao exemplo.
|