Files
pad/internal/server
xarmian e27f805ffc feat(web): unify dashboard onboarding banners around needs_onboarding signal (TASK-1530) (#594)
IDEA-1516 Phase 3. The pre-IDEA-1516 design split workspace onboarding
guidance across two banners — OnboardingIdeaBanner (gated on the
retired IDEA-1 / BACK-1 / FEAT-1 seed-item pattern from PLAN-1496) and
OnboardingChecklist (gated on a totalItems === 0 heuristic that
predates the canonical needs_onboarding flag from TASK-1504). Both
fired competing CTAs on the same screen; neither read the canonical
signal.

Backend (internal/server/handlers_dashboard.go):
- Add `NeedsOnboarding bool json:"needs_onboarding"` to
  DashboardResponse, populated via the existing
  Store.WorkspaceHasUserCreatedItems EXISTS query (same predicate
  AgentBootstrap.NeedsOnboarding uses). Web reads it from the
  dashboard fetch the page already does — no second round-trip
  against the heavier bootstrap endpoint.

Frontend:
- Add `needs_onboarding: boolean` to TS DashboardResponse type
- Delete OnboardingIdeaBanner.svelte entirely (signal retired,
  no remaining consumers); the back-end onboarding_seed field
  stays for now per spec — separate cleanup
- Delete OnboardingChecklist.svelte; replace with
  OnboardingNudgeBanner.svelte — single message + "Connect agent →"
  CTA that opens the workspace's already-mounted
  ConnectWorkspaceModal. Dismissible, preserves the existing
  `pad-onboarding-dismissed-{wsSlug}` localStorage key so users who
  dismissed the old checklist don't get re-prompted
- Workspace +page.svelte: collapse the two banner blocks into one
  gated on `needsOnboarding && !onboardingDismissed`; reshow button
  follows the same signal. Drop the now-orphaned `.connect-card`
  CSS — its function is subsumed by the banner's CTA. Drop the
  unused OnboardingIdeaBanner / OnboardingChecklist imports and the
  `onboardingSeed` derived state

Smart-suppression deferred to a follow-up. The existing
api.workspaces.claimCode endpoint returns suppression info but
generates a real claim code as a side effect in the not-suppressed
case — calling it on every workspace page-load with needs_onboarding=true
is awkward. The CTA still opens the modal, which renders its own
suppression state correctly; users get the right experience with one
extra click on the rare suppressed case. A dedicated read-only
GET /workspaces/{ws}/connect-status endpoint is a separate piece
of work.
2026-05-19 13:17:57 -04:00
..