sojorn/sojorn_docs/deployment/DEPLOYMENT.md

9.5 KiB
Raw Blame History

Sojorn - Deployment Guide

This guide walks through deploying the Sojorn backend to Supabase.


Prerequisites


1. Initialize Supabase Project

If you haven't already linked your local project to Supabase:

# 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:

# 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:

# 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:

# 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:

# 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:

-- 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:

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 or EasyCron:

  • 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:

-- 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.comYOUR_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:

# 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

# 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

-- 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

-- 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

# 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:

# Reset to a previous migration
supabase db reset --version 20260106000003

Roll back Edge Functions:

# 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:

# 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:


Example .env.local (For Development)

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:

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.