Files
resolutionflow/.ai/HANDOFF.md
Michael Chihlas 5935a47390
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
CI / frontend (pull_request) Successful in 7m8s
CI / backend (pull_request) Successful in 11m0s
CI / e2e (pull_request) Successful in 9m59s
docs(handoff): PR #165 merged; flag Stripe activation as current blocker
PR #165 (legal/contact pages + MarketingFooter) merged as ba45cfe.
All code blockers for self-serve cutover are now on main.

HANDOFF now flags that user is reporting trouble completing Stripe
live-mode activation (specific blocker not captured this session)
and lists likely candidates so next session can triage quickly:
apex DNS still missing at Namecheap, business-profile URL/phone
rejection, missing prod env var, webhook signing-secret mismatch,
or tax/identity verification step.

Adds the new /contact and /policies URLs to the Stripe business-
profile checklist, and a carry-forward note about the mailing-
address TODO that fires when the P.O. Box arrives. Appends a
2026-05-12 SESSION_LOG entry covering PR #164/#165 merges and the
current Stripe block.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 01:28:07 -04:00

6.7 KiB

HANDOFF.md

Last updated: 2026-05-12

Active task: Phase O cutover for self-serve signup. All code blockers are closed on main (PR #164 3f04911, PR #165 ba45cfe). Currently blocked on Stripe live-mode activation — user reports trouble completing it as of 2026-05-12 evening; specific blocker not captured in this session's doc update. Next session: ask the user for the exact Stripe error or stuck step, then triage. Likely candidates given prior session work: apex DNS still missing at Namecheap (Stripe's site verifier can't reach resolutionflow.com apex; www works); Stripe business profile rejecting one of the new URLs (/contact, /policies) or the phone number; missing prod env var (STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET / VITE_STRIPE_PUBLISHABLE_KEY); webhook signing-secret mismatch; tax/identity verification step blocking activation.

Where this session ended

PR #165 squash-merged (ba45cfe feat(legal): add /policies, /contact, /promotions pages + MarketingFooter (#165)):

  • New pages, all SPA, matching existing /privacy and /terms pattern: /policies (consolidated Customer Policies — customer service contact, return/refund/dispute policy, cancellation, U.S. legal and export restrictions, promotional terms; anchor IDs per subsection), /contact (phone (470) 949-4131, support/sales/billing/security inboxes, response-time SLAs), /promotions (stub stating no promotions currently active — satisfies Policies §6.2 cross-ref).
  • MarketingFooter (frontend/src/components/common/MarketingFooter.tsx) extracted from inline landing footer and mounted on /landing, /pricing, /contact-sales. Reuses existing landing-footer* CSS — must be rendered inside a .landing-page wrapper (documented in a JSX comment) because --lp-* vars are scoped there. All four legal links (Privacy / Terms / Policies / Contact) are now reachable from every marketing surface.
  • Privacy and Terms closing sections updated to point at /contact + /policies and the correct inbox per area (security@ and support@ respectively). Stale hello@resolutionflow.com mailto removed everywhere.
  • Mailing address left as TODO comments in ContactPage.tsx and PoliciesPage.tsx (one each). Rendered publicly as "available on request — email support@". Fill in when the P.O. Box is purchased.

tsc --project tsconfig.app.json --noEmit and eslint clean. Local vite build and tsc -b are blocked by root-owned node_modules/.tmp and node_modules/.vite-temp cache directories — CI rebuilds from a clean env and was green.

Working tree clean (only pre-existing untracked files: abc-feat-self-serve-signup-phase-2-design-...md, core.*, docs/architecture/, docs/tutorials/ — same set noted in prior handoffs as "do not stage").

Single alembic head: 4ce3e594cb87 (no schema changes in this PR).

Resume point

Phase O manual ops — entirely user-side, gated on the apex DNS fix below:

  1. Stripe Dashboard live-mode:
    • 3 Products (Starter, Pro, Enterprise). Monthly Prices for Starter ($19.99) + Pro ($29.99). No Prices on Enterprise (sales-led).
    • Customer Portal with plan-switching disabled.
    • Webhook at https://api.resolutionflow.com/api/v1/webhooks/stripe with 5 events. Save live signing secret.
    • Business profile fields: Customer service URL https://resolutionflow.com/contact. Refund/cancellation policy URL https://resolutionflow.com/policies. Terms https://resolutionflow.com/terms. Privacy https://resolutionflow.com/privacy. Phone (470) 949-4131. Mailing address per Stripe form (not required on website).
  2. Railway prod env: STRIPE_SECRET_KEY=sk_live_..., STRIPE_WEBHOOK_SECRET, STRIPE_PUBLISHABLE_KEY + VITE_STRIPE_PUBLISHABLE_KEY (frontend redeploy required — Vite bake-at-build, Lesson 60), OAUTH_REDIRECT_BASE=https://resolutionflow.com, SELF_SERVE_ENABLED=false (still false at this point), INTERNAL_TESTER_EMAILS=<allowlist>, prod Google + Microsoft OAuth credentials.
  3. Sync against prod: railway run python -m scripts.sync_stripe_plan_ids. Verify plan_billing rows have sk_live_* price IDs.
  4. Internal validation (Task 46): 9 scenarios with internal testers whose emails match INTERNAL_TESTER_EMAILS.
  5. Flag flip (Task 47): email pilots, set SELF_SERVE_ENABLED=true + VITE_SELF_SERVE_ENABLED=true (frontend redeploy). PostHog signup-funnel dashboard + Sentry alert at >1/hour Stripe webhook errors.

Open issues from prior session (non-code, user-side)

  • Apex DNS missing. resolutionflow.com (apex) returns no A/CNAME at the authoritative DNS (Namecheap per SOA dns1.registrar-servers.com.). When www was reconfigured in Railway, the apex record got dropped from the zone. www works (cert provisioned 2026-05-08 01:40 UTC, valid Let's Encrypt SAN). Symptom: apex unreachable from user's machine; Stripe verifier "URL couldn't be reached." User to re-add apex record at Namecheap (ALIAS Record host=@ value=c9g7uku8.up.railway.app) or re-add the apex as a Railway custom domain and follow Railway's DNS instructions. The Railway path is more durable.
  • Edge HSTS sticky state on user's machine. Browser remembers the earlier broken-cert visit. Fix: edge://net-internals/#hsts (delete resolutionflow.com and www.resolutionflow.com) + #dns clear host cache + #sockets flush.

Carry-forward

  • Annual pricing intentionally NOT implemented — user wants exit flexibility. Schema columns preserved as nullable. sync_stripe_plan_ids.py leaves annual fields NULL.
  • INTERNAL_TESTER_EMAILS parsed comma-separated → normalized lowercase list. Anonymous callers always see the global flag — allowlist never leaks via unauthenticated request content (regression test enforces).
  • Office-hours design doc at ~/.gstack/projects/chihlasm-resolutionflow/abc-feat-self-serve-signup-phase-2-design-20260507-112020.md (documentation-builder thesis). NOT yet adopted as roadmap — gated on 3 cold calls with external Directors of Onboarding.
  • Mailing address fill-in: search for TODO: replace with full mailing address in frontend/src/pages/ContactPage.tsx and frontend/src/pages/PoliciesPage.tsx (one each) once P.O. Box is purchased.
  • Bot-crawlability of legal pages: still SPA-rendered. Stripe didn't enforce content scraping last time (issue turned out to be DNS). If a future vendor review flags it, pre-render with vite-plugin-prerender-spa (~half day).
  • Frontend env additions for cutover: VITE_SELF_SERVE_ENABLED, VITE_GOOGLE_CLIENT_ID, VITE_MS_CLIENT_ID, VITE_OAUTH_REDIRECT_BASE, VITE_CALENDLY_URL, VITE_STRIPE_PUBLISHABLE_KEY.