61 lines
5.4 KiB
Markdown
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. |