Skip to Content

← All archived runs

Run: customer-action-items

run.md

Run: customer-action-items

  • branch: claude/funny-tesla-coelgd
  • pr: #501

00_intake/stub.md

Stub: Customer dashboard — customer action items

  • feature-slug: customer-action-items
  • epic: customer-dashboard-data
  • personas: Customer (acts on items); delivery team / system (raise items)
  • initiative: Build the Bridge / objective: Q2 2026 Objective 3 — Validate Technical Infrastructure & Payout Flow
  • depends-on: customer-project-foundation
  • sequence: 7 of 9

Problem

The "your actions" items in the ProjectStatusStrip (label, urgent, dueInDays, urgency: urgent | upcoming — e.g. "Approve integration access", "Confirm data mapping") are dummy. There is no action-items model. The generic notification model is title/body/link/read only — it has no due date, urgency, or completion semantics, and it is not project-scoped. These items represent work the customer must do to keep delivery moving, and some gate go-live.

Proposed change

  • Define a customer action-item record per project: label, dueDate (→ derived dueInDays), urgency (urgent | upcoming), a completed state, and an optional blocksGoLive flag.
  • Allow the delivery team (and/or the system at relevant journey steps) to raise an item, and the customer to complete / acknowledge it.
  • Wire the actions list in the ProjectStatusStrip to the real open items, sorted by urgency / due.

Acceptance criteria (rough)

  • A customer sees their real open action items with correct urgency and days-until-due.
  • Completing an item removes it from the dashboard and records who/when.
  • Items are project- and customer-scoped; another customer's items never appear.
  • No open items → a clean "nothing needs your attention" state.

Out of scope (this feature)

  • Deep-linking each action to its resolution flow (e.g. the actual "approve integration access" screen) — the item links out but those target flows are their own work.
  • Email/Ably reminders for due items — can be a follow-up.

Notes for Define

  • Decide who raises items (manual team action vs. system-generated at journey steps) and whether overdue, go-live-gating items should feed project-health-engine (sequenced before this).
  • touches: packages/services/src/db/models (new action-item model), packages/services/src/server, apps/web/components/dashboard/customer/project-status-strip.tsx.

01_define/output/spec.md

Spec: Customer action items — model, capture, and dashboard wiring

  • slug: customer-action-items
  • personas: Customer, Expert, CSM, SDM
  • touches: packages/services/src/db/models, packages/services/src/db/services/action-item, packages/services/src/db/services/customer-project, packages/services/src/server, apps/web/app/(app)/projects/[id], apps/web/app/(app)/customer/dashboard/page.tsx, apps/web/components/dashboard/customer/project-status-strip.tsx, apps/web/lib/mock/customer.ts
  • complexity: standard

Problem

The "your actions" list in the customer dashboard's ProjectStatusStrip (label, urgent, dueInDays, urgency — e.g. "Approve integration access", "Confirm data mapping") is dummy data from apps/web/lib/mock/customer.ts. There is no action-items model anywhere in the platform: the generic notification model is title/body/link/read only — it has no due date, urgency, completion semantics, or project scope. These items represent real work the customer must do to keep delivery moving, and some gate go-live. This is sequence 7 of 9 in the customer-dashboard-data epic; with the customer-project-foundation (sequence 1) read in place, this feature turns a mock surface into real, queryable per-project data, advancing Build the Bridge → Q2 2026 Objective 3 (Validate technical infrastructure & payout flow).

Proposed change

  • Action-item model. A new tenant-scoped ActionItem collection (separate, indexed — not an embedded sub-doc — because open items are queried per project frequently and written by multiple personas, mirroring the shipped Blocker model). Each record references a project (lead) and carries label, dueDate, urgency (urgent | upcoming), a status of open | completed (with completed metadata: completedBy, completedAt), and a blocksGoLive flag. dueInDays is derived at read time from dueDate (not stored). Indexed on { tenantId, lead, status } so "open items for this project" is a cheap query.
  • Action-item service. An actionItemService in packages/services/src/db/services/action-item/ (the index.ts class + instance.ts singleton pattern), exported via @sustentus/services/server, with: raise(leadId, { label, dueDate, urgency, blocksGoLive }), complete(actionItemId, byUserId) (sets status = completed + records who/when), and listOpenByLead(leadId) — returns open items with derived dueInDays, sorted by urgency then due date. listOpenByLead (and the blocksGoLive flag it surfaces) is the read a future project-health-engine consumes.
  • Delivery-team capture. A minimal raise/complete surface on the project detail page (apps/web/app/(app)/projects/[id]), scoped to that leadId and available to the delivery team (Expert/CSM/SDM): list the project's open items, raise a new one (label + due date + urgency + optional blocksGoLive), and mark one complete. Backed by "use server" actions following the existing (app)/.../actions.ts pattern (zod-validated, resolveActionContext / runActionBody).
  • Customer dashboard wiring. Extend the customerProjectService envelope (from customer-project-foundation) with actions[] = the open items for the signed-in customer's active project, and wire the ProjectStatusStrip "Your actions" list to them (replacing the mock). The customer can complete / acknowledge an item from the dashboard via a "use server" action scoped to their own active project; completing removes it from the list and records who/when. The actions block is removed from apps/web/lib/mock/customer.ts.

