Skip to content

feat: Add local Supabase (Docker) and waitlist table with seed#32

Open
JuliobaCR wants to merge 1 commit intoACTA-Team:developfrom
JuliobaCR:feat/supabase-waitlist-docker
Open

feat: Add local Supabase (Docker) and waitlist table with seed#32
JuliobaCR wants to merge 1 commit intoACTA-Team:developfrom
JuliobaCR:feat/supabase-waitlist-docker

Conversation

@JuliobaCR
Copy link

@JuliobaCR JuliobaCR commented Feb 26, 2026

Closes #23

Pull Request – Local Supabase Integration for Waitlist

ACTA Team,

First, I want to sincerely thank you for the opportunity to contribute to this critical infrastructure component 🙌
Building a self-contained, reproducible database environment for the waitlist feature aligns strongly with ACTA’s vision of decentralized, owner-controlled digital infrastructure. This implementation reflects the same principles of autonomy, auditability, and transparency that underpin verifiable credentials.

Executive Summary

This pull request implements a complete local Supabase (Docker) integration for waitlist data persistence, replacing the external Formspree dependency with an internal PostgreSQL-backed database 🗄️

The solution delivers three core benefits:

1️⃣ Data Ownership – Full control over waitlist records without vendor lock-in 🔐
2️⃣ Local Development Parity – Developers can replicate production environments locally 🧪
3️⃣ Operational Resilience – The application remains functional even when Supabase infrastructure is unavailable, via graceful fallback to placeholder credentials 🛡️

The implementation follows defense-in-depth security principles, enforces Row Level Security (RLS), and maintains full backward compatibility with existing functionality.

Problem Statement & Motivation

The previous waitlist implementation submitted directly to Formspree, introducing architectural limitations:

🔒 Vendor lock-in and dependency on third-party data access
📊 No direct querying capability for analytics, deduplication, or auditing
👁️ Limited operational visibility
🧭 Misalignment with ACTA’s self-hosted, auditable infrastructure philosophy

This PR restores full data ownership to ACTA while introducing zero breaking changes and supporting multiple deployment scenarios (local Docker, self-hosted Supabase, Supabase Cloud) 🌍

Technical Architecture

The solution implements a four-layer architecture with clear separation of concerns 🏗️

Layer 1 – Frontend (WaitlistForm in React/TypeScript)
✨ Client-side email validation
🤖 Honeypot field for bot detection
🔄 Four-state response management

Layer 2 – API Route (Next.js 15 App Router)
🛑 Honeypot verification
🧹 Payload validation and sanitization
🗄️ Database operations via Supabase client
📡 Structured HTTP error translation

Layer 3 – Supabase Client (TypeScript)
🔓 Public anon client for RLS-controlled inserts
🔐 Service role client (server-only)
🧩 Placeholder fallback logic
⚙️ Non-blocking graceful initialization

Layer 4 – Database (PostgreSQL via Supabase)
🆔 UUID primary key
📧 Email uniqueness constraint
📅 Indexed created_at for chronological sorting
🛡️ RLS policies: anonymous INSERT, service_role SELECT

Implementation Details

Database Migration

File: supabase/migrations/20250225000000_create_waitlist_table.sql

🆔 id (UUID, primary key, auto-generated)
📧 email (TEXT, NOT NULL, UNIQUE)
🏢 company_name (TEXT, nullable)
📝 use_case (TEXT, nullable)
⏱️ created_at (TIMESTAMPTZ, NOT NULL, default now())

📚 Created index waitlist_created_at_idx on created_at DESC

🔐 Enabled Row Level Security with:
➕ Anonymous INSERT policy
👁️ Service role SELECT policy

Design rationale:

🔎 UUID prevents sequential ID disclosure
♻️ UNIQUE email enforces deduplication at storage layer
🕒 Server-side timestamps prevent client clock skew
📈 DESC index optimizes “latest first” queries
🛡️ RLS enforces least privilege at database level

Seed Data

File: supabase/seed.sql

