feat: waitlist supabase api#33
Conversation
- Add POST /api/waitlist with email validation and Supabase insert - Return 409 on duplicate email, 503 on Supabase errors - Update WaitlistForm to submit to API (email, company_name, use_case) - Add duplicate/error states with appropriate messages Made-with: Cursor
|
@felipevega2x is attempting to deploy a commit to the ACTA Team on Vercel. A member of the Team first needs to authorize it. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughAdds a POST API endpoint at Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant WaitlistForm
participant API_Route as "API Route"
participant Supabase
participant Database
User->>WaitlistForm: Fill email, company, use_case
WaitlistForm->>WaitlistForm: Validate email + check honeypot
WaitlistForm->>API_Route: POST /api/waitlist {email, company_name, use_case}
API_Route->>API_Route: Validate & normalize payload
API_Route->>Supabase: Insert into public.waitlist
alt Insert succeeds
Supabase->>Database: Persist row
Database-->>Supabase: Confirm
Supabase-->>API_Route: Success
API_Route-->>WaitlistForm: 201 Created
WaitlistForm->>User: Show success, reset form
else Unique constraint violation
Supabase-->>API_Route: Unique constraint error
API_Route-->>WaitlistForm: 409 Conflict
WaitlistForm->>User: Show "email already on the waitlist"
else DB / config error
Supabase-->>API_Route: Error
API_Route-->>WaitlistForm: 503 / 500
WaitlistForm->>User: Show generic error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
Made-with: Cursor
Made-with: Cursor
588dc1e to
9d1fb52
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/features/waitlist/WaitlistForm.tsx (1)
38-53: Normalize email before client validation and submission.Client-side and server-side normalization are slightly misaligned. Trim/lowercase on the client to avoid false validation failures.
🔧 Proposed fix
- if (!validateEmail(email)) { + const normalizedEmail = email.trim().toLowerCase(); + if (!validateEmail(normalizedEmail)) { setStatus("error"); setErrorMessage("Please check your email and try again."); return; } @@ body: JSON.stringify({ - email, + email: normalizedEmail, company_name: company, use_case: message, }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/waitlist/WaitlistForm.tsx` around lines 38 - 53, Normalize the email before validating and submitting: create a normalizedEmail by trimming and lowercasing the existing email variable, use that normalizedEmail when calling validateEmail(email) (i.e., validateEmail(normalizedEmail)) and when building the POST body to /api/waitlist (replace email with normalizedEmail) so client-side validation and the server receive the same normalized value; update any status/error handling (setStatus, setErrorMessage, setIsSubmitting) to operate around this flow in WaitlistForm (functions: validateEmail, setStatus, setIsSubmitting, fetch to /api/waitlist).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/api/waitlist/route.ts`:
- Around line 41-42: The console.error calls in src/app/api/waitlist/route.ts
are logging raw error objects/messages (seen around the Supabase call and the
second error path) which can contain user emails; change those logs to avoid
printing error.message/raw error objects. Instead, log a sanitized, minimal
message and non-sensitive fields (e.g., error.code or status) from the Supabase
response and optionally a redacted/error id; do not include the submitted email
or full error text. Update the error handling in the POST handler (the function
handling the Supabase insert and the subsequent NextResponse.json error path) to
redact sensitive values (use a regex to mask emails if you must include them) or
omit them entirely and return a generic NextResponse.json error to the client.
- Around line 14-22: The handler currently assumes request.json() returns a
valid object and treats parse failures as server errors; update the logic around
the body parsing (the code that sets const body = (await request.json()) as
WaitlistPayload and the similar block around lines referenced 51-56) to
explicitly catch JSON parse errors and validate that body is a non-null object
before using body.email; if JSON.parse fails or body is not an object return
NextResponse.json({ error: "Malformed or invalid request body." }, { status: 400
}) instead of letting it fall through to the 500 catch, and keep the existing
EMAIL_REGEX/email presence checks afterward.
In `@src/lib/supabase.ts`:
- Around line 5-6: The constant PLACEHOLDER_KEY currently contains a JWT-shaped
token which trips secret scanners; replace its value with a clearly non-secret
sentinel (e.g., "PLACEHOLDER_KEY" or "REDACTED_PLACEHOLDER") in the declaration
of PLACEHOLDER_KEY so it no longer resembles a JWT; update any tests or places
that rely on the exact string if needed to use the new sentinel, and keep the
constant name and usage (PLACEHOLDER_KEY) unchanged.
---
Nitpick comments:
In `@src/features/waitlist/WaitlistForm.tsx`:
- Around line 38-53: Normalize the email before validating and submitting:
create a normalizedEmail by trimming and lowercasing the existing email
variable, use that normalizedEmail when calling validateEmail(email) (i.e.,
validateEmail(normalizedEmail)) and when building the POST body to /api/waitlist
(replace email with normalizedEmail) so client-side validation and the server
receive the same normalized value; update any status/error handling (setStatus,
setErrorMessage, setIsSubmitting) to operate around this flow in WaitlistForm
(functions: validateEmail, setStatus, setIsSubmitting, fetch to /api/waitlist).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 960bbe20-aefa-41a4-9f50-02fe87aaf8a4
📒 Files selected for processing (4)
src/app/api/waitlist/route.tssrc/features/how-it-works/HowItWorks.tsxsrc/features/waitlist/WaitlistForm.tsxsrc/lib/supabase.ts
| const body = (await request.json()) as WaitlistPayload; | ||
|
|
||
| const email = body.email?.trim().toLowerCase(); | ||
| if (!email || !EMAIL_REGEX.test(email)) { | ||
| return NextResponse.json( | ||
| { error: "A valid email address is required." }, | ||
| { status: 400 } | ||
| ); | ||
| } |
There was a problem hiding this comment.
Return 400 for malformed/non-object request bodies.
If JSON parsing fails or body is not an object, the handler falls into the catch block and returns 500. That should be a 400 client error.
🔧 Proposed fix
export async function POST(request: Request) {
try {
- const body = (await request.json()) as WaitlistPayload;
+ let body: WaitlistPayload;
+ try {
+ const parsed = await request.json();
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
+ return NextResponse.json(
+ { error: "Invalid request body." },
+ { status: 400 }
+ );
+ }
+ body = parsed as WaitlistPayload;
+ } catch {
+ return NextResponse.json(
+ { error: "Invalid JSON body." },
+ { status: 400 }
+ );
+ }Also applies to: 51-56
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/api/waitlist/route.ts` around lines 14 - 22, The handler currently
assumes request.json() returns a valid object and treats parse failures as
server errors; update the logic around the body parsing (the code that sets
const body = (await request.json()) as WaitlistPayload and the similar block
around lines referenced 51-56) to explicitly catch JSON parse errors and
validate that body is a non-null object before using body.email; if JSON.parse
fails or body is not an object return NextResponse.json({ error: "Malformed or
invalid request body." }, { status: 400 }) instead of letting it fall through to
the 500 catch, and keep the existing EMAIL_REGEX/email presence checks
afterward.
| console.error("[api/waitlist] Supabase error:", error.message); | ||
| return NextResponse.json( |
There was a problem hiding this comment.
Avoid logging raw error messages that may include submitted email.
Line 41 and Line 52 log raw error text/object. Database errors can contain duplicate key details with user email.
🔧 Proposed fix
- console.error("[api/waitlist] Supabase error:", error.message);
+ console.error("[api/waitlist] Supabase error", {
+ code: error.code,
+ status: error.status,
+ });
@@
- console.error("[api/waitlist] Unexpected error:", err);
+ console.error("[api/waitlist] Unexpected error", {
+ name: err instanceof Error ? err.name : "UnknownError",
+ });Also applies to: 52-52
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/api/waitlist/route.ts` around lines 41 - 42, The console.error calls
in src/app/api/waitlist/route.ts are logging raw error objects/messages (seen
around the Supabase call and the second error path) which can contain user
emails; change those logs to avoid printing error.message/raw error objects.
Instead, log a sanitized, minimal message and non-sensitive fields (e.g.,
error.code or status) from the Supabase response and optionally a redacted/error
id; do not include the submitted email or full error text. Update the error
handling in the POST handler (the function handling the Supabase insert and the
subsequent NextResponse.json error path) to redact sensitive values (use a regex
to mask emails if you must include them) or omit them entirely and return a
generic NextResponse.json error to the client.
Summary
Connects the waitlist form to our internal API so signups are stored in Supabase (
public.waitlist) instead of Formspree.Changes
API route
POST /api/waitlistpublic.waitlistusing server-side Supabase clientWaitlistForm
POST /api/waitlistwith{ email, company_name, use_case }Supabase client
Summary by CodeRabbit
New Features
Improvements