Acceptance criteria

  • An ActionItem model exists, tenant-scoped, attached to a project (lead), with label, dueDate, urgency (urgent | upcoming), status (open | completed) + completed metadata, and blocksGoLive, indexed on { tenantId, lead, status }.
  • actionItemService exposes raise, complete, and listOpenByLead (open items with derived dueInDays, sorted by urgency then due date), exported from @sustentus/services/server.
  • On the project detail page, a delivery-team member (Expert/CSM/SDM) can raise an item on the project (label + due date + urgency + optional go-live gate) and it appears in that project's open-items list.
  • A signed-in customer sees their real open action items on the dashboard with correct urgency and days-until-due, sorted by urgency / due date — not the mock list.
  • Completing an item (from the dashboard or the team surface) removes it from the dashboard and from listOpenByLead, and records who completed it and when.
  • Items are project- and customer-scoped via the foundation's active-project resolution (tenant + lead.customer); another customer's or tenant's items never appear.
  • A project with no open items renders the clean "nothing needs your attention" state, not a mock entry.
  • The actions block is removed from apps/web/lib/mock/customer.ts; the envelope's actions[] drives the strip and the remaining mock sections still render unchanged.

Out of scope

  • System-generated items at service-journey steps (e.g. auto-raising "approve integration access" when integration setup begins) — manual delivery-team capture only this round; auto-generation is a follow-up.
  • Wiring go-live-gating items into project-health-engine — that engine is not yet specced/built; this feature only supplies the queryable read (listOpenByLead + blocksGoLive) it will consume.
  • Deep-linking each action to its resolution flow (e.g. the real "approve integration access" screen) — the item links out, but those target flows are their own work.
  • Email / Ably reminders for due or overdue items.
  • A full team-side management console beyond minimal raise/complete (filtering, history, editing, reassignment, comments).

Open questions

  • none

02_build/output/notes.md

Build notes: customer-action-items

  • commits: feat: customer-action-items — model + service; feat: customer-action-items — team capture + dashboard wiring

What changed

  • packages/services/src/db/models/action-item.ts (new): tenant-scoped ActionItem model — lead, label, dueDate, urgency (urgent|upcoming), status (open|completed) + completedAt/ completedBy, blocksGoLive, createdBy. Indexed { tenantId, lead, status }. Mirrors the shipped Blocker model (same plugins: schema/softDelete/tenant). Exported via db/models/index.ts.
  • packages/services/src/db/services/action-item/ (new): ActionItemService + actionItemService singleton with raise, complete (optional leadId scope), and listOpenByLead (returns serialized OpenActionItem[] with derived dueInDays, sorted urgency-then-due). Exported via db/services/index.ts → flows through @sustentus/services/server.
  • packages/services/src/db/services/customer-project/index.ts: extended the envelope with actions: OpenActionItem[] (resolved from actionItemService.listOpenByLead for the active project) and added getActiveProjectLeadId so the customer completion path can scope to the customer's own project.
  • apps/web/app/(app)/projects/[id]/actions.ts: added raiseActionItemAction + completeActionItemAction (delivery-roles only), mirroring the blocker actions.
  • apps/web/components/service-leads/lead-action-items/ (new): server LeadActionItems + client ActionItemsPanel (raise form: label, due date, urgency, gates-go-live; complete per item) + loading. Wired into projects/[id]/page.tsx alongside LeadBlockers, behind the delivery-role gate.
  • apps/web/app/(app)/customer/dashboard/actions.ts (new): completeCustomerActionItemAction (customer-only), scoped to the customer's active-project lead so another project's/tenant's item is never completable.
  • apps/web/components/dashboard/customer/project-status-strip.tsx: Action type now matches the envelope (id, label, urgency, dueInDays, blocksGoLive); the "Your actions" card renders the real items and lets the customer mark each done (server action + router.refresh). Empty state copy is now "Nothing needs your attention right now".
  • apps/web/app/(app)/customer/dashboard/page.tsx: passes project.actions + the completion action to the strip.
  • apps/web/lib/mock/customer.ts: removed the actions block; the rest of the mock is unchanged.