🌐 Includes 8 representative records across different verticals
🔁 Uses ON CONFLICT (email) DO NOTHING to ensure idempotency

Backend Implementation

Supabase Client Library

File: src/lib/supabase.ts

🔓 Public anon client for safe client-side operations
🔐 Server-only service client isolated from client bundle
🧠 Placeholder credential detection
⚙️ Graceful fallback without crashing the application

If SUPABASE_SERVICE_ROLE_KEY is missing, a warning is logged and the anon client is used. The application never fails at startup due to missing credentials 🚀

API Route

File: src/app/api/waitlist/route.ts

🛑 Honeypot check – returns 200 silently for bots
📧 Email regex validation (/^[^\s@]+@[^\s@]+.[^\s@]+$/)
🧹 Payload sanitization
🗄️ Insert via getServiceSupabase()
🔁 Error translation:
⚠️ 23505 → 409 Conflict (duplicate email)
💥 Other DB errors → 500 Internal Server Error

Response Codes:

✅ 201 Created
❌ 400 Bad Request
⚠️ 409 Conflict
💥 500 Internal Server Error

Frontend Update

File: src/features/waitlist/WaitlistForm.tsx

🔄 Migrated endpoint from Formspree to /api/waitlist

Implements a 4-state response system:

⚪ idle
🟢 ok (201)
🟡 duplicate (409)
🔴 error (400/500)

🎨 All styling, UX, animations, and structure remain unchanged from the user perspective

Security Considerations

🔐 Service role key strictly server-side
🛡️ RLS enforced at database layer
🧪 Multi-layer validation (client, server, DB)
🤖 Honeypot bot protection
🚫 No hardcoded secrets
⚙️ Placeholder credentials prevent startup failures

Closing Remarks

🌐 This implementation reinforces infrastructure alignment with ACTA’s core values: auditability, decentralization, and self-controlled data

Even a waitlist signup should reflect those principles. Issue #23 provided the opportunity to design and implement a production-grade solution with careful architecture, strong security posture, and complete documentation.

Thank you again to the ACTA Team for the opportunity to contribute meaningfully to this ecosystem 🙏

For questions or follow-up:
Telegram: @JuliobaCR

Summary by CodeRabbit

Release Notes

  • New Features

    • Waitlist now persists submissions to a persistent database with duplicate email detection
    • Added local development support with optional database setup for testing
  • Documentation

    • Added comprehensive guide for setting up local development environment with database tools
  • Chores

    • Updated project configuration and dependencies for database integration
    • Added management scripts for local database operations

…sistence

Overview

Add complete local Supabase setup using Docker and Supabase CLI, providing
developers with a self-contained database environment for waitlist feature
development. The implementation includes database schema, migrations, seeding,
API integration, and comprehensive documentation.

Core Implementation

Database Layer

- Initialize Supabase project with local Docker configuration (supabase/config.toml)
- Create migration (20250225000000_create_waitlist_table.sql) with:
  * public.waitlist table: id (UUID PK), email (UNIQUE), company_name, use_case, created_at
  * Index on created_at DESC for efficient chronological queries
  * Row Level Security (RLS) policies enforcing anonymous inserts, service_role selects
- Add idempotent seed.sql with 8 production-ready sample data rows
- Use ON CONFLICT (email) DO NOTHING to ensure seed re-execution safety

Backend Integration

- Create Supabase client (src/lib/supabase.ts) with fallback resilience:
  * Placeholder credentials when environment variables missing or invalid
  * Service-only getServiceSupabase() function isolating service role key
  * Graceful console warnings when keys missing (non-blocking startup)
- Implement POST /api/waitlist route handler with:
  * Email validation (RFC-compliant regex)
  * Honeypot anti-bot field handling
  * Duplicate email detection (PostgreSQL 23505 → HTTP 409 Conflict)
  * Proper status codes: 201 Created, 400 Bad Request, 409 Conflict, 500 Internal Error
  * Server-side payload sanitization and database insert

Frontend Updates

