Skip to content

Add Kit-backed waiting list to invite-gated signup - #728

Merged
kody-bot merged 4 commits into
mainfrom
cursor/waiting-list-signup-e777
Jul 11, 2026
Merged

kody-bot merged 4 commits into
mainfrom
cursor/waiting-list-signup-e777

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 11, 2026 •

Copy link
Copy Markdown
Member

Summary

Public /signup now defaults to a waiting-list form (first name + email). Submissions go to POST /waiting-list, which looks up/creates a Kit subscriber and tags them waitlist::kody without overwriting existing CRM names. An I have a code control reveals the existing invite signup form (?code / ?invite / ?panel=invite also open it directly).

Kit forms cannot be created via API; Kent’s existing waitlists use the waitlist::… tag convention, so tagging is the integration surface. Tag waitlist::kody (id 21081721) was created in Kit for this.

Production secret

Please add GitHub Actions secret KIT_API_KEY (same value as Kody kitApiKey). Production deploy syncs it when set; without it, waiting-list joins return 503 while the rest of the app still deploys. Preview deploys intentionally omit the key so preview/E2E joins do not write to the production Kit audience.

System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ 300ae007 · Head: latest on cursor/waiting-list-signup-e777

Classification: extends — signup onboarding now includes a public Kit-backed waiting list while invite-gated account creation remains available.

Primitives touched

Primitive Group Impact
app-sessions auth extends — /signup waiting list + POST /waiting-list Kit tag join; invite signup unchanged behind reveal
app-ui surfaces extends — signup route UI defaults to waiting list with “I have a code” reveal
d1-app-db storage composes — reuses existing D1 rate-limit table for IP throttling

System map

Signup waiting-list joins flow from the Remix signup UI through a new auth handler into Kit; invite signup still uses the existing auth/invite path.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	appUi["app-ui<br/>/signup"]:::extended
	appSessions["app-sessions<br/>waiting-list + invites"]:::extended
	d1AppDb["d1-app-db<br/>rate limits"]:::touched
	kit["Kit API<br/>waitlist::kody tag"]:::untouched
	appUi -->|"waiting list form"| appSessions
	appUi -->|"I have a code → POST /auth"| appSessions
	appSessions -->|"checkRateLimit"| d1AppDb
	appSessions -->|"lookup/create + tag"| kit
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Change flow

sequenceDiagram
	participant User
	participant Signup as /signup
	participant API as POST /waiting-list
	participant Kit as api.kit.com
	User->>Signup: first name + email
	Signup->>API: JSON submit
	API->>Kit: lookup subscriber by email
	alt new subscriber
		API->>Kit: create with first_name
	end
	API->>Kit: tag waitlist::kody
	API-->>Signup: ok
	Note over Signup: “I have a code” reveals invite signup
Loading

Before / after

Surface Before After
/signup Always invite account form Waiting list by default; invite form on demand
Kit No waitlist integration Tag waitlist::kody via KIT_API_KEY

Invariants

Per-user isolation unchanged — waiting-list joins are anonymous marketing contacts in Kit, not Kody user accounts.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features
    • Added a public waiting-list signup flow on /signup for visitors without an invite code, including first name + email submission with validation and Kit-based joining.
    • Supports switching to invite-code signup from the same /signup experience, and enforces per-IP rate limiting with clear success/error messaging.
  • Bug Fixes
    • Updated the invite-based signup flow to include the correct “I have a code” step before entering invite details.
  • Documentation
    • Documented Kit waitlist configuration (KIT_API_KEY, KIT_WAITLIST_TAG_ID) and production vs preview behavior.
  • Tests
    • Added/expanded end-to-end and handler tests for waiting-list signup, rate limiting, and Kit failure/no-op scenarios.

Replace the default /signup view with a first-name + email waiting list
that upserts Kit subscribers and tags them waitlist::kody. Invite signup
stays available behind an "I have a code" control.
Hold the form element across the await so reset() cannot throw and
overwrite the success state with a false network error.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f62dec5a-e0b9-43db-be5c-cf757badb020

📥 Commits

Reviewing files that changed from the base of the PR and between 6ecf26b and 4604919.

📒 Files selected for processing (1)
  • packages/worker/client/routes/login.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/worker/client/routes/login.tsx

📝 Walkthrough

Walkthrough

Changes

Kit waiting-list signup

