Files
GTI_GERENCIADOR_FISCAL/docs/superpowers/plans/2026-09-24-fiscal-operational-ui.md
T

11 KiB

GTI Fiscal Operational UI Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking. Work inline; the operator authorized proceeding without additional design confirmation.

Goal: Make Resumo, Agents, Blockers and Jobs a fast, accessible, PT-BR operational workflow where each important aggregate reaches a filtered detail in one click, with revoked/inactive history excluded from live indicators.

Architecture: A single SQLAlchemy active-installation predicate is shared by dashboard aggregates and paged list queries. Small presenter helpers translate labels; Jinja templates render native links and bounded summaries using Gerenciador tokens. Routes preserve GET querystrings and offer explicit active/all history scopes.

Tech Stack: Existing FastAPI, SQLAlchemy, Jinja, CSS tokens, minimal vanilla JS, pytest, Playwright, scripts/deploy_hub.ps1.

Global Constraints

  • OPERATIONALLY_ACTIVE: Tenant.active IS TRUE AND Agent.enabled IS TRUE, excluding linked AgentEnrollment status REVOKED, FAILED, EXPIRED; no inference from client/installation names.
  • Installation.processing_enabled=false means paused jobs, not inactive server; keep it in health counts. Agents without linked enrollment remain active if Tenant and Agent are active.
  • Preserve history via scope=all; default scope=active across operational lists. Existing resolved blocker/history URLs remain reachable.
  • Preserve GTI Gerenciador client combobox, SSO, themes, HTTPS, Agent/runtime, fiscal engine and FIREBIRD_WRITES=0; no deletion of historical data.
  • All filtering and pagination server-side (50/page); bounded SQL aggregates before LIMIT 10; no N+1 or client-side loading of products.
  • Do not commit unless explicitly asked. Deploy exclusively through scripts/deploy_hub.ps1; no ad-hoc SSH/deploy script.

Task 1: Shared active scope and paginated inventory

Files: central/app/control_plane.py, central/tests/test_operational_view_models.py, central/app/web.py.

Interfaces: operational_installation_predicate() yields a SQLAlchemy condition on Tenant/Agent/Installation, using ~exists(select(AgentEnrollment.id).where(AgentEnrollment.agent_id == Agent.id, AgentEnrollment.status.in_(["REVOKED", "FAILED", "EXPIRED"]))). list_installations(..., scope="active", version=None) accepts scope=active|all; version="outdated" restricts to outdated versions. Web route validates scope/health/sort/version before querying and passes query_base with these filters.

  • RED: seed active, Tenant.active=False, Agent.enabled=False, ENROLLED and REVOKED linked cases and assert default list_installations contains only active ids; scope="all" contains every id and preserves health filtering. Assert a processing_enabled=False active installation remains visible. Run python -m pytest central/tests/test_operational_view_models.py -q and confirm missing scope behavior fails.
  • GREEN: add AgentEnrollment import/predicate, apply same predicate before both paged list and count; support version="outdated" via existing drift expression. Preserve SQL LIMIT/OFFSET and existing joins. Re-run focused test.
  • RED/GREEN: web TestClient /agents?scope=active&health=UNKNOWN and /agents?scope=all reflect selected filter, pagination links preserve scope; implement route validation and query_base, rerun python -m pytest central/tests/test_control_panel_pages.py -q.

Task 2: Operational dashboard aggregates and grouped attention

Files: central/app/control_plane.py, central/tests/test_operational_view_models.py.

Interfaces: dashboard_summary returns same keys as today plus grouped attention_items (<=10) with group_count, products_affected, link, priority and client/server identity. Blocker totals and failed-job counts only include open/current records attributed to active installations. Limit candidate groups after SQL GROUP BY (installation_id, field, blocker_type, reason_code); lower-case fields normalized to upper-case for breakdown. Dashboard does not load all blockers/products.

  • RED: seed revoked Agent enrollment with UNKNOWN snapshot, inactive tenant, disabled Agent, 26 NCM blockers on one active installation plus historical resolved blockers; assert active health/coverage/blocker/job aggregates exclude inactive rows, NCM becomes one attention group with 26 products, and len(attention_items) <= 10. Run focused operational test and observe incorrect counts/duplicate rows.
  • GREEN: reuse Task 1 predicate for health/snapshots/outdated/failed jobs. For blocker aggregation join Tenant→Installation→Agent, filter active/open; count distinct (tenant_id, product_code) and compute grouped fields before .limit(10), then order technical alerts before fiscal groups and outdated. Keep a bounded fixed number of SQL queries independent of product volume. Re-run focused test.
  • Measure number of executed SQL statements with SQLAlchemy before_cursor_execute for 1 vs 26 blockers; assert bounded query count and no statement per blocker. Compare SQL GROUP BY query on SQLite and PostgreSQL dialect compilation; inspect indexes from blocked_products(installation_id,resolved_at,field) and jobs(agent_id,status) before adding migration.

Task 3: Scoped Blockers and Jobs data models