- Refactor WaitlistForm component (src/features/waitlist/WaitlistForm.tsx):
  * Replace Formspree endpoint with internal /api/waitlist
  * Map form fields to database schema: company → company_name, message → use_case
  * Implement 4-state UX: idle, ok (201), duplicate (409), error (400/500)
  * Preserve existing styling and user experience patterns
  * Maintain loading and success states with appropriate messaging

Configuration & Scripts

- Add 4 npm scripts for database lifecycle management:
  * npm run db:start    → npx supabase start (Docker containers)
  * npm run db:stop     → npx supabase stop (Graceful shutdown)
  * npm run db:reset    → npx supabase db reset (Migrations + seed)
  * npm run db:migration <name> → npx supabase migration new (New migration)
- Install @supabase/supabase-js@^2.97.0 dependency
- Update .env.example with optional Supabase environment variables and documentation
- Extend .gitignore to exclude supabase/.temp/ (temporary files) and .env.local (local credentials)

Documentation

- Expand README.md with comprehensive "Local Supabase (Docker) — Optional" section:
  * Updated prerequisites (Docker Desktop, Supabase CLI marked as optional)
  * 5-step quick start guide for local development
  * Database scripts reference table
  * Supabase Studio access instructions
  * Detailed credential fallback behavior explanation
  * Testing instructions across different scenarios

Architecture & Design Patterns

Resilience & Graceful Degradation

The implementation follows fail-safe principles:
- App starts successfully with placeholder credentials (no environment variables required)
- Waitlist submissions execute without errors in all scenarios
- Real database persistence only when valid credentials provided
- Non-blocking warnings logged to console when optional services unavailable

Security Considerations

- Service role key exclusively server-side (never in client bundle)
- Row Level Security enforces anonymous insert-only, service-role full access
- Email uniqueness enforced at both database and application layers
- Input validation at multiple layers: client-side regex, server-side validation, database constraints
- No hardcoded secrets (all credentials via environment variables)

Code Quality

- Full TypeScript type safety across all new code
- Clear separation of concerns: client, API route, database client
- Comprehensive code comments explaining fallback behavior
- Follows Next.js and React best practices
- Maintains consistency with existing project architecture and styling

Acceptance Criteria Fulfillment

✓ README documents all prerequisites including optional Docker/Supabase CLI
✓ Documentation explains credentials are optional, app uses fallbacks
✓ Supabase client implements placeholder URLs and JWT tokens
✓ supabase/config.toml exists with default Supabase configuration
✓ All 4 npm scripts (db:start, db:stop, db:reset, db:migration) implemented
✓ Migration creates public.waitlist with required columns and indices
✓ Seed file contains exactly 8 rows with idempotent ON CONFLICT handling
✓ .env.example includes all 3 Supabase variables with documentation
✓ .gitignore properly excludes temporary and local credential files
✓ WaitlistForm successfully migrated from Formspree to Supabase backend
✓ API route validates all inputs, handles duplicates, manages database errors
✓ RLS policies enforce security while allowing anonymous signups

Testing Verification

- Syntax validation: All TypeScript files compile without errors
- Import resolution: All path aliases (@/lib, @/components) resolve correctly
- Dependency installation: @supabase/supabase-js available in node_modules
- File structure: All required files exist in correct locations
- Database schema: Migration includes table creation, indexing, RLS policies
- API functionality: Route handler exports POST, validates inputs, handles errors
- Component integration: WaitlistForm maps fields, handles all response states
- Documentation: README complete, .env.example documented, gitignore updated

Related Issue

Closes ACTA-Team#23 - Add local Supabase (Docker) and waitlist table with seed
@vercel
Copy link
Contributor

vercel bot commented Feb 26, 2026

@JuliobaCR is attempting to deploy a commit to the ACTA Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

Integrates Supabase as a database backend for the waitlist feature with local Docker-based development support. Adds environment configuration, API endpoint for form submissions, database schema with migrations and seed data, and updates the waitlist form to use the new backend instead of Formspree.

