From 69f328b4cde5233187f8d7456d70d1628abe12e1 Mon Sep 17 00:00:00 2001 From: "Victor \"David\" Medina" Date: Sat, 27 Jun 2026 10:33:27 -0400 Subject: [PATCH] fix(C-P1-S2): honest booking-tool routing (kill the Google-only dead-end) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Customer value: a spa/dental/fitness owner is never shown a connect path that can't read their data. Before, ANY booking_tool answer except 'Paper or phone' emitted 'Connect [tool]' -> /settings/integrations (Google-only) — an honest-looking dead-end for Acuity/Mindbody/Vagaro/Square shops. Fix in seedSetupActions(): only Google Calendar (the one live self-serve connector today) routes to the connect card; every other tool gets the HONEST CSV path ('Export a client list from [tool] to start today' -> /import), never a false connect promise. Also added the real ICP tools (Acuity, Mindbody, Jane) to the wellness + generic booking_tool options, aligned with the /import wording. Updated the cold-start honesty-contract test to assert the FIXED routing (Vagaro -> import-booking-csv -> /import) + added a Google-Calendar -> connect-booking case, so the test now guards the dead-end fix. tsc: 0 errors (vitest runs in CI — junction can't load its config locally). Deferred fast-follow: the 'notify me when one-click [tool] is ready' demand-signal endpoint/table + the StarterOnboardingWizard step-3 alignment (additive + gated). Co-Authored-By: Claude Opus 4.6 (1M context) --- __tests__/cold-start-brief.test.tsx | 11 +++++++++- lib/onboarding/cold-start.ts | 31 +++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/__tests__/cold-start-brief.test.tsx b/__tests__/cold-start-brief.test.tsx index 17f11caa..7d0983b8 100644 --- a/__tests__/cold-start-brief.test.tsx +++ b/__tests__/cold-start-brief.test.tsx @@ -37,7 +37,10 @@ describe("seedSetupActions (the honesty contract)", () => { "wellness", ); expect(actions).toHaveLength(3); - expect(actions[0].id).toBe("connect-booking"); + // P1-S2: a non-Google booking tool now routes to the HONEST CSV path (no Google- + // only /settings/integrations dead-end), still quoting the tool name. + expect(actions[0].id).toBe("import-booking-csv"); + expect(actions[0].href).toBe("/import"); expect(actions[0].why).toContain("Vagaro"); for (const a of actions) { expect(a.why.length).toBeGreaterThan(0); @@ -45,6 +48,12 @@ describe("seedSetupActions (the honesty contract)", () => { } }); + it("Google Calendar routes to the live self-serve connector (the only tool that self-connects today)", () => { + const actions = seedSetupActions({ booking_tool: "Google Calendar" }, "wellness"); + expect(actions[0].id).toBe("connect-booking"); + expect(actions[0].href).toBe("/settings/integrations"); + }); + it("paper-or-phone owners get the simple import path, not an integration dead end", () => { const actions = seedSetupActions({ booking_tool: "Paper or phone" }, "generic"); expect(actions[0].id).toBe("start-simple-import"); diff --git a/lib/onboarding/cold-start.ts b/lib/onboarding/cold-start.ts index e6fae88d..6f16d828 100644 --- a/lib/onboarding/cold-start.ts +++ b/lib/onboarding/cold-start.ts @@ -75,7 +75,7 @@ const QUESTION_SETS: Record = { id: "booking_tool", label: "Where do your bookings live?", kind: "choice", - options: ["Google Calendar", "Vagaro", "Square", "Paper or phone", "Other"], + options: ["Google Calendar", "Acuity", "Mindbody", "Vagaro", "Square", "Jane", "Paper or phone", "Other"], helps: "Connecting it is how real opportunities appear here.", }, ], @@ -135,7 +135,7 @@ const QUESTION_SETS: Record = { id: "booking_tool", label: "Where do your bookings live?", kind: "choice", - options: ["Google Calendar", "Square", "Paper or phone", "Other"], + options: ["Google Calendar", "Acuity", "Square", "Paper or phone", "Other"], helps: "Connecting it is how real opportunities appear here.", }, ], @@ -188,13 +188,28 @@ export function seedSetupActions( const v = resolveColdStartVertical(vertical); const tool = answers["booking_tool"]; + // P1-S2: route by whether the named tool has a LIVE self-serve connector. Only + // Google Calendar self-connects today; sending an Acuity/Mindbody/Vagaro/Square shop + // to the Google-only /settings/integrations is an honest-looking dead-end. Every + // other tool gets the honest CSV path (the fastest real path today) — never a false + // "connect" promise for a connector that doesn't exist yet. + const LIVE_SELF_SERVE_BOOKING = new Set(["Google Calendar"]); if (typeof tool === "string" && tool.length > 0 && tool !== "Paper or phone") { - out.push({ - id: "connect-booking", - headline: `Connect ${tool} so Relay can see your schedule`, - why: `You said your bookings live in ${tool}.`, - href: "/settings/integrations", - }); + if (LIVE_SELF_SERVE_BOOKING.has(tool)) { + out.push({ + id: "connect-booking", + headline: `Connect ${tool} so Relay can see your schedule`, + why: `You said your bookings live in ${tool}.`, + href: "/settings/integrations", + }); + } else { + out.push({ + id: "import-booking-csv", + headline: `Export a client list from ${tool} to start today`, + why: `One-click ${tool} connect is on our roadmap; a CSV export from ${tool} gets Relay working now.`, + href: "/import", + }); + } } else if (tool === "Paper or phone") { out.push({ id: "start-simple-import",