# Implementation Plan: Customer Health Score **Branch**: `245-customer-health-score` | **Date**: 2026-04-27 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/245-customer-health-score/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/245-customer-health-score/spec.md` ## Summary - Add one bounded `CustomerHealth` support namespace that derives workspace-health summaries from existing onboarding, provider, telemetry, `OperationRun`, findings, and review-pack truth. - Reuse the existing `/system` dashboard, existing dashboard window selector, and existing system widget family to show both aggregate health counts and an attention-needed workspace list. - Reuse the existing system tenant and workspace residual detail pages as decision-first follow-up surfaces by adding one read-only customer-health card above the existing diagnostics. - Keep the slice derived-only, Livewire v4-compatible, Filament v5-native, and free of migrations, new persistence, new panel providers, global-search changes, destructive actions, or asset changes. ## Technical Context **Language/Version**: PHP 8.4 (Laravel 12) **Primary Dependencies**: Laravel 12 + Filament v5 + Livewire v4 + Pest; existing `ProductTelemetrySummaryQuery`, `ProviderConnectionStateProjector`, `StuckRunClassifier`, `BadgeRenderer`, `SystemConsoleWindow`, system directory links, and system operations links **Storage**: N/A - no new persisted health truth **Testing**: Pest unit + feature tests only **Validation Lanes**: fast-feedback, confidence **Target Platform**: Sail-backed Laravel admin panel under `/system` **Project Type**: web **Performance Goals**: derive health summaries inline for the current system dashboard without background jobs, remote calls, or broad per-tenant page reconstruction **Constraints**: no new score table, no customer-facing surface, no CRM or billing workflow expansion, no direct `/admin` deep links, and no new badge taxonomy **Scale/Scope**: six fixed first-slice dimensions, one derived summary query, two dashboard widgets, one shared decision-first follow-up card on the existing system detail pages, and focused unit plus feature proof only ## First-Slice Dimension Inventory The first slice is locked to these six dimensions only: 1. **Onboarding readiness** — point-in-time signal derived from existing onboarding-readiness truth 2. **Provider connection health** — point-in-time signal derived from existing provider consent and verification truth 3. **Operational stability** — windowed signal derived from failed and stuck `OperationRun` truth using the selected `SystemConsoleWindow` 4. **Governance pressure** — point-in-time signal derived from active high-severity, overdue, or exception-warning findings truth 5. **Review-pack readiness** — narrow mixed signal derived from recent review-pack request context plus the latest relevant `ReviewPack` state 6. **Engagement freshness** — windowed signal derived from existing `product_usage_events` Any change to this dimension inventory requires an explicit spec update before implementation expands or swaps the slice. ## Health-Level Resolution Rules - Reuse existing `SystemHealth` levels only: `ok`, `warn`, `critical`, `unknown` - Overall level precedence is fixed for v1: `critical` > `warn` > `unknown` > `ok` - Windowed dimensions must honor the selected dashboard time window - Point-in-time dimensions must not pretend to share the same time basis as windowed dimensions - Missing or stale source truth must remain explicit and must never silently collapse to `ok` - Archived workspaces are excluded from active counts, and archived tenants do not contribute source truth into active workspace-health derivation - Attention-needed workspace ordering is fixed for v1: overall severity desc, non-`ok` dimension count desc, workspace name asc, then workspace id asc ## Review-Pack Readiness Rule `Recent` means the currently selected dashboard window. Request context comes from existing review-pack request telemetry when available, falling back to a `ReviewPack` created for the same workspace inside that same window. | Condition | Review-pack readiness level | Notes | |---|---|---| | No request context and no relevant pack activity in the selected window | `unknown` | The first slice does not infer periodic review obligations from silence | | Request context exists in the selected window and no relevant pack is usable yet | `warn` | Covers queued, running, or not-yet-materialized review-pack generation | | Latest relevant pack in the selected window is ready and not expired | `ok` | A usable recent review pack exists | | Latest relevant pack in the selected window is failed or expired | `critical` | Recent review-pack work ended unusably and needs attention | ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: native Filament dashboard plus existing custom system widget family and the existing residual system detail pages - **Shared-family relevance**: dashboard signals/cards, compact attention list, system-safe deep links, existing `SystemHealth` badges - **State layers in scope**: page, widget, window query, detail-link state, residual detail follow-up state - **Handling modes by drift class or surface**: review-mandatory - **Repository-signal treatment**: review-mandatory - **Special surface test profiles**: standard-native-filament - **Required tests or manual smoke**: functional-core, state-contract, follow-up-detail smoke - **Exception path and spread control**: none - **Active feature PR close-out entry**: Guardrail - **List-surface review standard**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/docs/product/standards/list-surface-review-checklist.md` applies to `CustomerHealthTopWorkspaces`; accepted compact-widget exceptions are no persistence trio, no bulk actions, no row click, and no empty-state CTA ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: `App\Filament\System\Pages\Dashboard`, `App\Filament\System\Pages\Directory\ViewTenant`, `App\Filament\System\Pages\Directory\ViewWorkspace`, `App\Filament\System\Widgets\ControlTowerHealthIndicator`, `App\Filament\System\Widgets\ControlTowerTopOffenders`, `App\Support\ProductTelemetry\ProductTelemetrySummaryQuery`, `App\Services\Providers\ProviderConnectionStateProjector`, `App\Support\SystemConsole\StuckRunClassifier`, existing `Finding` truth, existing `ReviewPack` truth, and platform-plane system link helpers - **Shared abstractions reused**: dashboard widget composition, dashboard time-window semantics, `BadgeRenderer` for `SystemHealth`, system-safe link helpers, existing residual system detail pages, and existing source-truth owners for provider, telemetry, operations, findings, and review packs - **New abstraction introduced? why?**: one bounded `CustomerHealth` support namespace with a fixed dimension catalog and one derived summary query is justified because the repo already has isolated source truths but no shared workspace-health derivation path - **Why the existing abstraction was sufficient or insufficient**: existing abstractions are sufficient for rendering and navigation but insufficient for deriving one explainable cross-domain workspace summary - **Bounded deviation / spread control**: no page-local health arithmetic, no second badge language, no persistence, and no customer-success surface. All health derivation must converge on the single `CustomerHealth` namespace. - **Platform-safe link contract**: every attention-needed workspace row must expose exactly one platform-safe next link. If a more specific platform-plane route is not appropriate, the row falls back to the existing system tenant-detail context instead of rendering with no link. Dashboard links into residual detail pages must preserve the selected time window so the follow-up card explains the same top drivers as the dashboard. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no - **Central contract reused**: N/A - **Delegated UX behaviors**: N/A - **Surface-owned behavior kept local**: N/A - **Queued DB-notification policy**: N/A - **Terminal notification path**: N/A - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes - **Provider-owned seams**: provider consent and verification outcomes on `ProviderConnection` - **Platform-core seams**: workspace-health dimensions, overall `SystemHealth` level, dominant reason labels, dashboard widget copy, and system-safe next links - **Neutral platform terms / contracts preserved**: customer health, workspace health, attention needed, operational stability, engagement freshness, review readiness - **Retained provider-specific semantics and why**: Microsoft verification and consent states remain provider-owned inputs because they are existing current-release truth already modeled on provider connections - **Bounded extraction or follow-up path**: `document-in-feature` only if one provider-specific dominant reason still needs text-only explanation instead of a platform-safe link in v1 ## Constitution Check *GATE: Must pass before implementation begins. Re-check after design changes.* - Inventory-first / snapshots-second: PASS - the slice derives health from existing observed truths only - Read/write separation: PASS - the slice is read-only - Graph contract path: PASS - no new Graph calls are added - RBAC-UX / workspace isolation / tenant isolation: PASS - system dashboard access rules remain authoritative and no tenant/admin viewer is introduced - Shared pattern reuse / `XCUT-001`: PASS - dashboard widget family, badge semantics, and system link helpers are reused explicitly - Proportionality / `PROP-001` and `ABSTR-001`: PASS - one bounded derived-query path is the narrowest reusable solution - Persisted truth / `PERSIST-001`: PASS - no new persistence is introduced - UI semantics / `UI-SEM-001`: PASS - the slice adds decision-support summaries only and does not create a new workflow hub - Filament-native UI / `UI-FIL-001`: PASS - the operator-facing impact stays on the existing dashboard widget family - Livewire v4 / Filament v5: PASS - the slice remains fully inside the current Filament v5 + Livewire v4 stack - Provider registration location: PASS - no provider registration changes are introduced; Laravel 11+ provider registration stays in `bootstrap/providers.php` - Global search rule: PASS - no resource or global-search changes are introduced - Destructive actions: PASS - none added - Asset strategy: PASS - no new assets are required, so deployment behavior for `filament:assets` remains unchanged - Test governance / `TEST-GOV-001`: PASS - proof remains in focused unit + feature lanes only ## Test Governance Check - **Test purpose / classification by changed surface**: Unit for dimension rules and summary derivation; Feature for `/system` dashboard rendering, explainability, authorization, and residual detail follow-up rendering - **Affected validation lanes**: fast-feedback, confidence - **Why this lane mix is the narrowest sufficient proof**: the slice is server-driven, read-only, and widget-based; browser automation would duplicate what focused unit and feature tests already prove - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/CustomerHealth/CustomerHealthDimensionCatalogTest.php tests/Unit/Support/CustomerHealth/WorkspaceHealthSummaryQueryTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/CustomerHealth/CustomerHealthDashboardWidgetsTest.php tests/Feature/System/CustomerHealth/CustomerHealthExplainabilityTest.php tests/Feature/System/CustomerHealth/CustomerHealthAuthorizationTest.php` - **Fixture / helper / factory / seed / context cost risks**: reuse existing workspaces, tenants, provider connections, onboarding sessions, telemetry events, operation runs, findings, and review packs; avoid browser setup and avoid new heavy support fixtures - **Expensive defaults or shared helper growth introduced?**: no - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: standard-native-filament relief - **Closing validation and reviewer handoff**: reviewers should confirm unknown handling, dominant reason explainability, platform-safe linking, absence of new persistence, and explicit selected-window semantics - **Disclosure-ladder proof**: reviewers should also confirm that default-visible dashboard content stays operator-first, raw or support-grade detail remains behind linked surfaces, and the two widgets do not duplicate the same visible decision summary - **Budget / baseline / trend follow-up**: none expected beyond ordinary feature-local upkeep - **Review-stop questions**: did the implementation add a persisted score model, customer-facing route, or second badge taxonomy; do unknown and recent-review-pack-request cases degrade honestly? - **Escalation path**: `reject-or-split` if the slice expands into CRM, billing, predictive scoring, or a new portfolio workbench page - **Active feature PR close-out entry**: Guardrail - **Test-governance outcome**: keep ## Project Structure ### Documentation (this feature) ```text specs/245-customer-health-score/ ├── checklists/ │ └── requirements.md ├── spec.md ├── plan.md └── tasks.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Filament/ │ │ └── System/ │ │ ├── Pages/ │ │ │ ├── Dashboard.php │ │ │ └── Directory/ │ │ │ ├── ViewTenant.php │ │ │ └── ViewWorkspace.php │ │ └── Widgets/ │ │ ├── CustomerHealthKpis.php │ │ └── CustomerHealthTopWorkspaces.php │ ├── Services/ │ │ └── Providers/ProviderConnectionStateProjector.php │ └── Support/ │ ├── CustomerHealth/ │ │ ├── CustomerHealthDimensionCatalog.php │ │ └── WorkspaceHealthSummaryQuery.php │ ├── ProductTelemetry/ProductTelemetrySummaryQuery.php │ └── SystemConsole/ ├── resources/views/filament/system/pages/directory/ │ ├── view-tenant.blade.php │ └── view-workspace.blade.php ├── resources/views/filament/system/widgets/customer-health-top-workspaces.blade.php └── tests/ ├── Unit/Support/CustomerHealth/ │ ├── CustomerHealthDimensionCatalogTest.php │ └── WorkspaceHealthSummaryQueryTest.php └── Feature/System/CustomerHealth/ ├── CustomerHealthDetailDecisionTest.php ├── CustomerHealthAuthorizationTest.php ├── CustomerHealthDashboardWidgetsTest.php └── CustomerHealthExplainabilityTest.php ``` **Structure Decision**: Single Laravel web application. The implementation adds one bounded support namespace and two dashboard widgets only. ## Complexity Tracking No constitution violations are required. The slice adds one derived summary path only and introduces no new persistence, no new state family, and no new workflow surface. ## Rollout & Risk Controls - Start on the existing `/system` dashboard only; do not introduce a new portfolio or customer-health page in v1. - Keep the first-slice dimension inventory fixed at six. Any added dimension requires a spec update. - Keep review-pack readiness narrow and operational, not programmatic or compliance-heavy. - Use explicit copy or visual grouping to distinguish point-in-time signals from windowed signals. - Guarantee one platform-safe next link per attention-needed workspace row by falling back to the existing system tenant-detail context when a more specific platform-plane route is not appropriate. ## Implementation Outline - Add `App\Support\CustomerHealth\CustomerHealthDimensionCatalog` as the single source for first-slice dimension labels, order, and level precedence rules. - Add `App\Support\CustomerHealth\WorkspaceHealthSummaryQuery` to derive per-workspace summaries from existing onboarding, provider, telemetry, operations, findings, and review-pack truth. - Add `App\Filament\System\Widgets\CustomerHealthKpis` for aggregate health counts. - Add `App\Filament\System\Widgets\CustomerHealthTopWorkspaces` plus a small Blade view for the attention-needed list. - Add one read-only customer-health decision card to the existing system tenant and workspace residual detail pages using the existing summary query and the same dominant drivers as the dashboard. - Register both widgets on the existing `App\Filament\System\Pages\Dashboard` and reuse existing system-safe link helpers only. ## Implementation Phases 1. **Foundation**: fixed dimension catalog + derived workspace summary query with core unknown-handling and review-pack-readiness rules + unit proof 2. **Dashboard summary**: aggregate KPI widget + system dashboard registration + feature proof 3. **Attention list**: compact unhealthy-workspace widget + system-safe links + explainability proof 4. **Detail follow-up**: residual system tenant/workspace detail card + preserved window context + follow-up rendering proof 5. **Safety hardening**: archived workspace plus tenant exclusions, deterministic ordering hardening, and authorization proof ## Constitution Check (Post-Design) Re-check result: PASS. The plan stays derived-only, reuses existing system dashboard and health presentation semantics, keeps Filament v5 + Livewire v4 intact, leaves provider registration in `bootstrap/providers.php` untouched, introduces no global-search or asset changes, adds no destructive actions, and keeps proof in narrow unit + feature lanes only.