TenantAtlas/specs/277-stored-reports-surface/research.md
Ahmed Darrazi db83112edc
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 6m41s
WIP: commit changes for PR to platform-dev
2026-05-06 01:50:13 +02:00

61 lines
5.4 KiB
Markdown

# Research: Stored Reports Surface v1
**Date**: 2026-05-06
**Branch**: `277-stored-reports-surface`
## Decision 1: Use one tenant-panel Filament resource with list and view pages
- **Decision**: Implement the new surface as one tenant-scoped Filament resource with a register and a read-only view page.
- **Rationale**: The repo already uses tenant-panel Filament resources with clickable-row inspection and infolist-style view pages for read-only registry surfaces. That keeps the slice inside the current UI contract, keeps Livewire behavior native, and avoids a bespoke report-view shell.
- **Alternatives considered**:
- Custom dashboard page or widget-only viewer: rejected because it would create a parallel navigation and interaction model for a standard read-only registry surface.
- Edit-page-as-view workaround: rejected because the constitution requires inspection surfaces to use view/infolist semantics rather than disabled edit forms.
## Decision 2: Reuse `StoredReport` and `ArtifactTruthPresenter` instead of creating new lifecycle truth
- **Decision**: Keep `StoredReport` as the only persisted truth and reuse `ArtifactTruthPresenter::forStoredReport()` for current versus historical retained state.
- **Rationale**: The presenter already computes retained lifecycle truth by comparing the current row to the latest same-family row for the tenant. A second status column, mirror record, or new presenter layer would duplicate truth the repo already has.
- **Alternatives considered**:
- Persist a `current` flag or second lifecycle column on `stored_reports`: rejected because current versus historical is already derivable from existing rows.
- Introduce a new stored-report-specific presenter or envelope system: rejected because `ArtifactTruthPresenter` already covers stored reports.
## Decision 3: Add explicit `permission_posture.view` instead of piggybacking on unrelated capabilities
- **Decision**: Introduce one bounded `permission_posture.view` capability alongside the existing `entra_roles.view` capability.
- **Rationale**: The spec requires family-aware browse and detail visibility. Reusing `provider.view`, `review_pack.view`, or `evidence.view` would blur ownership between the stored-report surface and downstream consumers.
- **Alternatives considered**:
- Reuse provider or evidence capabilities: rejected because the stored-report surface would become coupled to unrelated read paths.
- Introduce one generic `stored_report.view` capability: rejected because the repo already has two concrete families with separate product meanings, and family-aware filtering is part of the feature value.
## Decision 4: Support exactly two family summary branches and keep all other families out of v1
- **Decision**: Render explicit summary branches only for `permission_posture` and `entra.admin_roles`, and keep any unexpected report family entirely outside v1 browse and detail scope.
- **Rationale**: The repo has exactly two concrete stored-report families today. The narrowest correct implementation is explicit presentation for those families only. A local catch-all renderer would still need an authorization story and would widen the surface contract beyond the two repo-real families.
- **Alternatives considered**:
- Generic report-schema registry or plugin renderer: rejected because two concrete cases do not justify a framework.
- Local catch-all renderer for unexpected families: rejected because it widens the browse/detail contract without a bounded authorization story.
## Decision 5: Canonical drilldown stays on the one confirmed widget seam
- **Decision**: Make the stored-report detail route the canonical drilldown target for `AdminRolesSummaryWidget` only.
- **Rationale**: The widget is the clearest current repo-real missing launch point. The codebase does not currently expose broad Filament proof links to stored reports, so the package should not invent new local report cards or pseudo-view links just to claim convergence.
- **Alternatives considered**:
- Widget-only link with no register: rejected because it would leave stored-report browsing fragmented.
- Add new stored-report links to every evidence or review surface up front: rejected because repo truth does not currently show broad operator-facing stored-report launch affordances there.
## Decision 6: Keep proof in focused feature tests and skip browser by default
- **Decision**: Plan feature coverage for register behavior, entitlement behavior, detail presentation, and widget drilldown, with no default browser lane.
- **Rationale**: The surface is native Filament list and view behavior plus a widget link. The main risks are authorization and disclosure rules, not browser-only choreography.
- **Alternatives considered**:
- Browser smoke as a default requirement: rejected because the slice does not introduce a custom interaction model.
- Large unitized presentation layers: rejected because that would create indirection just to make testing easier.
## Final Research Outcome
- One native tenant-panel Filament resource is the narrowest correct surface shape.
- Existing stored-report truth and artifact-truth lifecycle semantics are sufficient; no new persistence or lifecycle framework is needed.
- `permission_posture.view` is the only new capability required.
- Summary rendering stays explicit for the two repo-real families and avoids a registry.
- Canonical drilldown starts and ends in v1 with the admin-roles widget seam.
- Focused feature tests are the honest default proving path.