mirror of
https://github.com/greedychipmunk/agent-skills.git
synced 2026-09-14 20:46:42 +08:00
bf1538eabe
Co-authored-by: greedychipmunk <492693+greedychipmunk@users.noreply.github.com>
11 KiB
11 KiB
Local Development Guide
Overview
Developing locally with Supabase provides a complete development environment that mirrors production, enabling fast iteration and testing without affecting your production database.
Prerequisites
Required Software
- Docker Desktop (or Docker Engine)
- macOS: Docker Desktop for Mac
- Windows: Docker Desktop for Windows
- Linux: Docker Engine
- Node.js (v16 or later)
- Git
Install Supabase CLI
npm install -g supabase
# or
brew install supabase/tap/supabase
Initial Setup
1. Initialize Project
# In your project root
supabase init
This creates:
supabase/
├── config.toml # Supabase configuration
├── seed.sql # Seed data for development
└── migrations/ # Database migrations
2. Configure Project
Edit supabase/config.toml:
[api]
enabled = true
port = 54321
schemas = ["public", "graphql_public"]
extra_search_path = ["public", "extensions"]
[db]
port = 54322
major_version = 15
[db.pooler]
enabled = false
port = 54329
pool_mode = "transaction"
default_pool_size = 20
max_client_conn = 100
[studio]
enabled = true
port = 54323
[inbucket]
enabled = true
port = 54324
smtp_port = 54325
pop3_port = 54326
[auth]
enabled = true
site_url = "http://localhost:3000"
additional_redirect_urls = ["https://localhost:3000"]
jwt_expiry = 3600
enable_refresh_token_rotation = true
refresh_token_reuse_interval = 10
[auth.email]
enable_signup = true
double_confirm_changes = true
enable_confirmations = false
[auth.external.google]
enabled = false
client_id = ""
secret = ""
redirect_uri = ""
3. Start Local Services
supabase start
Services started:
- API Gateway: http://localhost:54321
- Studio (Admin UI): http://localhost:54323
- Database: postgresql://postgres:postgres@localhost:54322/postgres
- Inbucket (Email testing): http://localhost:54324
4. Get Connection Details
supabase status
Save the output, especially:
- API URL
- anon key (for client)
- service_role key (for admin operations)
Development Workflow
Environment Variables
Create .env.local:
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-from-status
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key-from-status
Add to .gitignore:
.env.local
.env*.local
Database Migrations
Create Migration
# Create new migration
supabase migration new create_posts_table
Edit supabase/migrations/YYYYMMDDHHMMSS_create_posts_table.sql:
-- Create posts table
create table public.posts (
id uuid default gen_random_uuid() primary key,
title text not null,
content text,
author_id uuid references auth.users(id) not null,
created_at timestamptz default now() not null
);
-- Enable RLS
alter table public.posts enable row level security;
-- Create policies
create policy "Users can view all posts"
on public.posts for select
using (true);
create policy "Users can create their own posts"
on public.posts for insert
with check (auth.uid() = author_id);
Apply Migration
# Apply to local database
supabase db push
# Generate TypeScript types
supabase gen types typescript --local > types/database.types.ts
Seed Data
Edit supabase/seed.sql:
-- Insert test users (note: auth.users is managed by Supabase Auth)
-- Create test posts
insert into public.posts (title, content, author_id)
values
('First Post', 'This is my first post', 'uuid-here'),
('Second Post', 'This is my second post', 'uuid-here');
Apply seed:
supabase db reset # Resets DB and applies migrations + seed
Edge Functions
Create Function
supabase functions new hello
Edit supabase/functions/hello/index.ts:
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
serve(async (req) => {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { 'Content-Type': 'application/json' } }
)
})
Test Locally
# Terminal 1: Serve functions
supabase functions serve
# Terminal 2: Test with curl
curl -i --location --request POST \
'http://localhost:54321/functions/v1/hello' \
--header 'Authorization: ******' \
--header 'Content-Type: application/json' \
--data '{"name":"World"}'
Storage Testing
// Upload file to local storage
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${userId}/avatar.png`, file)
// Files stored in Docker volume
// Access via Studio: http://localhost:54323
Email Testing
Access Inbucket at http://localhost:54324 to view emails sent by Supabase Auth (signup confirmations, password resets, etc.)
Testing Strategies
Unit Tests
// tests/database.test.ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'http://localhost:54321',
process.env.SUPABASE_ANON_KEY!
)
describe('Posts', () => {
it('should create a post', async () => {
const { data, error } = await supabase
.from('posts')
.insert({ title: 'Test', author_id: 'uuid' })
.select()
.single()
expect(error).toBeNull()
expect(data.title).toBe('Test')
})
})
Integration Tests
# Run tests against local Supabase
npm test
# Reset database before tests
supabase db reset && npm test
RLS Policy Testing
// Test RLS policies
import { createClient } from '@supabase/supabase-js'
// Test as anonymous user
const anonClient = createClient(url, anonKey)
// Test as authenticated user
const authClient = createClient(url, anonKey)
await authClient.auth.signInWithPassword({ email, password })
// Test different scenarios
const { data: publicData } = await anonClient.from('posts').select()
const { data: privateData } = await authClient.from('posts').select()
Database Management
Reset Database
# Reset to clean state (reapplies migrations + seed)
supabase db reset
# Reset without seed
supabase db reset --no-seed
Inspect Database
# Database size
supabase inspect db size
# Table sizes
supabase inspect db tables
# Index usage
supabase inspect db index-usage
# Cache hit rate
supabase inspect db cache-hit
Direct Database Access
# Connect with psql
psql postgresql://postgres:postgres@localhost:54322/postgres
# Or use connection string from status
supabase status | grep "DB URL"
Syncing with Remote
Pull Remote Schema
# Link to remote project first
supabase link --project-ref your-project-ref
# Pull remote schema as new migration
supabase db pull
Push Local Changes
# Push local migrations to remote
supabase db push --linked
Troubleshooting
Services Won't Start
Check Docker
# Ensure Docker is running
docker ps
# Check Docker resources
# Docker Desktop > Settings > Resources
# Recommended: 4GB RAM, 2 CPUs minimum
Port Conflicts
# Check if ports are in use
lsof -i :54321 # API
lsof -i :54322 # Database
lsof -i :54323 # Studio
lsof -i :54324 # Inbucket
# Stop conflicting services or change ports in config.toml
Clean Start
# Stop and remove containers
supabase stop --no-backup
# Remove Docker volumes (CAUTION: deletes local data)
docker volume prune
# Start fresh
supabase start
Migration Issues
Repair Migration History
# Check migration status
supabase migration list
# Mark migration as applied without running
supabase migration repair 20230101000000 --status applied
# Mark migration as not applied
supabase migration repair 20230101000000 --status reverted
Regenerate Schema
# Generate migration from current database state
supabase db diff -f new_migration_name
Connection Issues
Database Connection
# Test connection
psql postgresql://postgres:postgres@localhost:54322/postgres -c "SELECT 1"
# Check logs
docker logs supabase_db_<project>
API Connection
# Test API
curl http://localhost:54321/rest/v1/
# Check logs
docker logs supabase_kong_<project>
Performance Issues
Slow Queries
# Enable query logging
# In psql:
ALTER DATABASE postgres SET log_statement = 'all';
ALTER DATABASE postgres SET log_duration = on;
# View logs
docker logs supabase_db_<project> | grep duration
Index Missing
# Check index usage
supabase inspect db index-usage
# Add indexes in migrations
CREATE INDEX idx_posts_author ON posts(author_id);
Best Practices
1. Use Migrations for Everything
- Never modify database schema manually
- Always create migrations for schema changes
- Keep migrations small and focused
2. Test RLS Policies Locally
- Create test users with different roles
- Test each policy thoroughly
- Use automated tests
3. Seed Data Properly
- Create realistic test data
- Include edge cases
- Use consistent UUIDs for testing
4. Version Control
# .gitignore
.env.local
.env*.local
supabase/.branches
supabase/.temp
5. Keep Local and Remote in Sync
# Regular sync workflow
supabase db pull # Get remote changes
supabase db reset # Apply locally
supabase db push # Push local changes
6. Use Different Environments
# Development
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
# Staging
NEXT_PUBLIC_SUPABASE_URL=https://staging.supabase.co
# Production
NEXT_PUBLIC_SUPABASE_URL=https://prod.supabase.co
7. Monitor Resources
- Check Docker Desktop resource usage
- Stop services when not in use
- Clean up old containers and volumes
Quick Reference
Common Commands
# Start/Stop
supabase start
supabase stop
supabase status
# Database
supabase db reset
supabase db push
supabase db pull
supabase db diff -f migration_name
# Migrations
supabase migration new name
supabase migration list
# Functions
supabase functions new name
supabase functions serve
supabase functions deploy
# Types
supabase gen types typescript --local > types/database.types.ts
URLs
- Studio: http://localhost:54323
- API: http://localhost:54321
- Database: postgresql://postgres:postgres@localhost:54322/postgres
- Inbucket: http://localhost:54324
Keys
Get from supabase status:
- anon key (public, client-side)
- service_role key (private, server-side only)