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 linkedAgentEnrollmentstatusREVOKED,FAILED,EXPIRED; no inference from client/installation names.Installation.processing_enabled=falsemeans 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; defaultscope=activeacross 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_installationscontains only active ids;scope="all"contains every id and preserveshealthfiltering. Assert aprocessing_enabled=Falseactive installation remains visible. Runpython -m pytest central/tests/test_operational_view_models.py -qand confirm missing scope behavior fails. - GREEN: add
AgentEnrollmentimport/predicate, apply same predicate before both paged list and count; supportversion="outdated"via existing drift expression. Preserve SQLLIMIT/OFFSETand existing joins. Re-run focused test. - RED/GREEN: web TestClient
/agents?scope=active&health=UNKNOWNand/agents?scope=allreflect selected filter, pagination links preserve scope; implement route validation and query_base, rerunpython -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_executefor 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 fromblocked_products(installation_id,resolved_at,field)andjobs(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); keeppage_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 scopedjob_idquery; 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.pyand 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, usequery_base/urlencodeto preserve filters and avoid XSS/unescaped params. Re-run HTML assertions. - Retain the Nova instalação combobox unchanged: TestClient asserts
client_idhidden, 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 ontr[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, andpython -m pytest agent/tests -q; capture totals and failures. Verify no runtime/engine/SSO/auth files changed;git diff --checkand 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(orpwsh -File .\scripts\deploy_hub.ps1if script requires pwsh) as documented indocs/DEPLOY_HUB.md. Checklogs/last_deploy_result.json, release health and publichttps://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=nenhumif no explicit request to commit, and truthful blockers where browser authentication/production smoke cannot be completed.