Supabase Setup Guide

Overview

This guide covers the complete Supabase setup for the Remind Tools monorepo, including database schema, Row Level Security policies, and Flutter integration.

Table of Contents

  1. Local Development Setup
  2. Database Schema
  3. Environment Configuration
  4. Flutter Integration
  5. Running Migrations
  6. Testing

Local Development Setup

Prerequisites

  • Node.js 18+ installed
  • Docker Desktop running
  • Flutter SDK installed

Install Supabase CLI

npm install -g @supabase/cli

Initialize Local Supabase

# From project root
cd /Users/rafalwolak/dev/flutter/remind_tools

# Start local Supabase services
supabase start

# This will output your local credentials:
# API URL: http://localhost:54321
# GraphQL URL: http://localhost:54321/graphql/v1
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323
# Anon key: [your-anon-key]
# Service key: [your-service-key]

Database Schema

The database schema is organized into versioned migrations in /supabase/migrations/:

Core Tables

  1. profiles - User profiles extending Supabase auth
  2. trips - User trips with AI suggestions
  3. places - Points of interest with PostGIS support
  4. itineraries - Daily planning for trips
  5. trip_collaborators - Trip sharing functionality
  6. audit_log - Data change tracking

Key Features

  • PostGIS extension for geospatial queries
  • Row Level Security (RLS) for multi-tenant isolation
  • Full-text search indexes on trips and places
  • Materialized views for performance optimization
  • Automatic profile creation on user signup

Environment Configuration

1. Create Environment File

Copy the example file and fill in your credentials:
cp .env.example .env.development

2. Edit .env.development

# Supabase Configuration
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=your-anon-key-from-supabase-start
SUPABASE_SERVICE_KEY=your-service-key-from-supabase-start

# Optional services
MAPBOX_ACCESS_TOKEN=
GEMINI_API_KEY=

3. Verify .gitignore

Ensure environment files are not committed:
# .gitignore should contain:
.env
.env.*
*.env

Flutter Integration

1. Bootstrap Workspace

melos bootstrap

2. Initialize Supabase in Your App

The Supabase client is configured in /packages/core/lib/infrastructure/database/supabase_client.dart In your main app file:
import 'package:core/core.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize logger
  LoggerService.initialize();
  
  // Initialize Supabase
  await SupabaseClientWrapper.initialize();
  
  runApp(MyApp());
}

3. Using the Supabase Client

import 'package:core/core.dart';

// Get client instance
final supabase = SupabaseClientWrapper.client;

// Check authentication
if (SupabaseClientWrapper.isAuthenticated) {
  final user = SupabaseClientWrapper.currentUser;
  print('Logged in as: ${user?.email}');
}

// Query data
final trips = await supabase
  .from('trips')
  .select()
  .order('created_at', ascending: false);

Running Migrations

Apply All Migrations

# Apply migrations to local database
supabase db reset

# This will:
# 1. Drop and recreate the database
# 2. Apply all migrations in order
# 3. Run seed.sql for test data

Create New Migration

# Create a new migration file
supabase migration new your_migration_name

# Edit the created file in supabase/migrations/

Push to Remote

# Link to remote project (first time only)
supabase link --project-ref your-project-ref

# Push migrations to remote
supabase db push

Testing

1. Test RLS Policies

-- Test as a specific user
SET LOCAL "auth.uid" TO '11111111-1111-1111-1111-111111111111';

-- Try to access trips
SELECT * FROM trips;

-- Should only see trips for that user

2. Test Helper Functions

-- Test nearby places search
SELECT * FROM find_nearby_places(
  35.6762, -- latitude (Tokyo)
  139.6503, -- longitude
  5000, -- radius in meters
  'restaurant' -- category filter
);

-- Test trip search
SELECT * FROM search_trips(
  'Tokyo adventure',
  NULL, -- user_id (NULL = all users)
  10, -- limit
  0 -- offset
);

3. Integration Tests

Create test files in /test/ directories:
import 'package:test/test.dart';
import 'package:core/core.dart';

void main() {
  setUpAll(() async {
    await SupabaseClientWrapper.initialize();
  });

  test('should create a trip', () async {
    final result = await SupabaseClientWrapper.client
      .from('trips')
      .insert({
        'title': 'Test Trip',
        'user_id': SupabaseClientWrapper.currentUser?.id,
      })
      .select()
      .single();
      
    expect(result['title'], equals('Test Trip'));
  });
}

Domain Entities

The domain entities are defined in /packages/data_models/lib/src/trips/entities/:
  • Profile - User profile with preferences
  • Trip - Trip with status tracking and budget
  • Place - Points of interest with location data
  • Itinerary - Daily activities and planning
Each entity includes:
  • Immutable properties with Equatable
  • Convenient helper methods
  • CopyWith pattern for updates
  • Validation logic

Security Best Practices

  1. Never commit credentials - Use environment files
  2. Use RLS policies - All tables have Row Level Security enabled
  3. Validate input - Use domain entities with validation
  4. Audit changes - audit_log table tracks important changes
  5. Use service role carefully - Only for admin operations

Troubleshooting

Common Issues

  1. Supabase not starting
    • Ensure Docker Desktop is running
    • Check port conflicts (54321, 54322, 54323)
    • Run supabase stop then supabase start
  2. Migration errors
    • Check SQL syntax in migration files
    • Ensure proper order of migrations
    • Review PostgreSQL logs: supabase db logs
  3. Authentication issues
    • Verify environment variables are loaded
    • Check Supabase auth settings
    • Ensure RLS policies are correct
  4. Flutter connection issues
    • Verify SUPABASE_URL and SUPABASE_ANON_KEY
    • Check network connectivity
    • Review Flutter console logs

Next Steps

  1. Implement repository pattern - Create repository interfaces in domain layer
  2. Add data sources - Implement remote and local data sources
  3. Create use cases - Business logic for trip management
  4. Build UI - Create Flutter widgets using BLoC pattern
  5. Add tests - Unit, widget, and integration tests

Resources