spec: refine 057 + extend 058 #67
5
.github/agents/copilot-instructions.md
vendored
5
.github/agents/copilot-instructions.md
vendored
@ -11,6 +11,7 @@ ## Active Technologies
|
|||||||
- PHP 8.4.x (Laravel 12) + Laravel 12, Filament v4, Livewire v3 (feat/047-inventory-foundations-nodes)
|
- PHP 8.4.x (Laravel 12) + Laravel 12, Filament v4, Livewire v3 (feat/047-inventory-foundations-nodes)
|
||||||
- PostgreSQL (JSONB for `InventoryItem.meta_jsonb`) (feat/047-inventory-foundations-nodes)
|
- PostgreSQL (JSONB for `InventoryItem.meta_jsonb`) (feat/047-inventory-foundations-nodes)
|
||||||
- PostgreSQL (JSONB in `operation_runs.context`, `operation_runs.summary_counts`) (056-remove-legacy-bulkops)
|
- PostgreSQL (JSONB in `operation_runs.context`, `operation_runs.summary_counts`) (056-remove-legacy-bulkops)
|
||||||
|
- PHP 8.4.15 (Laravel 12.47.0) + Filament v5.0.0, Livewire v4.0.1 (058-tenant-ui-polish)
|
||||||
|
|
||||||
- PHP 8.4.15 (feat/005-bulk-operations)
|
- PHP 8.4.15 (feat/005-bulk-operations)
|
||||||
|
|
||||||
@ -30,9 +31,9 @@ ## Code Style
|
|||||||
PHP 8.4.15: Follow standard conventions
|
PHP 8.4.15: Follow standard conventions
|
||||||
|
|
||||||
## Recent Changes
|
## Recent Changes
|
||||||
|
- 058-tenant-ui-polish: Added PHP 8.4.15 (Laravel 12.47.0) + Filament v5.0.0, Livewire v4.0.1
|
||||||
|
- 058-tenant-ui-polish: Added [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
|
||||||
- 056-remove-legacy-bulkops: Added PHP 8.4.x + Laravel 12, Filament v4, Livewire v3
|
- 056-remove-legacy-bulkops: Added PHP 8.4.x + Laravel 12, Filament v4, Livewire v3
|
||||||
- feat/047-inventory-foundations-nodes: Added PHP 8.4.x (Laravel 12) + Laravel 12, Filament v4, Livewire v3
|
|
||||||
- feat/042-inventory-dependencies-graph: Added PHP 8.4.x + Laravel 12, Filament v4, Livewire v3
|
|
||||||
|
|
||||||
|
|
||||||
<!-- MANUAL ADDITIONS START -->
|
<!-- MANUAL ADDITIONS START -->
|
||||||
|
|||||||
@ -31,5 +31,5 @@ ## Feature Readiness
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- This is a technical upgrade, but the spec intentionally describes outcomes and guardrails rather than implementation steps.
|
- This is a technical upgrade, but the spec describes outcomes and guardrails rather than implementation steps.
|
||||||
- Proceed to planning: identify concrete packages, versions, and migration steps in plan/tasks.
|
- Planning can capture concrete versions, dependency changes, and migration steps.
|
||||||
|
|||||||
@ -3,7 +3,7 @@ # Feature Specification: Admin UI Stack Upgrade (Panel + Suite)
|
|||||||
**Feature Branch**: `057-filament-v5-upgrade`
|
**Feature Branch**: `057-filament-v5-upgrade`
|
||||||
**Created**: 2026-01-20
|
**Created**: 2026-01-20
|
||||||
**Status**: Draft
|
**Status**: Draft
|
||||||
**Input**: Upgrade the existing admin UI stack to the next supported major release to maintain compatibility and support, and ensure no regressions for tenant isolation and Ops-UX/Monitoring guardrails.
|
**Input**: Upgrade the existing admin UI stack to the next supported major release to maintain compatibility and support, and ensure no regressions for tenant isolation and Monitoring/Operations safety guardrails.
|
||||||
|
|
||||||
## Clarifications
|
## Clarifications
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ ## User Scenarios & Testing *(mandatory)*
|
|||||||
|
|
||||||
### User Story 1 - Admin UI keeps working after upgrade (Priority: P1)
|
### User Story 1 - Admin UI keeps working after upgrade (Priority: P1)
|
||||||
|
|
||||||
Administrators can sign in and use the admin panel (navigation, resources, forms, tables, actions) without runtime errors after the upgrade.
|
Administrators can sign in and use the admin panel (navigation, lists, forms, actions) without runtime errors after the upgrade.
|
||||||
|
|
||||||
**Why this priority**: This is the minimum bar for the upgrade to be safe; if the admin UI is unstable, all operational work stops.
|
**Why this priority**: This is the minimum bar for the upgrade to be safe; if the admin UI is unstable, all operational work stops.
|
||||||
|
|
||||||
@ -75,18 +75,18 @@ ## Requirements *(mandatory)*
|
|||||||
|
|
||||||
### Functional Requirements
|
### Functional Requirements
|
||||||
|
|
||||||
- **FR-001**: The application MUST upgrade the admin panel stack to the next supported major release and its required compatible reactive UI layer.
|
- **FR-001**: The system MUST upgrade the admin UI stack to the next supported major release and remain fully functional for all in-scope admin workflows.
|
||||||
- **FR-002**: The application MUST continue to support the existing styling system without asset build failures.
|
- **FR-002**: The system MUST continue to support the existing styling and asset pipeline without build failures.
|
||||||
- **FR-003**: All existing Filament panels MUST load successfully for authorized users and preserve core interactions (navigation, tables, forms, actions, notifications, widgets).
|
- **FR-003**: All existing admin pages MUST load successfully for authorized users and preserve core interactions (navigation, lists, forms, actions, notifications, and global UI elements).
|
||||||
- **FR-004**: SPA-style navigation flows MUST continue to work, including global widget mounting and event delivery across navigation.
|
- **FR-004**: In-app navigation between admin pages MUST continue to work reliably, including any global progress indicators and event-driven UI behavior.
|
||||||
- **FR-005**: Everything rendered under the Monitoring → Operations navigation section (including widgets/partials/tabs) MUST remain DB-only: no outbound HTTP requests are permitted during page render or during background/automatic Livewire requests (polling/auto-refresh/hydration).
|
- **FR-005**: Everything rendered under the Monitoring → Operations navigation section (including widgets/partials/tabs) MUST remain DB-only: no outbound HTTP requests are permitted during page render or during background/automatic requests (polling/auto-refresh/hydration).
|
||||||
- **FR-010**: Any remote work initiated from Monitoring/Operations pages MUST be triggered only by explicit user actions (e.g., buttons) and MUST enqueue tracked operations (e.g., `OperationRun`-backed jobs) rather than performing outbound HTTP inline.
|
- **FR-006**: Tenant isolation MUST be preserved across requests and interactive UI behavior: all reads/writes/events/caches MUST scope to the active tenant.
|
||||||
- **FR-006**: Tenant isolation MUST be preserved across requests and Live UI interactions: all reads/writes/events/caches MUST scope to the active tenant.
|
- **FR-007**: Compatibility risks MUST be managed by producing an explicit inventory of affected third-party dependencies and documenting upgrade/replacement decisions.
|
||||||
- **FR-007**: Compatibility risks MUST be managed by producing an explicit inventory of affected third-party packages and documenting upgrade/replacement decisions.
|
|
||||||
- **FR-011**: If a third-party package is incompatible with the upgraded stack, the system MUST preserve equivalent functionality by upgrading or replacing the package; mixed-version pinning is not allowed. Any unavoidable feature loss MUST be handled as an explicit scope/decision change.
|
|
||||||
- **FR-012**: Database migrations are allowed only if strictly required for compatibility; they MUST be reversible and non-destructive (no data loss). Migrations MUST include a safe `down()` path and avoid drops without an explicit plan, and MUST be mentioned in release notes.
|
|
||||||
- **FR-008**: The upgrade MUST not introduce new Microsoft Graph read/write behavior; if any Graph-touching behavior changes are required, they MUST be explicitly specified with safety gates and observability updates.
|
- **FR-008**: The upgrade MUST not introduce new Microsoft Graph read/write behavior; if any Graph-touching behavior changes are required, they MUST be explicitly specified with safety gates and observability updates.
|
||||||
- **FR-009**: The upgrade MUST include a documented rollback procedure that restores the previous working state.
|
- **FR-009**: The upgrade MUST include a documented rollback procedure that restores the previous working state.
|
||||||
|
- **FR-010**: Any remote work initiated from Monitoring/Operations pages MUST be triggered only by explicit user actions and MUST enqueue a tracked operation (with an observable run record) rather than performing outbound HTTP inline.
|
||||||
|
- **FR-011**: If a third-party dependency is incompatible with the upgraded stack, the system MUST preserve equivalent functionality by upgrading or replacing the dependency; mixed-version pinning is not allowed. Any unavoidable feature loss MUST be handled as an explicit scope/decision change.
|
||||||
|
- **FR-012**: Database migrations are allowed only if strictly required for compatibility; they MUST be reversible and non-destructive (no data loss) and MUST be mentioned in release notes.
|
||||||
|
|
||||||
### Assumptions & Dependencies
|
### Assumptions & Dependencies
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ ### Assumptions & Dependencies
|
|||||||
### Key Entities *(include if feature involves data)*
|
### Key Entities *(include if feature involves data)*
|
||||||
|
|
||||||
- **Tenant**: The active tenant context that scopes all data access and UI state.
|
- **Tenant**: The active tenant context that scopes all data access and UI state.
|
||||||
- **OperationRun**: The persisted record of long-running operations shown in Monitoring/Operations views.
|
- **Run Record**: The persisted record of long-running operations shown in Monitoring/Operations views.
|
||||||
- **AuditLog**: The tenant-scoped audit trail used to retain accountability for sensitive actions.
|
- **AuditLog**: The tenant-scoped audit trail used to retain accountability for sensitive actions.
|
||||||
|
|
||||||
## Success Criteria *(mandatory)*
|
## Success Criteria *(mandatory)*
|
||||||
|
|||||||
22
specs/058-tenant-ui-polish/contracts/polling.md
Normal file
22
specs/058-tenant-ui-polish/contracts/polling.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Polling Contract — Calm UI Rules
|
||||||
|
|
||||||
|
## Principle
|
||||||
|
Polling is allowed only when it materially improves UX (active operations). It must be DB-only and must stop when no longer needed.
|
||||||
|
|
||||||
|
## Dashboard
|
||||||
|
- Polling is enabled only while active runs exist (queued/running) for the current tenant.
|
||||||
|
- Polling is disabled when:
|
||||||
|
- No active runs exist.
|
||||||
|
|
||||||
|
## Operations index
|
||||||
|
- Polling is enabled only while active runs exist.
|
||||||
|
- Polling is disabled when:
|
||||||
|
- No active runs exist.
|
||||||
|
|
||||||
|
## Modals
|
||||||
|
- No polling inside modals.
|
||||||
|
- When a modal is open, polling should not cause churn in the background.
|
||||||
|
|
||||||
|
## Technical approach
|
||||||
|
- Widgets: use `$pollingInterval = null` to disable polling.
|
||||||
|
- Tables: apply `$table->poll('10s')` only when active runs exist.
|
||||||
28
specs/058-tenant-ui-polish/contracts/ui.md
Normal file
28
specs/058-tenant-ui-polish/contracts/ui.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# UI Contracts — Tenant UI Polish
|
||||||
|
|
||||||
|
This feature does not introduce HTTP APIs. These contracts describe UI routing, filters, and definitions that must remain stable.
|
||||||
|
|
||||||
|
## Routes (tenant-scoped)
|
||||||
|
- Dashboard: tenant dashboard page (new custom page; replaces default dashboard entry).
|
||||||
|
- Inventory hub: Inventory cluster root (routes to first page/resource in cluster).
|
||||||
|
- Inventory items: Inventory items resource index, under cluster prefix.
|
||||||
|
- Inventory sync runs: Inventory sync runs resource index, under cluster prefix.
|
||||||
|
- Inventory coverage: Inventory coverage page, under cluster prefix.
|
||||||
|
- Operations index: `OperationRunResource` index (`/operations`).
|
||||||
|
- Operation run detail: `OperationRunResource` view page.
|
||||||
|
|
||||||
|
## Operations Tabs (FR-009)
|
||||||
|
Tabs filter the Operations table by:
|
||||||
|
- All: no extra constraints.
|
||||||
|
- Active: `status IN ('queued','running')`
|
||||||
|
- Succeeded: `status = 'completed' AND outcome = 'succeeded'`
|
||||||
|
- Partial: `status = 'completed' AND outcome = 'partial'`
|
||||||
|
- Failed: `status = 'completed' AND outcome = 'failed'`
|
||||||
|
|
||||||
|
## KPI Definitions
|
||||||
|
- Inventory coverage % = Restorable / Total (Partial is separate, does not inflate %).
|
||||||
|
- Drift stale threshold = 7 days.
|
||||||
|
- “Recent” lists default size = 10.
|
||||||
|
- “Active operations” shows two counts:
|
||||||
|
- All active runs (queued + running)
|
||||||
|
- Inventory-active runs (type = `inventory.sync`, queued + running)
|
||||||
76
specs/058-tenant-ui-polish/data-model.md
Normal file
76
specs/058-tenant-ui-polish/data-model.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Data Model — Tenant UI Polish
|
||||||
|
|
||||||
|
This feature is read-only. It introduces no schema changes.
|
||||||
|
|
||||||
|
## Entities
|
||||||
|
|
||||||
|
### Tenant
|
||||||
|
- **Role**: scope boundary for all queries.
|
||||||
|
- **Source**: `Tenant::current()` (Filament tenancy).
|
||||||
|
|
||||||
|
### OperationRun
|
||||||
|
- **Role**: operations feed, KPIs, and canonical “View run” destinations.
|
||||||
|
- **Key fields used** (existing):
|
||||||
|
- `tenant_id`
|
||||||
|
- `type`
|
||||||
|
- `status` (`queued|running|completed`)
|
||||||
|
- `outcome` (`succeeded|partial|failed|...`)
|
||||||
|
- `created_at`, `started_at`, `completed_at`
|
||||||
|
- `summary_counts`, `failure_summary` (JSONB)
|
||||||
|
|
||||||
|
**Derived values**:
|
||||||
|
- **Active**: `status IN ('queued','running')`
|
||||||
|
- **Terminal**: `status = 'completed'`
|
||||||
|
- **Avg duration (7 days)**: only terminal runs with `started_at` and `completed_at`.
|
||||||
|
|
||||||
|
### InventoryItem
|
||||||
|
- **Role**: inventory totals and coverage chips.
|
||||||
|
- **Key fields used** (existing, inferred from resources):
|
||||||
|
- `tenant_id`
|
||||||
|
- coverage-related flags / fields used to categorize: Restorable, Partial, Risk, Dependencies
|
||||||
|
|
||||||
|
**Derived values**:
|
||||||
|
- Total items
|
||||||
|
- Coverage % = `restorable / total` (if total > 0)
|
||||||
|
- Chip counts: Restorable, Partial, Risk, Dependencies
|
||||||
|
|
||||||
|
### InventorySyncRun
|
||||||
|
- **Role**: “Last Inventory Sync” and “Sync Runs” list.
|
||||||
|
- **Key fields used**:
|
||||||
|
- `tenant_id`
|
||||||
|
- status + timestamps
|
||||||
|
- any “selection_hash / selection payload” metadata used for display
|
||||||
|
|
||||||
|
### Finding (Drift Finding)
|
||||||
|
- **Role**: drift KPIs and “Needs Attention”.
|
||||||
|
- **Key fields used** (existing migration):
|
||||||
|
- `tenant_id`
|
||||||
|
- `severity` (enum-like string)
|
||||||
|
- `status` (open/closed)
|
||||||
|
- timestamps
|
||||||
|
- `scope_key` for grouping
|
||||||
|
|
||||||
|
**Derived values**:
|
||||||
|
- Open findings by severity
|
||||||
|
- Staleness: last drift scan older than 7 days
|
||||||
|
|
||||||
|
## KPI Queries (read-only)
|
||||||
|
|
||||||
|
### Dashboard
|
||||||
|
- Drift KPIs: counts of open findings by severity + stale drift indicator.
|
||||||
|
- Operations health: counts of active runs + failed/partial recent.
|
||||||
|
- Recent lists: latest 10 findings + latest 10 operation runs.
|
||||||
|
|
||||||
|
### Inventory hub
|
||||||
|
- Total items
|
||||||
|
- Coverage % (restorable/total)
|
||||||
|
- Last inventory sync (status + timestamp)
|
||||||
|
- Active operations: (all active runs) + (inventory.sync active runs)
|
||||||
|
|
||||||
|
### Operations index
|
||||||
|
- Total runs (30d)
|
||||||
|
- Active runs (queued + running)
|
||||||
|
- Failed/partial (7d)
|
||||||
|
- Avg duration (7d, terminal runs only)
|
||||||
|
|
||||||
|
All queries must be tenant-scoped.
|
||||||
164
specs/058-tenant-ui-polish/plan.md
Normal file
164
specs/058-tenant-ui-polish/plan.md
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
# Implementation Plan: Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||||
|
|
||||||
|
**Branch**: `058-tenant-ui-polish` | **Date**: 2026-01-20 | **Spec**: `specs/058-tenant-ui-polish/spec.md`
|
||||||
|
**Input**: Feature specification from `specs/058-tenant-ui-polish/spec.md`
|
||||||
|
|
||||||
|
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
- Build a drift-first, tenant-scoped dashboard with “Needs Attention” and recent lists.
|
||||||
|
- Make Inventory a hub using a Filament cluster to provide consistent left-side sub-navigation across Items / Sync Runs / Coverage.
|
||||||
|
- Upgrade Operations index to “orders-style” with KPIs + status tabs filtering the existing `OperationRunResource` table.
|
||||||
|
- Enforce DB-only renders (and DB-only polling) and a calm UI: polling only while active runs exist, and no polling churn in modals.
|
||||||
|
|
||||||
|
## Technical Context
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ACTION REQUIRED: Replace the content in this section with the technical details
|
||||||
|
for the project. The structure here is presented in advisory capacity to guide
|
||||||
|
the iteration process.
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Language/Version**: PHP 8.4.15 (Laravel 12.47.0)
|
||||||
|
**Primary Dependencies**: Filament v5.0.0, Livewire v4.0.1
|
||||||
|
**Storage**: PostgreSQL
|
||||||
|
**Testing**: Pest v4 (+ PHPUnit v12 runtime)
|
||||||
|
**Target Platform**: Web application (Filament admin panel)
|
||||||
|
**Project Type**: Web (Laravel monolith)
|
||||||
|
**Performance Goals**: Dashboard/Inventory/Operations render quickly (target <2s for typical tenants) with efficient tenant-scoped queries and no N+1.
|
||||||
|
**Constraints**: DB-only for all page renders and any polling/auto-refresh; avoid UI churn in modals.
|
||||||
|
**Scale/Scope**: Tenant-scoped surfaces; KPI math on existing `operation_runs`, `findings`, inventory tables.
|
||||||
|
|
||||||
|
## Constitution Check
|
||||||
|
|
||||||
|
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||||
|
|
||||||
|
- Inventory-first: clarify what is “last observed” vs snapshots/backups
|
||||||
|
- Read/write separation: any writes require preview + confirmation + audit + tests
|
||||||
|
- Graph contract path: Graph calls only via `GraphClientInterface` + `config/graph_contracts.php`
|
||||||
|
- Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
|
||||||
|
- Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
|
||||||
|
- Run observability: long-running/remote/queued work creates/reuses `OperationRun`; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log
|
||||||
|
- Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
|
||||||
|
- Data minimization: Inventory stores metadata + whitelisted meta; logs contain no secrets/tokens
|
||||||
|
|
||||||
|
Status: ✅ No constitution violations for this feature (read-only, DB-only, tenant-scoped; no Graph calls added).
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
### Documentation (this feature)
|
||||||
|
|
||||||
|
```text
|
||||||
|
specs/058-tenant-ui-polish/
|
||||||
|
├── plan.md # This file (/speckit.plan command output)
|
||||||
|
├── research.md # Phase 0 output (/speckit.plan command)
|
||||||
|
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||||
|
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||||
|
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||||
|
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Source Code (repository root)
|
||||||
|
<!--
|
||||||
|
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||||
|
for this feature. Delete unused options and expand the chosen structure with
|
||||||
|
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||||
|
not include Option labels.
|
||||||
|
-->
|
||||||
|
|
||||||
|
```text
|
||||||
|
app/
|
||||||
|
├── Filament/
|
||||||
|
│ ├── Clusters/ # New: Inventory cluster
|
||||||
|
│ ├── Pages/ # New/updated: tenant dashboard, inventory landing, coverage
|
||||||
|
│ ├── Resources/ # Updated: attach inventory resources to cluster; operations tabs/KPIs
|
||||||
|
│ └── Widgets/ # New/updated: KPI header widgets
|
||||||
|
├── Models/ # Existing: Tenant, OperationRun, Finding, InventoryItem, InventorySyncRun
|
||||||
|
└── Providers/Filament/
|
||||||
|
└── AdminPanelProvider.php # Update: discoverClusters(), dashboard page class
|
||||||
|
|
||||||
|
resources/
|
||||||
|
└── views/ # Optional: partials/views for dashboard sections
|
||||||
|
|
||||||
|
tests/
|
||||||
|
└── Feature/
|
||||||
|
├── Monitoring/ # Existing: Operations DB-only + tenant scope tests
|
||||||
|
└── Filament/ # Existing + new: Inventory/Dashboard page tests
|
||||||
|
```
|
||||||
|
|
||||||
|
**Structure Decision**: Laravel monolith + Filament (v5) conventions. Implement UI changes via:
|
||||||
|
- Filament Pages (dashboard + inventory pages)
|
||||||
|
- Filament Clusters (inventory sub-navigation)
|
||||||
|
- Filament Widgets (KPI headers / recent lists)
|
||||||
|
- Filament Resource list tabs (operations index filtering)
|
||||||
|
|
||||||
|
## Complexity Tracking
|
||||||
|
|
||||||
|
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Phase 0 — Outline & Research (complete)
|
||||||
|
|
||||||
|
- Output: `specs/058-tenant-ui-polish/research.md`
|
||||||
|
- Key decisions captured:
|
||||||
|
- Use Filament clusters for the Inventory hub sub-navigation.
|
||||||
|
- Use Filament widgets for KPI headers.
|
||||||
|
- Enable polling only while active runs exist.
|
||||||
|
|
||||||
|
## Phase 1 — Design & Contracts (complete)
|
||||||
|
|
||||||
|
### Data model
|
||||||
|
- Output: `specs/058-tenant-ui-polish/data-model.md`
|
||||||
|
- No schema changes required.
|
||||||
|
|
||||||
|
### UI contracts
|
||||||
|
- Output: `specs/058-tenant-ui-polish/contracts/ui.md`
|
||||||
|
- Output: `specs/058-tenant-ui-polish/contracts/polling.md`
|
||||||
|
|
||||||
|
### Provider registration (Laravel 11+)
|
||||||
|
- Panel providers remain registered in `bootstrap/providers.php` (no changes required for this feature unless adding a new provider).
|
||||||
|
|
||||||
|
### Livewire / Filament version safety
|
||||||
|
- Livewire v4.0+ (required by Filament v5) is in use.
|
||||||
|
|
||||||
|
### Asset strategy
|
||||||
|
- Prefer existing Filament theme CSS and hook classes; avoid publishing Filament internal views.
|
||||||
|
- No heavy assets expected; if any new panel assets are added, ensure deployment runs `php artisan filament:assets`.
|
||||||
|
|
||||||
|
### Destructive actions
|
||||||
|
- None introduced in this feature.
|
||||||
|
|
||||||
|
### Constitution re-check (post-design)
|
||||||
|
- ✅ Inventory-first: dashboard uses Inventory/Findings/OperationRun as last-observed state.
|
||||||
|
- ✅ Read/write separation: this feature is read-only.
|
||||||
|
- ✅ Graph contract path: no Graph calls added.
|
||||||
|
- ✅ Tenant isolation: all queries remain tenant-scoped.
|
||||||
|
- ✅ Run observability: only consumes existing `OperationRun` records; no new long-running work is introduced.
|
||||||
|
- ✅ Data minimization: no new payload storage.
|
||||||
|
|
||||||
|
## Phase 2 — Implementation Plan (next)
|
||||||
|
|
||||||
|
### Story 1 (P1): Drift-first tenant dashboard
|
||||||
|
- Create a custom Filament dashboard page (tenant-scoped) and wire it in `AdminPanelProvider` instead of the default `Dashboard::class`.
|
||||||
|
- Implement drift + ops KPIs and “Needs Attention” + recent lists using DB-only Eloquent queries.
|
||||||
|
- Implement conditional polling (only while active runs exist) using widget polling controls.
|
||||||
|
- Tests:
|
||||||
|
- Add DB-only coverage tests for the dashboard (no outbound HTTP; no queued jobs on render).
|
||||||
|
- Add tenant scope tests for the dashboard.
|
||||||
|
|
||||||
|
### Story 2 (P2): Inventory becomes a hub
|
||||||
|
- Add `discoverClusters()` to `AdminPanelProvider`.
|
||||||
|
- Create `InventoryCluster` and assign `$cluster` on inventory pages/resources.
|
||||||
|
- Add a shared inventory KPI header (widget) across the cluster surfaces.
|
||||||
|
- Tests:
|
||||||
|
- Extend existing inventory page tests to assert cluster pages load and remain tenant-scoped.
|
||||||
|
|
||||||
|
### Story 3 (P3): Operations index “orders-style”
|
||||||
|
- Update `OperationRunResource` list page to:
|
||||||
|
- Add KPI header widgets.
|
||||||
|
- Add tabs: All / Active / Succeeded / Partial / Failed.
|
||||||
|
- Enable table polling only while active runs exist.
|
||||||
|
- Tests:
|
||||||
|
- Extend operations tests to assert page renders with tabs and remains DB-only/tenant-scoped.
|
||||||
27
specs/058-tenant-ui-polish/quickstart.md
Normal file
27
specs/058-tenant-ui-polish/quickstart.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Quickstart — Tenant UI Polish
|
||||||
|
|
||||||
|
## Prereqs
|
||||||
|
- Run everything via Sail.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
- `vendor/bin/sail up -d`
|
||||||
|
- `vendor/bin/sail composer install`
|
||||||
|
|
||||||
|
## Run tests (targeted)
|
||||||
|
- `vendor/bin/sail artisan test tests/Feature/Monitoring/OperationsDbOnlyTest.php`
|
||||||
|
- `vendor/bin/sail artisan test tests/Feature/Monitoring/OperationsTenantScopeTest.php`
|
||||||
|
- `vendor/bin/sail artisan test tests/Feature/Filament/InventoryPagesTest.php`
|
||||||
|
|
||||||
|
When the feature is implemented, add + run:
|
||||||
|
- Dashboard DB-only + tenant scope tests (new).
|
||||||
|
|
||||||
|
## Manual QA (tenant-scoped)
|
||||||
|
- Sign in, select a tenant.
|
||||||
|
- Visit Dashboard: verify drift/ops KPIs, needs attention, and recent lists.
|
||||||
|
- Visit Inventory cluster: Items / Sync Runs / Coverage share left sub-navigation and KPI header.
|
||||||
|
- Visit Operations (`/operations`): KPI header + tabs filter table.
|
||||||
|
|
||||||
|
## Frontend assets
|
||||||
|
If UI changes don’t show:
|
||||||
|
- `vendor/bin/sail npm run dev`
|
||||||
|
- or `vendor/bin/sail npm run build`
|
||||||
66
specs/058-tenant-ui-polish/research.md
Normal file
66
specs/058-tenant-ui-polish/research.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# 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.
|
||||||
@ -5,6 +5,19 @@ # Feature Specification: Tenant UI Polish (Dashboard + Inventory Hub + Operation
|
|||||||
**Status**: Draft
|
**Status**: Draft
|
||||||
**Input**: User description: "Feature 058 — Tenant UI Polish: Dashboard + Inventory Hub + Operations \"Orders-style\" (v1)"
|
**Input**: User description: "Feature 058 — Tenant UI Polish: Dashboard + Inventory Hub + Operations \"Orders-style\" (v1)"
|
||||||
|
|
||||||
|
## Clarifications
|
||||||
|
|
||||||
|
### Session 2026-01-20
|
||||||
|
|
||||||
|
- Q: Coverage % definition for Inventory KPI header? → A: Coverage % = Restorable / Total (Partial remains a separate chip/number; main % stays conservative)
|
||||||
|
- Q: Drift stale threshold (last scan older than X days)? → A: 7 days
|
||||||
|
- Q: Inventory KPI “Active Operations” definition? → A: Show both counts: All active runs (queued + running) and Inventory-active runs (queued + running)
|
||||||
|
- Q: How many rows in “Recent” lists by default? → A: 10
|
||||||
|
|
||||||
|
### Session 2026-01-21
|
||||||
|
|
||||||
|
- Q: Operations index "Stuck" tab in v1? -> A: No "Stuck" tab in v1
|
||||||
|
|
||||||
## User Scenarios & Testing *(mandatory)*
|
## User Scenarios & Testing *(mandatory)*
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@ -34,6 +47,8 @@ ### User Story 1 - Drift-first tenant dashboard (Priority: P1)
|
|||||||
2. **Given** there are urgent drift issues (e.g., high severity open findings), **When** I view the Dashboard, **Then** they appear in the “Needs Attention” section with a CTA that navigates to a filtered view.
|
2. **Given** there are urgent drift issues (e.g., high severity open findings), **When** I view the Dashboard, **Then** they appear in the “Needs Attention” section with a CTA that navigates to a filtered view.
|
||||||
3. **Given** drift generation has a recent failed run, **When** I view the Dashboard, **Then** I can navigate from “Needs Attention” to the related operation run details.
|
3. **Given** drift generation has a recent failed run, **When** I view the Dashboard, **Then** I can navigate from “Needs Attention” to the related operation run details.
|
||||||
4. **Given** there is no drift data yet, **When** I view the Dashboard, **Then** the dashboard renders calmly with empty-state messaging and no errors.
|
4. **Given** there is no drift data yet, **When** I view the Dashboard, **Then** the dashboard renders calmly with empty-state messaging and no errors.
|
||||||
|
5. **Given** the last drift scan is older than 7 days, **When** I view the Dashboard, **Then** “Needs Attention” includes a “Drift stale” item with a CTA to investigate.
|
||||||
|
6. **Given** there are more than 10 drift findings and operation runs, **When** I view the Dashboard, **Then** each “Recent” list shows the 10 most recent items.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -101,9 +116,11 @@ ### Functional Requirements
|
|||||||
- **FR-004 (Inventory hub layout)**: System MUST provide an Inventory hub with left sub-navigation for Items, Sync Runs, and Coverage.
|
- **FR-004 (Inventory hub layout)**: System MUST provide an Inventory hub with left sub-navigation for Items, Sync Runs, and Coverage.
|
||||||
- **FR-005 (Inventory KPIs)**: Inventory hub MUST show a shared KPI header across Inventory subpages with:
|
- **FR-005 (Inventory KPIs)**: Inventory hub MUST show a shared KPI header across Inventory subpages with:
|
||||||
- Total Items
|
- Total Items
|
||||||
- Coverage % (covered items / total items)
|
- Coverage % (restorable items / total items; partial shown separately)
|
||||||
- Last Inventory Sync (status + timestamp)
|
- Last Inventory Sync (status + timestamp)
|
||||||
- Active Operations (queued + running)
|
- Active Operations (queued + running), showing both:
|
||||||
|
- All active runs
|
||||||
|
- Inventory-active runs
|
||||||
- **FR-006 (Inventory sync runs view)**: System MUST provide a “Sync Runs” view that lists only inventory synchronization runs.
|
- **FR-006 (Inventory sync runs view)**: System MUST provide a “Sync Runs” view that lists only inventory synchronization runs.
|
||||||
- **FR-007 (Coverage chips)**: System MUST standardize coverage chips to this set only: Restorable, Partial, Risk, Dependencies.
|
- **FR-007 (Coverage chips)**: System MUST standardize coverage chips to this set only: Restorable, Partial, Risk, Dependencies.
|
||||||
- **FR-008 (Operations index KPIs)**: Operations index MUST show tenant-scoped KPIs:
|
- **FR-008 (Operations index KPIs)**: Operations index MUST show tenant-scoped KPIs:
|
||||||
@ -111,14 +128,71 @@ ### Functional Requirements
|
|||||||
- Active Runs (queued + running)
|
- Active Runs (queued + running)
|
||||||
- Failed/Partial (7 days)
|
- Failed/Partial (7 days)
|
||||||
- Avg Duration (7 days, terminal runs only)
|
- Avg Duration (7 days, terminal runs only)
|
||||||
- **FR-009 (Operations tabs)**: Operations index MUST provide status tabs that filter the operations table: All, Active, Succeeded, Partial, Failed.
|
- **FR-009 (Operations tabs)**: Operations index MUST provide status tabs that filter the operations table: All, Active, Succeeded, Partial, Failed. No "Stuck" tab in v1.
|
||||||
- **FR-010 (Canonical terminology)**: System MUST use “Operations” as the canonical label (no legacy naming on these surfaces).
|
- **FR-010 (Canonical terminology)**: System MUST use “Operations” as the canonical label (no legacy naming on these surfaces).
|
||||||
- **FR-011 (Canonical links)**: “View run” links MUST always navigate to the canonical operation run detail view.
|
- **FR-011 (Canonical links)**: “View run” links MUST always navigate to the canonical operation run detail view.
|
||||||
- **FR-012 (Calm UI rules)**: System MUST avoid polling/churn in modals and avoid refresh loops; background updates should be used only where clearly necessary.
|
- **FR-012 (Calm UI rules)**: System MUST avoid polling/churn in modals and avoid refresh loops; background updates should be used only where clearly necessary. Auto-refresh on Dashboard and Operations index is allowed only while active runs (queued/running) exist, and MUST stop when there are no active runs.
|
||||||
|
- **FR-013 (Drift stale rule)**: System MUST flag drift as “stale” when the last drift scan is older than 7 days and surface it in “Needs Attention” with an investigation CTA.
|
||||||
|
- **FR-014 (Recent list sizing)**: System MUST show 10 rows by default for “Recent Drift Findings” and “Recent Operations”.
|
||||||
|
|
||||||
|
### OperationRun status mapping (for tabs and KPIs)
|
||||||
|
|
||||||
|
OperationRun uses two canonical fields that drive UI filters:
|
||||||
|
|
||||||
|
- `status`: execution lifecycle (e.g., queued/running/completed)
|
||||||
|
- `outcome`: terminal result (e.g., succeeded/partially_succeeded/failed/cancelled)
|
||||||
|
|
||||||
|
Tab filters MUST map exactly as:
|
||||||
|
|
||||||
|
- **All**: no status/outcome filter
|
||||||
|
- **Active**: `status IN (queued, running)`
|
||||||
|
- **Succeeded**: `status = completed AND outcome = succeeded`
|
||||||
|
- **Partial**: `status = completed AND outcome = partially_succeeded`
|
||||||
|
- **Failed**: `status = completed AND outcome = failed`
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- No “Stuck” tab in v1.
|
||||||
|
- Runs with `outcome = cancelled` appear under **All** only (unless a future “Cancelled” tab is added).
|
||||||
|
- Any legacy status/outcome values must already be normalized before reaching this UI (out of scope for this feature).
|
||||||
|
|
||||||
|
### KPI window definitions (timestamp basis)
|
||||||
|
|
||||||
|
All KPI windows are tenant-scoped and DB-only.
|
||||||
|
|
||||||
|
- **Total Runs (30 days)**: count OperationRuns by `created_at` within the last 30 days (includes all statuses/outcomes).
|
||||||
|
- **Active Runs**: current count where `status IN (queued, running)` (no time window).
|
||||||
|
- **Failed/Partial (7 days)**: count terminal runs where `status = completed AND outcome IN (failed, partially_succeeded)` and `completed_at` is within the last 7 days.
|
||||||
|
- **Avg Duration (7 days)**: average of `(completed_at - started_at)` for runs where `status = completed`, `started_at` and `completed_at` are present, and `completed_at` is within the last 7 days.
|
||||||
|
|
||||||
|
### Inventory coverage classification (Restorable/Partial/Risk/Dependencies)
|
||||||
|
|
||||||
|
Coverage chips and KPI aggregation MUST derive from the existing “policy type meta” and dependency capability signals (DB-only):
|
||||||
|
|
||||||
|
- `inventory_items.policy_type`
|
||||||
|
- `config('tenantpilot.supported_policy_types')` meta fields:
|
||||||
|
- `restore` (e.g., enabled / preview-only)
|
||||||
|
- `risk` (e.g., medium / medium-high / high)
|
||||||
|
- Dependency support computed via the existing coverage dependency resolver (based on contracts/config).
|
||||||
|
|
||||||
|
Definitions:
|
||||||
|
|
||||||
|
- **Restorable**: inventory items whose policy type meta has `restore = enabled`
|
||||||
|
- **Partial**: inventory items whose policy type meta has `restore = preview-only`
|
||||||
|
- **Risk**: inventory items whose policy type meta has `risk IN (medium-high, high)`
|
||||||
|
- **Dependencies**: inventory items whose policy type supports dependencies per the existing dependency capability resolver
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- This feature does not redefine coverage semantics; it standardizes UI rendering and KPI aggregation based on the existing policy type meta.
|
||||||
|
- If a policy type is unknown/missing meta, it MUST be treated conservatively (non-restorable) for KPI aggregation.
|
||||||
|
|
||||||
**Assumptions**:
|
**Assumptions**:
|
||||||
- Drift findings, inventory items, and operation runs already exist as tenant-scoped data sources.
|
- Drift findings, inventory items, and operation runs already exist as tenant-scoped data sources.
|
||||||
- “Coverage %” defaults to covered/total; if total is 0, coverage shows as not available.
|
- “Coverage %” is Restorable/Total; Partial is shown separately (e.g., chips/secondary metric). If total is 0, coverage shows as not available.
|
||||||
|
- “Drift stale” default threshold is 7 days.
|
||||||
|
- “Recent” list default size is 10.
|
||||||
|
- Auto-refresh behavior (DB-only): Dashboard and Operations index auto-refresh only while active runs exist; otherwise it stops.
|
||||||
- Creating/generating drift is out of scope unless it can be performed as an explicit, enqueue-only user action that results in an operation run.
|
- Creating/generating drift is out of scope unless it can be performed as an explicit, enqueue-only user action that results in an operation run.
|
||||||
|
|
||||||
### Key Entities *(include if feature involves data)*
|
### Key Entities *(include if feature involves data)*
|
||||||
|
|||||||
192
specs/058-tenant-ui-polish/tasks.md
Normal file
192
specs/058-tenant-ui-polish/tasks.md
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
---
|
||||||
|
description: "Task list for feature implementation"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tasks: Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||||
|
|
||||||
|
**Input**: Design documents from `specs/058-tenant-ui-polish/`
|
||||||
|
|
||||||
|
**Tests**: Required (Pest) — this feature changes runtime UI behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Setup (Shared Infrastructure)
|
||||||
|
|
||||||
|
- [ ] T001 Confirm feature inputs exist: specs/058-tenant-ui-polish/spec.md, specs/058-tenant-ui-polish/plan.md
|
||||||
|
- [ ] T002 Confirm Phase 0/1 artifacts exist: specs/058-tenant-ui-polish/research.md, specs/058-tenant-ui-polish/data-model.md, specs/058-tenant-ui-polish/contracts/ui.md, specs/058-tenant-ui-polish/contracts/polling.md, specs/058-tenant-ui-polish/quickstart.md
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Foundational (Blocking Prerequisites)
|
||||||
|
|
||||||
|
- [ ] T003 Create shared helper to detect “active runs exist” for tenant polling in app/Support/OpsUx/ActiveRuns.php
|
||||||
|
- [ ] T004 [P] Add focused tests for the helper in tests/Feature/OpsUx/ActiveRunsTest.php
|
||||||
|
|
||||||
|
**Checkpoint**: Shared polling predicate exists and is covered.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: User Story 1 — Drift-first tenant dashboard (Priority: P1) 🎯 MVP
|
||||||
|
|
||||||
|
**Goal**: Tenant-scoped dashboard that surfaces drift + ops KPIs and “Needs Attention”, DB-only.
|
||||||
|
|
||||||
|
**Independent Test**: Visiting the dashboard renders drift KPIs, ops KPIs, needs-attention CTAs, and recent lists (10 rows), with no outbound HTTP and no background work dispatched.
|
||||||
|
|
||||||
|
### Tests (US1)
|
||||||
|
|
||||||
|
- [ ] T005 [P] [US1] Add DB-only render test (no outbound HTTP, no background work) in tests/Feature/Filament/TenantDashboardDbOnlyTest.php
|
||||||
|
- [ ] T006 [P] [US1] Add tenant isolation test (no cross-tenant leakage) in tests/Feature/Filament/TenantDashboardTenantScopeTest.php
|
||||||
|
|
||||||
|
### Implementation (US1)
|
||||||
|
|
||||||
|
- [ ] T007 [US1] Create tenant dashboard page in app/Filament/Pages/TenantDashboard.php
|
||||||
|
- [ ] T008 [US1] Register the tenant dashboard page in app/Providers/Filament/AdminPanelProvider.php (replace default Dashboard page entry)
|
||||||
|
- [ ] T009 [P] [US1] Create dashboard KPI widget(s) in app/Filament/Widgets/Dashboard/DashboardKpis.php
|
||||||
|
- [ ] T010 [P] [US1] Create “Needs Attention” widget in app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||||
|
- [ ] T011 [P] [US1] Create “Recent Drift Findings” widget (10 rows) in app/Filament/Widgets/Dashboard/RecentDriftFindings.php
|
||||||
|
- [ ] T012 [P] [US1] Create “Recent Operations” widget (10 rows) in app/Filament/Widgets/Dashboard/RecentOperations.php
|
||||||
|
- [ ] T013 [US1] Wire widgets into the dashboard page in app/Filament/Pages/TenantDashboard.php (header/sections) and implement conditional polling per specs/058-tenant-ui-polish/contracts/polling.md
|
||||||
|
- [ ] T014 [US1] Implement drift stale rule (7 days) + CTA wiring in app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||||
|
- [ ] T015 [US1] Ensure all dashboard queries are tenant-scoped + DB-only in app/Filament/Pages/TenantDashboard.php and app/Filament/Widgets/Dashboard/*.php
|
||||||
|
|
||||||
|
**Checkpoint**: US1 is shippable as an MVP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: User Story 2 — Inventory becomes a hub module (Priority: P2)
|
||||||
|
|
||||||
|
**Goal**: Inventory becomes a cluster “hub” with consistent left sub-navigation and a shared KPI header across Items / Sync Runs / Coverage.
|
||||||
|
|
||||||
|
**Independent Test**: Navigating Items → Sync Runs → Coverage keeps consistent sub-navigation and shared KPI header, tenant-scoped and DB-only.
|
||||||
|
|
||||||
|
### Tests (US2)
|
||||||
|
|
||||||
|
- [ ] T016 [P] [US2] Add DB-only render test for Inventory hub surfaces in tests/Feature/Filament/InventoryHubDbOnlyTest.php
|
||||||
|
- [ ] T017 [P] [US2] Extend/adjust inventory navigation smoke coverage in tests/Feature/Filament/InventoryPagesTest.php
|
||||||
|
|
||||||
|
### Implementation (US2)
|
||||||
|
|
||||||
|
- [ ] T018 [US2] Enable cluster discovery in app/Providers/Filament/AdminPanelProvider.php (add `discoverClusters(...)`)
|
||||||
|
- [ ] T019 [US2] Create Inventory cluster class in app/Filament/Clusters/Inventory/InventoryCluster.php
|
||||||
|
- [ ] T020 [US2] Assign Inventory cluster to inventory pages in app/Filament/Pages/InventoryLanding.php and app/Filament/Pages/InventoryCoverage.php
|
||||||
|
- [ ] T021 [US2] Assign Inventory cluster to inventory resources in app/Filament/Resources/InventoryItemResource.php and app/Filament/Resources/InventorySyncRunResource.php
|
||||||
|
- [ ] T022 [P] [US2] Create shared Inventory KPI header widget in app/Filament/Widgets/Inventory/InventoryKpiHeader.php
|
||||||
|
- [ ] T023 [US2] Add Inventory KPI header widget to InventoryLanding in app/Filament/Pages/InventoryLanding.php
|
||||||
|
- [ ] T024 [US2] Add Inventory KPI header widget to InventoryCoverage in app/Filament/Pages/InventoryCoverage.php
|
||||||
|
- [ ] T025 [US2] Add Inventory KPI header widget to Inventory items list in app/Filament/Resources/InventoryItemResource.php (or its list page)
|
||||||
|
- [ ] T026 [US2] Add Inventory KPI header widget to Inventory sync runs list in app/Filament/Resources/InventorySyncRunResource.php (or its list page)
|
||||||
|
- [ ] T027 [US2] Ensure Inventory KPI definitions match specs/058-tenant-ui-polish/contracts/ui.md (coverage % restorable/total; partial separate; two active operations counts)
|
||||||
|
- [ ] T041 [US2] Inventory coverage semantics reference (A2)
|
||||||
|
- Identify and document the exact source-of-truth fields for Inventory KPI aggregation:
|
||||||
|
- `inventory_items.policy_type`
|
||||||
|
- `config('tenantpilot.supported_policy_types')` meta fields (`restore`, `risk`)
|
||||||
|
- Dependency support via existing dependency capability resolver
|
||||||
|
- Ensure KPI and chips read from this source only (DB-only).
|
||||||
|
- DoD:
|
||||||
|
- One canonical place documented and referenced by inventory KPIs.
|
||||||
|
- No “magic” or duplicated classification logic across pages/widgets.
|
||||||
|
- [ ] T028 [US2] Ensure “Sync Runs” view is inventory-only per spec in app/Filament/Resources/InventorySyncRunResource.php (query/filter by run type/intent if needed)
|
||||||
|
- [ ] T029 [US2] Standardize coverage chips set on coverage-related surfaces in app/Filament/Pages/InventoryCoverage.php (Restorable, Partial, Risk, Dependencies only)
|
||||||
|
|
||||||
|
**Checkpoint**: Inventory hub behaves as a module with consistent sub-navigation + header.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: User Story 3 — Operations index “Orders-style” (Priority: P3)
|
||||||
|
|
||||||
|
**Goal**: Operations index shows KPIs + status tabs + table, with calm conditional polling.
|
||||||
|
|
||||||
|
**Independent Test**: Visiting Operations index shows KPIs and tabs that filter runs per specs/058-tenant-ui-polish/contracts/ui.md, DB-only, calm.
|
||||||
|
|
||||||
|
### Tests (US3)
|
||||||
|
|
||||||
|
- [ ] T030 [P] [US3] Extend Operations DB-only test assertions in tests/Feature/Monitoring/OperationsDbOnlyTest.php (assert tabs/KPI labels appear)
|
||||||
|
- [ ] T031 [P] [US3] Extend Operations tenant isolation coverage in tests/Feature/Monitoring/OperationsTenantScopeTest.php (assert tab views don’t leak)
|
||||||
|
|
||||||
|
### Implementation (US3)
|
||||||
|
|
||||||
|
- [ ] T032 [P] [US3] Create Operations KPI header widget in app/Filament/Widgets/Operations/OperationsKpiHeader.php
|
||||||
|
- [ ] T033 [US3] Add KPIs to the Operations list page in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||||
|
- [ ] T034 [US3] Implement status tabs (All/Active/Succeeded/Partial/Failed) on Operations list page in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||||
|
- [ ] T035 [US3] Ensure tab filter logic matches specs/058-tenant-ui-polish/contracts/ui.md by adjusting queries in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||||
|
- [ ] T036 [US3] Implement conditional polling for Operations list (only while active runs exist) by wiring table polling in app/Filament/Resources/OperationRunResource.php and/or app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||||
|
- [ ] T037 [US3] Ensure canonical “View run” links still route to OperationRunResource view pages (no legacy routes)
|
||||||
|
- Verify existing canonical link helper `App\Support\OperationRunLinks` is used consistently.
|
||||||
|
- If no suitable helper exists for a given surface, add a minimal equivalent and use it everywhere.
|
||||||
|
|
||||||
|
- [ ] T042 [US3] Operations terminology sweep (FR-010)
|
||||||
|
- Goal: The UI uses the canonical label “Operations” consistently; no legacy naming remains.
|
||||||
|
- Audit + fix in:
|
||||||
|
- Navigation label(s)
|
||||||
|
- Page titles / breadcrumbs
|
||||||
|
- Resource titles / headings
|
||||||
|
- Any links mentioning “Bulk Operation Runs” or legacy run naming
|
||||||
|
- DoD:
|
||||||
|
- No occurrences of legacy labels remain in UI surfaces for Monitoring/Operations.
|
||||||
|
- `rg -n "Bulk Operation|BulkOperationRun|Bulk Operation Runs" app resources` returns 0 matches (or matches only in tests explicitly allowed).
|
||||||
|
- If ripgrep is unavailable, use `grep -R` with the same patterns.
|
||||||
|
|
||||||
|
**Checkpoint**: Operations index is “orders-style” with calm refresh behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: Polish & Cross-Cutting Concerns
|
||||||
|
|
||||||
|
- [ ] T038 [P] Run formatting on changed files in app/** and tests/** via `vendor/bin/sail bin pint --dirty`
|
||||||
|
- [ ] T039 Run targeted tests from specs/058-tenant-ui-polish/quickstart.md and ensure green
|
||||||
|
- [ ] T040 [P] Smoke-check key pages render for a tenant in tests/Feature/Filament/AdminSmokeTest.php (add assertions only if gaps are found)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies & Execution Order
|
||||||
|
|
||||||
|
### User Story Dependencies
|
||||||
|
|
||||||
|
- US1 (P1) is standalone and can ship first.
|
||||||
|
- US2 (P2) can be implemented after foundational polling helper; it touches the panel provider and inventory pages/resources.
|
||||||
|
- US3 (P3) can be implemented after foundational polling helper; it touches the operations resource list page.
|
||||||
|
|
||||||
|
Suggested order (MVP-first): Phase 1 → Phase 2 → US1 → US2 → US3 → Polish.
|
||||||
|
|
||||||
|
### Parallel Opportunities (examples)
|
||||||
|
|
||||||
|
- US1: T009–T012 can be developed in parallel (different widget files).
|
||||||
|
- US2: T022 can be developed in parallel while T018–T021 are in review.
|
||||||
|
- US3: T032 can be developed in parallel with test updates (T030–T031).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Parallel Execution Examples (per user story)
|
||||||
|
|
||||||
|
### US1
|
||||||
|
- T005 [P] [US1] tests/Feature/Filament/TenantDashboardDbOnlyTest.php
|
||||||
|
- T006 [P] [US1] tests/Feature/Filament/TenantDashboardTenantScopeTest.php
|
||||||
|
- T009 [P] [US1] app/Filament/Widgets/Dashboard/DashboardKpis.php
|
||||||
|
- T010 [P] [US1] app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||||
|
- T011 [P] [US1] app/Filament/Widgets/Dashboard/RecentDriftFindings.php
|
||||||
|
- T012 [P] [US1] app/Filament/Widgets/Dashboard/RecentOperations.php
|
||||||
|
|
||||||
|
### US2
|
||||||
|
- T016 [P] [US2] tests/Feature/Filament/InventoryHubDbOnlyTest.php
|
||||||
|
- T022 [P] [US2] app/Filament/Widgets/Inventory/InventoryKpiHeader.php
|
||||||
|
|
||||||
|
### US3
|
||||||
|
- T030 [P] [US3] tests/Feature/Monitoring/OperationsDbOnlyTest.php
|
||||||
|
- T031 [P] [US3] tests/Feature/Monitoring/OperationsTenantScopeTest.php
|
||||||
|
- T032 [P] [US3] app/Filament/Widgets/Operations/OperationsKpiHeader.php
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Strategy
|
||||||
|
|
||||||
|
### MVP First (US1 only)
|
||||||
|
|
||||||
|
1. Complete Phase 1 + Phase 2
|
||||||
|
2. Implement US1 (dashboard)
|
||||||
|
3. Run: `vendor/bin/sail artisan test tests/Feature/Filament/TenantDashboardDbOnlyTest.php`
|
||||||
|
4. Run: `vendor/bin/sail artisan test tests/Feature/Filament/TenantDashboardTenantScopeTest.php`
|
||||||
|
|
||||||
|
### Incremental Delivery
|
||||||
|
|
||||||
|
- Add US2 next (Inventory hub), then US3 (Operations index).
|
||||||
|
- After each story, run its targeted tests + the cross-cutting DB-only tests.
|
||||||
Loading…
Reference in New Issue
Block a user