Document Infra authorization codes for protected domains (myvexx.com) and update backlog.
274 lines
9.6 KiB
Markdown
274 lines
9.6 KiB
Markdown
# Feature Specification: Domínios VM112 — Purge & Histórico (017)
|
||
|
||
**Criado:** 2026-06-16
|
||
**Actualizado:** 2026-06-19 (extensões Spec 026 · Spec 032)
|
||
**Solicitado por:** Roger
|
||
**Status:** v1 + v2 concluídos · Fase 3 VM112 pendente
|
||
**Prioridade:** P1 (testes E2E + padrão de limpeza)
|
||
**Sistema:** Desk VM122 + Wizard VM112
|
||
**Módulo:** `vm112-domains`
|
||
**UI purge:** página **Serviços** (Spec 018)
|
||
**UI histórico:** **Eventos → Histórico de purges**
|
||
|
||
---
|
||
|
||
## Resumo
|
||
|
||
Técnicos **Admin** (`super_admin`, `ops_lead`) executam **purge completo** de domínios VM112 (Carbonio, site, portal, Cloudflare, Traefik/SNI, registos Desk) a partir da página **Serviços**, com timeline ao vivo no drawer lateral.
|
||
|
||
**v2 (2026-06-16):** cada purge fica **persistido** em SQLite e consultável em **Eventos → Histórico de purges** — lista clicável + modal com timeline, utilizador e serviços removidos.
|
||
|
||
**Uso inicial:** limpar domínios de teste para reentrarem no wizard. **Futuro:** padrão de limpeza de dados por domínio.
|
||
|
||
---
|
||
|
||
## Módulo Desk (Spec 015)
|
||
|
||
| Campo | Valor |
|
||
|-------|--------|
|
||
| `id` | `vm112-domains` |
|
||
| `label` | Domínios VM112 |
|
||
| `default_enabled` | `true` |
|
||
| `nav_views` | _(vazio — purge na página Serviços, histórico em Eventos)_ |
|
||
|
||
---
|
||
|
||
## RBAC
|
||
|
||
| Acção | Perfis |
|
||
|-------|--------|
|
||
| Executar purge (Serviços) | `super_admin`, `ops_lead` + **senha Root** |
|
||
| Ver histórico de purges (Eventos) | `super_admin`, `ops_lead` |
|
||
| Listar / detalhe job purge | `super_admin`, `ops_lead` |
|
||
|
||
Técnicos `technician` e `noc` **não** acedem.
|
||
|
||
---
|
||
|
||
## UI — Serviços (Spec 018)
|
||
|
||
### Tile E-mail Tenant → modal purge
|
||
|
||
1. **Resumo** — domínio, mail host, admin portal, contas Carbonio, zona CF
|
||
2. **Infra** — passos `get_status()` (Carbonio, DNS, SNI, Traefik)
|
||
3. **Contas** — lista e-mails Carbonio
|
||
4. **Zona perigosa — Purge** (Admin only)
|
||
- Aviso irreversível
|
||
- Confirmação: digitar domínio exacto
|
||
- Campo **senha Root** (Desk)
|
||
- Botão «Apagar domínio e todos os dados»
|
||
5. **Drawer lateral** `vm112-purge-drawer` — timeline em tempo real durante execução
|
||
|
||
---
|
||
|
||
## API Desk (VM122)
|
||
|
||
| Método | Path | Descrição |
|
||
|--------|------|-----------|
|
||
| GET | `/api/v1/vm112/domains?q=` | Lista domínios orquestrados (proxy VM112) |
|
||
| GET | `/api/v1/vm112/domains/{domain}` | Detalhe + infra status |
|
||
| POST | `/api/v1/vm112/domains/{domain}/purge/jobs` | **Recomendado** — purge async + polling |
|
||
| GET | `/api/v1/vm112/purge/jobs/{job_id}` | Estado / timeline do job |
|
||
| POST | `/api/v1/vm112/purge/jobs/{job_id}/recover` | Recuperar job após timeout UI |
|
||
| GET | `/api/v1/vm112/purge/jobs?limit=&offset=` | **v2** — lista histórico persistido |
|
||
| POST | `/api/v1/vm112/domains/{domain}/purge/stream` | Purge SSE (legado Traefik) |
|
||
| POST | `/api/v1/vm112/domains/{domain}/purge` | Purge síncrono (legado) |
|
||
|
||
**Body purge:**
|
||
```json
|
||
{
|
||
"confirm_domain": "iofficebooks.com",
|
||
"root_password": "********"
|
||
}
|
||
```
|
||
|
||
**Validações purge:**
|
||
1. `user.role` ∈ {super_admin, ops_lead}
|
||
2. `verify_password(root_password, hash do user root)`
|
||
3. `confirm_domain` === domínio (case-insensitive)
|
||
4. Domínio ∉ blocklist (`ligbox.com.br`, etc.)
|
||
5. Proxy VM112 `POST /api/admin/domains/{domain}/purge` com `X-Api-Key`
|
||
|
||
**Pós-purge Desk:** apagar `audit_domains`, `webhook_events`, `tickets`, `assist_sessions`, `audit_checks` com referência ao domínio.
|
||
|
||
---
|
||
|
||
## API VM112
|
||
|
||
| Método | Path | Auth |
|
||
|--------|------|------|
|
||
| GET | `/api/admin/domains` | `X-Api-Key` |
|
||
| GET | `/api/admin/domains/{domain}` | `X-Api-Key` |
|
||
| POST | `/api/admin/domains/{domain}/purge` | `X-Api-Key` |
|
||
| GET | `/api/admin/domains/purge-jobs/{job_id}` | `X-Api-Key` _(memória, efémero)_ |
|
||
|
||
**Purge VM112 (ordem):**
|
||
1. Apagar contas Carbonio (`zmprov da`)
|
||
2. Apagar domínio Carbonio (`zmprov dd`)
|
||
3. Remover portal users com `planned_corporate_email` no domínio
|
||
4. Apagar `/opt/ligbox-sites/domains/{domain}/`
|
||
5. Apagar zona Cloudflare (se existir na conta Ibytera)
|
||
6. Remover `mail.{domain}` do SNI + routers Traefik (CT114)
|
||
7. Apagar logs sessão JSONL com referência ao domínio
|
||
|
||
---
|
||
|
||
## Fase 2 — Jobs async + polling (implementado)
|
||
|
||
`POST /api/v1/vm112/domains/{domain}/purge/jobs` inicia thread em background.
|
||
UI faz polling `GET /api/v1/vm112/purge/jobs/{id}` a cada 2s.
|
||
|
||
**Motivo:** SSE longo falhava via Traefik (`504` / `Failed to fetch` ~60–79s).
|
||
**Fix nginx Desk:** `proxy_read_timeout 600s` em `frontend/nginx.conf`.
|
||
|
||
Persistência SQLite (`vm112_purge_jobs`) criada nesta fase — base para v2.
|
||
|
||
---
|
||
|
||
## Fase 2 — SSE (implementado, legado)
|
||
|
||
`POST /api/v1/vm112/domains/{domain}/purge/stream` · `text/event-stream`
|
||
|
||
| type | Conteúdo |
|
||
|------|----------|
|
||
| `step` | `{ label, at, status, detail }` |
|
||
| `heartbeat` | `{ elapsed }` — cada 5s |
|
||
| `error` | purge falhou |
|
||
| `done` | `{ desk, vm112, domain }` |
|
||
|
||
Ordem: validação → VM112 (heartbeat) → passos VM112 → passos Desk → concluído.
|
||
|
||
---
|
||
|
||
## v2 — Histórico de purges (implementado 2026-06-16)
|
||
|
||
### Problema resolvido
|
||
|
||
| Antes | Depois |
|
||
|-------|--------|
|
||
| Timeline só ao vivo no drawer | Histórico persistente no Desk |
|
||
| Dados em SQLite sem UI | Lista + modal de detalhe |
|
||
| VM112 jobs em memória (efémero) | Fonte de verdade: VM122 `ops.db` |
|
||
| Purges «desapareciam» ao fechar modal | Consulta por domínio, data, utilizador |
|
||
|
||
**Nota:** purges **antes** da persistência (ex.: `betinsport.com`) não aparecem no histórico.
|
||
|
||
### UI — Eventos
|
||
|
||
- Aba **Webhooks** (existente)
|
||
- Aba **Histórico de purges** (Admin only)
|
||
- Lista: Job ID, domínio, status, utilizador, resumo Desk, data, duração VM112
|
||
- Clique na linha → modal com:
|
||
1. Cabeçalho (domínio, status, utilizador, data, job id)
|
||
2. Removido no Desk — webhook_events, tickets, audit_domains, assist_sessions, audit_checks
|
||
3. Removido na VM112 — Carbonio, portal, site, Cloudflare, Traefik
|
||
4. Timeline completa (`timeline_json`)
|
||
|
||
### Persistência
|
||
|
||
| Campo | Valor |
|
||
|-------|--------|
|
||
| Base | `/var/lib/ligbox-ops-platform/ops.db` (Docker: `/data/ops.db`) |
|
||
| Tabela | `vm112_purge_jobs` |
|
||
| Colunas | `timeline_json`, `desk_json`, `vm112_json`, `by_user`, `status`, `created_at` |
|
||
|
||
### Ficheiros v2
|
||
|
||
| Ficheiro | Alteração |
|
||
|----------|-----------|
|
||
| `api/app/vm112_purge_jobs.py` | `list_jobs()`, schema, persistência |
|
||
| `api/app/vm112_domains_routes.py` | `GET /purge/jobs` |
|
||
| `frontend/assets/app.js` | `renderPurgeHistory()`, modal, aba Eventos |
|
||
| `frontend/index.html` | Toolbar Eventos + `purge-history-modal` |
|
||
| `frontend/assets/styles.css` | Estilos lista/modal |
|
||
|
||
### Critérios de aceitação v2
|
||
|
||
1. Admin vê aba «Histórico de purges» em Eventos.
|
||
2. Lista mostra purges com status, utilizador, data e resumo Desk.
|
||
3. Clique abre modal com timeline completa e contagens por serviço.
|
||
4. Badges correctos: `done`, `error`, `running`, `queued`.
|
||
5. `technician` / `noc` não vêem a aba.
|
||
|
||
### Consulta manual (SSH VM122)
|
||
|
||
```bash
|
||
sqlite3 /var/lib/ligbox-ops-platform/ops.db \
|
||
"SELECT id, domain, status, by_user, created_at FROM vm112_purge_jobs ORDER BY created_at DESC;"
|
||
```
|
||
|
||
```bash
|
||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||
"https://desk.ligbox.com.br/api/v1/vm112/purge/jobs/57845ca1c5c64b53"
|
||
```
|
||
|
||
---
|
||
|
||
## Extensão — Spec 026 (purge Traefik validation)
|
||
|
||
Validação YAML + smoke onboard pós-remoção Traefik (CT114). Incidente 2026-06-19: `dynamic.yml` inválido após purge → 404 global no onboard.
|
||
|
||
**Spec dedicada:** `specs/026-purge-traefik-validation/spec.md`
|
||
|
||
---
|
||
|
||
## Extensão — Spec 032 (purge autorização extra)
|
||
|
||
Domínios em `PURGE_EXTRA_AUTH_DOMAINS` (ex.: `myvexx.com`) exigem **código de autorização** gerado pelo root em **Infra** (senha Root), além da validação purge normal.
|
||
|
||
| Camada | Regra |
|
||
|--------|--------|
|
||
| Blocklist | `ligbox.com.br`, `itecnologys.com` — purge proibido |
|
||
| Extra auth | Código único + senha Root |
|
||
| Normal | Senha Root (Spec 017 v1) |
|
||
|
||
**Spec dedicada:** `specs/032-purge-domain-extra-auth/spec.md`
|
||
**UI geração:** Infraestrutura → «Códigos autorização purge»
|
||
**UI consumo:** Serviços → modal purge (campo código)
|
||
|
||
---
|
||
|
||
## Fase 3 — VM112 passos em tempo real (pendente)
|
||
|
||
VM112 (`/opt/ligbox-wizard`) emitir passos individuais durante execução (Carbonio, CF, Traefik) em vez de bloco único + heartbeat. Alterações no wizard, não só no Desk.
|
||
|
||
---
|
||
|
||
## Critérios de aceitação (v1)
|
||
|
||
1. Admin executa purge a partir de Serviços.
|
||
2. Purge com senha root errada → erro na timeline.
|
||
3. Purge com domínio confirmado errado → HTTP 400.
|
||
4. Após purge, domínio ausente em Carbonio, ligbox-sites e Desk.
|
||
5. Drawer mostra progresso ao vivo; job persiste em SQLite.
|
||
|
||
---
|
||
|
||
## Fora de escopo
|
||
|
||
- Purge parcial (só contas, só DNS)
|
||
- Scheduler de limpeza automática
|
||
- Export CSV/PDF do histórico
|
||
- Filtro por domínio/data na lista de histórico
|
||
- Retenção automática / purge de jobs antigos
|
||
- Link directo Serviços → histórico do domínio
|
||
|
||
---
|
||
|
||
## Conclusão (2026-06-16)
|
||
|
||
A Spec 017 cobre o ciclo completo de purge de domínio VM112:
|
||
|
||
| Fase | Entrega | Estado |
|
||
|------|---------|--------|
|
||
| v1 | Purge completo via Serviços + validação Root | ✅ |
|
||
| Fase 2 | Jobs async, polling, persistência SQLite | ✅ |
|
||
| Fase 2 SSE | Timeline drawer (legado) | ✅ |
|
||
| **v2** | Histórico em Eventos — lista + modal audit trail | ✅ |
|
||
| **032** | Códigos autorização extra (myvexx.com) — Infra + Serviços | ✅ |
|
||
| **026** | Validação Traefik pós-purge | ✅ |
|
||
| Fase 3 | Passos VM112 em tempo real no wizard | ⏳ |
|
||
|
||
**Purges registados (exemplo):** `myvexx.com`, `diarissima.com`, `ibytera.com` — visíveis em Eventos → Histórico de purges.
|
||
|
||
**Próximo passo natural:** Fase 3 no wizard VM112; depois filtros/export no histórico se necessário.
|