Acceptance criteria status

  • ActionItem model — tenant-scoped, lead-attached, all fields + index present.
  • actionItemService exposes raise/complete/listOpenByLead (derived dueInDays, sorted), exported from @sustentus/services/server.
  • Delivery-team raise on the project detail page (label + due date + urgency + optional go-live gate) → appears in the project's open-items list.
  • Customer sees real open items on the dashboard with correct urgency + days-until-due, sorted.
  • Completing (dashboard or team surface) drops it from the dashboard and listOpenByLead, and records completedBy/completedAt.
  • Project- and customer-scoped via the foundation resolution; customer completion is additionally leadId-scoped.
  • No open items → clean "nothing needs your attention" state (no mock entry).
  • actions removed from the mock; the envelope's actions[] drives the strip; remaining mock sections render unchanged.

Verify result

  • mechanical checks (format · lint · typecheck · build) run in CI + the Vercel preview, not here. Release reads them back from the PR's check runs. No check expected to fail.

Notes for review

  • The customer completion is deliberately scoped by leadId (resolved from the signed-in customer's active project) on top of the tenant scope — the team path relies on the delivery-role + tenant gate like the blocker flow does.
  • dueInDays is derived at read time (not stored), so it stays correct without a write; overdue items render "Overdue by N days".
  • project-health-engine is not built yet — this only supplies the queryable read (listOpenByLead surfaces blocksGoLive); wiring into health is that feature's job (per the spec's Out of scope).

03_release/output/changelog.md

Changelog: customer-action-items

Live entry: apps/help/app/changelog/2026-06-22-customer-action-items/page.mdx Personas: customer, expert, csm, sdm


See and clear the actions that keep your project moving

The "Your actions" strip on your dashboard now shows the real things your delivery team needs from you, so nothing that holds up go-live slips through the cracks:

  • See each open action with how soon it's due and whether it's urgent, sorted so the most pressing sits at the top.
  • Mark an action done straight from your dashboard, and it drops off your list.
  • Your delivery team (expert, CSM, or SDM) raises these actions from the project page, with a due date, an urgency, and an optional flag for the ones that gate go-live.
  • A project with nothing outstanding shows a clean "nothing needs your attention" state, so an empty list really means you're clear.

03_release/output/investor-update.md

Customers can now see and clear the actions that keep delivery moving

Who it's for: Customers, plus the delivery team (experts, CSMs, SDMs) What shipped: The delivery team raises action items on a project — with due dates and urgency — and the customer sees and completes them on their dashboard. Why it matters: Fewer projects stall on missed customer steps, advancing Build the bridge → Q2 objective 3, validate technical infrastructure & payout flow.

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

03_release/output/release.md

Release: customer-action-items

  • pr: #501 · merged: pending (awaiting green CI on the fix + Ready-to-merge tick)
  • CI: green on the Build commit; re-running after the release commits (docs + daysUntil fix)
  • technical docs: no technical docs impact (the services page documents entrypoints/structure, not individual db services; db/ already covers the new model + service)
  • business docs: updated — business/feature-role-matrix/projects (action-item rows), business/service-journey/delivery (customer action items section)
  • release notes: both — changelog entry + investor draft in this PR
  • deploy: pending (post-merge)
  • sent: pending (after green deploy)

Review summary

/code-review (high effort) on the origin/main...HEAD diff. Backend (model/service/actions) came back clean — tenant + lead scoping verified (customer completion is leadId-scoped to their own active project; cross-customer/cross-tenant completion blocked), exports wire through @sustentus/services/server, sort/await/ObjectId guards all correct. Frontend clean — server action correctly passed as a prop to the client strip, no dangling mock actions reference, envelope/strip types align, dashboards app unaffected.

  • daysUntil derived dueInDays from the current instant with Math.ceil, giving an off-by-one ("due today" misrender, and a day's drift west of UTC) — fixed on branch: anchor both ends to start-of-UTC-day and round. (packages/services/src/db/services/action-item/index.ts)
  • Per-user-timezone storage of a date-only picker — accepted: inherent to <input type="date">; matches the milestone/blocker date handling; out of scope for this round.

Acceptance check (vs spec)

  • ActionItem model — tenant-scoped, lead-attached, all fields + { tenantId, lead, status } index — verified in action-item.ts.
  • actionItemService raise/complete/listOpenByLead (derived dueInDays, sorted urgency-then-due), exported from @sustentus/services/server — verified through db/index.ts barrel.
  • Delivery-team raise on the project detail page → appears in the open-items list — LeadActionItems + raiseActionItemAction, delivery-role gated.
  • Customer sees real open items with correct urgency + days-until-due, sorted — envelope actions[] → strip; dueInDays fix applied.
  • Completing (dashboard or team) removes it + records who/when — complete sets status/completedAt/completedBy; listOpenByLead filters status: open.
  • Project- and customer-scoped — foundation active-project resolution; customer completion additionally leadId-scoped.
  • Empty state — strip renders "nothing needs your attention right now".
  • Mock actions removed; envelope drives the strip; remaining mock sections unchanged.