TenantAtlas/specs/082-action-surface-contract/tasks.md
ahmido a770b32e87 feat: action-surface contract inspect affordance + clickable rows (#100)
Implements Spec 082 updates to the Filament Action Surface Contract:

- New required list/table slot: InspectAffordance (clickable row via recordUrl preferred; also supports View action or primary link column)
- Retrofit view-only tables to remove lone View row action buttons and use clickable rows
- Update validator + guard tests, add golden regression assertions
- Add docs: docs/ui/action-surface-contract.md

Tests (local via Sail):
- vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php
- vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceValidatorTest.php
- vendor/bin/sail artisan test --compact tests/Feature/Rbac/ActionSurfaceRbacSemanticsTest.php
- vendor/bin/sail artisan test --compact tests/Feature/Filament/EntraGroupSyncRunResourceTest.php

Notes:
- Filament v5 / Livewire v4 compatible.
- No destructive-action behavior changed in this PR.

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #100
2026-02-08 20:31:36 +00:00

128 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: "Task list for Spec 082 implementation"
---
# Tasks: Action Surface Contract + CI Enforcement
**Input**: Design documents from `/specs/082-action-surface-contract/`
**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/, quickstart.md
**Tests**: Required (Pest) — this feature adds/changes CI enforcement.
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Introduce the new support namespace and a guard-test entry point.
- [X] T001 Create ActionSurface namespaces in app/Support/Ui/ActionSurface/
- [X] T002 [P] Add guard test skeleton in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T003 [P] Add validator test skeleton in tests/Feature/Guards/ActionSurfaceValidatorTest.php
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Core contract model + discovery + validation that all user stories rely on.
- [X] T004 Create enums for component/profile/slot in app/Support/Ui/ActionSurface/Enums/ActionSurfaceComponentType.php
- [X] T005 [P] Create slot + exemption value objects in app/Support/Ui/ActionSurface/ActionSurfaceExemption.php
- [X] T006 [P] Create declaration + defaults DTOs in app/Support/Ui/ActionSurface/ActionSurfaceDeclaration.php
- [X] T007 Implement profile definitions (required slots per profile) in app/Support/Ui/ActionSurface/ActionSurfaceProfileDefinition.php
- [X] T008 Implement in-scope discovery (tenant discovery roots + admin explicit registrations/routes; exclude Widgets and System panel) in app/Support/Ui/ActionSurface/ActionSurfaceDiscovery.php
- [X] T009 Implement declaration contract validation (declare-or-exempt; reason required; More label; Export default) in app/Support/Ui/ActionSurface/ActionSurfaceValidator.php
- [X] T010 Add fast unit-style tests for validator rules in tests/Feature/Guards/ActionSurfaceValidatorTest.php (pure validation logic, no DB or Filament boot)
**Checkpoint**: Validator can enumerate + validate in-scope components deterministically.
---
## Phase 3: User Story 1 — Prevent incomplete UI action surfaces (Priority: P1) 🎯 MVP
**Goal**: CI fails if an in-scope Filament component lacks a declaration (or an explicit exemption with a non-empty reason).
**Independent Test**: Add a new in-scope Filament component without a declaration; run the guard and confirm it fails with an actionable message; add a declaration/exemption and confirm it passes.
- [X] T011 [US1] Implement the CI guard that runs validation in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T012 [US1] Add baseline exemptions registry in app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php (reason required, explicit class allowlist with shrink-over-time rule)
- [X] T013 [US1] Wire exemptions into validator output in app/Support/Ui/ActionSurface/ActionSurfaceValidator.php
- [X] T014 [US1] Make guard output actionable (class + slot + hint) in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T015 [US1] Add tests proving widgets are excluded from scope in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T031 [US1] Add tests proving unknown classes are not auto-exempted and every exemption reason is non-empty in tests/Feature/Guards/ActionSurfaceContractTest.php
**Checkpoint**: Guard passes on main branch state, but blocks missing declarations going forward.
---
## Phase 4: User Story 2 — Consistent, enterprise-grade actions and empty-state guidance (Priority: P2)
**Goal**: Provide consistent action-surface conventions (More grouping, Export default for RunLog/ReadOnly, empty-state CTA) and demonstrate them on representative surfaces.
**Independent Test**: Pick one CRUD-style list and one run-log style list; verify each has expected action areas (header/row/bulk/empty-state; detail header actions) and consistent ordering/grouping.
- [X] T016 [P] [US2] Define required slots for CRUD/ReadOnly/RunLog/RelationManager profiles in app/Support/Ui/ActionSurface/ActionSurfaceProfileDefinition.php
- [X] T017 [P] [US2] Enforce defaults: More label + Export expectation for ReadOnly/RunLog in app/Support/Ui/ActionSurface/ActionSurfaceValidator.php
- [X] T018 [US2] Add a declaration to a representative CRUD surface in app/Filament/Resources/PolicyResource.php
- [X] T019 [US2] Ensure list empty-state CTA exists for the CRUD surface in app/Filament/Resources/PolicyResource/Pages/ListPolicies.php
- [X] T020 [US2] Add a declaration to a representative RunLog surface in app/Filament/Resources/OperationRunResource.php
- [X] T021 [US2] Ensure Export bulk action is present (or exempted with reason) for the RunLog surface in app/Filament/Resources/OperationRunResource.php
- [X] T022 [US2] Add a declaration to one embedded relationship sub-list in app/Filament/Resources/PolicyResource/RelationManagers/VersionsRelationManager.php
- [X] T023 [US2] Add tests asserting the representative declarations satisfy required slots in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T032 [US2] Add representative runtime test asserting PolicyResource row/bulk grouping uses “More” conventions in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T033 [US2] Add representative runtime test asserting canonical tenantless “View run” link usage in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T035 [US2] Add golden regression tests for “view-only lists use clickable rows without row actions” in tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T036 [US2] Document action-surface contract rules (including “no lone View button; prefer clickable rows”) in docs/ui/action-surface-contract.md
**Checkpoint**: At least one CRUD + one RunLog + one embedded sub-list visibly follow the conventions.
---
## Phase 5: User Story 3 — Predictable RBAC behavior for members vs non-members (Priority: P3)
**Goal**: Validate consistent 404 vs 403 semantics and disabled-UI behavior for capability-gated actions.
**Independent Test**: Use a representative surface and verify (a) non-member receives not-found, and (b) member without capability receives forbidden and sees disabled UI with a helpful explanation.
- [X] T024 [P] [US3] Add non-member 404 route test on representative operations detail route in tests/Feature/Rbac/ActionSurfaceRbacSemanticsTest.php
- [X] T025 [US3] Add member-without-capability 403 server-side test by attempting to execute ListEntraGroupSyncRuns::sync_groups as a readonly member in tests/Feature/Filament/EntraGroupSyncRunResourceTest.php
- [X] T026 [US3] In that 403 test, assert no EntraGroupSyncJob is pushed and no EntraGroupSyncRun is created for the tenant in tests/Feature/Filament/EntraGroupSyncRunResourceTest.php
- [X] T027 [US3] Ensure disabled-UI semantics are covered for the same action (visible + disabled + standard tooltip) in tests/Feature/Filament/EntraGroupSyncRunResourceTest.php
- [X] T034 [US3] Add representative observability/audit regression assertion for an operation-start action (OperationRun record present with scope + actor) in tests/Feature/Guards/ActionSurfaceContractTest.php
**Checkpoint**: One surface per profile has coverage for 404 vs 403 semantics.
---
## Phase 6: Polish & Cross-Cutting Concerns
- [X] T028 [P] Run formatter on changed files via vendor/bin/sail bin pint --dirty
- [X] T029 Run focused guard tests via vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php
- [X] T030 Run RBAC semantics test via vendor/bin/sail artisan test --compact tests/Feature/Rbac/ActionSurfaceRbacSemanticsTest.php
---
## Dependencies & Execution Order
- Setup (Phase 1) → Foundational (Phase 2) → US1 (Phase 3) → US2/US3 (Phases 45 can proceed in parallel) → Polish (Phase 6)
## Parallel Opportunities
- Phase 2: DTOs/enums (T004T006) can be done in parallel.
- US2: Profile definition + validator rules (T016T017) can be done in parallel.
- US3: Test scaffolding (T024) can be done in parallel with US2 retrofit tasks.
## Parallel Example: US2
- T018 (PolicyResource declaration) can be implemented in parallel with T020 (OperationRunResource declaration).
## Implementation Strategy
### MVP First (US1 only)
1. Complete Phase 1 + Phase 2.
2. Implement Phase 3 (US1) guard + exemptions.
3. Validate guard behavior by adding/removing a declaration locally.
### Incremental Delivery
- Add US2 representative surfaces next (PolicyResource + OperationRunResource + one RelationManager).
- Add US3 RBAC semantics tests last (keeps scope tight while contract infrastructure stabilizes).