Changes

Cohort / File(s) Summary
Configuration & Environment
.env.example, .gitignore
Added Supabase credentials (URL, anon key, service role key) as optional environment variables with explanatory comments; extended gitignore to exclude local env files and Supabase temporary directories.
Dependencies & Scripts
package.json
Added @supabase/supabase-js dependency and four new npm scripts (db:start, db:stop, db:reset, db:migration) for local Supabase CLI management.
Documentation
README.md
Added comprehensive Local Supabase setup instructions, including Docker/Supabase CLI prerequisites, available database scripts, credential configuration, and behavior when env vars are missing (uses placeholders).
Supabase Infrastructure
supabase/config.toml, supabase/.gitignore, supabase/migrations/20250225000000_create_waitlist_table.sql, supabase/seed.sql
Established local Supabase project configuration with ports, authentication, and storage settings; created waitlist table schema with email uniqueness, RLS policies for anonymous inserts and service-role reads; populated seed data with eight sample waitlist entries.
Supabase Client Setup
src/lib/supabase.ts
Implemented client factory with fallback placeholders for missing/invalid env vars to prevent startup crashes; exports public Supabase client and getServiceSupabase() helper that uses service role key when available, falling back to anon client with warning.
Waitlist API & Form Integration
src/app/api/waitlist/route.ts, src/features/waitlist/WaitlistForm.tsx
Created POST endpoint validating email, handling duplicate submissions (409), and inserting into waitlist table; updated form to call new API instead of Formspree, mapping field names (companycompany_name, messageuse_case) and displaying duplicate status message.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Connect WaitlistForm to Supabase (API + form) #28 — Directly addresses the follow-up objective of implementing a dedicated API endpoint (POST /api/waitlist) and updating the form component to submit to internal backend instead of Formspree, with Supabase integration for persistent storage.

Poem

🐰 A rabbit hops with glee,
Supabase sets the waitlist free!
Local Docker, seeds that grow,
From form to database, data will flow.
No more Formspree, we've built our own—
The warren's data safe back home! 🏠✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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 PR title clearly and concisely summarizes the main change: adding local Supabase Docker integration and implementing the waitlist table with seed data, which matches the primary objectives.
Linked Issues check ✅ Passed All acceptance criteria from linked issue #23 are met: Supabase local setup with config.toml and npm scripts, waitlist table migration with proper schema and RLS, idempotent seed data, fallback client credentials, updated .env.example and README documentation, and Next.js API route implementation.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #23 objectives: Supabase infrastructure, waitlist table, seed data, client implementation, API route, form refactoring, and documentation. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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 and usage tips.

@gitguardian
Copy link

gitguardian bot commented Feb 26, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - JSON Web Token 7505964 src/lib/supabase.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/lib/supabase.ts (1)

53-59: Log missing service-role warning only once.

Current fallback warning emits on every call, which can flood logs in production-like traffic.

