From 8bbfaf6ac66de95e555e8534dd3efa4e4371eafd Mon Sep 17 00:00:00 2001 From: gti Date: Tue, 22 Sep 2026 16:43:20 -0300 Subject: [PATCH] docs: specify operational control panel ux --- ...-control-panel-operational-ux-v1-design.md | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-22-control-panel-operational-ux-v1-design.md diff --git a/docs/superpowers/specs/2026-09-22-control-panel-operational-ux-v1-design.md b/docs/superpowers/specs/2026-09-22-control-panel-operational-ux-v1-design.md new file mode 100644 index 0000000..b2dfdee --- /dev/null +++ b/docs/superpowers/specs/2026-09-22-control-panel-operational-ux-v1-design.md @@ -0,0 +1,111 @@ +# Control Panel Operational UX Refinement V1 + +## Scope + +Refine the existing FastAPI/Jinja2 control panel for daily GTI operations. The +panel must answer which client/server needs attention, why, and which safe +operator action is available. This work does not change fiscal rules, the +Hub/Agent protocol, Firebird access, AI write controls, or deployment. + +## Design Choices + +The implementation keeps the existing server-rendered architecture: + +- `control_plane.py` remains the bounded query/view-model layer. +- A small presentation helper formats UTC timestamps using a configurable UI + timezone, defaulting to `America/Bahia`. +- Existing models are reused. `FiscalContextEntry` stores validated operator + context, `Job` schedules reprocessing, and `AuditEvent` records the complete + action context. No new write capability is introduced. +- Jinja2 templates receive operational view models, not raw ORM rows. Technical + IDs remain secondary detail information. +- CSS remains project-local and JavaScript is limited to progressive enhancement; + blocker resolution is a server-rendered form, not a `window.confirm` action. + +## Dashboard Semantics + +Health cards include `ONLINE`, `DEGRADED`, `OFFLINE`, `FAILED`, and `UNKNOWN`. +The query layer exposes a reconciled total and tests enforce: + +`agents_total == online + degraded + offline + failed + unknown`. + +Fiscal metrics are separate: + +- `safe_blocked_products`: distinct active products represented by open blockers. +- `open_blockers`: active blocker rows. + +The dashboard labels these independently and never presents one as the other. +Attention items are a deterministic maximum of ten, ordered by `FAILED`, +`DEGRADED`, `OFFLINE`, `UNKNOWN`, required blockers, and important version +drift. Each item contains client, display name, hostname, main problem, age, +and a safe detail/filter link. Failed jobs and outdated Agents are compact +sections with empty states. + +## Presentation + +UTC remains the storage/API representation. The UI renders both a human short +form (`22/09/2026 16:11`) and relative age (`há 8 min`); the full technical +timestamp is available as a `title` attribute. The timezone comes from +`UI_TIMEZONE`, with `America/Bahia` as the development default. + +Agents lead with client, display name, and hostname. Technical health and fiscal +status are separate badges. Fiscal coverage includes total, complete, safe +blocked, failed, and percentage with a worst-coverage sort option. + +Jobs show client, installation/display name, hostname, job ID, kind, status, +human timestamps, duration, and error. Blockers show client/installation, +product, field, type, deterministic operational priority, age, and links to a +detail page. + +## Blocker Operations + +The blockers page has visible server-side filters for client, installation, +field, blocker type, status, age, and product/search. Its summary reports open +blockers, distinct affected products, distinct affected clients, and field +breakdown (`CFOP`, `ST`, `ICMS`, `CSOSN`, `NCM`, `OTHER`). + +Priority is operational only and deterministic: + +- `CRITICAL`: technical/unsafe condition that prevents processing. +- `HIGH`: required field missing for an active product or a relevant conflict. +- `NORMAL`: safe blocker without immediate operational urgency. +- `LOW`: optional/reference enrichment. + +Clicking a blocker opens a detail page with evidence, first/last seen, retry +count, related events/jobs, and resolution history. The resolution form shows +the client, server, product, description, field, type, reason, evidence, and +current value. It accepts a validated context key, value, scope (`PRODUCT`, +`GROUP`, or `COMPANY`), and reason/note. Known enum keys are validated by the +existing `context_keys` rules; arbitrary context values cannot bypass backend +validation. + +On save, the transaction creates/updates the validated `FiscalContextEntry`, +creates a bounded reprocess job for the product, and records an audit event +containing operator, timestamp, client, installation, product, blocker, +context key/scope/value, reason, before/after values, and reprocess job ID. +The operation remains protected by human auth, CSRF, and authorization. It +cannot enable AI writes, Firebird writes, SQL, or shell execution. + +## Detail Pages and Events + +Agent detail shows client/display name/hostname first, technical/fiscal/version +badges, human last-seen, version, company, UF, CRT, and secondary technical IDs. +Fiscal summary is bounded and links to filtered blockers. Event rows have human +timestamps, severity, event type, message, and related job/product links, with +server-side severity/type/date/job/product filters and pagination. + +## Password Policy + +Weak local development passwords are allowed only when explicitly enabled by +`ALLOW_WEAK_DEV_PASSWORD=1` and only when `APP_ENV` is not `production`. +Production always requires the strong password policy. The existing local admin +credential is not changed. + +## Verification + +Tests cover health reconciliation, metrics distinction, timestamps, attention +ordering/limit, fiscal percentage, human job identity/duration, blocker filters +and detail, resolution validation/audit/CSRF/authorization, events, and +environment-aware password policy. Full `tests`, `central/tests`, and +`agent/tests` regressions plus local route/runtime and bounded performance +smokes are required before completion.