# Sojorn - Deployment Guide This guide walks through deploying the Sojorn backend to Supabase. --- ## Prerequisites - [Supabase CLI](https://supabase.com/docs/guides/cli) installed - [Supabase account](https://supabase.com) created - A Supabase project (create at [app.supabase.com](https://app.supabase.com)) - [Deno](https://deno.land) installed (for local Edge Function testing) --- ## 1. Initialize Supabase Project If you haven't already linked your local project to Supabase: ```bash # Login to Supabase supabase login # Link to your Supabase project supabase link --project-ref YOUR_PROJECT_REF # Get your project ref from: https://app.supabase.com/project/YOUR_PROJECT/settings/general ``` --- ## 2. Deploy Database Migrations Apply all schema migrations to your Supabase project: ```bash # Push all migrations to production supabase db push # Verify migrations were applied supabase db remote commit ``` **Migrations will create:** - All tables (profiles, posts, comments, etc.) - Row Level Security policies - Helper functions (has_block_between, is_mutual_follow, etc.) - Trust system functions - Trending system tables --- ## 3. Seed Categories Run the seed script to populate default categories: ```bash # Connect to remote database and run seed script psql postgresql://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres \ -f supabase/seed/seed_categories.sql ``` Replace: - `[YOUR-PASSWORD]` with your database password (from Supabase dashboard) - `[YOUR-PROJECT-REF]` with your project reference **This creates 12 categories:** - general (default enabled) - quiet, gratitude, learning, writing, questions (opt-in) - grief, struggle, recovery (sensitive, opt-in) - care, solidarity, world (opt-in) --- ## 4. Deploy Edge Functions Deploy all Edge Functions to Supabase: ```bash # Deploy all functions at once supabase functions deploy publish-post supabase functions deploy publish-comment supabase functions deploy block supabase functions deploy report supabase functions deploy feed-personal supabase functions deploy feed-sojorn supabase functions deploy trending supabase functions deploy calculate-harmony ``` Or deploy individually as you build them. --- ## 5. Set Environment Variables Edge Functions need access to secrets. Set these in your Supabase project: ```bash # Set CRON_SECRET for scheduled harmony calculation supabase secrets set CRON_SECRET=$(openssl rand -base64 32) ``` **Environment variables automatically available to Edge Functions:** - `SUPABASE_URL` – Your Supabase project URL - `SUPABASE_ANON_KEY` – Public anon key - `SUPABASE_SERVICE_ROLE_KEY` – Service role key (admin access) --- ## 6. Schedule Harmony Calculation (Cron) The `calculate-harmony` function should run daily to recalculate user trust scores. ### Option 1: Supabase Cron (Coming Soon) Supabase is adding native cron support. When available: ```sql -- In SQL Editor SELECT cron.schedule( 'calculate-harmony-daily', '0 2 * * *', -- 2 AM daily $$ SELECT net.http_post( url := 'https://YOUR_PROJECT_REF.supabase.co/functions/v1/calculate-harmony', headers := jsonb_build_object( 'Authorization', 'Bearer YOUR_CRON_SECRET', 'Content-Type', 'application/json' ) ); $$ ); ``` ### Option 2: External Cron (GitHub Actions) Create `.github/workflows/harmony-cron.yml`: ```yaml name: Calculate Harmony Daily on: schedule: - cron: '0 2 * * *' # 2 AM UTC daily workflow_dispatch: # Allow manual trigger jobs: calculate: runs-on: ubuntu-latest steps: - name: Trigger harmony calculation run: | curl -X POST \ https://YOUR_PROJECT_REF.supabase.co/functions/v1/calculate-harmony \ -H "Authorization: Bearer ${{ secrets.CRON_SECRET }}" \ -H "Content-Type: application/json" ``` Set `CRON_SECRET` in GitHub Secrets. ### Option 3: External Cron Service Use [cron-job.org](https://cron-job.org) or [EasyCron](https://www.easycron.com): - URL: `https://YOUR_PROJECT_REF.supabase.co/functions/v1/calculate-harmony` - Method: POST - Header: `Authorization: Bearer YOUR_CRON_SECRET` - Schedule: Daily at 2 AM --- ## 7. Verify RLS Policies Test that Row Level Security is working correctly: ```sql -- Test as a regular user (should only see their own trust state) SET request.jwt.claims TO '{"sub": "USER_ID_HERE"}'; SELECT * FROM trust_state; -- Should return 1 row (user's own) -- Test block enforcement (users shouldn't see each other if blocked) INSERT INTO blocks (blocker_id, blocked_id) VALUES ('user1', 'user2'); SET request.jwt.claims TO '{"sub": "user1"}'; SELECT * FROM profiles WHERE id = 'user2'; -- Should return 0 rows -- Reset RESET request.jwt.claims; ``` --- ## 8. Configure Cloudflare (Optional) Add basic DDoS protection and rate limiting: 1. **Add your domain to Cloudflare** 2. **Set up a CNAME:** - `api.yourdomain.com` → `YOUR_PROJECT_REF.supabase.co` 3. **Enable rate limiting:** - Limit: 100 requests per minute per IP - Apply to: `/functions/v1/*` 4. **Enable Bot Fight Mode** --- ## 9. Test Edge Functions ### Using curl: ```bash # Get a user JWT token from Supabase Auth (sign up or log in first) export TOKEN="YOUR_JWT_TOKEN" # Test publishing a post curl -X POST https://YOUR_PROJECT_REF.supabase.co/functions/v1/publish-post \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "category_id": "CATEGORY_UUID", "body": "This is a friendly test post." }' # Test getting personal feed curl https://YOUR_PROJECT_REF.supabase.co/functions/v1/feed-personal \ -H "Authorization: Bearer $TOKEN" # Test Sojorn feed curl https://YOUR_PROJECT_REF.supabase.co/functions/v1/feed-sojorn?limit=20 \ -H "Authorization: Bearer $TOKEN" ``` ### Using Postman: Import this collection: - Base URL: `https://YOUR_PROJECT_REF.supabase.co/functions/v1` - Authorization: Bearer Token (paste your JWT) - Test all endpoints --- ## 10. Monitor and Debug ### View Edge Function Logs ```bash # Tail logs for a specific function supabase functions logs publish-post --tail # Or view in Supabase Dashboard: # https://app.supabase.com/project/YOUR_PROJECT/logs/edge-functions ``` ### View Database Logs ```sql -- Check audit log for recent events SELECT * FROM audit_log ORDER BY created_at DESC LIMIT 50; -- Check recent reports SELECT * FROM reports ORDER BY created_at DESC LIMIT 20; -- Check trust state distribution SELECT tier, COUNT(*) FROM trust_state GROUP BY tier; ``` ### Monitor Performance ```sql -- Slow queries SELECT * FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10; -- Active connections SELECT * FROM pg_stat_activity; ``` --- ## 11. Backup Strategy ### Automated Backups (Supabase Pro) Supabase Pro includes daily backups. Enable in: - Dashboard → Settings → Database → Backups ### Manual Backup ```bash # Export database schema and data pg_dump -h db.YOUR_PROJECT_REF.supabase.co \ -U postgres -d postgres \ --no-owner --no-acl \ > backup_$(date +%Y%m%d).sql ``` --- ## 12. Security Checklist Before going live: - [ ] All RLS policies enabled and tested - [ ] Service role key kept secret (never in client code) - [ ] Anon key is public (safe to expose) - [ ] CRON_SECRET is strong and secret - [ ] Rate limiting enabled (Cloudflare or Supabase) - [ ] HTTPS only (enforced by default) - [ ] Database password is strong - [ ] No SQL injection vulnerabilities in Edge Functions - [ ] Audit log captures all sensitive actions - [ ] Trust score cannot be manipulated directly by users --- ## 13. Rollback Plan If something goes wrong: ### Roll back migrations: ```bash # Reset to a previous migration supabase db reset --version 20260106000003 ``` ### Roll back Edge Functions: ```bash # Delete a function supabase functions delete publish-post # Redeploy previous version (if you have git history) git checkout previous_commit supabase functions deploy publish-post ``` ### Restore database from backup: ```bash # Using Supabase Dashboard (Pro plan) # Settings → Database → Backups → Restore # Or manually: psql postgresql://postgres:[PASSWORD]@db.[PROJECT_REF].supabase.co:5432/postgres \ < backup_20260105.sql ``` --- ## 14. Production Checklist Before public launch: - [ ] All migrations deployed - [ ] All Edge Functions deployed - [ ] Categories seeded - [ ] Harmony cron job scheduled - [ ] RLS policies tested - [ ] Rate limiting configured - [ ] Monitoring enabled - [ ] Backup strategy confirmed - [ ] Error tracking set up (Sentry, LogRocket, etc.) - [ ] Load testing completed - [ ] Security audit completed - [ ] Transparency pages published - [ ] Privacy policy and ToS published - [ ] Data export and deletion tested - [ ] Flutter app connected to production API --- ## Support For deployment issues: - [Supabase Discord](https://discord.supabase.com) - [Supabase Docs](https://supabase.com/docs) - [Sojorn GitHub Issues](https://github.com/yourusername/sojorn/issues) --- ## Example .env.local (For Development) ```bash SUPABASE_URL=http://localhost:54321 SUPABASE_ANON_KEY=your_local_anon_key SUPABASE_SERVICE_ROLE_KEY=your_local_service_role_key CRON_SECRET=test_cron_secret ``` Get local keys from: ```bash supabase status ``` --- ## Next Steps After deployment: 1. Build and deploy Flutter client 2. Set up user signup flow 3. Add admin tooling for moderation 4. Monitor harmony score distribution 5. Gather beta feedback 6. Iterate on tone detection accuracy 7. Optimize feed ranking based on engagement patterns --- **Sojorn backend is ready to support thoughtful, structural moderation from day one.**