# Spec 030 — Agentic Ops UI (Mission Board) **Criado:** 2026-06-20 **Solicitado por:** Roger **Prioridade:** P1 (UX operacional — pós Spec 029 MVP) **Status:** ✅ Implementado (UI-A/B/C) — produção VM122 **Sistema:** Desk VM122 · view `agentic-ops` **Relacionado:** Spec **029** (API + agentes) · Spec **033** (proc-card / modal) · Spec **019** (hub CH-* — futuro link) **Referências externas (padrões UX, não fork):** - [Mission Control](https://github.com/builderz-labs/mission-control) — mission board, inbox, timeline, SSE - [Agent Track Dashboard](https://github.com/jenna-studio/agent-track-dashboard) — kanban por agente/tarefa --- ## Problema actual (029 MVP) | Sintoma | Causa | |---------|--------| | 140+ threads repetidas | Cada tick cron cria finding + thread novo (mesmo cenário) | | 3 colunas iguais visualmente | Roster, inbox e findings competem sem hierarquia | | Dropdown de threads inútil | Lista longa, sem agrupamento | | Operador perde foco | Não há “o que fazer agora” num só sítio | **Objectivo:** transformar Agentic Ops num **painel de comando** (mission board), não num dump de mensagens. --- ## Princípios de design 1. **Um problema = um card** — deduplicação por `scenario_id` (não por `finding_id`) 2. **Severidade manda** — layout lido de cima: Crítico → Alto → Aviso → OK 3. **Agente visível** — cor/avatar por A0–A7 + Vigia (Spec 029 roster) 4. **Acção humana clara** — cada card: título, última detecção, passo sugerido (T0/T1), botões Ack / Abrir thread / Atribuir 5. **Contexto à direita** — thread + chat Copiloto só quando o operador selecciona um card 6. **Status bar sempre visível** — tier T0/T1, Ollama, último tick, contagem aberta --- ## Wireframe — desktop (≥1200px) ```text ┌──────────────────────────────────────────────────────────────────────────────┐ │ AGENTIC OPS [T1 · Ollama OK] último tick 06:32 │ 12 abertos │ ↻ │ ├────────────┬─────────────────────────────────────────────────┬───────────────┤ │ FROTA │ MISSION BOARD (kanban horizontal) │ CONTEXTO │ │ │ │ │ │ ● Maestro │ ┌─ CRÍTICO ─┐ ┌─ ALTO ────┐ ┌─ AVISO ──┐ ┌ OK ┐│ Thread #47 │ │ ○ Pulso │ │ (vazio) │ │ FOSSBill │ │ OpenPanel│ │ 5 ││ FOSS VM123 │ │ ○ Trilho │ │ │ │ VM123 │ │ bridge │ │ ││ │ │ ○ Copiloto │ │ │ │ gap 415m │ │ funil 10 │ │ ││ [timeline] │ │ … │ └───────────┘ └───────────┘ └──────────┘ └────┘│ Vigia → humano│ │ │ ↑ card activo (borda) │ │ │ [filtro │ Card: cenário · agente · há 8 min · ack │ [responder] │ │ agente] │ │ │ │ │ Timeline compacta (últimas 24h, collapsible) │ Copiloto A6 │ │ │ ████░░ ticks · 4 findings únicos │ [perguntar…] │ └────────────┴─────────────────────────────────────────────────┴───────────────┘ ``` ### Mobile / tablet (<1200px) - Tab bar: **Board** | **Frota** | **Contexto** - Kanban vira lista vertical por severidade (accordion) --- ## Componentes UI | Componente | Descrição | Ficheiro alvo (v1) | |------------|-----------|-------------------| | `AgenticStatusBar` | tier, ollama, last_tick, counts | `agentic-ops.js` ou `agentic-ops/` | | `AgentFleetRail` | A0–A7 compacto + pulse se finding aberto | idem | | `MissionBoard` | 4 colunas severidade, cards deduplicados | idem | | `IncidentCard` | cenário, agente, age, action, CTA | idem | | `RunTimeline` | últimos N ticks / runs (sparkline ou lista) | idem | | `ContextPanel` | thread messages + reply + chat A6 | idem | | `EmptyState` | “Nenhum alerta — último tick OK” | idem | **Tokens visuais:** reutilizar `styles.css` Desk (`.card`, `.pill`, `.badge`, cores SOC existentes). **Cores por agente (proposta):** | ID | Accent | Uso | |----|--------|-----| | A0 Maestro | `#6366f1` | coordenação | | A1 Pulso | `#22c55e` | nós/VM112 | | A2 Trilho | `#3b82f6` | rede/DNS | | A6 Copiloto | `#a855f7` | chat | | Vigia | `#f59e0b` | findings T0 | | A7 Remediador | `#ef4444` | acções (futuro) | --- ## Modelo de dados — deduplicação (backend) ### Regra - **Incidente activo** = 1 por `(scenario_id)` enquanto existir finding `open` (não ack) - Novos ticks **actualizam** o incidente (last_seen, count, latest_finding_id) em vez de criar thread nova - Thread **reutilizada** via `related_scenario_id` (nova coluna) ou lookup por cenário ### Tabela nova (proposta) ```sql CREATE TABLE agent_incidents ( id INTEGER PRIMARY KEY, scenario_id TEXT NOT NULL UNIQUE, primary_agent TEXT NOT NULL, severity TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'open', -- open | ack | resolved title TEXT NOT NULL, latest_finding_id INTEGER, occurrence_count INTEGER NOT NULL DEFAULT 1, first_seen_at TEXT NOT NULL, last_seen_at TEXT NOT NULL, suggested_human_action TEXT, thread_id INTEGER, acknowledged_at TEXT, acknowledged_by TEXT ); ``` ### API nova (v1.1 agents) | Método | Path | Descrição | |--------|------|-----------| | GET | `/api/v1/agents/incidents` | Lista deduplicada para kanban (`?status=open`) | | GET | `/api/v1/agents/incidents/{id}` | Detalhe + timeline runs recentes | | POST | `/api/v1/agents/incidents/{id}/ack` | Ack incidente + fecha thread inbox | | GET | `/api/v1/agents/overview` | Status bar: last_tick, counts by severity, ollama | **Compatibilidade:** endpoints 029 (`/inbox`, `/findings`, `/threads`) mantidos; UI 030 consome preferencialmente `/incidents` + `/overview`. Ver [`contracts/agentic-ui-api.md`](contracts/agentic-ui-api.md). --- ## Fluxos operador ```mermaid flowchart LR A[Login Desk] --> B[Agentic Ops] B --> C{Overview} C --> D[Mission Board] D --> E[Seleccionar card] E --> F[Context Panel: thread] F --> G{Acção} G --> H[Ack / Arquivar] G --> I[Reply humano] G --> J[Chat A6 T1] H --> D I --> F J --> F ``` --- ## Fases de entrega | Fase | Entrega | Depende | |------|---------|---------| | **UI-A** | Status bar + Mission Board (dados actuais `/findings` agrupados no frontend) | — | | **UI-B** | Backend `agent_incidents` + dedup no tick | UI-A | | **UI-C** | Fleet rail + timeline + mobile tabs | UI-A | | **UI-D** | SSE/poll 30s (live refresh) | Spec 029 H3 | | **UI-E** | Link card → ticket Desk / CH-* hub | Spec 019 | Detalhe: [`tasks.md`](tasks.md). --- ## Critérios de aceitação - [ ] Operador vê **≤10 cards** para os 4 cenários recurrentes actuais (não 140 threads) - [ ] Card mostra: severidade, agente, cenário, “há X min”, acção sugerida - [ ] Click card abre contexto com thread **única** por cenário - [ ] Ack remove card da coluna activa - [ ] Status bar reflecte último tick worker (<15 min em produção) - [ ] Layout responsivo (3 tabs em mobile) - [ ] Zero regressão auth JWT / RBAC Spec 027 --- ## Fora de scope (030) - Substituir API 029 por Mission Control externo - WebSocket full-duplex (fica UI-D / Spec 029 H3) - Runbooks R0–R3 automáticos (Spec 029 H2) - React rewrite completo do Desk (opcional fase futura `agentic-ops/` Vite) --- ## Referências internas - [`design/wireframes.md`](design/wireframes.md) — detalhe visual e estados - [`contracts/agentic-ui-api.md`](contracts/agentic-ui-api.md) — contrato API v1.1 - Spec 029 [`agents-roster.md`](../029-agentic-ops-runbooks/agents-roster.md)