# Implementation Plan: Spec 330 - Environment Dashboard / Baseline Compare Productization **Branch**: `330-environment-dashboard-baseline-compare-productization` | **Date**: 2026-05-19 | **Spec**: `specs/330-environment-dashboard-baseline-compare-productization/spec.md` **Input**: User-provided Spec 330 and repo inspection. ## Summary Productize two existing environment-owned strategic surfaces into decision-first governance pages: ```text Is this environment ready, blocked, stale, or requiring review? Which baseline drift requires action? ``` The implementation must keep current routes, source truth, RBAC, environment-owned scope, and OperationRun semantics. It must not add new backend readiness/drift/proof engines. Environment Dashboard should elevate status, reason, impact, proof, and one primary next action before technical detail. Baseline Compare should elevate assignment, compare trust, drift impact, evidence/proof, and one primary next action before findings detail, raw diff, or diagnostics. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52.0. **Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Tailwind CSS 4.2.2. **Storage**: PostgreSQL; no schema change expected. **Testing**: Pest 4 Feature/Livewire/Browser tests. **Validation Lanes**: confidence and browser; targeted navigation/context guard filters. **Target Platform**: Laravel Sail locally; Dokploy/container deployment posture unchanged. **Project Type**: Laravel monolith under `apps/platform`. **Performance Goals**: DB-only page render; no Graph/provider API calls during render; no broad new query families. **Constraints**: No new persisted truth, migration, package, queue, scheduler, storage, env var, deployment asset, compatibility route, or legacy alias support. **Scale/Scope**: Two existing environment-owned Filament pages, existing widget/view structures, feature-local payload helpers if needed, focused tests, and browser smoke. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed existing operator-facing strategic environment-owned surfaces. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: - `/admin/workspaces/{workspace}/environments/{environment}` - `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare` - `apps/platform/app/Filament/Pages/EnvironmentDashboard.php` - `apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardOverview.php` - `apps/platform/resources/views/filament/widgets/dashboard/environment-dashboard-overview.blade.php` - `apps/platform/resources/views/filament/widgets/dashboard/environment-dashboard-context-chips.blade.php` - `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php` - `apps/platform/app/Filament/Pages/BaselineCompareLanding.php` - `apps/platform/resources/views/filament/pages/baseline-compare-landing.blade.php` - **No-impact class, if applicable**: N/A. - **Native vs custom classification summary**: Native Filament Dashboard/Page/Widget plus existing Blade composition; no new UI framework. - **Shared-family relevance**: dashboard signals, status messaging, action links, proof links, OperationRun links, baseline compare state, diagnostics disclosure. - **State layers in scope**: route-owned environment, page payload, widget payload, Baseline Compare launch query state (`baseline_profile_id`, `subject_key`, `nav`), and existing session/context guard behavior. - **Audience modes in scope**: operator-MSP, manager, governance operator, support reviewer where authorized. - **Decision/diagnostic/raw hierarchy plan**: decision first, proof path visible, diagnostics collapsed, raw/support hidden or gated. - **Raw/support gating plan**: collapsed by default and capability-gated through existing support diagnostics/raw capabilities where exposed. - **One-primary-action / duplicate-truth control**: one dominant next action per page; secondary links/cards support the decision rather than repeat the same verdict. - **Handling modes by drift class or surface**: review-mandatory for UI-002 and UI-061 strategic surfaces; document-in-feature for any UI coverage registry no-change decision. - **Repository-signal treatment**: Spec 325 target images are direction only; runtime claims must be repo-verified, derived, unavailable, or deferred. - **Special surface test profiles**: `global-context-shell`, `monitoring-state-page`, `shared-detail-family`. - **Required tests or manual smoke**: Feature/Livewire tests for decision layout, false-green guard, RBAC/scope/disclosure plus Pest Browser smoke for explicit environment routes, no-baseline/action-needed/drift states, diagnostics collapsed, raw detail hidden, cross-workspace denial, and static tenant copy guard. - **Exception path and spread control**: none expected. Any new dangerous action, schema, capability, backend proof source, or route family requires spec/plan/tasks update first. - **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage. - **UI/Productization coverage decision**: active spec package carries productization proof. Update UI coverage registry only if route/archetype/coverage classification changes; otherwise document why UI-002/UI-061 plus Spec 325 artifacts are sufficient. - **Coverage artifacts to update**: none expected unless implementation changes route/archetype state. - **Navigation / Filament provider-panel handling**: no panel provider registration changes expected. Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`. - **Screenshot or page-report need**: screenshots required; full page report optional unless implementation materially changes coverage classification. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: Environment Dashboard page, dashboard widgets, dashboard summary builder, Baseline Compare Landing page/view, baseline stats/aggregate helpers, backup/recovery helpers, provider permission view models, OperationRun links, resource policies, `UiEnforcement`, and browser fixtures/tests. - **Shared abstractions reused**: `EnvironmentDashboardSummaryBuilder`, `EnvironmentDashboardSummary`, `BaselineCompareStats`, `TenantGovernanceAggregateResolver`, `OperationRunLinks`, `ManagedEnvironmentLinks`, `OperationUxPresenter`, `OpsUxBrowserEvents`, `BadgeRenderer`, `UiEnforcement`, policies/capability resolvers. - **New abstraction introduced? why?**: none. Page-local private helpers may be added only to reduce Blade complexity or duplicate payload calculation. - **Why the existing abstraction was sufficient or insufficient**: Existing paths provide source truth, authorization, links, compare state, backup/recovery/readiness signals, and OperationRun proof. They do not fully enforce the first-read decision hierarchy and collapsed diagnostics disclosure. - **Bounded deviation / spread control**: no public readiness/proof/disclosure framework; keep composition local to the two surfaces. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes, through existing Baseline Compare start action and proof links. No new OperationRun type or lifecycle behavior. - **Central contract reused**: `OperationRunLinks`, `OperationUxPresenter`, `OpsUxBrowserEvents`, existing `OperationRunPolicy`, existing operation detail routes, and `BaselineCompareService::startCompare()`. - **Delegated UX behaviors**: compare queued toast, run-enqueued browser event, open operation link, blocked/cannot-start messaging, and tenant/workspace-safe URLs stay on the existing Ops UX path. - **Surface-owned behavior kept local**: display-only proof availability labels and next-action hierarchy. - **Queued DB-notification policy**: unchanged / N/A. - **Terminal notification path**: unchanged. - **Exception path**: none. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: display-only provider readiness/permissions and static copy guard. - **Provider-owned seams**: existing provider connection, Microsoft/Entra/Intune required permissions, provider tenant ID where source records require it. - **Platform-core seams**: workspace, environment, readiness, proof, baseline, drift, evidence, operation, review, diagnostics. - **Neutral platform terms / contracts preserved**: workspace, environment, provider, required permissions, operation proof, evidence, review, baseline, drift, diagnostics. - **Retained provider-specific semantics and why**: Microsoft/Entra/Intune can remain at source/provider-boundary labels only. - **Bounded extraction or follow-up path**: Provider Readiness Productization remains a separate follow-up spec. ## Constitution Check - **Inventory-first, snapshots-second**: Environment and compare surfaces derive from last-observed inventory, explicit snapshots, backups, evidence, reviews, and operations; no new source truth is created. - **Read/write separation by default**: Pages remain read/decision-first. Existing compare start is the only high-impact operation start and already requires confirmation/authorization/OperationRun. - **Single Contract Path to Graph**: No Graph/provider API calls may be added to page render. - **Deterministic Capabilities**: Reuse existing `Capabilities`, `CapabilityResolver`, resource policies, `UiEnforcement`, and route authorization. - **RBAC-UX**: UI visibility is not security. Server-side policies/gates remain authoritative for operations, evidence, review packs, backup/restore, provider permissions, and diagnostics. - **Workspace/environment isolation**: Both pages require explicit route-bound environment. Non-member or mismatched workspace/environment access is 404. - **OperationRun UX**: Existing compare start and operation links reuse shared OperationRun UX helpers; no local lifecycle/notification behavior. - **UI-COV-001**: Existing strategic surfaces UI-002 and UI-061 materially change. Active spec package must carry repo-truth map, tests, screenshots, and coverage close-out decision. - **TEST-GOV-001**: Targeted Feature and Browser lanes are explicit. Browser cost is named and scoped. - **PROP-001 / BLOAT-001**: No new source of truth, persisted entity, enum/status family, public abstraction, proof engine, or cross-domain UI framework. - **UI-FIL-001**: Use native Filament components/shared primitives first; custom Blade must preserve Filament semantics, accessibility, dark mode, and one-primary-action hierarchy. - **Filament v5 / Livewire v4**: Livewire v4.0+ compliance required. No Livewire v3 or Filament v3/v4 APIs. - **Panel provider location**: panel providers remain in `apps/platform/bootstrap/providers.php`; no provider registration change expected. - **Global search**: no resource global search change expected. If a resource is touched, it must retain safe View/Edit pages or disable global search. - **Destructive/high-impact actions**: no destructive action introduced. Existing compare start remains confirmed/capability-gated/OperationRun-backed. - **Assets**: no Filament asset registration expected; `filament:assets` deployment posture unchanged. ## Current Repo Truth Summary Existing verified Environment Dashboard surfaces: - `EnvironmentDashboard` extends Filament `Dashboard` and renders `EnvironmentDashboardContextChips`, `ManagedEnvironmentTriageArrivalContinuity`, `DashboardKpis`, and `EnvironmentDashboardOverview`. - `EnvironmentDashboard::getUrl()` resolves route-owned `ManagedEnvironment` and strips workspace/environment parameters into `ManagedEnvironmentLinks::viewUrl()`. - `EnvironmentDashboardSummaryBuilder` already derives context, posture, KPIs, recommended actions, governance status, readiness cards, active operation summary, and recent operations from existing models/services. - Current dashboard view renders recommended actions, governance status, active operations requiring attention, and right-side readiness cards. - Existing browser tests already assert dashboard context chips, KPI cards, readiness cards, ranked actions, and no table-first layout. Existing verified Baseline Compare surfaces: - `BaselineCompareLanding` is environment-owned at slug `workspaces/{workspace}/environments/{environment}/baseline-compare`. - It rejects old workspace-style `/admin/baseline-compare-landing?environment_id=` URLs and remembered environment fallback. - It strips legacy scope keys from generated URLs while preserving `baseline_profile_id`, `subject_key`, and `nav`. - `BaselineCompareStats::forTenant()` derives states including `no_tenant`, `no_assignment`, `no_snapshot`, `invalid_scope`, `comparing`, `failed`, `idle`, and `ready`. - Existing compare start action uses `Action::make('compareNow')->requiresConfirmation()->action(...)`, `BaselineCompareService::startCompare()`, `UiEnforcement`, `OperationUxPresenter`, and `OpsUxBrowserEvents`. - Current Blade already has explanation/stats, no-assignment/no-snapshot empty states, coverage warnings, evidence gap details, findings summaries, and diagnostics section; diagnostics are currently rendered when present and must become collapsed/default-secondary. Known productization gaps: - Environment Dashboard needs a more explicit decision card/question and proof/action panel instead of equal-weight dashboard sections. - Environment Dashboard readiness dimensions should map to source truth and unavailable states in the spec map before implementation. - Baseline Compare needs a first-read drift/action decision card, no-baseline actionable unavailable state, proof/disclosure panel, and raw diff/diagnostics collapsed by default. - Baseline Compare must avoid false all-clear copy when zero findings coexist with evidence/coverage/trust gaps. ## Existing Repository Surfaces Likely Affected Runtime files, only during later implementation: - `apps/platform/app/Filament/Pages/EnvironmentDashboard.php` - `apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardOverview.php` - `apps/platform/resources/views/filament/widgets/dashboard/environment-dashboard-overview.blade.php` - `apps/platform/resources/views/filament/widgets/dashboard/environment-dashboard-context-chips.blade.php` - `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php` - `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummary.php` - `apps/platform/app/Filament/Pages/BaselineCompareLanding.php` - `apps/platform/resources/views/filament/pages/baseline-compare-landing.blade.php` - `apps/platform/resources/lang/en/*` and `apps/platform/resources/lang/de/*` only where touched copy follows existing localization conventions. Tests, only during later implementation: - `apps/platform/tests/Feature/Filament/TenantDashboardTenantScopeTest.php` - `apps/platform/tests/Feature/Filament/TenantDashboardDbOnlyTest.php` - `apps/platform/tests/Feature/Rbac/DashboardRecoveryPostureVisibilityTest.php` - `apps/platform/tests/Feature/Rbac/TenantDashboardArrivalContextVisibilityTest.php` - `apps/platform/tests/Feature/Filament/BaselineCompareEnvironmentRouteContractTest.php` - `apps/platform/tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php` - `apps/platform/tests/Feature/Filament/BaselineCompareExplanationSurfaceTest.php` - `apps/platform/tests/Feature/Rbac/DriftLandingUiEnforcementTest.php` - `apps/platform/tests/Feature/Navigation/Spec322AdminSurfaceScopeContractTest.php` - `apps/platform/tests/Feature/Navigation/Spec322EnvironmentCtaUrlContractTest.php` - `apps/platform/tests/Feature/ManagedEnvironment/ManagedEnvironmentCopyNeutralizationGuardTest.php` - `apps/platform/tests/Browser/Spec330EnvironmentDashboardBaselineCompareSmokeTest.php` Spec/UI artifacts: - `specs/330-environment-dashboard-baseline-compare-productization/repo-truth-map.md` - screenshot artifacts under `specs/330-environment-dashboard-baseline-compare-productization/artifacts/screenshots/` - optional UI coverage registry updates only if implementation materially changes route/archetype/coverage state. ## Domain / Model Implications - No new model, table, migration, enum, status family, persisted display state, or public service contract. - Environment readiness must derive from: - `ManagedEnvironment` and workspace relation. - `ProviderConnection` status/health/consent/readiness fields. - `ManagedEnvironmentPermission` and required permissions view model. - `TenantBackupHealthResolver`, `TenantBackupHealthAssessment`, backup sets/schedules. - `RestoreSafetyResolver` and restore/recovery evidence presentation. - `TenantGovernanceAggregateResolver`, `Finding`, `FindingException`, and baseline compare stats. - `EvidenceSnapshot`, `EnvironmentReview`, `ReviewPack`, and related links. - `OperationRun` attention/freshness/outcome and `OperationRunLinks`. - Baseline drift/action state must derive from: - `BaselineTenantAssignment`, `BaselineProfile`, `BaselineSnapshot`, `BaselineSnapshotTruthResolver`. - `BaselineCompareStats`, `TenantGovernanceAggregate`, `BaselineCompareSummaryAssessment`, `operatorExplanation`. - `Finding` drift findings/severity counts. - Evidence gap summaries/details and compare diagnostics only as secondary/collapsed context. - Existing compare OperationRun relation and links. ## UI / Filament Implications - Filament v5 and Livewire v4.0+ compliance must be preserved. - Keep panel provider registration unchanged. - Use Filament sections/buttons/badges/actions and existing shared primitives where suitable. - Avoid fake charts, fake health, fake compliance, fake customer-safe, fake restore confidence, or generic KPI dashboard expansion. - Environment Dashboard target order: - header/scope - main readiness decision card - readiness dimensions - right-side proof/action/disclosure panel - ranked next actions - operations/reviews/evidence/backup/provider details as secondary context - diagnostics collapsed - Baseline Compare target order: - header/scope - main drift/action decision card - no-baseline visual Compare readiness stepper/pipeline and compact available inputs when compare is blocked by missing assignment - assignment / compare trust / drift summary only when a baseline-backed compare state exists - right-side evidence/proof/disclosure panel - findings/evidence-gap summary - raw diff/details collapsed or secondary ## Livewire / Page State Implications - Environment Dashboard and Baseline Compare must rely on route-owned environment context. - Baseline Compare launch context (`baseline_profile_id`, `subject_key`, `nav`) remains initialization/query state only; it must not override environment ownership. - Existing `BaselineCompareLanding::monitoringPageStateContract()` should remain consistent with Spec 198/319 contracts. - Clean old workspace-style URLs and legacy query aliases must not establish environment context. - Cross-workspace route mismatches stay 404. ## RBAC / Policy Implications Reuse existing authorization: - Environment page visibility: environment membership and `TENANT_VIEW`. - Provider permissions/readiness: required permissions routes and existing provider/permission capabilities. - Backup posture: backup-set/schedule capabilities and policies. - Restore/recovery proof: restore-run/backup capabilities and policies. - Baseline compare view: environment access and `TENANT_VIEW`. - Compare start: `TENANT_SYNC` through existing `UiEnforcement`. - Baseline profile links: `BaselineProfileResource` authorization/policies. - Drift findings: `FindingResource` / finding capabilities. - Evidence snapshots: `EvidenceSnapshotPolicy` / evidence capability. - Review and review packs: `EnvironmentReviewResource`, `ReviewPackResource`, policies. - Operation proof: `OperationRunPolicy` and link helpers. - Diagnostics/raw detail: `SUPPORT_DIAGNOSTICS_VIEW` or stricter existing raw/support capability. No new permission semantics should be added unless implementation proves existing capabilities cannot express the action and spec/plan/tasks are updated first. ## Audit / Observability Implications - No new audit events are expected for read-only productization. - Existing support diagnostics modal on Environment Dashboard already writes audit/telemetry and must remain authorized/redacted. - Existing Baseline Compare start audit/OperationRun behavior remains unchanged. - Do not imply OperationRun completion proves environment health or compare acceptability. ## Test Strategy Feature/Livewire tests: - Repo truth map existence and required sections. - Environment Dashboard decision layout. - Environment Dashboard no false green when proof is missing. - Environment Dashboard ranked next actions. - Baseline Compare decision layout. - Baseline Compare no-baseline actionable unavailable state. - Baseline Compare drift/evidence state with raw details hidden by default. - Diagnostics hidden/collapsed by default across both pages. - Environment-owned route contract and legacy alias rejection. - Static `tenant` platform-copy guard. - RBAC for visible/hidden actions and raw diagnostics. Browser tests: - Explicit Environment Dashboard route non-empty/action-needed state. - Explicit Baseline Compare route no-baseline state. - Baseline Compare compare/drift state if fixtures support it. - Diagnostics collapsed and raw details absent by default. - Cross-workspace/invalid environment safe denial. - Dynamic display name containing `Tenant` allowed, static tenant copy absent. - Required screenshots under the Spec 330 artifacts path. Validation: - Targeted Feature/Livewire tests. - Targeted Browser smoke. - Context/route guard filter for EnvironmentDashboard, BaselineCompare, AdminSurfaceScope, EnvironmentOwned, LegacyTenant, and Spec322. - `pint --dirty`. - `git diff --check`. ## Implementation Phases ### Phase 1 - Repo Truth And Current UI Audit - Inspect Environment Dashboard page/widget/summary builder/tests. - Inspect Baseline Compare Landing page/view/stats/tests. - Inspect Spec 325 target images/briefs and UI audit reports. - Create/update `repo-truth-map.md`. - Confirm exact source/capability/fallback for every visible element. - Stop if a desired visible element requires new backend truth. ### Phase 2 - Environment Dashboard Productization - Add a first-read readiness question and decision card. - Refine existing summary builder/widget payloads to expose status/reason/impact/proof/next-action without new state persistence. - Add/right-size proof/action panel and ranked actions. - Keep useful existing cards/details as secondary context. - Collapse diagnostics/raw support by default. ### Phase 3 - Baseline Compare Productization - Add a first-read drift/action question and decision card. - Render no-baseline/no-snapshot/no-compare states as actionable unavailable states. - Show assignment, compare trust, drift impact, evidence/proof, and operation proof before findings/raw details. - Collapse raw diff/diagnostics by default. - Preserve existing compare start action semantics and matrix/detail links. ### Phase 4 - Route, RBAC, Copy, And Disclosure Guards - Verify route-owned environment context. - Reject remembered fallback and legacy aliases. - Guard cross-workspace mismatches. - Gate/hide unavailable actions. - Preserve dynamic names containing `Tenant`; remove static platform `tenant` copy. - Ensure no false green claims. ### Phase 5 - Browser Smoke And Screenshots - Add browser smoke file. - Create required screenshots where generated. - Confirm diagnostics collapsed and raw details absent by default. - Confirm no context drift. ### Phase 6 - Validation And Close-Out - Run focused Feature/Livewire/browser tests. - Run targeted Spec 314-322 context guards. - Run Pint and diff check. - Report full suite status honestly. - Record no migrations/packages/env/queues/storage/deployment assets/backcompat/legacy aliases. ## Risk Controls - Treat Spec 325 images as direction only; map every visible element to repo truth. - Use unavailable/deferred states instead of inventing proof. - Do not broaden Baseline Compare Matrix scope. - Do not turn Environment Dashboard into a generic M365/admin-center status page. - Keep OperationRun as execution proof, not health proof. - Keep raw diagnostics collapsed/capability-gated. ## Rollout / Deployment Considerations - No migration expected. - No seeders expected. - No env var expected. - No queue/scheduler/storage change expected. - No package change expected. - No deployment asset change expected unless implementation unexpectedly registers Filament assets; current expectation is no `filament:assets` change beyond existing deployment posture. - Staging validation should focus on route-owned environment behavior, no-baseline/action-needed states, diagnostics collapsed, and no static `tenant` copy. ## Candidate Selection Gate Passed. Spec 330 was directly user-provided, is aligned with Spec 325 strategic target surfaces and post-Spec 329 follow-up sequencing, is not already present as an active/completed package, preserves completed Specs 314-329, and is scoped to two existing environment-owned pages. ## Spec Readiness Gate Expected pass after `spec.md`, `plan.md`, `tasks.md`, `repo-truth-map.md`, and `checklists/requirements.md` are generated and preparation analysis finds no blocking consistency issues.