Database Setup
acodeaday uses PostgreSQL for storing problems, user progress, submissions, and test cases. We recommend using Supabase, which provides a managed PostgreSQL database with additional features.
Database Overview
The application requires five core tables:
- problems - Problem metadata (title, description, difficulty, etc.)
- problem_languages - Language-specific code (starter code, solutions, function signatures)
- test_cases - Test inputs and expected outputs
- user_progress - Spaced repetition tracking (times solved, next review date, mastery)
- submissions - Submission history (code, results, runtime)
Option 1: Supabase Cloud (Recommended)
Supabase provides a free PostgreSQL database with 500 MB storage and unlimited API requests.
1. Create Supabase Account
- Go to supabase.com
- Sign up for a free account
- Click "New Project"
2. Create Project
Fill in project details:
- Name: acodeaday
- Database Password: Choose a strong password (save this!)
- Region: Choose closest to your location
- Pricing Plan: Free
Wait 2-3 minutes for project initialization.
3. Get Database Credentials
Connection String
- Go to Settings > Database
- Scroll to "Connection string"
- Copy the URI format
- Replace
[YOUR-PASSWORD]with your database password
Example:
postgresql://postgres:your-password@db.abc123xyz.supabase.co:5432/postgresConvert to async format for SQLAlchemy:
postgresql+asyncpg://postgres:your-password@db.abc123xyz.supabase.co:5432/postgresAPI Credentials
- Go to Settings > API
- Copy:
- Project URL (e.g.,
https://abc123xyz.supabase.co) - anon/public key (starts with
eyJ...)
- Project URL (e.g.,
4. Configure Backend .env
Update backend/.env:
DATABASE_URL=postgresql+asyncpg://postgres:YOUR_PASSWORD@db.YOUR_PROJECT_ID.supabase.co:5432/postgres
SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
SUPABASE_KEY=YOUR_ANON_KEY5. Allow Your IP Address
If connecting from your local machine:
- Go to Settings > Database
- Scroll to "Connection Pooling"
- Add your IP to the allowlist (or disable IP restrictions for development)
6. Run Migrations
cd backend
uv run alembic upgrade headThis creates all required tables in your Supabase database.
7. Verify Tables
- In Supabase dashboard, go to Table Editor
- You should see:
problems,problem_languages,test_cases,user_progress,submissions
Option 2: Local Supabase
For offline development or full control, run Supabase locally.
1. Install Supabase CLI
macOS:
brew install supabase/tap/supabaseWindows/Linux:
npm install -g supabase2. Initialize Supabase
cd acodeaday
supabase initThis creates a supabase/ directory with configuration.
3. Start Local Supabase
supabase startThis starts:
- PostgreSQL on
http://localhost:54322 - Studio (web UI) on
http://localhost:54323 - API on
http://localhost:54321
First run takes ~5 minutes to download Docker images.
4. Get Local Credentials
After startup, the CLI displays credentials:
API URL: http://localhost:54321
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
Studio URL: http://localhost:54323
anon key: eyJ...
service_role key: eyJ...5. Configure Backend .env
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:54322/postgres
SUPABASE_URL=http://localhost:54321
SUPABASE_KEY=eyJ... # Use the anon key from CLI output6. Run Migrations
cd backend
uv run alembic upgrade head7. Access Supabase Studio
Open http://localhost:54323 to view tables and data in the web UI.
Option 3: Plain PostgreSQL
If you prefer plain PostgreSQL without Supabase:
1. Install PostgreSQL
macOS:
brew install postgresql@15
brew services start postgresql@15Ubuntu/Debian:
sudo apt install postgresql postgresql-contrib
sudo systemctl start postgresqlWindows: Download from postgresql.org
2. Create Database
# Create database
psql postgres
CREATE DATABASE acodeaday;
\q3. Configure Backend .env
DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/acodeadayNote: Without Supabase, authentication features won't work. You'll need to implement custom auth or disable auth in the backend.
4. Run Migrations
cd backend
uv run alembic upgrade headDatabase Migrations
Run Migrations
Apply all pending migrations:
uv run alembic upgrade headCheck Current Version
uv run alembic currentView Migration History
uv run alembic historyRollback Migrations
# Rollback one migration
uv run alembic downgrade -1
# Rollback all migrations (WARNING: deletes all data)
uv run alembic downgrade baseCreate New Migration
After modifying models in app/models.py:
uv run alembic revision --autogenerate -m "Add new column"Review the generated migration in alembic/versions/, then apply:
uv run alembic upgrade headSeed Data
Seed Problems
Load initial problems from YAML files:
uv run python scripts/seed_problems.py seedThis loads problems from backend/data/problems/.
Verify Seeded Data
Via API:
curl http://localhost:8000/api/problemsVia Supabase Studio:
- Open Supabase Studio
- Go to Table Editor > problems
- You should see 15+ problems
Via psql:
psql $DATABASE_URL
SELECT title, difficulty FROM problems;
\qDatabase Schema
problems
CREATE TABLE problems (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
description TEXT NOT NULL,
difficulty TEXT CHECK (difficulty IN ('easy', 'medium', 'hard')),
pattern TEXT NOT NULL,
sequence_number INTEGER UNIQUE NOT NULL,
constraints JSONB NOT NULL,
examples JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);problem_languages
CREATE TABLE problem_languages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
problem_id UUID REFERENCES problems(id) ON DELETE CASCADE,
language TEXT NOT NULL,
starter_code TEXT NOT NULL,
reference_solution TEXT NOT NULL,
function_signature JSONB NOT NULL,
UNIQUE(problem_id, language)
);test_cases
CREATE TABLE test_cases (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
problem_id UUID REFERENCES problems(id) ON DELETE CASCADE,
input JSONB NOT NULL,
expected JSONB NOT NULL,
sequence INTEGER NOT NULL,
UNIQUE(problem_id, sequence)
);user_progress
CREATE TABLE user_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) NOT NULL,
problem_id UUID REFERENCES problems(id) ON DELETE CASCADE,
times_solved INTEGER DEFAULT 0,
last_solved_at TIMESTAMP,
next_review_date DATE,
is_mastered BOOLEAN DEFAULT FALSE,
show_again BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, problem_id)
);submissions
CREATE TABLE submissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) NOT NULL,
problem_id UUID REFERENCES problems(id) ON DELETE CASCADE,
code TEXT NOT NULL,
language TEXT NOT NULL,
passed BOOLEAN NOT NULL,
runtime_ms INTEGER,
submitted_at TIMESTAMP DEFAULT NOW()
);Backup and Restore
Backup (Supabase Cloud)
Use pg_dump via Supabase connection:
pg_dump "postgresql://postgres:PASSWORD@db.PROJECT_ID.supabase.co:5432/postgres" > backup.sqlRestore
psql "postgresql://postgres:PASSWORD@db.PROJECT_ID.supabase.co:5432/postgres" < backup.sqlBackup (Local Supabase)
supabase db dump -f backup.sqlTroubleshooting
"Connection refused"
- Verify database is running (Supabase dashboard or
pg_isready) - Check
DATABASE_URLformat:postgresql+asyncpg://(notpostgresql://) - Ensure your IP is allowlisted in Supabase
"SSL required"
Add ?sslmode=require to connection string:
postgresql+asyncpg://...?sslmode=requireMigration errors
# Check current migration state
uv run alembic current
# View pending migrations
uv run alembic history
# Force to specific version (use with caution)
uv run alembic stamp head"Database does not exist"
- Verify database name in connection string
- Create database if using plain PostgreSQL
- Check Supabase project status
Slow queries
Add indexes for frequently queried columns:
CREATE INDEX idx_user_progress_user_id ON user_progress(user_id);
CREATE INDEX idx_user_progress_next_review ON user_progress(next_review_date);(These are already in migrations)
Next Steps
- Backend Setup - Connect backend to database
- Adding Problems - Seed more problems
- Environment Variables - Configure all env vars