Files: central/app/control_plane.py, central/app/web.py, central/tests/test_operational_view_models.py, central/tests/test_control_panel_pages.py.

Interfaces: list_blockers/blocker_filter_summary(..., scope="active") and list_jobs(..., scope="active") reuse Task 1 active condition; jobs_status_summary(..., scope="active") returns counts PENDING/RUNNING/COMPLETED/FAILED using one GROUP BY. Web GET routes accept scope, keep valid filters/query_base on pagination, and expose a selected job_id result with untruncated error. status=RESOLVED&scope=all retains historic blocker access.

  • RED: tests for active defaults excluding revoked/inactive records, scope="all" preserving history, status="RESOLVED", /blockers?field=NCM&scope=active, /jobs?status=FAILED&scope=active&job_id=123, and no product dropdown; run focused tests and see active-scope failures.
  • GREEN: apply active predicate after existing joins (for blocker query, require linked active installation only when scope=active); keep page_size=50, filters and count separate. Add small status GROUP BY and route params. Render one selected job detail from the returned page data or a single scoped job_id query; full error only there. Re-run focused tests.

Task 4: Human-readable presentation and dashboard/filters markup

Files: central/app/panel_presentation.py, central/templates/dashboard.html, central/templates/agents.html, central/templates/blockers.html, central/templates/jobs.html, central/tests/test_control_panel_pages.py, central/tests/test_operational_view_models.py.

Interfaces: job_status_label, job_kind_label, blocker_type_label, blocker_reason_label, priority_label, fiscal_status_label map known enums, falling back to readable text; retain raw value on details. All dashboard health cards are <a class="metric metric-link" href="/agents?scope=active&health=...">; blocker field positive links preserve scope/status; zero stays text. Filter chips and clear links display active selections.

  • RED: TestClient HTML assertions for card→health filter, breakdown NCM→field, failed jobs→FAILED, outdated→version, selected filters/clear actions, human PT-BR labels; confirm old HTML fails.
  • GREEN: add presenter mappings to panel_presentation.py and include presentation fields in view-model dictionaries; render cards as links, attention groups with count/CTA, compact failed jobs/outdated; edit Agents table to combine identity columns, Blockers table product link + human labels, Jobs compact columns + detail/error. Keep historical routes intact, use query_base/urlencode to preserve filters and avoid XSS/unescaped params. Re-run HTML assertions.
  • Retain the Nova instalação combobox unchanged: TestClient asserts client_id hidden, searchable active Gerenciador-only clients, keyboard/mouse JS and server-side validation still present.

Task 5: Interaction/CSS and responsive presentation

Files: central/static/control-panel.css, central/static/control-panel.js, templates from Task 4.

  • RED: browser preview at 1366/1920/375 exposes horizontal scroll on Agents today and non-clickable cards; capture snapshot/measure scrollWidth, focus order and toolbar visibility.
  • GREEN: use only var(--cor-*) tokens for .metric-link:hover/:focus-visible, active-filter chips, grouped attention, semantic badges, compact tables and responsive 375px row layout. Set Agents table sizing to available content area and hide secondary fields below tablet; no 960px minimum for Agents on desktop. Keep Blockers/Jobs list bounded and filters stacked on mobile. Vanilla JS event delegation on tr[data-href] for mouse clicks outside existing links; keep primary <a> for Tab/Enter and avoid nested controls/intercepting modifier clicks.
  • Browser check at 1366x768, 1920x1080, 375px for focus-visible, Tab/Enter (and Space on buttons), no desktop horizontal scroll in Agents, readable names, light/dark styles. Adjust CSS and repeat visual checks until criteria pass.

Task 6: Full verification and official deploy

Files: scripts/deploy_hub.ps1 (execute only; do not edit), test suites.

  • Run python -m pytest central/tests -q, python -m pytest tests -q, and python -m pytest agent/tests -q; capture totals and failures. Verify no runtime/engine/SSO/auth files changed; git diff --check and inspect status/diff.
  • Verify dashboard query count and, if SQL plan shows a missing index, first add a small Alembic migration plus migration test, re-run affected and full tests, and deploy with the same official script. No migrations solely for aesthetics.
  • Use authenticated browser smoke on Resumo, Agents, Blockers, Jobs and Nova instalação; click Resumo→Online/Total/NCM/failed job/outdated Agent and navigate back. Recheck server-side selected filters and disabled/revoked exclusion at 1920x1080, 1366x768, 375px in light and dark. If production SSO login is unavailable, do equivalent smoke with TestClient/local preview and report production visual check as blocked.
  • Run only powershell -ExecutionPolicy Bypass -File .\scripts\deploy_hub.ps1 (or pwsh -File .\scripts\deploy_hub.ps1 if script requires pwsh) as documented in docs/DEPLOY_HUB.md. Check logs/last_deploy_result.json, release health and public https://gtifiscal.gtigrupo.com.br/health. No ad-hoc SSH, no write to Firebird, no client action.
  • Report the user-requested field list with observed evidence; COMMITS=nenhum if no explicit request to commit, and truthful blockers where browser authentication/production smoke cannot be completed.