Stability checkpoint — Customer Churn Phase D (Insights page) + dual-backend ML serving fully visible in UI
- feat(insights): Phase D — Churn risk page at /insights/churn
- fix(insights): prettier --write on churn-insights files
Minor bump (1.1 → 1.2) because Phase D ships a new public page + sidebar group + ApiService surface.
CI :
- ✅ Main pipeline #2482937405 green — https://gitlab.com/mirador1/mirador-ui/-/pipelines/2482937405
- ✅ MR pipeline #2482846547 green for !170 — https://gitlab.com/mirador1/mirador-ui/-/pipelines/2482846547
- ✅ Phase D MR !169 merged via auto-merge — https://gitlab.com/mirador1/mirador-ui/-/merge_requests/169
- ✅ Fix MR !170 (prettier --write) merged — https://gitlab.com/mirador1/mirador-ui/-/merge_requests/170
Local test pass :
- ✅ npx ng test — 374 tests pass (54 test files), including 4 new churn-insights-helpers spec cases (riskClass + formatProbability + canSubmitChurnSearch boundary contracts).
- ✅ npm run build -- --configuration production — BUILD SUCCESS, new churn-insights-component lazy chunk, no bundle budget regression. Initial total 668 kB raw / 184 kB transfer (well under 800 kB warning / 1 MB error).
- ✅ npx prettier --check 'src/app/features/insights/churn/**/*.{ts,html,scss,json}' — All matched files use Prettier code style.
- ✅ npx eslint src/app/features/insights/churn — clean.
- ⏭ Manual Lighthouse pass on /insights/churn — DEFERRED to next stability checkpoint.
- ⏭ Real backend ONNX promotion smoke test — DEFERRED until Phase F's ConfigMap is provisioned (the page renders the 503 "ConfigMap pending" UX correctly when polled today).
Manual responsive check :
- ✅ Mobile 375 px (iPhone SE) : widgets stack to single column, tap targets ≥ 44 px on Predict + Refresh, table scales (no horizontal scroll), SVG drift chart scales via viewBox + preserveAspectRatio.
- ✅ Mobile 390 px (iPhone 12) : identical pattern, sidebar collapses correctly.
- ✅ Desktop 1280 px : 3 widgets visible in a column with comfortable max-width 1200 px ; "Insights" sidebar group clickable.
Regression check vs stable-v1.1.6 :
- ✅ Existing routes (/, /customers, /orders, /products, /diagnostic, etc.) all still navigate ; sidebar still has every prior group.
- ✅ ApiService new method predictCustomerChurn(id) added ; existing methods unchanged.
- ✅ Bundle treemap unchanged shape — Phase D's new lazy chunk doesn't bloat the initial bundle (separate chunk-PXNXXX.js for /insights/churn).
- LLM integration : the UI is now a CONSUMER of the dual-backend ML inference layer. Calls POST /customers/{id}/churn-prediction on whichever backend is active (Java or Python — same wire shape per ADR-0060). Renders ChurnPrediction (probability + risk band + top features + model_version + predicted_at).
- AI Observability : visible top_features list in the UI (placeholder until Phase E ships SHAP per-prediction explanations) ; visible model_version label for audit + drift correlation.
- Tooling for agents : not directly relevant to UI — but the page is what an LLM CLIENT (not server) of the prediction tool would render to a human consumer.
- AuthN : the page inherits the global JWT / X-API-Key auth from ApiService. No bespoke auth in the new route.
- AuthZ : no special role required. The endpoint is read-only.
- CSP / dependency posture : npm audit clean, security:audit job green, no new third-party HTTP client.
- New page : /insights/churn with 3 widgets (search-by-id + Top-10 at-risk + drift placeholder).
- New "Insights" sidebar group with the 🤖 icon (room for future ML pages without nav reshuffle).
- Search index : "Churn risk" entry under the global keyboard shortcut.
- Breaking-API check vs prev tag : none. Net additions only.
- Deploy targets : same multi-cloud matrix (unchanged from prev tag).
- ⏭ N/A on the IaC side — the UI doesn't own deployment manifests beyond GitLab Pages + the canary nginx behind the backend ingress.
- ⏭ N/A direct — the UI surfaces backend metrics rather than producing its own.
- Coverage : Vitest spec count 374 (vs ~370 at prev tag) ; the new helpers spec contributes 4 cases.
- Static analysis : ESLint flat config + Prettier + circular-deps lint all green.
- Mobile responsive : verified at 375/390/1280 px (per the binding constraint in CLAUDE.md).
- Pipeline stages green : lint (eslint, prettier, hadolint, openapi-types-drift, secret-scan) | typecheck | unit-tests + unit-tests:node20 | bundle-size-check | build:production | e2e:kind | typedoc | sonarcloud (manual) | trivy + grype + sbom + dockle + cosign.
- Compat matrix : Node 20 + Node 22 (default) — unchanged baselines.
- Release engineering : Conventional Commits respected. MINOR bump (1.1.6 → 1.2.0) per the new public surface.
- Pure helpers extracted to churn-insights-helpers.ts — same Angular-free split as customers-helpers.ts (Phase B-7) so the spec doesn't need TestBed.
- Lazy-loaded standalone component (Angular 21 zoneless) — initial bundle stays under budget.
- File length : churn-insights.component.ts 524 LOC, churn-insights-helpers.ts 40 LOC, churn-insights-helpers.spec.ts 60 LOC — all under the 1 000 ceiling.
- ADRs : amended shared ADR-0061 (consumer-side Phase D documented) via shared !4.
- Angular 21 zoneless + signals (signal-based searchIdRaw, computed canSubmitSearch, ChangeDetectionStrategy.OnPush).
- Mobile-responsive : 375/390/1280 px verified, tap targets ≥ 44 px, SVG chart scales, sidebar drawer pattern consistent with rest of UI.
- Bundle budgets respected ; new lazy chunk for /insights/churn keeps initial bundle unchanged.
- Raw SVG charts (drift placeholder) per the no-charting-library constraint.
- Pure helpers + test pattern reused (customer-helpers.ts model) so contributors can pattern-match for the next ML page (anomaly detection, segmentation).
- Clear UX errors for backend states : 503 → "ConfigMap pending (ADR-0062)", 404 → "Customer not found", 422 → "Invalid customer id". Toasts on first error so the user notices even off-screen.
- Drift widget is a placeholder until Phase E's MLflow tracking + KS-test daily series ships. Layout sketch in place so the data swap is one-line.
- Top-N at-risk fetches the first 50 customers + iterates predictions in parallel (forkJoin). For real production loads, a bulk /insights/churn/top?n=10 backend endpoint would be more efficient — deferred to Phase E.
- Mobile responsive verified manually at 375/390/1280 px ; no automated viewport spec yet (the existing Playwright e2e:kind suite covers it indirectly).
- stable-v1.2.1 : Lighthouse audit on /insights/churn + automated viewport spec.
- stable-v1.3.0 : Phase E consumption — drift series rendered from MLflow / Grafana data.