# Feature Specification: Audit Overview Dashboard (009)

**Feature Branch**: `009-ops-audit-overview`

**Created**: 2026-06-08

**Status**: Draft

**Input**: Dashboard estilo Cloudflare Ops — health e scorecard por tenant/EmailServer (~10 nós), com 8 checks read-only alinhados ao portal onboarding. Primeira entrega do Track A (AUD-1, AUD-2, AUD-3).

**Depends on**: MVP Ops VM122 (API, worker, tenants table); VM112 como primeiro tenant auditado

## User Scenarios & Testing *(mandatory)*

### User Story 1 — Overview multi-tenant (Priority: P1)

A equipa ops abre `/ops/overview` (ou tab Infra expandida) e vê cards por tenant registado com estado global: OK / Atenção / Crítico.

**Why this priority**: Core da visão "painel cheio de informação" — saúde de todos os nós num ecrã.

**Independent Test**: Com VM112 registada, overview mostra card com score 6/8 checks OK.

**Acceptance Scenarios**:

1. **Given** tenant VM112 com todos checks verdes, **When** overview carrega, **Then** card mostra `healthy` e score `8/8`.
2. **Given** check DKIM falhou, **When** overview carrega, **Then** card mostra `degraded` e lista check falhado.
3. **Given** tenant API inacessível, **When** collector falha, **Then** card mostra `unknown` com timestamp última tentativa.

---

### User Story 2 — Scorecard 8 checks por domínio (Priority: P1)

Por tenant, a equipa vê detalhe dos 8 checks alinhados ao wizard portal: Carbonio, nginx/vhost, certificado LE, MX, SPF, DKIM, DMARC, webmail HTTP.

**Why this priority**: Diagnóstico actionable — sabe exactamente o que corrigir sem SSH manual.

**Independent Test**: Abrir scorecard VM112 para `diarissima.com` (ou domínio activo) e ver 8 linhas com pass/fail.

**Acceptance Scenarios**:

1. **Given** domínio com SPF correcto, **When** scorecard renderiza, **Then** check `spf` = pass com valor detectado.
2. **Given** certificado expira em < 14 dias, **When** scorecard renderiza, **Then** check `cert` = warn.
3. **Given** webmail responde HTTP 200, **When** check `webmail`, **Then** pass com URL testada.

---

### User Story 3 — Collectors automáticos (Priority: P1)

Worker Ops executa collectors read-only periodicamente (sem alterar sistemas remotos) e persiste snapshots.

**Why this priority**: Dados frescos sem refresh manual; base para alertas futuros.

**Independent Test**: Após ciclo worker (≤ 15 min), `GET /api/v1/audit/overview` reflecte dados novos.

**Acceptance Scenarios**:

1. **Given** worker activo, **When** passam 10 minutos, **Then** `last_audit_at` actualiza.
2. **Given** collector DNS timeout, **When** falha, **Then** check marcado `error` com mensagem; outros checks continuam.

---

### User Story 4 — Domínios monitorizados (Priority: P2)

Cada tenant pode ter 1+ domínios monitorizados (inicialmente domínios vistos em eventos onboarding ou lista manual).

**Why this priority**: EmailServers multi-domínio; MVP pode começar com domínio principal do tenant.

**Independent Test**: Domínio de evento `account.created` aparece automaticamente em scorecard.

**Acceptance Scenarios**:

1. **Given** evento `account.created` para `foo.com`, **When** próximo audit cycle, **Then** `foo.com` entra em domínios monitorizados do tenant VM112.

---

### Edge Cases

