TenantAtlas/specs/058-tenant-ui-polish/research.md
2026-01-21 08:12:46 +01:00

67 lines
3.3 KiB
Markdown

# Research — Tenant UI Polish (Dashboard + Inventory Hub + Operations)
## Goal
Deliver a drift-first, tenant-scoped UI polish pass that is:
- DB-only on render and on any auto-refresh.
- Calm (polling only when needed; no modal churn).
- Consistent IA (Inventory hub sub-navigation; canonical Operations).
## Existing Code & Patterns (to reuse)
### Operations
- Canonical list/detail already exist via `OperationRunResource` (`/operations`).
- Tenant scoping already enforced in `OperationRunResource::getEloquentQuery()`.
- Detail view already uses conditional polling with safeguards (tab hidden / modal open) via `RunDetailPolling`.
### Inventory
- Inventory entry page exists as `InventoryLanding`.
- Inventory “Items” and “Sync Runs” are currently resources (`InventoryItemResource`, `InventorySyncRunResource`).
- Inventory sync “start surface” already follows constitution rules: authorize → create/reuse `OperationRun` → enqueue job → “View run”.
### Monitoring DB-only + Tenant isolation tests
- Monitoring/Operations has DB-only tests and tenant scope tests.
- Inventory landing + coverage have basic smoke tests.
## Key Decisions
### Decision: Use Filament clusters to implement the Inventory “hub” navigation
- **Decision**: Create an Inventory cluster and attach:
- `InventoryLanding` (page)
- Inventory items resource
- Inventory sync runs resource
- `InventoryCoverage` (page)
- **Rationale**: Filament clusters are designed for “common sub-navigation between pages”, including mixing pages and resources.
- **Notes**:
- Requires enabling cluster discovery in the panel provider.
- Sub-navigation position will be set to `Start` to achieve left-side navigation.
### Decision: Implement KPI headers as widgets (StatsOverviewWidget / TableWidget)
- **Decision**: Use Filament widgets for KPI headers on:
- Tenant dashboard (drift + ops)
- Inventory hub (inventory KPIs)
- Operations index (ops KPIs)
- **Rationale**: Widgets are first-class, composable, and can optionally poll (with `$pollingInterval`) while remaining DB-only.
### Decision: “Calm UI” auto-refresh strategy
- **Decision**:
- Dashboard + Operations index: enable polling only while active runs exist.
- Widgets/tables: polling is disabled when no active runs exist.
- No polling inside modals.
- **Rationale**: Matches FR-012 and avoids background churn.
- **Implementation approach**:
- Use Filament polling mechanisms:
- Widgets: `$pollingInterval = null | '10s'` depending on “active runs exist”.
- Tables: enable `$table->poll('10s')` only when “active runs exist”.
### Decision: No Graph / remote dependencies
- **Decision**: All queries for this feature are Eloquent/PostgreSQL queries.
- **Rationale**: Matches constitution and SC-005.
## Alternatives Considered
- **Custom Blade layouts for hub navigation**: Rejected because clusters provide consistent sub-nav across resources/pages without fragile view overrides.
- **Always-on polling**: Rejected to comply with calm UI rules and avoid waste.
- **Keep `Monitoring/Operations` as canonical**: Rejected because `OperationRunResource` is already the canonical Operations surface with correct routing and detail pages.
## Open Questions
None — all “NEEDS CLARIFICATION” items are resolved for planning.