# Spec 039 — Catálogo Mestre de Autorização Ligbox OPS **Criado:** 2026-06-29 **Solicitado por:** Roger **Status:** Aprovado Roger 2026-06-29 — catálogo completo (TODAS superfícies) **Prioridade:** P0 (governança — pré-requisito da UI Matriz + Controle de acesso) **Estende:** Spec **003** (RBAC base), **027** (matriz por função), **015** (módulos Desk), **019** (Console) **Sistemas:** VM122 Desk · VM123 Console/Finance · VM112 Onboard · VM104 Wazuh · Infra (Proxmox, Traefik, pfSense) --- ## 1. Problema (demanda Roger) Hoje sabemos que **root / `super_admin`** faz tudo (criar, autorizar, gerir, trocar senha), mas **não está documentado nem exposto na UI** o mapa completo de: - O que **cada função** (`SU`, `CO`, `TEC`, `NOC`, …) pode fazer - **Porquê** (regra de negócio / risco) - **Onde** (Desk, Console, FOSS, Odoo, OpenPanel, VM112, APIs internas) - **A nível de ação** (não só “módulo ON/OFF”): ex. deletar instância OpenPanel, atualizar processo, purge domínio, aprovar runbook A7 Sem este catálogo, a **Matriz de Acesso** e o **Controle de acesso** mostram toggles e módulos, mas **não fecham o mapa** de atribuições por posição. **Objetivo desta spec:** ser a **fonte única de verdade** para enumerar operações × funções × ambientes, alimentar a Matriz UI (Spec 027-UI) e implementação RBAC (`permissions.py`, bindings Odoo-style, provisionamento VM123). --- ## 2. Relação com specs existentes | Documento | Nível | O que falta para Matriz completa | |-----------|-------|----------------------------------| | [Spec 027](../027-desk-rbac-function-matrix/spec.md) | Função × módulo × ambiente (✅🔒🔗) | Granularidade por **ação** dentro de cada módulo/produto | | [Spec 027 UI](../027-desk-rbac-function-matrix/ui-access-matrix.md) | Wireframes Matriz | Dados estruturados (YAML) por ação | | [vm123-product-roles](../027-desk-rbac-function-matrix/contracts/vm123-product-roles.md) | FOSS/Odoo/OpenPanel grupos | Lista exaustiva endpoints FOSS + OpenPanel CE | | `platform_role_catalog.py` | Bindings por função | Sincronizar com catálogo 039 | | `permissions.py` | ~30 helpers `can_*` | Um helper por `action_id` do catálogo | | Controle de acesso (UI) | Toggles informativos | Persistência + ligação a `action_id` | **Regra:** Spec 039 **não substitui** 027 — **detalha** cada célula da matriz 027 em linhas de ação auditáveis. --- ## 3. Taxonomia de autorização ### 3.1 Camadas ```text FUNÇÃO (desk_role) ex.: super_admin, ops_lead → código UI: SU, CO, TEC └── MÓDULO / PRODUTO ex.: admin-users, foss.client, openpanel.site └── AÇÃO ex.: user.create, domain.purge, instance.delete └── RECURSO ex.: desk_user, vm112_domain, openpanel_vhost ``` ### 3.2 Níveis de efeito (`access_level`) | Código | Significado | UI Matriz | |--------|-------------|-----------| | `full` | CRUD / executar sem aprovação | ✅ | | `approve` | Executar após aprovação humana | 🟡 | | `read` | Só leitura (pode mascarar PII) | 🔒 | | `link` | Deep-link / abrir consola externa | 🔗 | | `api` | Só via API Desk (M2M ou token) | ⚙️ | | `system` | Conta sistema / agente | 🤖 | | `none` | Proibido | ❌ | ### 3.3 Superfícies (`surface`) | ID | Descrição | Host | |----|-----------|------| | `desk` | Ligbox Ops Desk (VM122 UI + API) | desk.ligbox.com.br | | `console` | Ligbox Ops Console (Spec 019) | console.ligbox.com.br | | `vm112` | Wizard + Carbonio + API onboard | onboard.ligbox.com.br | | `vm123_foss` | FOSSBilling Admin API | financeiro.ligbox.com.br | | `vm123_odoo` | Odoo 16 XML-RPC | financeiro.ligbox.com.br/odoo | | `vm123_openpanel` | OpenPanel / OpenAdmin / bridge | openpanel.ligbox.com.br | | `infra` | Proxmox, Traefik, pfSense, SSH hosts | LAN | | `agents` | Agentes A0–A7 | VM122 agentic | ### 3.4 Identificador de ação (`action_id`) Formato: `{surface}.{domain}.{verb}` — exemplos: - `desk.auth.user.create` - `desk.auth.user.freeze` - `vm112.domain.purge` - `vm123_openpanel.instance.delete` - `vm123_foss.invoice.void` - `console.case.runbook.execute` --- ## 4. Catálogo de funções (códigos UI) | Código | `desk_role` | Categoria | Mandato resumido | |--------|-------------|-----------|------------------| | **RO** | `root` (utilizador) | Sistema | Conta física dono — bypass humano; não é role atribuível | | **SU** | `super_admin` | Ops | Tudo no Desk + purge + users + módulos + agentes | | **CO** | `ops_lead` | Ops | Operação diária, audit, domínios, tickets, aprovações ops | | **TEC** | `technician` | Ops | Tickets atribuídos, assist/takeover, migração e-mail | | **NOC** | `noc` | Ops | Monitorização read-only, Wazuh, dados mascarados | | **SAD** | `sales_admin` | Comercial | Pipeline, billing validation, FOSS/Odoo manager | | **SSU** | `sales_support` | Comercial | CRM, pedidos, clientes — sem validar billing | | **FIN** | `finance` | Negócio | FOSS/Odoo fiscal, faturas, inadimplência | | **MKT** | `marketing` | Negócio | Campanhas, produtos FOSS, leads | | **SEO** | `seo` | Negócio | DNS, sites OpenPanel, performance | | **DEV** | `developer` | Plataforma | Código, GitHub, APIs, deploy Desk | | **DVO** | `devops` | Plataforma | Infra, Proxmox, OpenAdmin, SSH | | **SOC** | `security_analyst` | Plataforma | Incidentes, Wazuh rules, resposta | | **CMS** | `content_editor` | Plataforma | Sites clientes OpenPanel | | **AIO** | `agentic_operator` | Plataforma | Aprovar runbooks A7, findings | | **SVC** | `api_service` | Sistema | M2M webhooks, provisionamento | | **AGT** | `agent_system` | Sistema | Agentes IA autónomos | | **PTR** | `partner` | Comercial | Revendedor — clientes próprios, OpenPanel Reseller, FOSS scoped | ### 4.1 Funções RBAC custom (UI) Funções criadas via `POST /rbac/roles` **MUST** herdar de um único template: | Template permitido | `desk_role` base | Uso | |--------------------|------------------|-----| | **CO** | `ops_lead` | Coordenação, aprovações ops, purge (sem gestão users) | | **TEC** | `technician` | Suporte restrito — tickets assigned, assist | **Proibido:** herdar de SU, FIN, DVO ou escolha livre de permissões avulsas no MVP. --- ## 5. Inventário de ações — Controle de identidade (Desk VM122) ### 5.1 Gestão de utilizadores (`desk.auth.*`) | action_id | Descrição | SU | CO | Demais | API / UI | |-----------|-----------|:--:|:--:|:------:|----------| | `desk.auth.user.list` | Listar utilizadores Desk | full | none | none | GET `/v1/auth/users` | | `desk.auth.user.create` | Criar utilizador (directo) | full | none | none | *gap — hoje só via registo+aprovação* | | `desk.auth.user.approve_registration` | Aprovar pedido cadastro | full | **full** | none | POST `/v1/auth/registration-requests/{id}/approve` | | `desk.auth.user.reject_registration` | Rejeitar pedido | full | **full** | none | POST `.../reject` | | `desk.auth.user.edit` | Editar nome, role, display | full | none | none | PATCH `/v1/auth/users/{username}` | | `desk.auth.user.freeze` | Desactivar conta (`active=false`) | full | none | **SSU: none** | PATCH `active` | | `desk.auth.user.password.reset` | Definir nova senha (admin) | full | none | none | PATCH `password` | | `desk.auth.user.2fa.reset` | Reset TOTP + backup codes | full | none | none | POST `.../reset-2fa` | | `desk.auth.user.delete` | Remover utilizador | none | none | none | *não implementado — usar freeze* | | `desk.auth.user.groups.assign` | Ligar grupos/bindings VM123 | full | none | none | Fase 3 `vm123/identity` | | `desk.auth.role.create` | Criar função custom RBAC | full | none | none | POST `/rbac/roles` | | `desk.auth.role.clone` | Clonar função | full | none | none | POST `/rbac/roles/{id}/clone` | | `desk.auth.role.freeze` | Pausar função | full | none | none | PATCH `/rbac/roles/{id}/status` | | `desk.auth.modules.toggle` | Activar/desactivar módulos Desk | full | none | none | PATCH `/v1/modules/{id}` | **Porquê:** credenciais humanas Ligbox = superfície de ataque máxima. **Excepção Roger:** CO aprova cadastros; freeze/reset senha permanece **SU only**; **SSU nunca congela**. ### 5.2 Conta própria (`desk.account.*`) | action_id | Descrição | Quem | |-----------|-----------|------| | `desk.account.password.change` | Trocar própria senha + 2FA | Qualquer autenticado | | `desk.account.2fa.setup` | Configurar TOTP | Qualquer autenticado | | `desk.account.console_handoff` | Token para Console | Staff com acesso Console | --- ## 6. Inventário — Módulos Desk (por `module_id`) Cada módulo (Spec 015 `registry.py`) decompõe-se em **acções UI + API**. Resumo por módulo: ### 6.1 `core` — Dashboard, Tickets, Conta | action_id | Descrição | SU | CO | TEC | NOC | SAD | SSU | |-----------|-----------|:--:|:--:|:---:|:---:|:---:|:---:| | `desk.ticket.list` | Ver tickets | full | full | full | read* | full | full | | `desk.ticket.read` | Detalhe ticket | full | full | full | read* | full | full | | `desk.ticket.patch` | Actualizar estado/notas | full | full | assigned | none | full | full | | `desk.ticket.assign` | Atribuir responsável | full | full | self | none | full | full | | `desk.ticket.close` | Fechar ticket | full | full | assigned | none | full | full | | `desk.dashboard.kpi` | KPIs resumo | full | full | full | read | full | full | \* NOC: dados sensíveis mascarados (Spec 003). ### 6.2 `overview-home` — Serviços IaaS (Spec 018) | action_id | Descrição | SU | CO | TEC | DVO | FIN | |-----------|-----------|:--:|:--:|:---:|:---:|:---:| | `desk.services.client.list` | Listar clientes/domínios | full | full | full | read | read | | `desk.services.catalog.read` | Catálogo cPanel/serviços | full | full | full | read | read | | `desk.services.process.update` | Actualizar processo onboard | full | full | read | api | none | | `desk.purge.auth.generate` | Gerar código purge (root pwd) | full | none | none | none | none | ### 6.3 `vm112-domains` + purge (Spec 017, 032) | action_id | Descrição | SU | CO | TEC | DVO | |-----------|-----------|:--:|:--:|:---:|:---:| | `vm112.domain.list` | Listar domínios orquestrados | full | full | read | read | | `vm112.domain.read` | Detalhe domínio | full | full | read | read | | `vm112.domain.purge` | Purge completo domínio | full | full | none | approve | | `vm112.purge.job.recover` | Recuperar job purge falhado | full | full | none | full | ### 6.4 `assist` — Wizard takeover (Spec 010) | action_id | Descrição | SU | CO | TEC | |-----------|-----------|:--:|:--:|:---:| | `desk.assist.session.list` | Sessões activas wizard | full | full | full | | `desk.assist.takeover` | Assumir sessão cliente | full | full | assigned | | `desk.assist.handoff` | Passar sessão | full | full | full | | `desk.assist.action.execute` | Acções assist aprovadas | full | full | assigned | ### 6.5 `billing-recurrence` (Spec 023) | action_id | Descrição | SU | CO | FIN | SAD | SSU | |-----------|-----------|:--:|:--:|:---:|:---:|:---:| | `desk.billing.account.read` | Ficha conta cliente | full | full | full | full | read | | `desk.billing.state.validate` | Validar billing_state | full | full | full | full | none | | `desk.billing.link.foss` | Deep-link FOSS | full | full | full | full | link | ### 6.6 `email-migration` (Spec 013, 019) | action_id | Descrição | SU | CO | TEC | DVO | |-----------|-----------|:--:|:--:|:---:|:---:| | `desk.migration.job.create` | Criar job imapsync | full | full | full | read | | `desk.migration.job.cancel` | Cancelar job | full | full | assigned | none | | `desk.migration.dns.gate` | Gate DNS pré-migração | full | full | full | read | ### 6.7 `infra` / `infra2-soc` (Spec 033) | action_id | Descrição | SU | CO | DVO | SOC | DEV | |-----------|-----------|:--:|:--:|:---:|:---:|:---:| | `desk.infra.stack.read` | Stack health VMs | full | full | full | full | read | | `desk.infra.stack.probe` | Executar probe serviço | full | full | full | read | api | | `desk.infra.deploy` | Deploy API/frontend | full | none | full | none | full | ### 6.8 `agentic-ops` (Spec 029, 030) | action_id | Descrição | SU | CO | AIO | SOC | DEV | |-----------|-----------|:--:|:--:|:---:|:---:|:---:| | `desk.agent.finding.read` | Ver findings | full | full | full | full | full | | `desk.agent.runbook.approve` | Aprovar remediação A7 | full | full | full | scope | none | | `desk.agent.binding.toggle` | UI/Focus/Approve agente×função | full | none | none | none | none | ### 6.9 `events`, `leads`, `audit`, `dns` Ver matriz Spec 027 §3.2 — cada endpoint `main.py` mapeia para `action_id` (anexo A em `contracts/action-catalog.yaml`). --- ## 7. Inventário — VM123 produtos (granular) ### 7.1 FOSSBilling (`vm123_foss.*`) Módulos API: `client`, `order`, `invoice`, `product`, `service`, `staff`, `support`, `extension`, hosting→OpenPanel. | action_id | sales_admin | sales_support | finance | marketing | developer | |-----------|:-----------:|:-------------:|:-------:|:---------:|:---------:| | `vm123_foss.client.create` | full | full | full | none | api | | `vm123_foss.client.delete` | full | none | full | none | none | | `vm123_foss.order.create` | full | full | read | none | api | | `vm123_foss.invoice.create` | full | read | full | none | none | | `vm123_foss.invoice.void` | full | none | full | none | none | | `vm123_foss.product.edit` | full | read | read | full | api | | `vm123_foss.staff.manage` | none | none | read | none | api | | `vm123_foss.hosting.provision` | full | full | read | none | api | Detalhe endpoints: [vm123-product-roles.md §2](../027-desk-rbac-function-matrix/contracts/vm123-product-roles.md). ### 7.2 Odoo 16 (`vm123_odoo.*`) | action_id | sales_admin | sales_support | finance | |-----------|:-----------:|:-------------:|:-------:| | `vm123_odoo.partner.read` | full | full | full | | `vm123_odoo.partner.write` | full | full | full | | `vm123_odoo.sale.order.create` | full | full | read | | `vm123_odoo.invoice.post` | full | none | full | | `vm123_odoo.account.move.validate` | none | none | full | Grupos: `group_sale_manager`, `group_sale_salesman`, `account.group_account_manager`. ### 7.3 OpenPanel (`vm123_openpanel.*`) | action_id | Descrição | SU | **CO** | SAD | SSU | SEO | CMS | DVO | |-----------|-----------|:--:|:--:|:---:|:---:|:---:|:---:|:---:| | `vm123_openpanel.site.create` | Novo site/vhost | full | full | full | full | full | full | full | | `vm123_openpanel.site.delete` | **Remover instância** | full | **full** | none | none | none | none | **none** | | `vm123_openpanel.ssl.manage` | Certificados LE | full | full | link | link | full | full | full | | `vm123_openpanel.db.create` | Base de dados | full | full | link | link | full | full | full | | `vm123_openpanel.cron.manage` | Cron jobs | full | full | none | none | read | full | full | | `vm123_openpanel.backup.restore` | Restaurar backup | full | full | none | none | none | read | full | | `vm123_openpanel.openadmin.access` | Painel OpenAdmin :2087 | full | full | link | none | link | none | full | | `vm123_openpanel.autologin.client` | Login cliente (bridge) | full | full | full | full | full | full | link | **Gap actual:** Desk não expõe toggles por `action_id` OpenPanel — só deep-links e provisionamento M2M. --- ## 8. Inventário — Console (Spec 019) **Decisão Roger:** Console na **mesma Matriz** do Desk (superfície `console`, aba dedicada, RBAC herda role Desk via handoff). | action_id | Descrição | SU | CO | TEC | SOC | AIO | |-----------|-----------|:--:|:--:|:---:|:---:|:---:| | `console.case.create` | Abrir chamado CH-* | full | full | full | full | read | | `console.case.assign` | Assumir chamado | full | full | full | full | none | | `console.case.timeline.read` | Timeline correlacionada | full | full | full | full | full | | `console.discover.search` | Discover (estilo Wazuh) | full | full | read | full | read | | `console.runbook.execute` | Executar runbook | full | full | none | scope | approve | | `console.wizard.assist.view` | Passo actual wizard | full | full | full | read | read | | `console.link.wazuh` | Deep-link VM104 | full | full | read | full | read | Console autentica via **handoff** Desk (`/v1/auth/console-handoff`) — RBAC herda role Desk. --- ## 9. Inventário — Partner / Revendedor (`partner` · PTR) | action_id | Descrição | PTR | Notas | |-----------|-----------|:---:|-------| | `desk.partner.dashboard.read` | Dashboard revendedor (clientes próprios) | full | Módulo `partner-portal` | | `vm123_foss.client.create` | Criar cliente FOSS (scoped) | full | Só tenants do partner | | `vm123_foss.order.create` | Pedidos FOSS | full | | | `vm123_foss.invoice.read` | Ver faturas clientes | read | Sem void | | `vm123_openpanel.site.create` | Provisionar hosting cliente | full | Via bridge | | `vm123_openpanel.autologin.client` | Painel cliente | full | | | `vm123_openpanel.site.delete` | Deletar instância | none | Só SU/CO Ligbox | | `desk.auth.*` | Qualquer gestão Desk | none | | | `console.*` | Console ops | none | | **OpenPanel nativo:** role `reseller` (Spec 028). **FOSS:** grupo `ligbox-partner` (criar no Admin). --- ## 10. Inventário — VM112 Wizard | action_id | Descrição | SU | CO | TEC | DEV | |-----------|-----------|:--:|:--:|:---:|:---:| | `vm112.wizard.session.read` | Estado sessão onboard | full | full | assigned | read | | `vm112.carbonio.mailbox.create` | Criar caixa mail | api | api | api | api | | `vm112.carbonio.block.release` | Libertar ACCOUNT_EXISTS | full | full | none | api | | `vm112.dns.verify` | Verificar DNS wizard | full | full | read | read | | `vm112.api.webhook.emit` | Emitir evento (sistema) | system | system | system | system | --- ## 11. Matriz resumida — Quem faz o quê (visão Roger) | Área | Quem manda | Porquê | |------|------------|--------| | Criar/editar/freeze utilizadores Desk | **SU** | Credenciais internas | | **Aprovar cadastros** | **SU**, **CO** | Roger — CO autónomo | | **Congelar users** | **SU only** — **SSU nunca** | Segregação comercial | | Purge domínio / dados cliente | **SU**, **CO** (DVO recover job) | Irreversível — Spec 032 | | Validar billing / faturação | **SU**, **CO**, **FIN**, **SAD** | Segregação comercial vs financeira | | FOSS pedidos e clientes | **SAD**, **SSU**, **PTR** (scoped) | Linha de frente | | FOSS faturas / void | **FIN**, **SU** | Risco fiscal | | **OpenPanel delete instance** | **SU**, **CO only** | Downtime — Roger 2026-06-29 | | OpenPanel conteúdo sites | **CMS**, **SEO**, **MKT** | Operação editorial | | Tickets / assist | **TEC** (assigned), **CO**, **SU** | Menor privilégio | | Infra / deploy | **DVO**, **DEV**, **SU** | Separação código vs infra | | Agentes A7 remediação | **AIO**, **CO**, **SU** | Human-in-the-loop | | Módulos Desk ON/OFF | **SU** | Feature flags globais | | **Console** | Mesma matriz Desk | Handoff — Roger | | **RBAC custom** | Herda **CO** ou **TEC** | Templates only | --- ## 12. Implementação — fechar o mapa na UI ### Fase A — Catálogo (esta spec) ✅ - [x] Taxonomia `action_id` - [x] Inventário por superfície (Desk + VM123 + Console + VM112 + Partner) - [x] Decisões Roger validadas (§13) ### Fase B — `contracts/action-catalog.yaml` ✅ v1.1 - Lista machine-readable: `action_id`, `label`, `surface`, `roles{}`, `api_route`, `spec_ref` - Gerar toggles Controle de acesso + export CSV Matriz ### Fase C — API RBAC - `GET /rbac/actions` — catálogo completo - `PATCH /rbac/roles/{id}/actions` — persistir overrides (só SU) - `permissions.py`: `can_action(role, action_id)` único entry point ### Fase D — UI - Aba **Controle de acesso**: toggles ligados a YAML (não só informativos) - Abas Matriz: filtrar por `surface` (Desk | FOSS | Odoo | OpenPanel | Console) - Sidebar função: mostrar **contagem de acções** full/read/none --- ## 13. Decisões Roger (2026-06-29) — FECHADAS | # | Pergunta | Decisão | |---|----------|---------| | 1 | `sales_support` congela utilizadores? | **Não** — só SU | | 2 | `ops_lead` aprova cadastros sem SU? | **Sim** — CO autónomo | | 3 | Deletar instância OpenPanel | **SU + CO only** (não DVO) | | 4 | Console na mesma Matriz? | **Sim** — mesma matriz Desk | | 5 | RBAC custom herda de? | **CO ou TEC only** | | 6 | Partner/revendedor | **Nesta spec** — função `partner` (PTR) | | 7 | Prioridade granularidade | **TODOS** — Desk + FOSS + Odoo + OpenPanel + Console | **Implementação código (parcial):** `can_approve_registration`, `can_openpanel_delete` → SU+CO; rotas registo actualizadas. --- ## 14. Critérios de aceite - **FR-039-001**: Cada `action_id` MUST ter exactamente uma linha no catálogo YAML. - **FR-039-002**: Cada função humana MUST ter coluna em todas as tabelas §5–9. - **FR-039-003**: UI Controle de acesso MUST reflectir catálogo (não lista hardcoded). - **FR-039-004**: Alteração de permissão MUST gerar audit log (`rbac_audit`). - **FR-039-005**: RO/root MUST NOT aparecer como role atribuível — só nota §4. - **FR-039-006**: Função `partner` MUST estar no catálogo com scope tenant isolado. - **FR-039-007**: RBAC custom MUST declarar `inherits_from: ops_lead | technician`. --- ## Anexos - `contracts/action-catalog.yaml` — inventário estruturado (geração automática) - `../027-desk-rbac-function-matrix/spec.md` — matriz macro - `../../projects/ops-desk/api/app/platform_role_catalog.py` — bindings código - `../../projects/ops-desk/api/app/permissions.py` — guards actuais