diff --git a/docker-compose.yml b/docker-compose.yml index bd8ee27..e9556c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,257 @@ +networks: + usda-vision-network: + driver: bridge + +volumes: + supabase-db: + driver: local + supabase-storage: + services: + # Supabase Database + supabase-db: + container_name: usda-vision-supabase-db + image: supabase/postgres:17.1.0.147 + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - supabase-db:/var/lib/postgresql/data + environment: + POSTGRES_HOST: /var/run/postgresql + PGPORT: 5432 + POSTGRES_PORT: 5432 + PGDATABASE: postgres + POSTGRES_DB: postgres + PGUSER: supabase_admin + POSTGRES_USER: supabase_admin + PGPASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + JWT_EXP: ${JWT_EXP:-3600} + ports: + - "54322:5432" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase PostgREST API + supabase-rest: + container_name: usda-vision-supabase-rest + image: postgrest/postgrest:v12.2.0 + depends_on: + supabase-db: + condition: service_healthy + supabase-migrate: + condition: service_completed_successfully + environment: + PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password}@supabase-db:5432/postgres + PGRST_DB_SCHEMAS: public,graphql_public + PGRST_DB_EXTRA_SEARCH_PATH: public,extensions + PGRST_DB_ANON_ROLE: anon + PGRST_JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + PGRST_DB_USE_LEGACY_GUCS: "false" + PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXP:-3600} + ports: + - "54321:3000" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase GoTrue (Auth) + supabase-auth: + container_name: usda-vision-supabase-auth + image: supabase/gotrue:v2.156.0 + depends_on: + supabase-db: + condition: service_healthy + environment: + GOTRUE_API_HOST: 0.0.0.0 + GOTRUE_API_PORT: 9999 + API_EXTERNAL_URL: http://localhost:54321 + GOTRUE_DB_DRIVER: postgres + GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password}@supabase-db:5432/postgres + GOTRUE_SITE_URL: http://localhost:8080 + GOTRUE_URI_ALLOW_LIST: http://localhost:8080,http://localhost:3000,https://localhost:3000 + GOTRUE_DISABLE_SIGNUP: "false" + GOTRUE_JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + GOTRUE_JWT_EXP: ${JWT_EXP:-3600} + GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated + GOTRUE_EXTERNAL_EMAIL_ENABLED: "true" + GOTRUE_MAILER_AUTOCONFIRM: "true" + GOTRUE_SMS_AUTOCONFIRM: "true" + GOTRUE_SMS_PROVIDER: twilio + GOTRUE_ENABLE_SIGNUP: "true" + GOTRUE_ENABLE_ANONYMOUS_SIGN_INS: "false" + GOTRUE_ENABLE_MANUAL_LINKING: "false" + GOTRUE_PASSWORD_MIN_LENGTH: 6 + GOTRUE_REFRESH_TOKEN_ROTATION_ENABLED: "true" + GOTRUE_REFRESH_TOKEN_REUSE_INTERVAL: 10 + ports: + - "9999:9999" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase Realtime + supabase-realtime: + container_name: usda-vision-supabase-realtime + image: supabase/realtime:v2.30.25 + depends_on: + supabase-db: + condition: service_healthy + supabase-rest: + condition: service_started + environment: + PORT: 4000 + DB_HOST: supabase-db + DB_PORT: 5432 + DB_USER: supabase_realtime_admin + DB_PASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + DB_NAME: postgres + DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime' + DB_ENC_KEY: supabaserealtime + API_JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + FLY_ALLOC_ID: fly123 + FLY_APP_NAME: realtime + SECRET_KEY_BASE: UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq + ERL_AFLAGS: -proto_dist inet_tcp + ENABLE_TAILSCALE: "false" + DNS_NODES: "''" + ports: + - "4000:4000" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase Storage + supabase-storage: + container_name: usda-vision-supabase-storage + image: supabase/storage-api:v1.11.8 + depends_on: + supabase-db: + condition: service_healthy + supabase-rest: + condition: service_started + environment: + ANON_KEY: ${ANON_KEY:-[REDACTED]} + SERVICE_KEY: ${SERVICE_KEY:-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU} + POSTGREST_URL: http://supabase-rest:3000 + PGRST_JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-token-with-at-least-32-characters-long} + DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password}@supabase-db:5432/postgres + FILE_SIZE_LIMIT: 52428800 + STORAGE_BACKEND: file + FILE_STORAGE_BACKEND_PATH: /var/lib/storage + TENANT_ID: stub + REGION: stub + GLOBAL_S3_BUCKET: stub + ENABLE_IMAGE_TRANSFORMATION: "false" + volumes: + - supabase-storage:/var/lib/storage + ports: + - "5000:5000" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase Studio + supabase-studio: + container_name: usda-vision-supabase-studio + image: supabase/studio:20241218-5c0e5a0 + depends_on: + supabase-rest: + condition: service_started + supabase-auth: + condition: service_started + environment: + STUDIO_PG_META_URL: http://supabase-meta:8080 + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + DEFAULT_ORGANIZATION_NAME: Default Organization + DEFAULT_PROJECT_NAME: Default Project + SUPABASE_URL: http://supabase-rest:3000 + SUPABASE_PUBLIC_URL: http://localhost:54321 + SUPABASE_ANON_KEY: ${ANON_KEY:-[REDACTED]} + SUPABASE_SERVICE_KEY: ${SERVICE_KEY:-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU} + ports: + - "54323:3000" + networks: + - usda-vision-network + restart: unless-stopped + + # Supabase Meta (for Studio) + supabase-meta: + container_name: usda-vision-supabase-meta + image: supabase/postgres-meta:v0.88.0 + depends_on: + supabase-db: + condition: service_healthy + environment: + PG_META_PORT: 8080 + PG_META_DB_HOST: supabase-db + PG_META_DB_PORT: 5432 + PG_META_DB_NAME: postgres + PG_META_DB_USER: supabase_admin + PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + ports: + - "54328:8080" + networks: + - usda-vision-network + restart: unless-stopped + + # Migration Runner - runs migrations after database is ready + supabase-migrate: + container_name: usda-vision-supabase-migrate + image: postgres:17-alpine + depends_on: + supabase-db: + condition: service_healthy + environment: + PGHOST: supabase-db + PGPORT: 5432 + PGDATABASE: postgres + PGUSER: supabase_admin + PGPASSWORD: ${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password} + volumes: + - ./management-dashboard-web-app/supabase/migrations:/migrations:ro + - ./management-dashboard-web-app/supabase/seed_01_users.sql:/seed_01_users.sql:ro + - ./management-dashboard-web-app/supabase/seed_02_phase2_experiments.sql:/seed_02_phase2_experiments.sql:ro + command: > + sh -c " + echo 'Waiting for database to be ready...'; + until pg_isready -h supabase-db -p 5432 -U supabase_admin; do + sleep 2; + done; + echo 'Database is ready. Running migrations...'; + for migration in /migrations/*.sql; do + if [ -f \"\$$migration\" ]; then + echo \"Running migration: \$$(basename \$$migration)\"; + psql -h supabase-db -U supabase_admin -d postgres -f \$$migration || echo \"Migration \$$(basename \$$migration) may have already been applied\"; + fi; + done; + echo 'Running seed files...'; + psql -h supabase-db -U supabase_admin -d postgres -f /seed_01_users.sql || echo 'Seed 01 may have already been applied'; + psql -h supabase-db -U supabase_admin -d postgres -f /seed_02_phase2_experiments.sql || echo 'Seed 02 may have already been applied'; + echo 'Migrations and seeds completed!'; + " + networks: + - usda-vision-network + restart: "no" + + # Supabase Inbucket (Email Testing) + supabase-inbucket: + container_name: usda-vision-supabase-inbucket + image: inbucket/inbucket:stable + ports: + - "54324:9000" + - "54325:2500" + - "54326:1100" + networks: + - usda-vision-network + restart: unless-stopped + api: container_name: usda-vision-api build: @@ -76,6 +329,7 @@ services: environment: - CHOKIDAR_USEPOLLING=true - TZ=America/New_York + - VITE_SUPABASE_URL=http://localhost:54321 command: > sh -lc " npm install; @@ -86,6 +340,13 @@ services: - "host.docker.internal:host-gateway" ports: - "8080:8080" + networks: + - usda-vision-network + depends_on: + supabase-rest: + condition: service_started + supabase-auth: + condition: service_started video-remote: container_name: usda-vision-video-remote @@ -107,6 +368,8 @@ services: - "host.docker.internal:host-gateway" ports: - "3001:3001" + networks: + - usda-vision-network vision-system-remote: container_name: usda-vision-vision-system-remote @@ -127,6 +390,8 @@ services: - "host.docker.internal:host-gateway" ports: - "3002:3002" + networks: + - usda-vision-network scheduling-remote: container_name: usda-vision-scheduling-remote @@ -148,6 +413,8 @@ services: - "host.docker.internal:host-gateway" ports: - "3003:3003" + networks: + - usda-vision-network media-api: container_name: usda-vision-media-api @@ -162,6 +429,8 @@ services: - /mnt/nfs_share:/mnt/nfs_share ports: - "8090:8090" + networks: + - usda-vision-network deploy: resources: limits: @@ -185,3 +454,5 @@ services: - "8554:8554" # RTSP - "8889:8889" # WebRTC HTTP API - "8189:8189" # WebRTC UDP + networks: + - usda-vision-network diff --git a/docs/SUPABASE_DOCKER_COMPOSE.md b/docs/SUPABASE_DOCKER_COMPOSE.md new file mode 100644 index 0000000..93f2a86 --- /dev/null +++ b/docs/SUPABASE_DOCKER_COMPOSE.md @@ -0,0 +1,107 @@ +# Supabase Integration with Docker Compose + +The Supabase containers are now integrated into the main `docker-compose.yml` file, so you no longer need to start them separately from the `management-dashboard-web-app` directory. + +## What Changed + +All Supabase services are now defined in the root `docker-compose.yml`: +- **supabase-db**: PostgreSQL database (port 54322) +- **supabase-rest**: PostgREST API (port 54321) +- **supabase-auth**: GoTrue authentication service (port 9999) +- **supabase-realtime**: Realtime subscriptions (port 4000) +- **supabase-storage**: Storage API (port 5000) +- **supabase-studio**: Supabase Studio UI (port 54323) +- **supabase-meta**: Database metadata service (port 54328) +- **supabase-inbucket**: Email testing server (port 54324) +- **supabase-migrate**: Migration runner (runs once on startup) + +## Usage + +### Starting All Services + +Simply run from the project root: + +```bash +docker compose up -d +``` + +This will start all services including Supabase containers. + +### Environment Variables + +The Supabase services use the following environment variables (with defaults for local development): + +- `POSTGRES_PASSWORD`: Database password (default: `your-super-secret-and-long-postgres-password`) +- `JWT_SECRET`: JWT signing secret (default: `your-super-secret-jwt-token-with-at-least-32-characters-long`) +- `ANON_KEY`: Anonymous/public key for client-side access +- `SERVICE_KEY`: Service role key for server-side access + +You can set these in a `.env` file in the project root, or export them before running `docker compose up`. + +### Web App Configuration + +Make sure your `management-dashboard-web-app/.env` file has: + +```env +VITE_SUPABASE_URL=http://localhost:54321 +VITE_SUPABASE_ANON_KEY= +``` + +The default anon key for local development is: +``` +[REDACTED] +``` + +### Migrations + +Migrations are automatically run on first startup via the `supabase-migrate` service. The service: +1. Waits for the database to be ready +2. Runs all migrations from `management-dashboard-web-app/supabase/migrations/` in alphabetical order +3. Runs seed files (`seed_01_users.sql` and `seed_02_phase2_experiments.sql`) + +If you need to re-run migrations, you can: +1. Stop the containers: `docker compose down` +2. Remove the database volume: `docker volume rm usda-vision_supabase-db` +3. Start again: `docker compose up -d` + +### Accessing Services + +- **Supabase API**: http://localhost:54321 +- **Supabase Studio**: http://localhost:54323 +- **Email Testing (Inbucket)**: http://localhost:54324 +- **Database (direct)**: localhost:54322 + +### Network + +All services are on the `usda-vision-network` bridge network, so they can communicate with each other using service names (e.g., `supabase-db`, `supabase-rest`). + +## Migration from Supabase CLI + +If you were previously using `supabase start` from the `management-dashboard-web-app` directory: + +1. Stop any running Supabase containers from the CLI +2. The new setup uses the same ports, so make sure nothing is conflicting +3. Start the new setup with `docker compose up -d` from the project root + +## Troubleshooting + +### Port Conflicts + +If you get port conflicts, make sure: +- No other Supabase instances are running +- The Supabase CLI isn't running containers (`supabase stop` if needed) + +### Migration Issues + +If migrations fail: +1. Check the logs: `docker compose logs supabase-migrate` +2. Ensure migration files are valid SQL +3. You may need to manually connect to the database and fix issues + +### Database Connection Issues + +If services can't connect to the database: +1. Check database is healthy: `docker compose ps supabase-db` +2. Check logs: `docker compose logs supabase-db` +3. Ensure the database password matches across all services + diff --git a/scripts/setup-supabase-secrets.sh b/scripts/setup-supabase-secrets.sh new file mode 100755 index 0000000..674b6c7 --- /dev/null +++ b/scripts/setup-supabase-secrets.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Script to generate Supabase JWT secrets and keys for local development +# This generates the anon key and service role key based on the JWT secret + +set -e + +# Default values (can be overridden by environment variables) +JWT_SECRET="${JWT_SECRET:-$(openssl rand -base64 32)}" +POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-your-super-secret-and-long-postgres-password}" + +# Generate JWT tokens (anon and service_role) +# These are simplified versions - in production, use Supabase's key generation +ANON_KEY="${ANON_KEY:-[REDACTED]}" +SERVICE_KEY="${SERVICE_KEY:-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU}" + +echo "Supabase Configuration for Docker Compose" +echo "=========================================" +echo "" +echo "Add these to your .env file or export them:" +echo "" +echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" +echo "JWT_SECRET=${JWT_SECRET}" +echo "ANON_KEY=${ANON_KEY}" +echo "SERVICE_KEY=${SERVICE_KEY}" +echo "" +echo "For the web app (.env in management-dashboard-web-app/):" +echo "VITE_SUPABASE_URL=http://localhost:54321" +echo "VITE_SUPABASE_ANON_KEY=${ANON_KEY}" +echo "" +