6.3 KiB
6.3 KiB
Research — Spec 076 (Permissions Enterprise UI)
Decisions
1) Build a dedicated tenant-scoped Filament Page
- Decision: Implement a new Filament Page under the tenant panel route (
/admin/t/{tenant}/...) for the “Required permissions” enterprise remediation UX. - Rationale:
- The existing
TenantResourceinfolist entry is a raw list; Spec 076 requires a two-layer remediation layout (overview + matrix) and feature grouping. - A dedicated Page can provide operator-first UX without bloating the tenant detail resource.
- The existing
- Alternatives considered:
- Extending the existing
TenantResourceview: rejected because it couples a complex remediation UI to a general-purpose resource view and makes verification deep-linking/clustering harder.
- Extending the existing
2) Use stored + config-based data only at render time (DB-only render)
- Decision: The page loads required permissions from
config('intune_permissions.permissions')and granted/missing statuses from thetenant_permissionstable viaTenantPermissionService::compare($tenant, persist: false, liveCheck: false, useConfiguredStub: false). - Rationale:
- Satisfies FR-076-008 (no external network calls during page view).
- Reuses existing data normalization and status modeling.
- Alternatives considered:
- Calling Graph on page view (
liveCheck: true): rejected (explicitly out of scope and violates DB-only render).
- Calling Graph on page view (
3) Authorization semantics: non-member 404, member missing capability 403
- Decision:
- Non-member tenant access remains deny-as-not-found (404) via the Admin panel middleware (
DenyNonMemberTenantAccess). - Page access is capability-gated via
Page::canAccess()usingCapabilities::TENANT_VIEW.
- Non-member tenant access remains deny-as-not-found (404) via the Admin panel middleware (
- Rationale:
- Matches Constitution RBAC-UX-002 and RBAC-UX-003.
- Ensures correct semantics for both initial request and Livewire requests.
- Alternatives considered:
- Enforcing capability only in
mount()with customabort(...): rejected becausecanAccess()is the consistent Filament entry-point gate and keeps nav hiding in sync.
- Enforcing capability only in
4) Badge semantics: use centralized domains only
- Decision:
- Per-permission badges:
BadgeDomain::TenantPermissionStatus. - Overall status badge:
BadgeDomain::VerificationReportOverallwith values fromVerificationReportOverall.
- Per-permission badges:
- Rationale:
- Constitution BADGE-001 requires centralized semantic mapping.
5) Filters/search implementation: server-side Livewire state, in-memory filtering
- Decision: Represent filter/search state as Livewire properties on the Page and filter the already-loaded permission array in-memory.
- Rationale:
- Dataset size is small (config-defined permissions), so in-memory filtering is fast and stable.
- Enables programmatic tests for filtering/copy payload generation without relying on browser JS.
- Alternatives considered:
- Filament
Tableswith query-backed filters: rejected as unnecessary complexity for a config-driven list. - Pure client-side Alpine filtering: rejected due to weaker automated testability.
- Filament
6) Copy-to-clipboard: “copy payload modal” + robust clipboard fallback
- Decision: Implement copy actions that open a modal (or inline panel) containing the exact newline-separated payload; a “Copy” button uses the existing robust Alpine clipboard fallback pattern.
- Rationale:
- Clipboard APIs are browser-only; Livewire actions cannot write directly to clipboard.
- Reuses proven fallback approach in
resources/views/filament/partials/json-viewer.blade.php. - Makes copy output auditable/visible before copying (enterprise-friendly).
- Alternatives considered:
- Attempting server-side copy: not possible.
7) Verify-step clustering: emit clustered checks in verification_report
- Decision:
- Extend the queued verification job (
ProviderConnectionHealthCheckJob) to write a verification report that includes the existing connection check plus 5–6 permission cluster checks. - Update the onboarding wizard Verify step to render
OperationRun.context.verification_report(viaVerificationReportViewer) and show checks issues-first.
- Extend the queued verification job (
- Rationale:
- The project already has a report schema (
VerificationReportSchema) and writer (VerificationReportWriter). - Clustering in the report keeps the experience consistent across the wizard and operation-run detail views.
- The project already has a report schema (
- Alternatives considered:
- Cluster in Blade only: rejected because it does not affect summary/overall and can drift between views.
8) Enterprise correctness: refresh Observed permissions during the verification run
- Decision:
- The queued verification run (Operation Run) attempts a live Graph refresh for Observed permissions and persists it to
tenant_permissions. - Viewer surfaces (Required Permissions page, onboarding Verify step, operation run viewer) remain DB-only at render time.
- If the refresh fails (429/network), permission clusters degrade to warnings with retry guidance and MUST NOT assert “missing permissions” based on stale/empty inventory.
- The queued verification run (Operation Run) attempts a live Graph refresh for Observed permissions and persists it to
- Rationale:
- Prevents false “missing” findings when the stored inventory is empty/stale.
- Keeps all external calls in the queued run, maintaining the DB-only render rule.
Open questions resolved (NEEDS CLARIFICATION → decision)
“Enabled features” for impact summary
- Decision: In Spec 076 scope, treat “enabled features” as the feature tags present in
config('intune_permissions.permissions'). - Rationale: There is no current per-tenant feature-enable registry in the codebase; feature tags already exist and are deterministic.
- Future upgrade path: If/when tenant-specific enablement exists, compute relevance by intersecting enabled features with permission feature tags.
Check cluster proposal (stable keys)
Target: 5–7 checks; issues-first.
provider.connection.check(existing)permissions.admin_consent(overall admin consent / application permissions missing)permissions.directory_groupspermissions.intune_configurationpermissions.intune_appspermissions.intune_rbac_assignmentspermissions.scripts_remediations(optional / skip when irrelevant)
Each permission-derived check:
- Pass: no missing permissions in its mapped set
- Fail/Blocked: any missing required permission in its set
- Skip: cluster mapped permissions set is empty (or feature not relevant)
- Next step: “Open required permissions” deep link to the new page (optionally pre-filtered by Feature).