TenantAtlas/specs/277-stored-reports-surface/tasks.md
ahmido c44f683aa6 277-stored-reports-surface → platform-dev (#333)
Auto-created PR: committing all local changes and pushing branch `277-stored-reports-surface` to remote.

Please review and adjust the title/description as needed.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #333
2026-05-06 00:04:53 +00:00

184 lines
14 KiB
Markdown

---
description: "Task list for Stored Reports Surface v1"
---
# Tasks: Stored Reports Surface v1
**Input**: Design documents from `specs/277-stored-reports-surface/`
**Prerequisites**: `specs/277-stored-reports-surface/spec.md`, `specs/277-stored-reports-surface/plan.md`, `specs/277-stored-reports-surface/checklists/requirements.md`, `specs/277-stored-reports-surface/research.md`, `specs/277-stored-reports-surface/data-model.md`, `specs/277-stored-reports-surface/quickstart.md`, `specs/277-stored-reports-surface/contracts/tenant-stored-reports-surface.logical.openapi.yaml`
**Tests**: REQUIRED (Pest). Keep proof bounded to focused `Feature` coverage in `apps/platform/tests/Feature/StoredReports/`, a narrow update to `apps/platform/tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php`, and the required UI smoke coverage in `apps/platform/tests/Browser/Spec277StoredReportsSurfaceSmokeTest.php`.
**Operations**: No new `OperationRun` family. Existing scan and generation actions remain on their current surfaces.
**RBAC**: Wrong-tenant or non-member access remains `404`; in-scope actors missing the relevant report-family capability remain `403`; collection visibility requires at least one supported report-family capability.
**Shared Pattern Reuse**: Reuse `StoredReport`, `ArtifactTruthPresenter`, centralized badge semantics, and the current admin-roles widget launch seam. Do not create a report registry, analytics console, or second lifecycle system.
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration remains unchanged in `apps/platform/bootstrap/providers.php`. The new stored-report resource is not globally searchable and adds no new asset strategy.
**Organization**: Tasks are grouped by user story so browse, detail, and canonical drilldown behavior stay independently implementable and testable. This package productizes existing stored-report truth and stops before generic reporting scope.
**Review Outcome**: `acceptable-special-case`
**Workflow Outcome**: `keep`
**Test-governance Outcome**: `keep`
## Test Governance Checklist
- [x] Lane assignment stays `fast-feedback` and `confidence` and remains the narrowest sufficient proof.
- [x] New or changed tests stay in `apps/platform/tests/Feature/StoredReports/`, `apps/platform/tests/Feature/EntraAdminRoles/`, and the required narrow browser smoke file only.
- [x] Shared helpers stay cheap by default; stored-report setup should reuse the current factory and tenant fixtures.
- [x] Planned validation commands cover register behavior, entitlement behavior, detail presentation, widget drilldown, and the required narrow browser smoke without widening into heavy-governance lanes.
- [x] The declared surface test profile remains `standard-native-filament` and `shared-detail-family` only.
- [x] Any drift toward a report engine, cross-tenant hub, or generic registry resolves as `reject-or-split`, not hidden scope.
## Phase 1: Setup (Shared Context)
**Purpose**: Confirm the current stored-report, artifact-truth, and launch seams before runtime changes begin.
- [x] T001 Review `specs/277-stored-reports-surface/spec.md`, `specs/277-stored-reports-surface/plan.md`, `specs/277-stored-reports-surface/checklists/requirements.md`, `specs/277-stored-reports-surface/research.md`, `specs/277-stored-reports-surface/data-model.md`, and `specs/277-stored-reports-surface/quickstart.md` together so the slice stays on existing stored-report truth.
- [x] T002 [P] Confirm the current stored-report truth and lifecycle anchors in `apps/platform/app/Models/StoredReport.php`, `apps/platform/database/factories/StoredReportFactory.php`, and `apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php`.
- [x] T003 [P] Confirm the current repo-real launch seam in `apps/platform/app/Filament/Widgets/Tenant/AdminRolesSummaryWidget.php` and `apps/platform/resources/views/filament/widgets/tenant/admin-roles-summary.blade.php`.
- [x] T004 [P] Confirm the current tenant-panel read-only resource patterns in `apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php`, `apps/platform/app/Filament/Resources/ReviewPackResource.php`, and their related feature tests.
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Lock authorization, test coverage, and setup before the new surface is built.
**Critical**: No user-story work should begin until this phase is complete.
- [x] T005 [P] Add failing feature coverage in `apps/platform/tests/Feature/StoredReports/StoredReportEntitlementEnforcementTest.php` for collection visibility, direct-detail access, family-filtered rows, and `404` versus `403` semantics.
- [x] T006 [P] Add failing feature coverage in `apps/platform/tests/Feature/StoredReports/StoredReportResourceTest.php` for tenant-scoped list behavior, current versus historical visibility, search, filter options, and honest empty-state behavior.
- [x] T007 [P] Add failing feature coverage in `apps/platform/tests/Feature/StoredReports/StoredReportDetailPresentationTest.php` for allowed current permission-posture detail, allowed historical Entra admin-roles detail, collapsed raw payload disclosure, and integrity-anchor rendering when present.
- [x] T008 [P] Prepare the minimal widget test fixtures or helpers in `apps/platform/tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php` for a report-present state and a capability-blocked state so US3 can add one bounded assertion set.
- [x] T009 Add `Capabilities::PERMISSION_POSTURE_VIEW` in `apps/platform/app/Support/Auth/Capabilities.php` and map it in `apps/platform/app/Services/Auth/RoleCapabilityMap.php` with bounded read-only role coverage.
- [x] T010 Keep stored-report test setup cheap by extending `apps/platform/database/factories/StoredReportFactory.php` only as needed for current and historical supported-family fixtures.
**Checkpoint**: Authorization and proving seams are ready for the stored-report resource implementation.
---
## Phase 3: User Story 1 - Browse current stored reports for one tenant (Priority: P1)
**Goal**: Entitled actors can browse current and historical stored reports for the active tenant in one first-class register.
**Independent Test**: Open `/admin/t/{tenant}/stored-reports`, confirm current and historical behavior, and verify family-aware visibility and filters.
### Tests for User Story 1
- [x] T011 [P] [US1] Extend `apps/platform/tests/Feature/StoredReports/StoredReportResourceTest.php` to cover clickable-row inspection, history toggle behavior, and family-aware filter visibility on the tenant panel.
### Implementation for User Story 1
- [x] T012 [US1] Create `apps/platform/app/Filament/Resources/StoredReportResource.php` with tenant ownership, `isGloballySearchable = false`, family-aware `canViewAny()` behavior, and a read-only action-surface declaration.
- [x] T013 [US1] Create `apps/platform/app/Filament/Resources/StoredReportResource/Pages/ListStoredReports.php` with a tenant-scoped query, report-family filters, history visibility, search, clickable rows, and no row or bulk mutation actions.
- [x] T014 [US1] Add bounded family-summary extraction on the stored-report resource or list page using current payload shapes and existing artifact-truth badges rather than a shared registry.
- [x] T015 [US1] Wire the list empty state to an honest next step such as the tenant overview, without implying the stored-report surface can generate reports itself.
**Checkpoint**: The tenant panel has one calm stored-report register that stays tenant-scoped, read-only, and family-aware.
---
## Phase 4: User Story 2 - Inspect a retained report without false calmness (Priority: P1)
**Goal**: Entitled actors can inspect one stored report and immediately understand what it says, whether it is current or historical, and when it was measured.
**Independent Test**: Open one current permission-posture report and one historical Entra admin-roles report and verify lifecycle truth, measured time, bounded summary, and progressive disclosure.
### Tests for User Story 2
- [x] T016 [P] [US2] Extend `apps/platform/tests/Feature/StoredReports/StoredReportDetailPresentationTest.php` to cover the one-primary-action rule, current-report jump on historical rows, and the absence of speculative unsupported-family rendering in v1.
### Implementation for User Story 2
- [x] T017 [US2] Create `apps/platform/app/Filament/Resources/StoredReportResource/Pages/ViewStoredReport.php` as a read-only view page using infolist sections for artifact truth, family summary, lineage, and collapsed raw payload.
- [x] T018 [US2] Reuse `ArtifactTruthPresenter::forStoredReport()` in the detail surface and keep any “current report” lookup local to `StoredReportResource` and `ViewStoredReport` instead of broadening the artifact envelope.
- [x] T019 [US2] Keep the detail page to one dominant next action, `Open current report`, only when the viewed row is historical, and keep all mutation actions out of scope.
**Checkpoint**: Stored-report detail behaves like a true inspection surface rather than a pseudo-editor or diagnostics dump.
---
## Phase 5: User Story 3 - Follow stored-report truth from the tenant admin-roles widget (Priority: P2)
**Goal**: The current admin-roles widget launch seam points to the canonical stored-report detail route instead of leaving operators in a fragmented local view.
**Independent Test**: Launch the current Entra admin-roles report from `AdminRolesSummaryWidget` and confirm the canonical tenant stored-report detail route opens.
### Tests for User Story 3
- [x] T020 [P] [US3] Extend `apps/platform/tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php` to prove canonical stored-report drilldown and capability-gated absence without widening the proving suite.
### Implementation for User Story 3
- [x] T021 [US3] Update `apps/platform/app/Filament/Widgets/Tenant/AdminRolesSummaryWidget.php` and `apps/platform/resources/views/filament/widgets/tenant/admin-roles-summary.blade.php` so `viewReportUrl` resolves to the canonical tenant stored-report detail route when the actor can view Entra admin roles.
- [x] T022 [US3] Keep convergence bounded to `AdminRolesSummaryWidget`; do not add new stored-report links to `EvidenceSnapshotResource`, `ReviewPackResource`, or `TenantReviewResource` in v1.
- [x] T023 [US3] Ensure generated detail URLs preserve tenant-panel routing semantics and that direct detail access keeps family-aware authorization behavior.
**Checkpoint**: The admin-roles widget definitely launches the canonical detail route, and any additional convergence remains bounded to repo-real affordances.
---
## Phase 6: Polish & Cross-Cutting Validation
**Purpose**: Validate the bounded slice and stop before reporting-platform scope creeps in.
- [x] T024 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/StoredReports/StoredReportResourceTest.php tests/Feature/StoredReports/StoredReportEntitlementEnforcementTest.php`.
- [x] T025 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/StoredReports/StoredReportDetailPresentationTest.php tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php`.
- [x] T026 [P] Run `cd apps/platform && ./vendor/bin/sail pint` on the touched application and test files; `./vendor/bin/sail pint --dirty` reported no tracked dirty files because several feature files were new.
- [x] T027 [P] Review touched code to confirm Filament stays on Livewire v4, provider registration remains unchanged in `apps/platform/bootstrap/providers.php`, the new resource stays out of global search, no new asset strategy appears, and no report engine or analytics scope slipped in.
- [x] T028 [P] Record the final guardrail and test-governance outcome in the active feature close-out without widening into cross-tenant browse, raw export, or generic report-framework work.
---
## Dependencies & Execution Order
### Phase Dependencies
- **Phase 1 (Setup)**: no dependencies; start immediately.
- **Phase 2 (Foundational)**: depends on Phase 1 and blocks all user stories.
- **Phase 3 (US1)**: depends on Phase 2 and establishes the primary browse surface.
- **Phase 4 (US2)**: depends on Phase 2 and should ship with US1 so the register opens into a finished detail surface.
- **Phase 5 (US3)**: depends on Phase 2 and should follow once the canonical detail route exists.
- **Phase 6 (Polish)**: depends on all desired user stories being complete.
### User Story Dependencies
- **US1 (P1)**: independently testable after Phase 2 and delivers the primary operator value.
- **US2 (P1)**: independently testable after Phase 2 and should ship with US1 so the browse surface is meaningful.
- **US3 (P2)**: independently testable after Phase 2 and can follow once the canonical detail route is in place.
### Within Each User Story
- Write the listed Pest coverage first and make it fail for the intended gap.
- Keep implementation inside the resource, widget, capability, and existing report-truth seams named above.
- Re-run the narrowest relevant validation command after each story checkpoint before moving on.
---
## Implementation Strategy
### Suggested MVP Scope
- MVP = **US1 + US2 together**. The feature only closes the operator gap when the register and detail surface both exist.
### Incremental Delivery
1. Complete Phase 1 and Phase 2.
2. Deliver US1 so operators can browse current and historical stored reports.
3. Deliver US2 so the browse surface opens into a trustworthy detail surface.
4. Deliver US3 by wiring the canonical detail route into the current admin-roles widget seam.
5. Finish with the focused validation and guardrail review in Phase 6.
### Team Strategy
1. Settle capability and test shape first.
2. Parallelize failing test authoring within the stored-report feature family before runtime edits.
3. Serialize merges around `StoredReportResource`, `ViewStoredReport`, and `AdminRolesSummaryWidget` so route and vocabulary drift does not spread.
---
## Deferred Follow-Ups / Non-Goals
- report generation, scheduling, or rerun actions from the stored-report surface
- raw payload download or export
- cross-tenant or workspace-wide stored-report browsing
- customer-facing stored-report consumption
- generic report registry, renderer framework, or analytics console