gantt-board/SUPABASE_SETUP.md

5.1 KiB

Supabase Setup Guide for Gantt Board

Step 1: Create a Supabase Project

Since Supabase CLI is not installed, we'll use the Supabase Dashboard:

  1. Go to https://supabase.com/dashboard
  2. Click "New Project"
  3. Choose your organization
  4. Enter project details:
    • Name: gantt-board (or your preferred name)
    • Database Password: Generate a strong password (save this!)
    • Region: Choose closest to your users (e.g., us-east-1 for US East Coast)
  5. Click "Create New Project"
  6. Wait for the project to be created (~2 minutes)

Step 2: Get Your Credentials

Once the project is created:

  1. Go to Project SettingsAPI
  2. Copy these values:
    • Project URL (e.g., https://xxxxxx.supabase.co)
    • anon/public key (under "Project API keys")
    • service_role key (under "Project API keys" - keep this secret!)

Step 3: Create the Database Schema

  1. Go to the SQL Editor in the left sidebar
  2. Click "New Query"
  3. Copy and paste the contents of supabase/schema.sql (created below)
  4. Click "Run"

This creates all tables with proper:

  • Primary keys (using UUID)
  • Foreign key constraints
  • Indexes for performance
  • Row Level Security (RLS) policies

Step 4: Set Environment Variables

Create a .env.local file in your project root with the credentials from Step 2:

# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-project-url.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key-here

Important: Never commit .env.local to git. It's already in .gitignore.

Step 5: Install Supabase Client

npm install @supabase/supabase-js

Step 6: Migrate Data from SQLite

Run the migration script to copy your existing data:

npx tsx scripts/migrate-to-supabase.ts

This will:

  1. Read all data from your local SQLite database
  2. Insert it into Supabase
  3. Handle conflicts and dependencies (users first, then projects, etc.)

Step 7: Test Locally

npm run dev

Test all functionality:

  • Login/logout
  • Create/edit tasks
  • Create/edit projects
  • Create/edit sprints
  • User management

Sprint date verification:

  • Create a sprint with startDate/endDate from date inputs (for example 2026-02-16 to 2026-02-22).
  • Confirm UI displays the same calendar dates without shifting a day earlier in local timezone.
  • Confirm sprints.start_date and sprints.end_date are stored as YYYY-MM-DD in Supabase.

Step 8: Deploy to Vercel

Add Environment Variables in Vercel:

  1. Go to your Vercel dashboard
  2. Select the gantt-board project
  3. Go to SettingsEnvironment Variables
  4. Add all variables from .env.local:
    • NEXT_PUBLIC_SUPABASE_URL
    • NEXT_PUBLIC_SUPABASE_ANON_KEY
    • SUPABASE_SERVICE_ROLE_KEY

Deploy:

vercel --prod

Or push to git and let Vercel auto-deploy.

Troubleshooting

Connection Issues

  • Verify your Supabase URL and keys are correct
  • Check if your Supabase project is active (not paused)
  • Ensure your IP is not blocked in Supabase settings

Row Level Security Errors

  • The schema includes RLS policies
  • Anonymous users can only read public data
  • Authenticated users can only modify their own data
  • Service role bypasses RLS (used for admin operations)

Data Migration Issues

  • If migration fails mid-way, you can re-run it
  • The script uses upsert, so existing data won't be duplicated
  • Check the error message for specific constraint violations

Off-by-One Sprint Date Display

  • Root cause: using new Date("YYYY-MM-DD") directly can parse as UTC and render as the previous day in some local time zones.
  • Expected behavior in this app:
    • Sprint start date = local 12:00:00 AM for selected day.
    • Sprint end date = local 11:59:59.999 PM for selected day.
  • API behavior:
    • /api/sprints normalizes startDate and endDate to YYYY-MM-DD before persistence.
    • Invalid date format on PATCH /api/sprints returns 400.
  • API payload examples:
    • POST /api/sprints
      • { "name": "Sprint 1", "startDate": "2026-02-16", "endDate": "2026-02-22", "status": "active", "projectId": "<uuid>" }
    • PATCH /api/sprints
      • { "id": "<sprint-id>", "startDate": "2026-02-16T00:00:00.000Z", "endDate": "2026-02-22T23:59:59.999Z" }
      • stored as date-only values in Supabase DATE columns

Architecture Changes

Before (SQLite):

  • File-based database stored in data/tasks.db
  • Sessions stored in SQLite
  • Works only on single server

After (Supabase):

  • PostgreSQL database hosted by Supabase
  • JWT-based session tokens
  • Works on multiple servers/Vercel edge functions
  • Real-time subscriptions possible (future enhancement)

Security Notes

  1. Never expose SUPABASE_SERVICE_ROLE_KEY to the client

    • Only use it in server-side code (API routes, server actions)
    • The anon key is safe to expose (it's in NEXT_PUBLIC_)
  2. Row Level Security is enabled

    • Tables have policies that restrict access
    • Users can only see/modify their own data
    • Admin operations use service role key
  3. Password hashing remains the same

    • We use scrypt hashing (same as SQLite version)
    • Passwords are never stored in plain text