Layer / File(s) Summary
Route and environment contracts
packages/worker/src/app/routes.ts, packages/worker/src/app/router.ts, packages/worker/src/env-schema.ts
Adds the POST /waiting-list route, registers its action handler, and defines optional Kit configuration variables.
Kit integration and request handling
packages/worker/src/app/kit-waitlist.ts, packages/worker/src/app/handlers/waiting-list.ts, packages/worker/src/app/*waitlist.node.test.ts
Validates and rate-limits submissions, handles production and non-production Kit behavior, creates and tags subscribers, and tests success and failure paths.
Signup panel and end-to-end flow
packages/worker/client/routes/login.tsx, e2e/*signup*.spec.ts
Adds waiting-list and invite-code signup states, submits waiting-list requests, and tests navigation and success messaging.
Secret synchronization and documentation
.github/workflows/*.yml, docs/contributing/..., packages/worker/.env.example
Synchronizes KIT_API_KEY to Workers, omits it from preview deployments, and documents Kit waiting-list configuration and signup behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SignupUI
  participant WaitingListAction
  participant RateLimitD1
  participant KitAPI
  SignupUI->>WaitingListAction: POST /waiting-list
  WaitingListAction->>RateLimitD1: Check client-IP limit
  WaitingListAction->>KitAPI: Look up, create, or tag subscriber
  KitAPI-->>WaitingListAction: Return subscriber result
  WaitingListAction-->>SignupUI: Return signup result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a Kit-backed waiting-list flow to the invite-gated signup experience.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/waiting-list-signup-e777

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kody-bot
kody-bot marked this pull request as ready for review July 11, 2026 14:08
@github-actions

github-actions Bot commented Jul 11, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-728.kody-a99.workers.dev

Worker: kody-pr-728
D1: kody-pr-728-db
KV: kody-pr-728-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/deploy.yml (1)

128-139: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Make the production Kit secret contract consistent.

The production workflow permits KIT_API_KEY to be absent, while the PR objective says production requires it; the setup manifest repeats the optional wording. Either make the sync mandatory and document that requirement, or explicitly define deployments without the secret as supported but unavailable.

  • .github/workflows/deploy.yml#L128-L139: replace --set-from-env-optional KIT_API_KEY with mandatory synchronization if production must require the secret.
  • docs/contributing/setup-manifest.md#L149-L153: document the secret as required for production and optional only for non-production environments.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy.yml around lines 128 - 139, Make the production
KIT_API_KEY contract mandatory: update the deployment command in
.github/workflows/deploy.yml lines 128-139 to use required synchronization for
KIT_API_KEY, and update docs/contributing/setup-manifest.md lines 149-153 to
state that the secret is required in production but optional for non-production
environments.
.github/workflows/preview.yml (1)

267-285: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not send preview signups to the production Kit audience.

Every preview receives the repository KIT_API_KEY, so /waiting-list calls the live Kit API. Manual or E2E preview submissions can therefore create persistent production subscribers. Use an isolated preview key/audience, or leave the key unset and mock Kit in previews.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/preview.yml around lines 267 - 285, Update the preview
workflow’s worker secret synchronization around KIT_API_KEY so previews cannot
use the repository production Kit credentials. Configure an isolated preview Kit
key/audience, or omit KIT_API_KEY and enable the existing preview/mock behavior,
ensuring /waiting-list submissions never reach the production Kit API.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/app/kit-waitlist.ts`:
- Around line 74-106: Add a deadline-driven AbortSignal to
subscribeToKitWaitlist and pass it to both Kit fetchImpl calls so slow requests
are cancelled. Detect timeout/abort failures and map them to the existing 502
response path, while preserving current handling for non-timeout Kit errors and
successful subscriber tagging.
- Around line 74-80: Update the waitlist submission flow around the
createResponse request to check whether the email already has a Kit subscriber
before creating it; avoid sending first_name or skip the create call for
existing subscribers so their CRM name is preserved. Add a regression test
covering an existing subscriber and confirming their name is not overwritten.
- Around line 83-114: Preserve Kit response status in subscribeToKitWaitlist()
by throwing a typed error that distinguishes 4xx client failures from 5xx
responses and network errors. In waiting-list.ts lines 30-33 and 157-159, update
the handler to refund the rate-limit slot only for network or transient 5xx
failures, never for Kit 4xx responses; add a regression test covering a 422
response and confirming the slot is not refunded.

---

Outside diff comments:
In @.github/workflows/deploy.yml:
- Around line 128-139: Make the production KIT_API_KEY contract mandatory:
update the deployment command in .github/workflows/deploy.yml lines 128-139 to
use required synchronization for KIT_API_KEY, and update
docs/contributing/setup-manifest.md lines 149-153 to state that the secret is
required in production but optional for non-production environments.

In @.github/workflows/preview.yml:
- Around line 267-285: Update the preview workflow’s worker secret
synchronization around KIT_API_KEY so previews cannot use the repository
production Kit credentials. Configure an isolated preview Kit key/audience, or
omit KIT_API_KEY and enable the existing preview/mock behavior, ensuring
/waiting-list submissions never reach the production Kit API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 49c45b3f-3356-421c-9ed7-8849a88a8a79

📥 Commits

Reviewing files that changed from the base of the PR and between 300ae00 and 033c563.

📒 Files selected for processing (18)
  • .github/workflows/deploy.yml
  • .github/workflows/preview.yml
  • docs/contributing/architecture/authentication.md
  • docs/contributing/architecture/primitives.yaml
  • docs/contributing/environment-variables.md
  • docs/contributing/project-intent.md
  • docs/contributing/setup-manifest.md
  • e2e/invite-signup-verification.spec.ts
  • e2e/waiting-list-signup.spec.ts
  • packages/worker/.env.example
  • packages/worker/client/routes/login.tsx
  • packages/worker/src/app/handlers/waiting-list.node.test.ts
  • packages/worker/src/app/handlers/waiting-list.ts
  • packages/worker/src/app/kit-waitlist.node.test.ts
  • packages/worker/src/app/kit-waitlist.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/env-schema.ts

Comment thread packages/worker/src/app/kit-waitlist.ts Outdated
Comment thread packages/worker/src/app/kit-waitlist.ts Outdated
Comment thread packages/worker/src/app/kit-waitlist.ts Outdated
Look up existing subscribers before create so public joins cannot overwrite
CRM names, bound Kit fetches with a timeout, refund rate-limit slots only
for transient failures, and keep preview deploys off the production Kit
audience.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6ecf26b. Configure here.

Comment thread packages/worker/client/routes/login.tsx Outdated
Comment thread packages/worker/client/routes/login.tsx
Comment thread packages/worker/client/routes/login.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/worker/src/app/kit-waitlist.ts (1)

122-226: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding tests for timeout and server-error classification paths.

Current tests cover new subscriber creation, existing subscriber (no overwrite), and client 4xx classification. Missing: timeout/network failure (kitFetch abort path → kind: 'network') and server 5xx classification (kind: 'server'). Adding these would round out coverage for the error paths that drive rate-limit refund behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/kit-waitlist.ts` around lines 122 - 226, The tests
for subscribeToKitWaitlist should cover both error-classification paths
mentioned: add a timeout/network-failure case exercising kitFetch’s abort path
and asserting kind: 'network', and add a 5xx response case asserting kind:
'server'. Keep the existing creation, existing-subscriber, and 4xx
classification tests unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/worker/src/app/kit-waitlist.ts`:
- Around line 122-226: The tests for subscribeToKitWaitlist should cover both
error-classification paths mentioned: add a timeout/network-failure case
exercising kitFetch’s abort path and asserting kind: 'network', and add a 5xx
response case asserting kind: 'server'. Keep the existing creation,
existing-subscriber, and 4xx classification tests unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f32f32c-c127-4413-8e00-9ab1651c0504

📥 Commits

Reviewing files that changed from the base of the PR and between 033c563 and 6ecf26b.

📒 Files selected for processing (8)
  • .github/workflows/preview.yml
  • docs/contributing/architecture/authentication.md
  • docs/contributing/environment-variables.md
  • docs/contributing/setup-manifest.md
  • packages/worker/src/app/handlers/waiting-list.node.test.ts
  • packages/worker/src/app/handlers/waiting-list.ts
  • packages/worker/src/app/kit-waitlist.node.test.ts
  • packages/worker/src/app/kit-waitlist.ts
✅ Files skipped from review due to trivial changes (4)
  • docs/contributing/environment-variables.md
  • docs/contributing/setup-manifest.md
  • .github/workflows/preview.yml
  • docs/contributing/architecture/authentication.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/worker/src/app/handlers/waiting-list.node.test.ts
  • packages/worker/src/app/handlers/waiting-list.ts

Keep invite codes optional client-side for non-production open signup,
prefill from ?code/?invite, and sync the invite panel when signup search
params change.
@kody-bot
kody-bot merged commit d446b3b into main Jul 11, 2026
5 checks passed
@kody-bot
kody-bot deleted the cursor/waiting-list-signup-e777 branch July 11, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants