Source:
ocean/docs/adr/ADR-042-supabase-development-best-practices.md| ✏️ Edit on GitHub
ADR-042: Supabase Development Best Practices
Status
Accepted
Context
The Ocean platform is built on Supabase as the primary backend infrastructure. We need to ensure we're following Supabase best practices for security, performance, and maintainability.
Decision
Establish and follow Supabase best practices across the platform.
Current Implementation
1. Authentication & Security
Row Level Security (RLS)
- ✅ All tables have RLS enabled
- ✅ Policies use JWT claims for user identification
- ✅ Fail-closed approach (deny by default)
-- Example: Organizations RLS
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view their organizations"
ON organizations FOR SELECT
USING (
auth.uid() IN (
SELECT user_id FROM organization_members
WHERE organization_id = organizations.id
)
);
JWT Security
- ✅ Using modern JWT keys (no legacy
sb_secret_*) - ✅ Service role keys only in Edge Functions
- ✅ Anon key for client-side with RLS
2. Database Design
Schema Organization
- ✅ Public schema for user-facing tables
- ✅ Auth schema managed by Supabase
- ✅ Storage schema for file management
Naming Conventions
- ✅ Snake_case for all database objects
- ✅ Consistent field naming (created_at, updated_at)
- ✅ Foreign key naming pattern:
<table>_<field>
Indexes
- ✅ Primary keys on all tables
- ✅ Foreign key indexes for joins
- ⚠️ Missing: Composite indexes for common query patterns
3. Edge Functions
Authentication Pattern
- ✅ Shared wrapper for consistent auth
- ✅ CORS handling in all functions
- ✅ Proper error responses
export const createAuthenticatedFunction = (handler) => {
return serve(async (req) => {
const corsHeaders = handleCors(req)
if (req.method === 'OPTIONS') return new Response(null, { headers: corsHeaders })
const { user, error } = await authenticateRequest(req)
if (error) return error
return handler(req, { user, supabase: createClient(req) })
})
}
Performance
- ✅ Connection pooling via Supabase client
- ✅ Minimal cold starts with shared utilities
- ⚠️ Missing: Response caching for expensive operations
4. Real-time Features
Subscriptions
- ✅ Using Postgres Changes for real-time updates
- ✅ Filtered subscriptions to reduce bandwidth
- ⚠️ Not implemented: Presence features
5. Storage
File Management
- ✅ Bucket-based organization
- ✅ RLS policies on storage objects
- ⚠️ Missing: Image transformation policies
6. Migrations
Version Control
- ✅ Sequential migrations with timestamps
- ✅ Atomic operations (transactions)
- ✅ Down migrations where possible
-- Example migration structure
BEGIN;
-- Schema changes
ALTER TABLE organizations
ADD COLUMN IF NOT EXISTS neon_tenant_id TEXT;
-- Data migrations
UPDATE organizations
SET neon_tenant_id = gen_random_uuid()::text
WHERE neon_tenant_id IS NULL;
-- Constraints
ALTER TABLE organizations
ALTER COLUMN neon_tenant_id SET NOT NULL;
COMMIT;
7. Performance Optimization
Query Optimization
- ✅ Using
select()with specific columns - ✅ Proper pagination with cursors
- ✅ Limiting result sets
- ⚠️ Missing: Query performance monitoring
Connection Management
- ✅ Single client instance per context
- ✅ Connection pooling in Edge Functions
- ✅ Proper client disposal
8. Error Handling
Database Errors
- ✅ Consistent error response format
- ✅ Proper error codes (PGRST prefixes)
- ✅ User-friendly error messages
Retry Logic
- ✅ Exponential backoff for transient failures
- ✅ Idempotent operations
- ⚠️ Missing: Circuit breaker pattern
9. Testing
Local Development
- ✅ Local Supabase for development
- ✅ Seed data for testing
- ✅ Migration testing before deployment
10. Monitoring & Observability
Logging
- ✅ Structured logging in Edge Functions
- ⚠️ Missing: Centralized log aggregation
- ⚠️ Missing: Performance metrics
Recommendations
High Priority
- Add composite indexes for common query patterns
- Implement query performance monitoring
- Add response caching for expensive operations
- Set up centralized logging with log aggregation
Medium Priority
- Implement circuit breaker for external services
- Add image transformation policies for storage
- Enable connection pooling configuration
- Add database backup automation
Low Priority
- Implement presence features for collaboration
- Add GraphQL subscriptions for real-time updates
- Create data archival strategy
Best Practices Summary
✅ Currently Following
- Row Level Security on all tables
- Proper JWT key management
- Snake_case naming conventions
- Edge Function authentication wrapper
- Atomic migrations with version control
- Proper error handling
- Local development environment
⚠️ Areas for Improvement
- Query performance monitoring
- Response caching strategies
- Centralized logging
- Composite indexes for performance
- Circuit breaker implementation
- Automated backups
❌ Not Implemented
- Real-time presence
- Image transformations
- GraphQL subscriptions
- Data archival
Related ADRs
- ADR-005: Supabase JWT Authentication
- ADR-014: Cloud-First Testing Strategy
- ADR-028: Local Testing Environment
- ADR-035: Atomic Provisioning Pattern
- ADR-036: Unified Field Naming Convention