Skip to main content
Supabase provides the authentication and database backend for Galey Cloud. This guide walks through creating a project, setting up the database schema, and configuring security policies.

Creating a Supabase Project

1

Sign up or log in

Go to supabase.com and create an account or log in
2

Create new project

  • Click “New Project”
  • Choose your organization or create a new one
  • Enter a project name (e.g., “galey-cloud-prod”)
  • Generate a strong database password (save this securely)
  • Select a region close to your users
  • Click “Create new project”
Project creation takes 1-2 minutes. The database password cannot be recovered, so save it securely.
3

Wait for provisioning

Your project will be provisioned with a PostgreSQL database, authentication service, and API endpoints.

Setting Up Authentication

1

Configure email authentication

  1. Navigate to AuthenticationProviders in the Supabase dashboard
  2. Email provider should be enabled by default
  3. For production, enable “Confirm email” to verify user emails
  4. Set “Site URL” to your production domain (e.g., https://galey.example.com)
2

Configure redirect URLs

  1. Go to AuthenticationURL Configuration
  2. Add your Vercel deployment URL to Redirect URLs:
    https://your-app.vercel.app/auth/callback
    https://your-custom-domain.com/auth/callback
    
  3. For local development, also add:
    http://localhost:3000/auth/callback
    
3

Optional: Configure OAuth providers

For Google, GitHub, or other OAuth providers:
  1. Go to AuthenticationProviders
  2. Enable desired providers
  3. Add OAuth credentials from respective platforms
  4. Configure redirect URLs in OAuth provider settings

Running Database Migrations

Galey Cloud uses two main tables: albums and photos. The SQL migration scripts are located in scripts/ directory.

Migration 1: Create Albums Table

1

Open SQL Editor

Navigate to SQL Editor in the Supabase dashboard
2

Create albums table

Copy and paste the following SQL script:
scripts/001_create_albums.sql
CREATE TABLE IF NOT EXISTS public.albums (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

ALTER TABLE public.albums ENABLE ROW LEVEL SECURITY;

CREATE POLICY "albums_select_own" ON public.albums
  FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "albums_insert_own" ON public.albums
  FOR INSERT WITH CHECK (auth.uid() = user_id);

CREATE POLICY "albums_update_own" ON public.albums
  FOR UPDATE USING (auth.uid() = user_id);

CREATE POLICY "albums_delete_own" ON public.albums
  FOR DELETE USING (auth.uid() = user_id);
3

Execute the script

Click Run or press Ctrl/Cmd + Enter to execute the SQL
You should see “Success. No rows returned” indicating the table and policies were created.

Migration 2: Create Photos Table

1

Open new query

In the SQL Editor, start a new query
2

Create photos table

Copy and paste the following SQL script:
scripts/002_create_photos.sql
CREATE TABLE IF NOT EXISTS public.photos (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  album_id UUID REFERENCES public.albums(id) ON DELETE SET NULL,
  blob_url TEXT NOT NULL,
  file_name TEXT NOT NULL,
  file_size BIGINT,
  file_type TEXT,
  width INT,
  height INT,
  created_at TIMESTAMPTZ DEFAULT now()
);

ALTER TABLE public.photos ENABLE ROW LEVEL SECURITY;

CREATE POLICY "photos_select_own" ON public.photos
  FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "photos_insert_own" ON public.photos
  FOR INSERT WITH CHECK (auth.uid() = user_id);

CREATE POLICY "photos_update_own" ON public.photos
  FOR UPDATE USING (auth.uid() = user_id);

CREATE POLICY "photos_delete_own" ON public.photos
  FOR DELETE USING (auth.uid() = user_id);
3

Execute the script

Click Run to create the photos table and security policies

Verify Tables Created

1

Check Table Editor

  1. Navigate to Table Editor in the Supabase dashboard
  2. You should see two tables: albums and photos
  3. Click on each table to verify the schema matches the migrations

Understanding Row-Level Security Policies

All tables have Row-Level Security (RLS) enabled to ensure users can only access their own data.

Albums Table Policies

Policy NameOperationRule
albums_select_ownSELECTUser can only read their own albums
albums_insert_ownINSERTUser can only create albums for themselves
albums_update_ownUPDATEUser can only update their own albums
albums_delete_ownDELETEUser can only delete their own albums

Photos Table Policies

Policy NameOperationRule
photos_select_ownSELECTUser can only read their own photos
photos_insert_ownINSERTUser can only upload photos for themselves
photos_update_ownUPDATEUser can only update their own photos
photos_delete_ownDELETEUser can only delete their own photos
All policies use auth.uid() = user_id to ensure authenticated users can only access their own data. This prevents data leaks even if there’s a bug in the application code.

Getting API Keys

You’ll need two API keys for your application:
1

Navigate to API settings

Go to SettingsAPI in the Supabase dashboard
2

Copy Project URL

Copy the Project URL (e.g., https://xxxxx.supabase.co)This will be used as NEXT_PUBLIC_SUPABASE_URL
3

Copy anon/public key

Under Project API keys, copy the anon public keyThis will be used as NEXT_PUBLIC_SUPABASE_ANON_KEY
Do NOT use the service_role secret key in your Next.js application. This key bypasses RLS and should only be used in secure server environments.
4

Save keys securely

Store these values temporarily - you’ll add them to Vercel environment variables in the next steps

Testing the Connection

Before deploying, verify your Supabase setup works correctly:
1

Set up local environment

Create .env.local in your project root:
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
2

Install dependencies

npm install
# or
pnpm install
3

Run development server

npm run dev
4

Test authentication

  1. Navigate to http://localhost:3000/auth/sign-up
  2. Create a test account
  3. Check Supabase dashboard → AuthenticationUsers to verify user was created
  4. Try logging in at http://localhost:3000/auth/login
5

Verify database access

  1. Log into your test account
  2. Try creating an album
  3. Check Supabase dashboard → Table Editoralbums to verify the record
  4. Verify you can only see your own data (RLS is working)

Optional: Database Indexes

For better performance with large datasets, add indexes:
-- Index for faster user album lookups
CREATE INDEX idx_albums_user_id ON public.albums(user_id);

-- Index for faster user photo lookups
CREATE INDEX idx_photos_user_id ON public.photos(user_id);

-- Index for faster album photo lookups
CREATE INDEX idx_photos_album_id ON public.photos(album_id);

-- Index for sorting by creation date
CREATE INDEX idx_photos_created_at ON public.photos(created_at DESC);

Troubleshooting

”JWTExpired” errors

  • Check that your Site URL and Redirect URLs are configured correctly
  • Ensure cookies are enabled in your browser
  • Verify the JWT expiry settings in AuthenticationSettings

”Row-level security policy violation”

  • Verify the user is authenticated before making database requests
  • Check that user_id is set correctly when inserting records
  • Review RLS policies in AuthenticationPolicies

”Failed to fetch” errors

  • Verify your NEXT_PUBLIC_SUPABASE_URL is correct
  • Check browser console for CORS errors
  • Ensure Supabase project is active (not paused)

Next Steps

Environment Variables

Set up all required environment variables

Vercel Deployment

Deploy your application to Vercel

Build docs developers (and LLMs) love