♻️ Suggested refactor
+let hasWarnedMissingServiceRole = false;
+
 export function getServiceSupabase(): SupabaseClient {
   if (!rawServiceRoleKey || isPlaceholder(rawServiceRoleKey)) {
-    if (typeof window === "undefined") {
+    if (typeof window === "undefined" && !hasWarnedMissingServiceRole) {
       console.warn(
         "[supabase] SUPABASE_SERVICE_ROLE_KEY is missing – falling back to anon client. " +
           "Waitlist inserts will use RLS policies. Set the key in .env.local for full access.",
       );
+      hasWarnedMissingServiceRole = true;
     }
     return supabase;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/supabase.ts` around lines 53 - 59, The console.warn about a missing
SUPABASE_SERVICE_ROLE_KEY is currently emitted on every call; to avoid log
flooding add a module-level boolean flag (e.g., warnedMissingServiceRole =
false) and, inside the existing check that uses rawServiceRoleKey and
isPlaceholder (and the typeof window === "undefined" branch), only call
console.warn the first time by testing the flag and then setting it to true;
update the warning block where rawServiceRoleKey/isPlaceholder is checked so
subsequent calls are silent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Line 118: The README currently over-promises that the waitlist form "submits
without errors" when Supabase env vars are missing; change the sentence to
guarantee only that the app will start and the waitlist form will be available,
but that persistence and successful responses are not guaranteed — e.g., replace
the clause "the waitlist form submits without errors (requests simply won't be
persisted)" with wording that the form may attempt submission but requests may
not be saved and may return errors or no-op when Supabase is unconfigured.

In `@src/lib/supabase.ts`:
- Around line 9-10: The constant PLACEHOLDER_ANON_KEY currently contains a
JWT-looking string which triggers secret scanners; replace its value with a
clearly non-JWT sentinel (for example a descriptive string like
"PLACEHOLDER_ANON_KEY_NOT_A_JWT" or similar) and update any tests or mocks that
expect the old literal to use the new sentinel instead; keep the constant name
PLACEHOLDER_ANON_KEY unchanged so all references (e.g., places that import or
read PLACEHOLDER_ANON_KEY) continue to work and no runtime behavior changes.

In `@supabase/migrations/20250225000000_create_waitlist_table.sql`:
- Around line 6-15: The current column-level UNIQUE on public.waitlist.email is
case-sensitive and should be replaced with a case-insensitive unique index:
remove the UNIQUE keyword from the email column definition and instead create a
unique index such as waitlist_email_ci_idx on public.waitlist using lower(email)
(e.g. CREATE UNIQUE INDEX waitlist_email_ci_idx ON public.waitlist
(lower(email))); keep the created_at index (waitlist_created_at_idx) as-is and
ensure any existing data is normalized or checked for conflicts before creating
the new unique index.

---

Nitpick comments:
In `@src/lib/supabase.ts`:
- Around line 53-59: The console.warn about a missing SUPABASE_SERVICE_ROLE_KEY
is currently emitted on every call; to avoid log flooding add a module-level
boolean flag (e.g., warnedMissingServiceRole = false) and, inside the existing
check that uses rawServiceRoleKey and isPlaceholder (and the typeof window ===
"undefined" branch), only call console.warn the first time by testing the flag
and then setting it to true; update the warning block where
rawServiceRoleKey/isPlaceholder is checked so subsequent calls are silent.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 546e6f7 and 7505964.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • .env.example
  • .gitignore
  • README.md
  • package.json
  • src/app/api/waitlist/route.ts
  • src/features/waitlist/WaitlistForm.tsx
  • src/lib/supabase.ts
  • supabase/.gitignore
  • supabase/config.toml
  • supabase/migrations/20250225000000_create_waitlist_table.sql
  • supabase/seed.sql


### Local Supabase (Docker) — Optional

The project includes a full local Supabase setup for waitlist persistence. **This is entirely optional.** When Supabase environment variables are missing or contain placeholder values, the app starts normally and the waitlist form submits without errors (requests simply won't be persisted).
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Soften the “submits without errors” guarantee.

The current text over-promises behavior when Supabase is unconfigured. Prefer wording that guarantees app startup, but not guaranteed waitlist persistence/success response.

📝 Suggested wording
-The project includes a full local Supabase setup for waitlist persistence. **This is entirely optional.** When Supabase environment variables are missing or contain placeholder values, the app starts normally and the waitlist form submits without errors (requests simply won't be persisted).
+The project includes a full local Supabase setup for waitlist persistence. **This is entirely optional.** When Supabase environment variables are missing or contain placeholder values, the app starts normally, but waitlist requests may fail or be non-persistent until Supabase is configured.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The project includes a full local Supabase setup for waitlist persistence. **This is entirely optional.** When Supabase environment variables are missing or contain placeholder values, the app starts normally and the waitlist form submits without errors (requests simply won't be persisted).
The project includes a full local Supabase setup for waitlist persistence. **This is entirely optional.** When Supabase environment variables are missing or contain placeholder values, the app starts normally, but waitlist requests may fail or be non-persistent until Supabase is configured.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 118, The README currently over-promises that the waitlist
form "submits without errors" when Supabase env vars are missing; change the
sentence to guarantee only that the app will start and the waitlist form will be
available, but that persistence and successful responses are not guaranteed —
e.g., replace the clause "the waitlist form submits without errors (requests
simply won't be persisted)" with wording that the form may attempt submission
but requests may not be saved and may return errors or no-op when Supabase is
unconfigured.

Comment on lines +9 to +10
const PLACEHOLDER_ANON_KEY =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace JWT-shaped placeholder key to avoid secret-scanner failures.

This literal is flagged as a leaked JWT pattern and can block CI/security checks even as a placeholder. A non-JWT sentinel string is safer.

🔧 Suggested fix
-const PLACEHOLDER_ANON_KEY =
-  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
+const PLACEHOLDER_ANON_KEY = "placeholder-anon-key";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const PLACEHOLDER_ANON_KEY =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
const PLACEHOLDER_ANON_KEY = "placeholder-anon-key";
🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 10-10: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/supabase.ts` around lines 9 - 10, The constant PLACEHOLDER_ANON_KEY
currently contains a JWT-looking string which triggers secret scanners; replace
its value with a clearly non-JWT sentinel (for example a descriptive string like
"PLACEHOLDER_ANON_KEY_NOT_A_JWT" or similar) and update any tests or mocks that
expect the old literal to use the new sentinel instead; keep the constant name
PLACEHOLDER_ANON_KEY unchanged so all references (e.g., places that import or
read PLACEHOLDER_ANON_KEY) continue to work and no runtime behavior changes.

Comment on lines +6 to +15
email text not null unique,
company_name text,
use_case text,

-- Timestamps
created_at timestamptz not null default now()
);

-- Index for listing by date
create index waitlist_created_at_idx on public.waitlist (created_at desc);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat supabase/migrations/20250225000000_create_waitlist_table.sql

Repository: ACTA-Team/website

Length of output: 878


Replace case-sensitive UNIQUE constraint with case-insensitive unique index.

PostgreSQL's UNIQUE on text is case-sensitive, allowing Alice@x.com and alice@x.com to both be inserted despite appearing identical. This weakens deduplication and can result in duplicate responses from the same user across case variations.

Proposed fix
 create table public.waitlist (
   id uuid primary key default gen_random_uuid(),

   -- Form data
-  email text not null unique,
+  email text not null,
   company_name text,
   use_case text,

   -- Timestamps
   created_at timestamptz not null default now()
 );

 -- Index for listing by date
 create index waitlist_created_at_idx on public.waitlist (created_at desc);
+create unique index waitlist_email_ci_idx
+  on public.waitlist (lower(trim(email)));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
email text not null unique,
company_name text,
use_case text,
-- Timestamps
created_at timestamptz not null default now()
);
-- Index for listing by date
create index waitlist_created_at_idx on public.waitlist (created_at desc);
create table public.waitlist (
id uuid primary key default gen_random_uuid(),
-- Form data
email text not null,
company_name text,
use_case text,
-- Timestamps
created_at timestamptz not null default now()
);
-- Index for listing by date
create index waitlist_created_at_idx on public.waitlist (created_at desc);
create unique index waitlist_email_ci_idx
on public.waitlist (lower(trim(email)));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/migrations/20250225000000_create_waitlist_table.sql` around lines 6
- 15, The current column-level UNIQUE on public.waitlist.email is case-sensitive
and should be replaced with a case-insensitive unique index: remove the UNIQUE
keyword from the email column definition and instead create a unique index such
as waitlist_email_ci_idx on public.waitlist using lower(email) (e.g. CREATE
UNIQUE INDEX waitlist_email_ci_idx ON public.waitlist (lower(email))); keep the
created_at index (waitlist_created_at_idx) as-is and ensure any existing data is
normalized or checked for conflicts before creating the new unique index.

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.

1 participant