ligbox-ops-platform/specs/018-service-orchestration/spec.md
Ligbox Spec Hub edffd8b3c0 feat(desk): Serviços IaaS perf, Escopo OPS cards e blocklist UI (Spec 017/018)
Cache VM112/VM122 para lista e detalhe domínio, modal purge com loading animado,
cards Escopo OPS clicáveis (camada + Spec + navegação), blocklist visível na UI,
e documentação nas specs e anais de referência 20260625.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 18:53:57 +00:00

669 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Feature Specification: Orquestração de Serviços — Cliente & Catálogo (018)
**Criado:** 2026-06-16
**Actualizado:** 2026-06-25 (performance + Escopo OPS clicável + camadas tiles)
**Solicitado por:** Roger
**Status:** Fase 1 concluída (Desk VM122)
**Wizard cliente:** inalterado na VM112 — só e-mail (`vm112-mail`)
**Prioridade:** P1
**Sistema:** Desk VM122 (+ proxies VM112, futuro multi-wizard)
**Módulo Desk:** `overview-home` (nav **Serviços**)
**Depende de:** Spec 015 (módulos), Spec 017 (purge domínio VM112)
---
## Resumo
A página **Serviços** substitui a visão estreita «Contas / lista de domínios» por um painel operacional estilo **cPanel/WHM**: o técnico sénior selecciona um **cliente** e vê **tiles de serviços** contratados ou disponíveis (e-mail tenant, servidor dedicado, firewall, cloud, Wazuh, site).
**Fase 1 (esta entrega):** UI e modelo conceptual no frontend; clientes derivados dos domínios VM112; apenas **E-mail Tenant** activo com purge Spec 017 intacto.
**Fase 2:** API Desk `clients` + `service_instances` em SQLite.
**Fase 3:** Registry de wizards por `service_catalog.code` e purge por instância.
### Performance — Serviços IaaS (2026-06-25)
**Cadeia:** Desk `servicos.js` → VM122 `GET /api/v1/vm112/domains` → VM112 `GET /api/admin/domains`**`zmprov gad`** (~5s sem cache).
| Camada | Problema | Mitigação | Deploy |
|--------|----------|-----------|--------|
| **VM112** | `zmprov gad` a cada pedido | Cache 90s `gad_all_domains` + lista orquestrada 60s; invalidação em `cd`/`dd`/purge | `deploy/vm112-wizard/perf-domains-list-20260625/` ✅ 2026-06-25 |
| **VM122 API** | Proxy repetia VM112 lenta | Cache 60s `VM112_DOMAINS_CACHE_TTL` | `vm112_domains.py` ✅ |
| **Desk frontend** | Ecrã preso «A carregar…» | `sessionStorage` stale-while-revalidate + dedup fetch | `servicos.js` ✅ |
| **Poll** | 30s sobrecarregava VM112 | Poll **90s** em `overview-home` | `app.js` ✅ |
| **Sessão** | API restart expulsava user | Rede ≠ logout (`ensureValidSession`) | `auth.js` ✅ |
**Resultados medidos (2026-06-25):**
| Pedido | Antes | Depois |
|--------|-------|--------|
| VM112 `/api/admin/domains` (2.º hit) | ~511s | **~0,03s** |
| VM112 `/api/admin/domains/{domain}` (2.º hit) | ~1520s | **~0,04s** |
| VM112 detalhe (1.º hit, cold) | ~20s serial | **~16s** paralelo (infra+gaa+CF) |
| Desk `/api/v1/vm112/domains` (cache quente) | ~16s | **~0,08s** |
| Desk `/api/v1/vm112/domains/{domain}` (cache quente) | ~15s+ | **~3s** (1.º após lista) / **~0,1s** (2.º) |
| 1.º hit pós-restart wizard | — | ~6s lista / ~16s modal purge |
### Modal Purge / «Gerir» (2026-06-25)
**Endpoint:** `GET /api/v1/vm112/domains/{domain}` → VM112 `get_domain_detail()`.
| Gargalo | Tempo | Mitigação |
|---------|-------|-----------|
| `get_status()` — SSH CT114, DNS, HTTPS | ~9s | Cache `infra_status:{domain}` 90s |
| `zmprov gaa` (contas) | ~3s | Cache `accounts_list:{domain}` 45s |
| Cloudflare API | ~12s | Paralelo + cache `domain_detail:{domain}` 120s |
| UI ecrã branco | UX | **Skeleton** imediato com dados da lista clientes |
**Frontend:** `servicos.js` — modal abre com dados do cliente seleccionado; purge form activa após load.
**Loading UX (2026-06-25):** barra indeterminada, etapas VM112 rotativas, botão spinner — ver Spec **017** § UI Serviços loading.
**Desk API:** cache proxy detalhe 45s (`VM112_DOMAIN_DETAIL_TTL`).
### Escopo OPS — cards clicáveis (2026-06-25)
Coluna direita: cada escopo é **card botão** com **camada**, **Spec** e **destino**.
| ID | Label | Camada | Spec | Destino ao clicar |
|----|-------|--------|------|-------------------|
| `carbonio` | Carbonio | Aplicação MOSP | 017 | Modal Serviços (detalhe/purge) |
| `site` | ligbox-sites | Tenant utilizador | 017 | Modal Serviços |
| `portal` | Portal users | Tenant utilizador | 028 | Console `/admin/dominio?domain=` |
| `cloudflare` | Cloudflare | Infraestrutura | 037 | Console DNS Viewer |
| `traefik` | Traefik / SNI | Infraestrutura | 026 | Desk Infra CODE |
| `desk` | Desk OPS | Aplicação MOSP | 017 | Desk Eventos tab Purges |
**Blocklist UI:** clientes `ligbox.com.br` / `itecnologys.com` — badge 🔒 na lista; banner no painel Escopo; purge modal desactivado (`purge_blocked` API).
**Tiles centro:** badge camada (`Tenant utilizador` · `Aplicação MOSP` · `Infraestrutura`) + badge comercial (`SaaS` / `IaaS`).
**Navegação:** `window.DeskNavigate.go('events', { eventsTab: 'purges' })` — helper em `app.js`.
**Cache bust frontend (VM122):** `servicos.js`, `styles.css`, `app.js``?v=20260625align1`.
---
```json
{
"domains": [ "..." ],
"cached": true,
"cache_age_sec": 12
}
```
**Regra deploy Roger:**
1. VM112: `systemctl restart ligbox-wizard` invalida cache wizard (~6s no 1.º Serviços IaaS).
2. VM122: preferir `docker cp` sem restart; se restart API, Desk mostra cache browser.
3. Purge/create domain invalida cache VM112 automaticamente.
Ver também Spec **017** § cache listagem domínios.
---
## Problema
| Hoje | Necessidade |
|------|-------------|
| Lista plana de domínios | Vista por **cliente** |
| Nome «Contas» ambíguo | **Serviços** — escala para novos produtos |
| Purge acoplado à lista | Purge no tile **E-mail Tenant** (Spec 017) |
| Um wizard (mail) | Vários wizards futuros (firewall, cloud, Wazuh) |
---
## Nomenclatura
| Camada | Valor |
|--------|--------|
| ID módulo / view | `overview-home` (sem breaking change) |
| Menu lateral | **Serviços** |
| Título página | **Orquestração de Serviços** |
| Subtítulo | *Clientes Ligbox — serviços activos, estado OPS e acções* |
| JS global | `DeskServices` (alias `DeskAccounts` para compat.) |
---
**Fase 1 (esta entrega):** UI e modelo conceptual no frontend; clientes derivados dos domínios VM112; apenas **E-mail Tenant** activo com purge Spec 017 intacto.
**Fase 2:** API Desk `clients` + `service_instances` em SQLite.
**Fase 3:** Registry de wizards por `service_catalog.code` e purge por instância.
**Fase 4:** Catálogo comercial completo — níveis «Pizza as a Service» + Managed Open Source.
**Posicionamento Ligbox (MSP):**
> *«Pegamos soluções open source e entregamos como serviço gerenciado — em cloud privada Ligbox, VPS dedicado ou infraestrutura local do cliente.»*
---
## Visão de oferta — «Pizza as a Service» (Roger, 2026)
A analogia **Pizza as a Service** descreve **quem gere o quê** entre cliente e provedor. Quanto mais camadas a Ligbox opera, mais «as a service» o produto é — e mais valor (e SLA) o cliente compra.
### Legenda de responsabilidade (camadas da «pizza»)
| Camada (de baixo para cima) | Equivalente técnico Ligbox |
|-----------------------------|----------------------------|
| Eletricidade / Gás | Datacenter, energia, link, Hetzner/host |
| Fogão | Hypervisor — Proxmox VE, VMs, CTs |
| Fogo | SO, rede, firewall base, hardening |
| Pizza (massa/base) | Runtime — Docker, Nginx, Traefik, DB engine |
| Toppings | Aplicação open source — Carbonio, Nextcloud, ERPNext |
| Bebidas | Integrações — DNS, SSL, backup, monitoramento |
| Conversas | Uso pelo cliente — utilizadores finais, dados de negócio |
**Azul (cliente gere)** · **Laranja (Ligbox gere)**
---
### Nível 1 — Tradicional → Consultoria / Suporte sob demanda
*Equivalente: «Feito em casa» — cliente gere tudo; Ligbox ajuda quando chamada.*
| Gerido pelo **cliente** | Oferecido pela **Ligbox** |
|-------------------------|---------------------------|
| Servidores físicos / on-prem | Consultoria Linux |
| Rede | Troubleshooting |
| Sistema operacional | Instalação inicial |
| Banco de dados | Treinamento técnico |
| Backup | Auditoria de segurança |
| Aplicação | Documentação |
| Segurança operacional | — |
| Campo catálogo | Valor |
|----------------|-------|
| `delivery_model` | `traditional` |
| `code` (ex.) | `consulting_hour`, `audit_security`, `linux_training` |
| Stack típica | Ubuntu Server, Debian, Proxmox VE (no lado do cliente) |
| Modelo comercial | Hora técnica · pacote suporte mensal básico |
| Wizard Desk | Não — ticket + assist takeover (Spec 010) |
| Tile UI | «Suporte» — sem instância provisionada |
---
### Nível 2 — IaaS → Infraestrutura gerenciada
*Equivalente: «Leve e Asse» — Ligbox entrega infra pronta; cliente cuida da aplicação.*
| Gerido pela **Ligbox** | Gerido pelo **cliente** |
|------------------------|-------------------------|
| VPS / Cloud | Aplicação |
| Virtualização (Proxmox) | Dados |
| Firewall (pfSense) | Utilizadores da app |
| Backup do servidor | — |
| Monitoramento 24/7 | — |
| SO + hardening | — |
| Campo catálogo | Valor |
|----------------|-------|
| `delivery_model` | `iaas` |
| `code` (ex.) | `managed_vps`, `managed_backup`, `vpn_corporate`, `firewall`, `monitoring_host` |
| Stack Ligbox | Proxmox VE, Docker, Nginx, pfSense, Grafana, Prometheus |
| Modelo comercial | Mensal fixo — ex. *«Servidor Linux totalmente gerenciado»* |
| Wizard Desk | `wizard-iaas-vps` (futuro) — VM, IP, backup job |
| Tile UI | Firewall, Cloud/VPS, Monitoring host — badge **IaaS** |
**Ligbox hoje (parcial):** regras Proxmox, pfSense WAN, VM112 como nó — encaixa neste nível para a camada «fogão+fogo».
---
### Nível 3 — PaaS → Plataforma gerenciada
*Equivalente: «Delivery» — ambiente pronto para deploy; cliente traz código/dados.*
| Gerido pela **Ligbox** | Gerido pelo **cliente** |
|------------------------|-------------------------|
| Infraestrutura (IaaS) | Código da aplicação |
| Banco de dados gerido | Dados de negócio |
| Deploy / CI/CD | — |
| Backup + SSL | — |
| Escalabilidade | — |
| Campo catálogo | Valor |
|----------------|-------|
| `delivery_model` | `paas` |
| `code` (ex.) | `k8s_managed`, `postgres_managed`, `cicd_pipeline`, `api_hosting` |
| Stack Ligbox | Kubernetes, PostgreSQL, Redis, GitLab, Traefik |
| Modelo comercial | Mensal por ambiente / por pipeline |
| Wizard Desk | `wizard-paas-k8s`, `wizard-paas-db` (futuro) |
| Tile UI | DevOps / CI/CD — badge **PaaS** |
---
### Nível 4 — SaaS → Solução completa gerenciada
*Equivalente: «Restaurante» — cliente só utiliza.*
| Gerido pela **Ligbox** | Gerido pelo **cliente** |
|------------------------|-------------------------|
| Tudo (infra → app → users ops) | Apenas **uso** — login, conteúdo, processos de negócio |
| Actualizações, segurança, backup | — |
| Monitoramento, suporte SLA | — |
| Campo catálogo | Valor |
|----------------|-------|
| `delivery_model` | `saas` |
| `code` (ex.) | `email_tenant`, `erpnext`, `suitecrm`, `nextcloud`, `wiki_js`, `bitwarden`, `zammad` |
| Modelo comercial | Por utilizador/mês · mensal por domínio · tier SLA |
| Wizard Desk | `vm112-mail` (e-mail) · wizards por produto (futuro) |
| Tile UI | E-mail Tenant (activo Fase 1) — badge **SaaS** |
**Ligbox hoje:** **E-mail Tenant** (Carbonio + portal + DNS + Traefik) = **SaaS / Managed Open Source** — produto flagship.
---
### Nível 5 — Managed Open Source Services (MOSP) — modelo ideal MSP
Camada comercial que a Ligbox deve priorizar: **software open source operado pela Ligbox; cliente só consome.**
| Serviço | Tecnologia | `catalog.code` | Cobrança sugerida | `delivery_model` |
|---------|------------|----------------|-------------------|------------------|
| E-mail corporativo (tenant) | Carbonio | `email_tenant` | mensal / domínio | `saas` |
| E-mail dedicado | Mailcow / VM dedicada | `mail_dedicated` | mensal / servidor | `saas` |
| Cloud Storage | Nextcloud | `nextcloud` | por utilizador | `saas` |
| ERP | ERPNext | `erpnext` | por utilizador | `saas` |
| CRM | SuiteCRM | `suitecrm` | por utilizador | `saas` |
| Wiki corporativa | Wiki.js | `wiki_js` | mensal | `saas` |
| Password Manager | Bitwarden | `bitwarden` | por utilizador | `saas` |
| Helpdesk | Zammad | `zammad` | mensal | `saas` |
| Chat corporativo | Mattermost | `mattermost` | mensal | `saas` |
| Git privado | Gitea | `gitea` | por utilizador | `saas` |
| VPN empresarial | WireGuard | `vpn_corporate` | por empresa | `iaas` |
| Monitoramento | Zabbix / Wazuh | `wazuh_domain`, `monitoring_host` | mensal | `iaas` / `saas` |
| Backup | Restic + MinIO | `backup_baas` | por GB | `iaas` |
| Firewall | pfSense | `firewall` | mensal | `iaas` |
| Site / CMS | ligbox-sites | `site_cms` | mensal | `saas` |
**Regra de produto:** cada linha do catálogo tem `delivery_model`, `managed_layers[]` (quais camadas da pizza a Ligbox opera) e `wizard_id` quando provisionável.
---
## Portfólio Ligbox — mapa completo (futuro)
### Infraestrutura
| Produto | Nível | `code` | Estado Desk |
|---------|-------|--------|-------------|
| Linux Managed Server | IaaS | `managed_vps` | Planeado |
| VPS Management | IaaS | `cloud` | Tile «Em breve» |
| Backup as a Service | IaaS | `backup_baas` | Planeado |
| Monitoring as a Service | IaaS/SaaS | `monitoring_host` | Parcial (Grafana/Infra) |
### Segurança
| Produto | Nível | `code` | Estado Desk |
|---------|-------|--------|-------------|
| Firewall as a Service | IaaS | `firewall` | Tile «Em breve» |
| VPN as a Service | IaaS | `vpn_corporate` | Planeado |
| Vulnerability Scanning | Tradicional | `vuln_scan` | Planeado |
| Wazuh SOC por domínio | SaaS | `wazuh_domain` | Tile «Em breve» + Infra 2 |
### Aplicações open source (MOSP)
| Produto | Nível | `code` | Estado Desk |
|---------|-------|--------|-------------|
| E-mail Tenant | SaaS | `email_tenant` | **Activo** (Spec 017 purge) |
| E-mail dedicado | SaaS | `mail_dedicated` | Tile «Em breve» |
| Nextcloud | SaaS | `nextcloud` | Planeado |
| ERP (ERPNext) | SaaS | `erpnext` | Planeado |
| CRM (SuiteCRM) | SaaS | `suitecrm` | Planeado |
| Site / CMS | SaaS | `site_cms` | Derivado VM112 |
| Wiki.js | SaaS | `wiki_js` | Planeado |
| Bitwarden | SaaS | `bitwarden` | Planeado |
| Zammad | SaaS | `zammad` | Planeado |
| Mattermost | SaaS | `mattermost` | Planeado |
| Gitea | SaaS | `gitea` | Planeado |
### DevOps
| Produto | Nível | `code` | Estado Desk |
|---------|-------|--------|-------------|
| Docker Hosting | PaaS | `docker_hosting` | Planeado |
| Kubernetes Hosting | PaaS | `k8s_managed` | Planeado |
| CI/CD Pipeline | PaaS | `cicd_pipeline` | Planeado |
### Suporte transversal
| Produto | Nível | `code` | Canal Desk |
|---------|-------|--------|------------|
| SLA empresarial | Overlay | `sla_enterprise` | Tickets + SLA fields |
| Monitoramento 24/7 | Overlay | `noc_24x7` | Infra + alertas |
| Administração remota | Tradicional | `remote_admin` | Assist takeover |
| Consultoria Linux | Tradicional | `consulting_hour` | Tickets |
---
## Modelo conceptual (actualizado)
```
Cliente (org)
└── Instância de serviço (service_instance)
├── service_catalog.code (email_tenant, firewall, nextcloud, …)
├── service_catalog.delivery_model (traditional | iaas | paas | saas)
├── managed_layers[] (datacenter, hypervisor, os, runtime, app, ops)
├── status (planned | provisioning | active | degraded | suspended)
├── commercial_plan (hourly | monthly_fixed | per_user | per_gb)
├── wizard_id (vm112-mail, wizard-iaas-vps, …)
├── sla_tier (basic | business | enterprise)
└── bindings[] (domain, vm_id, zone_id, agent_id, k8s_ns)
```
### Matriz de responsabilidade por `delivery_model`
| Camada | traditional | iaas | paas | saas |
|--------|:-----------:|:----:|:----:|:----:|
| Datacenter / link | C | L | L | L |
| Hypervisor / VM | C | L | L | L |
| SO / rede / firewall | C | L | L | L |
| Runtime (Docker, proxy) | C | C | L | L |
| BD / deploy / SSL | C | C | L | L |
| Aplicação open source | C | C | C | L |
| Backup / monitoramento | C | L | L | L |
| Utilizadores finais / dados negócio | C | C | C | C |
*C = Cliente · L = Ligbox*
### Catálogo de serviços — MVP + roadmap MOSP
| code | Label UI | delivery_model | Wizard | Fase Desk |
|------|----------|----------------|--------|-----------|
| `email_tenant` | E-mail Tenant | saas | `vm112-mail` | **Activo** |
| `site_cms` | Site / CMS | saas | `vm112-mail` | Derivado VM112 |
| `mail_dedicated` | Servidor E-mail Dedicado | saas | TBD | Em breve |
| `firewall` | Firewall (pfSense) | iaas | `wizard-iaas-fw` | Em breve |
| `cloud` | Cloud / VPS gerenciado | iaas | `wizard-iaas-vps` | Em breve |
| `wazuh_domain` | Wazuh / SOC por domínio | saas | `wizard-soc-wazuh` | Em breve |
| `vpn_corporate` | VPN empresarial | iaas | TBD | Planeado |
| `backup_baas` | Backup as a Service | iaas | TBD | Planeado |
| `nextcloud` | Nextcloud | saas | TBD | Planeado |
| `erpnext` | ERP (ERPNext) | saas | TBD | Planeado |
| `monitoring_host` | Monitoramento 24/7 | iaas | TBD | Planeado |
| `consulting_hour` | Consultoria / suporte | traditional | — (ticket) | Planeado |
### Derivação Fase 1 — Cliente a partir do domínio VM112
Enquanto não existir tabela `clients`:
| Campo cliente | Origem |
|---------------|--------|
| `client_id` | `domain` (chave estável) |
| `display_name` | `domain` |
| `subtitle` | `portal_admin_email` ou «sem admin portal» |
| `health` | `ok` se `carbonio_exists`, senão `warn` |
Cada domínio VM112 = **1 cliente** com pelo menos uma instância `email_tenant`.
### Separação VM122 vs VM112 (Roger — clarificação)
| Onde | Papel |
|------|--------|
| **Desk VM122** (`/opt/ligbox-ops-platform`) | Orquestração MOSP — clientes, tenants de oferta, purge OPS, estado |
| **Portal VM112** (`/opt/ligbox-wizard`) | **Apenas** wizard e-mail/domínio — Hero e `/onboard` **não** recebem catálogo multi-produto |
| **Futuro** | Cada oferta MOSP → wizard próprio (pode provisionar Proxmox, servidor físico, etc.) |
A página Serviços no Desk é o **painel do técnico**; os wizards são **um por produto**, nunca um megamenu na Hero da 112.
---
## Reteste E2E — wizard e-mail/domínio (após purge)
### Pré-requisitos
1. Domínio de teste **ausente** em VM112 (lista Serviços vazia para esse domínio)
2. Desk: menu **Serviços** → purge Spec 017 se ainda existir lixo
3. Utilizador Desk: `super_admin` ou `ops_lead`
### Passos
| # | Acção | Verificação |
|---|--------|-------------|
| 1 | Desk → **Serviços** → seleccionar domínio teste | Tile **E-mail Tenant** activo ou cliente ausente |
| 2 | Se existir: tile E-mail → **Purge** (senha Root + confirmar domínio) | Domínio desaparece da lista |
| 3 | Portal `onboard.ligbox.com.br` ou `onboard.ibytera.com` | Self-Service → registo → `/onboard` |
| 4 | Wizard: domínio → DNS → conta → infra | Webhooks no Desk (Tickets/Eventos) |
| 5 | Desk → **Serviços** → Actualizar | Cliente reaparece; tenant E-mail **Activo** |
| 6 | Modal: infra steps verdes, contas Carbonio | Purge disponível para próximo ciclo |
### Domínios protegidos (sem purge)
`ligbox.com.br`, `itecnologys.com`
## UI — Layout 3 colunas
```
┌─────────────────────────────────────────────────────────────────┐
│ Orquestração de Serviços [Actualizar] │
│ stats: clientes | e-mail activo | sites | logins portal │
├──────────────┬────────────────────────────┬─────────────────────┤
│ CLIENTES │ SERVIÇOS DO CLIENTE │ ESCOPO OPS │
│ [pesquisa] │ (tiles cPanel) │ (contexto serviço) │
│ • domain A │ [E-mail Tenant] activo │ Carbonio, CF, … │
│ • domain B │ [Site/CMS] activo │ nota purge │
│ │ [Firewall] em breve │ │
│ │ [Cloud] em breve │ │
│ │ [Wazuh] em breve │ │
└──────────────┴────────────────────────────┴─────────────────────┘
```
### Coluna Clientes
- Lista scrollável de todos os clientes (domínios VM112)
- Pesquisa: domínio, e-mail admin, login portal
- Badge saúde (verde/laranja)
- Clique selecciona cliente e actualiza tiles + escopo
### Coluna Serviços (centro)
- Grid de tiles por entrada do `SERVICE_CATALOG`
- Estados visuais: `active`, `inactive`, `planned`
- **Fase 2+:** badge `delivery_model` (IaaS / PaaS / SaaS / Suporte) e cor por nível
- **Fase 2+:** agrupamento por categoria — Infra · Segurança · Apps · DevOps · Suporte
- Tile **E-mail Tenant** activo → clique abre **modal Spec 017** (detalhe + purge)
- Tile **Site/CMS** → informativo (sem purge separado na Fase 1)
- Tiles `planned` → não clicáveis, label «Em breve» + tooltip com stack e modelo comercial
### Coluna Escopo OPS
- **Cards clicáveis** (2026-06-25) — camada (tenant / app / infra), Spec, destino OPS
- Lista dos escopos purge / operação quando serviço seleccionado
- **E-mail Tenant:** 6 escopos Spec 017 (Carbonio → Desk) — mapa na tabela § Escopo OPS cards
- **Blocklist:** banner + badge 🔒 para `ligbox.com.br`, `itecnologys.com`
- **Futuro:** escopo dinâmico por `service_catalog.purge_scopes_json`
- Indicador visual **quem gere** cada camada (matriz pizza — cliente vs Ligbox)
- Nota: purge requer senha Root no modal (serviços SaaS provisionados)
- Sem cliente seleccionado: texto de ajuda + link para portfólio (doc interna)
---
## Purge (sem regressão — Spec 017)
| Item | Mantido |
|------|---------|
| API | `POST /api/v1/vm112/domains/{domain}/purge` |
| Body | `confirm_domain`, `root_password` |
| RBAC | `super_admin`, `ops_lead` |
| Blocklist | `ligbox.com.br`, `itecnologys.com` |
| Escopos VM112 | Carbonio, site, portal, CF, Traefik, Desk |
| Modal | `#vm112-domain-modal` (index.html) |
O purge continua **por domínio** na Fase 1; na Fase 3 passa a `POST /api/v1/service-instances/{id}/purge` com escopo do catálogo.
---
## RBAC
Igual Spec 017 — `can_manage_vm112_domains()``super_admin`, `ops_lead`.
---
## API — Fase 1 (sem alteração)
Reutiliza endpoints Spec 017:
| Método | Path |
|--------|------|
| GET | `/api/v1/vm112/domains` |
| GET | `/api/v1/vm112/domains/{domain}` |
| POST | `/api/v1/vm112/domains/{domain}/purge` |
---
## API — Fase 2 (planeada)
| Método | Path | Descrição |
|--------|------|-----------|
| GET | `/api/v1/services/catalog` | Catálogo fixo + `delivery_model`, stack, wizard, preço ref |
| GET | `/api/v1/services/catalog/{code}` | Detalhe produto + matriz responsabilidade |
| GET | `/api/v1/clients?q=` | Lista clientes |
| GET | `/api/v1/clients/{id}` | Cliente + instâncias + bindings + SLA |
| POST | `/api/v1/service-instances` | Provisionar (trigger wizard por produto) |
| PATCH | `/api/v1/service-instances/{id}` | Suspender, reactivar, alterar plano |
| POST | `/api/v1/service-instances/{id}/purge` | Purge por instância (escopo do catálogo) |
### SQLite (Fase 2)
```sql
clients (
id, name, tax_id, primary_email,
hosting_mode, -- ligbox_cloud | dedicated_vps | customer_onprem
sla_tier, created_at
)
service_catalog (
code, label, category, -- infra | security | apps | devops | support
delivery_model, -- traditional | iaas | paas | saas
managed_layers_json, -- ["hypervisor","os","app",…]
technology_stack_json, -- ["Carbonio","Traefik",…]
wizard_id,
commercial_model, -- hourly | monthly_fixed | per_user | per_gb
purge_scopes_json,
default_enabled
)
service_instances (
id, client_id, catalog_code, status,
external_ref, meta_json,
commercial_plan, monthly_value_cents,
provisioned_at, expires_at
)
service_bindings (
instance_id, resource_type, resource_id
-- resource_type: domain | vm_id | zone_id | agent_id | k8s_namespace | ticket_id
)
```
### `hosting_mode` do cliente
| Valor | Significado | Pizza |
|-------|-------------|-------|
| `ligbox_cloud` | Hospedado na infra Ligbox (Proxmox/Hetzner) | Ligbox gere datacenter+fogão |
| `dedicated_vps` | VPS dedicado gerido pela Ligbox | IaaS+ |
| `customer_onprem` | Infra no cliente; Ligbox suporta/audita | Tradicional+ |
Um mesmo cliente pode misturar modos por instância de serviço (ex.: e-mail SaaS Ligbox + ERP on-prem com suporte tradicional).
---
## Ficheiros — Fase 1
| Ficheiro | Alteração |
|----------|-----------|
| `frontend/assets/accounts.js` | Refactor → `DeskServices`, layout 3 colunas |
| `frontend/assets/styles.css` | Classes `.servicos-*` |
| `frontend/index.html` | Nav «Serviços», cache bust |
| `frontend/assets/app.js` | Títulos view |
| `api/app/modules/registry.py` | Label módulo «Serviços» |
---
## Critérios de aceite — Fase 1
- [x] Menu mostra **Serviços** (não «Contas»)
- [x] Lista **todos** os clientes/domínios VM112 na coluna esquerda
- [x] Seleccionar cliente mostra tiles de catálogo (≥1 activo para e-mail)
- [x] Tile E-mail Tenant abre modal com detalhe + purge funcional
- [x] Purge remove domínio e actualiza lista (Spec 017)
- [x] Tiles futuros visíveis como «Em breve»
- [x] Escopo OPS visível na coluna direita
- [x] Escopo OPS **cards clicáveis** com camada + Spec + navegação (2026-06-25)
- [x] Blocklist visível na UI (lista + banner Escopo + modal)
- [x] Modal purge com **loading animado** durante consulta VM112
- [x] Tiles com badge **camada** (tenant / app / infra)
- [x] RBAC inalterado
---
## Critérios de aceite — Fase 2 (catálogo comercial)
- [ ] `GET /api/v1/services/catalog` devolve todos os produtos MOSP com `delivery_model`
- [ ] Tiles agrupados por categoria (Infra, Segurança, Apps, DevOps, Suporte)
- [ ] Badge IaaS / PaaS / SaaS / Suporte em cada tile
- [ ] Coluna OPS mostra matriz «cliente vs Ligbox» para serviço seleccionado
- [ ] Cliente com `hosting_mode` visível no banner
- [ ] Instâncias `traditional` ligadas a tickets (sem wizard)
---
## Critérios de aceite — Fase 3 (multi-wizard)
- [ ] Cada `catalog.code` com `wizard_id` abre wizard correcto
- [ ] Provisionar firewall → pfSense + regras + binding `vm_id`
- [ ] Provisionar Wazuh → agente + binding + link Infra 2 SOC
- [ ] Purge por `service_instance` com escopo do catálogo (não hardcoded domínio)
---
## Critérios de aceite — Fase 4 (MSP comercial)
- [ ] Plano comercial por instância (`commercial_plan`, valor ref.)
- [ ] SLA tier no cliente e alertas quando degradado
- [ ] Relatório «o que a Ligbox gere» exportável para proposta comercial (PDF/markdown)
- [ ] Upsell: tiles «Não contratado» com CTA interno para técnico sénior
---
## Evolução multi-wizard (Fase 3)
1. `service_catalog.wizard_id` aponta para endpoint VM112 ou outro nó
2. Tile activo com acção «Abrir wizard» / «Retomar onboarding»
3. Wazuh: binding `agent_id` + link para Infra 2 SOC
4. Firewall: binding `vm_id` + link pfSense API
5. Produtos MOSP (Nextcloud, ERPNext): wizard dedicado ou Helm + PaaS base
6. Produtos **traditional**: sem wizard — cria ticket + sessão assist (Spec 010)
### Prioridade sugerida de wizards (Roger)
| Ordem | Produto | Nível | Justificativa |
|-------|---------|-------|---------------|
| 1 | E-mail Tenant | SaaS | **Em produção** — VM112 |
| 2 | Firewall pfSense | IaaS | Já existe stack Proxmox + API |
| 3 | Wazuh por domínio | SaaS | Infra 2 SOC parcial |
| 4 | VPS gerenciado | IaaS | Base para outros produtos |
| 5 | Nextcloud | SaaS | Alto valor MOSP |
| 6 | ERPNext | SaaS | Upsell empresarial |
| 7 | K8s / CI/CD | PaaS | Clientes dev |
---
## Valor para o Técnico de Suporte Sénior
| Necessidade OPS | Como a página Serviços responde |
|-----------------|----------------------------------|
| «O que este cliente comprou?» | Tiles por `delivery_model` + estado |
| «O que nós gerimos vs cliente?» | Matriz pizza / `managed_layers` |
| «Onde está provisionado?» | Bindings (domínio, VM, zona, agente) |
| «Posso apagar para teste?» | Purge Spec 017 (e-mail) → generalizado Fase 3 |
| «Qual wizard retomar?» | `wizard_id` + estado `provisioning` |
| «Isto é incidente ou gap comercial?» | Tile «Não contratado» vs `degraded` |
---
## Referências
- Spec 017 — purge domínio VM112
- Spec 015 — registry módulos `overview-home`
- Spec 010 — assist takeover (suporte tradicional)
- VM112 API — `/api/admin/domains`
- Analogia comercial — **Pizza as a Service** (On-Prem → IaaS → PaaS → SaaS)
- Posicionamento MSP — **Managed Open Source Services (MOSP)**