- Tenant sem domínios conhecidos: scorecard vazio com hint "aguardar onboarding".
- Check intermitente (DNS): último resultado + contagem falhas consecutivas.
- VM112 portal down: checks locais Carbonio via API read-only falham gracefully.
- Múltiplos tenants (futuro 10 nós): overview pagina ou scroll; MVP suporta ≥ 3.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: Ops DEVE expor `GET /api/v1/audit/overview` — lista tenants com status agregado e score.
- **FR-002**: Ops DEVE expor `GET /api/v1/audit/tenants/{id}/scorecard?domain=` — 8 checks detalhados.
- **FR-003**: Worker DEVE executar collectors a cada `AUDIT_INTERVAL_SEC` (default 600s).
- **FR-004**: Collectors DEVEM ser read-only — sem zmprov write, sem alterar DNS/Traefik.
- **FR-005**: Os 8 checks MVP: `carbonio`, `nginx_vhost`, `cert_le`, `dns_mx`, `dns_spf`, `dns_dkim`, `dns_dmarc`, `webmail_http`.
- **FR-006**: Resultado por check: `pass` | `warn` | `fail` | `error` | `skip` + `message` + `checked_at`.
- **FR-007**: Persistência em SQLite: tabelas `audit_domains`, `audit_checks` (último snapshot por tenant+domain+check).
- **FR-008**: UI DEVE ter view **Overview** (ou expandir Infra) com grid de cards tenant.
- **FR-009**: UI DEVE permitir drill-down scorecard por tenant/domínio.
- **FR-010**: Domínios auto-registados a partir de eventos webhook `account.created` / `onboarding.completed`.
- **FR-011**: VM112 primeiro tenant: collectors usam API portal read-only (`/onboarding/infrastructure/status/{domain}`, `/dns/verify/{domain}`) + HTTP externo DNS/webmail.

### Key Entities

- **Audit Domain**: tenant_id, domain, source (`onboarding` | `manual`), added_at.
- **Audit Check**: check_id, status, message, evidence (JSON), checked_at.
- **Tenant Health**: aggregated from worst check status.

### Status aggregation rules

| Pior check | Tenant status |
|------------|---------------|
| fail | critical |
| error | critical |
| warn | degraded |
| pass/skip | healthy |

## Success Criteria *(mandatory)*

- **SC-001**: Overview carrega em < 2s com 3 tenants e 5 domínios.
- **SC-002**: 8/8 checks executados para domínio activo VM112 em ciclo worker.
- **SC-003**: Equipa identifica problema deliverability (SPF/DKIM/DMARC) via scorecard sem SSH.
- **SC-004**: Dados actualizados automaticamente ≤ 15 min (configurável).
- **SC-005**: Zero writes em sistemas remotos durante audit (verificável por logs).

## Assumptions

- VM112 portal API acessível na LAN `:8090` (já usado por `vm112/status`).
- Checks DNS via resolver público (8.8.8.8) ou biblioteca dns.resolver — read-only.
- Webmail check: HEAD/GET `https://mail.{domain}/` timeout 10s.
- Cert check: expiry via portal infra status ou TLS handshake directo.
- Postgres não necessário — SQLite suficiente para MVP.
- Agentes IA (AUD-4) fora de scope — só collectors determinísticos.

## Dependencies

- Constitution v1.0.0
- Tenant registry (tabela `tenants` existente)
- Worker Redis container existente em VM122
- Feature 004 opcional (auto-domínios) — pode usar só `account.created` events já existentes

## Out of Scope

- Agentes IA A1/A2/A3 (AUD-4, AUD-5)
- Alterações automáticas / remediation
- Poll Wazuh API
- Auth RBAC (003)
- Alertas email/ntfy por check fail
- 10 tenants hardcoded — registo manual OK para MVP além de VM112

## The 8 Checks (aligned portal)

| ID | Check | Fonte read-only |
|----|-------|-----------------|
| 1 | carbonio | Portal ou zmprov read via API VM112 |
| 2 | nginx_vhost | `infrastructure/status` → carbonio_nginx_vhost |
| 3 | cert_le | infra status → cert expiry |
| 4 | dns_mx | DNS lookup MX → mail.{domain} |
| 5 | dns_spf | DNS TXT SPF |
| 6 | dns_dkim | DNS TXT default._domainkey |
| 7 | dns_dmarc | DNS TXT _dmarc |
| 8 | webmail_http | HTTPS mail.{domain} status code |
