Skip to Content

← All archived runs

Run: customer-detail-parity

run.md

Run: customer-detail-parity

  • branch: claude/customer-detail-parity-pipeline-qtb3dl
  • pr: #704

01_define/output/spec.md

Spec: Customer detail-page parity

  • slug: customer-detail-parity
  • personas: Customer
  • touches: apps/web/app/(app)/customer/activity/page.tsx, apps/web/app/(app)/customer/invoices/page.tsx, apps/web/app/(app)/customer/dashboard/page.tsx, apps/web/components/dashboard/customer/*
  • complexity: standard

Problem

Web's customer sub-pages diverged from demo's agreed design — a gap this demo-web-parity epic exists to close, advancing the Refine the Bridge initiative (Q2 2026 — O1 vendor engagement: customer-side clarity is what sustains delivery and CSAT). Three divergences remain now that the shared DetailPageShell and design tokens have already landed (stubs detail-page-shell-web and design-system-reconciliation, both done):

  1. Activity — the page hardcodes every entry's impact badge to the literal "No impact" (apps/web/app/(app)/customer/activity/page.tsx:89) instead of rendering demo's three impact variants off each entry's impactTag, and it drops demo's latest-update summary banner (the data — latestSummary / latestTime — already flows from getCustomerActivity; only the page ignores it).
  2. Invoices — the page uses a 4-KPI grid + standalone progress card rather than demo's two-card story ("Payments so far" + "Next payment due").
  3. Dashboard — the customer dashboard header lost demo's "Start a new project" call-to-action (Compass → the project-intake flow).

Proposed change

Re-skin the three customer pages to demo's design, keeping web's real (server-resolved) data:

  • Activity page — restore demo's latest-update summary banner (an AlertBanner fed by the feed's latestSummary + latestTime) at the top of the activity card, and render each entry's impact badge through a three-variant config (no-impact / minor-delay / delays-go-live) keyed off the entry's impactTag, replacing the hardcoded "No impact" literal. This is UI-only: the activity service is unchanged, so today's real entries still resolve to no-impact until a future health-engine feature supplies an impact signal — the page gains the capability to show the right variant, not fabricated impact (see Out of scope).
  • Invoices page — adopt demo's two-card frame — "Payments so far" (paid + work-delivered + a delivered-vs-total progress bar) and "Next payment due" — while retaining web's fuller live finance fields (Total contract, Value delivered, Outstanding, and the real next-due invoice reference/date/amount) inside those two cards. The standalone 4-KPI grid and separate progress card are folded into the two-card layout.
  • Dashboard header — add demo's "Start a new project" CTA (Compass icon) to the customer dashboard header, linking to /projects/create (web's project-intake flow, the equivalent of demo's /project-discovery).

Acceptance criteria

  • The customer activity page shows a latest-update summary banner at the top of the activity card, populated from the feed's latestSummary and latestTime (and rendering the empty-state copy when there is no activity).
  • Each activity entry's impact badge is rendered through a three-variant config (no-impact → "No impact", minor-delay → "Minor delay", delays-go-live → "Delays go live") keyed off the entry's impactTag, not a hardcoded literal — so an entry carrying a non-no-impact tag would render the matching amber/red badge.
  • The customer invoices page uses demo's two-card structure ("Payments so far" + "Next payment due") with a delivered-vs-total progress bar, and still surfaces web's live finance fields (paid, value delivered, total contract, outstanding, and the real next-due invoice ref/date/amount).
  • The customer dashboard header shows a "Start a new project" CTA (Compass icon) linking to /projects/create.
  • All three pages continue to render inside DetailPageShell with the existing back-navigation, real tenant/customer-scoped data, and empty-state fallbacks; pnpm lint and typecheck pass.

Out of scope

  • Deriving real impact tags in the activity service. The audit log carries no go-live impact signal today (by design — that's the health engine's job), so this run wires the UI to impactTag but does not add service-side derivation. Real entries continue to resolve to no-impact until a future feature supplies the signal. Documented divergence: web shows honest (currently uniform) impact rather than demo's mock variety.
  • Customer messaging, satisfaction/CSAT, and the customer workspace page (web-only lean-subset — no work this run).
  • The web-only action-item completion interaction (intentional enrichment; a documented divergence, left as-is).
  • Any change to getCustomerActivity / the finance resolver or their data shapes — the pages consume the existing server contracts unchanged.

Open questions

none — the two design forks (impact-tag depth; invoices richness) were resolved with the owner during Define: UI-only impact wiring, and demo's two-card frame retaining web's richer finance KPIs.

02_build/output/notes.md

Build notes: customer-detail-parity

  • commits: feat: customer-detail-parity — activity impact tags + summary banner, two-card invoices, dashboard CTA

What changed

  • apps/web/components/dashboard/customer/impact-badge.tsx (new): shared ImpactBadge + ImpactTag — the three-variant config (no-impact / minor-delay / delays-go-live) lifted out of value-section so the activity page, invoices, and the dashboard share one vocabulary.
  • apps/web/app/(app)/customer/activity/page.tsx: added the latest-update summary banner (AlertBanner, fed by the feed's latestSummary / latestTime) and replaced the hardcoded "No impact" literal with <ImpactBadge impact={item.impactTag} />. UI-only — the activity service is unchanged (real entries still resolve to no-impact until a health-engine feature supplies impact; documented divergence in the spec).
  • apps/web/app/(app)/customer/invoices/page.tsx: replaced the 4-KPI grid + standalone progress/next-due cards with demo's two-card frame — "Payments so far" (paid + work-delivered StatBoxes, delivered-vs-total progress, and the retained live KPIs: total contract, paid to date, outstanding) and "Next payment due" (warning banner + ref/date/amount rows).
  • apps/web/app/(app)/customer/dashboard/page.tsx: added the "Start a new project" CTA (Compass icon, outline Button) linking to /projects/create in the header, alongside the existing project-id badge.
  • apps/web/components/dashboard/customer/value-section.tsx: refactored to consume the shared ImpactBadge (removed the now-duplicated local config).

Acceptance criteria status

  • Activity page shows a latest-update summary banner from latestSummary / latestTime; empty-state copy still renders when there is no activity (banner suppressed when latestSummary is null).
  • Each activity entry's impact badge renders through the three-variant ImpactBadge keyed off entry.impactTag — a non-no-impact tag renders the matching amber/red badge — no hardcoded literal.
  • Invoices page uses demo's two-card structure ("Payments so far" + "Next payment due") with a delivered-vs-total progress bar, retaining web's live finance fields (paid, value delivered, total contract, outstanding, next-due ref/date/amount).
  • Customer dashboard header shows a "Start a new project" CTA (Compass icon) linking to /projects/create (confirmed customer-allowed in route-policies.ts).
  • All three pages still render inside DetailPageShell with back-navigation, real tenant/customer-scoped data, and empty-state fallbacks; lint/typecheck run in CI.

Verify result

  • Mechanical checks (format · lint · typecheck · build) run in CI + the Vercel preview, not here. No check is expected to fail: changes are presentational, reuse existing components (StatBox, SummaryRow, AlertBanner), and add no new service/data contracts. entry.impactTag ("no-impact") is assignable to the widened ImpactTag prop, so no type error from the UI-only wiring.

Notes for review

  • The activity impact badges will render "No impact" against today's real data — by design (see the spec's Out of scope). The UI now supports the amber/red variants for when the audit log carries an impact signal.
  • /projects/create is web's intake flow (the equivalent of demo's /project-discovery), confirmed customer-accessible.

03_release/output/changelog.md

Changelog: customer-detail-parity

Live entry: apps/help/app/changelog/2026-07-27-customer-detail-parity/page.mdx

  • personas: customer
  • title: Your project activity, invoices and dashboard are clearer than ever

Your customer pages now work the way the rest of Sustentus does. Project activity opens with a summary of your latest update, and every entry is labelled with its impact on your go-live date, so you can see at a glance what matters. Your invoices page brings everything into two simple cards — what you have paid and what has been delivered against it, and the next payment due — while still showing the full picture: total contract, outstanding, and the exact invoice coming up. And you can now start a new project straight from your dashboard header.

03_release/output/investor-update.md

Customers get a clearer, consistent view of their project

Who it's for: Customers What shipped: The customer activity, invoices and dashboard pages now match our shared design — a latest-update summary, impact-tagged activity, a two-card payments view, and a one-click start-a-new-project action. Why it matters: Sharper dashboard usability under Refine the Bridge, supporting Q2 Objective 1 — establish product-market fit with vendor partners.

All five acceptance criteria verified on the preview deploy.

Dig deeper: <merged-PR URL> · <changelog entry URL>

03_release/output/release.md

Release: customer-detail-parity

  • pr: #704 (https://github.com/sustentus/sustentus/pull/704) · merged: pending (gate ticked, squash-merging)
  • CI: green — "Quality Project" (format · lint · typecheck · build) success; preview + prod DB migrate success/skipped; Claude review job skipped (ENABLE_CLAUDE_REVIEW not set) so the diff was self-reviewed at medium effort
  • technical docs: no technical docs impact — presentation-only re-skin; no new/changed app, package, route, env var, build step, or architecture
  • business docs: no business docs impact — customer capabilities unchanged (activity, invoices, project creation already existed and are documented; /projects/create was already customer-allowed). The CTA surfaces an existing flow; only presentation changed
  • release notes: both — changelog entry (apps/help/app/changelog/2026-07-27-customer-detail-parity) + investor draft in this PR
  • sent: pending — investor update to be sent after merge

Review summary

  • Diff is exactly 9 files (5 source/component + stub move + 3 run files) vs origin/main; the local main ref was stale so main...HEAD over-reported — verified against origin/main...HEAD and the PR's own changed-files count.
  • Extracted ImpactBadge (+ ImpactTag) from value-section so the activity page, invoices, and dashboard share one impact-tag vocabulary rather than triplicating the config — a simplification, not new surface. Refactored value-section onto it.
  • Conventions clean: arrow functions, type not interface, named imports, sentence-case copy, cn() for class merging, server components (no needless "use client"). No dead code, debug, or leftover scaffolding.
  • UI-only impact wiring is a documented divergence (spec Out of scope): real entries render "No impact" until a health-engine feature supplies an impact signal; the three-variant badge is ready for when it does.

Acceptance check (vs spec)

  • Activity page shows the latest-update summary banner from latestSummary/latestTime; empty-state copy still renders when there is no activity (banner suppressed when latestSummary is null).
  • Each entry's impact badge renders via the three-variant ImpactBadge keyed off entry.impactTag — a non-no-impact tag renders amber/red — no hardcoded literal.
  • Invoices page uses demo's two-card structure ("Payments so far" + "Next payment due") with a delivered-vs-total progress bar, retaining web's live finance fields (paid, value delivered, total contract, outstanding, next-due ref/date/amount).
  • Customer dashboard header shows the "Start a new project" CTA (Compass icon) → /projects/create (verified customer-allowed in route-policies.ts).
  • All three pages still render inside DetailPageShell with back-navigation, real tenant/customer-scoped data, and empty-state fallbacks; format/lint/typecheck green in CI.