sojorn/sojorn_docs/deployment/SEEDING_SETUP.md
Patrick Britton 38653f5854 Sojorn Backend Finalization & Cleanup - Complete Migration from Supabase
##  Phase 1: Critical Feature Completion (Beacon Voting)
- Add VouchBeacon, ReportBeacon, RemoveBeaconVote methods to PostRepository
- Implement beacon voting HTTP handlers with confidence score calculations
- Register new beacon routes: /beacons/:id/vouch, /beacons/:id/report, /beacons/:id/vouch (DELETE)
- Auto-flag beacons at 5+ reports, confidence scoring (0.5 base + 0.1 per vouch)

##  Phase 2: Feed Logic & Post Distribution Integrity
- Verify unified feed logic supports all content types (Standard, Quips, Beacons)
- Ensure proper distribution: Profile Feed + Main/Home Feed for followers
- Beacon Map integration for location-based content
- Video content filtering for Quips feed

##  Phase 3: The Notification System
- Create comprehensive NotificationService with FCM integration
- Add CreateNotification method to NotificationRepository
- Implement smart deep linking: beacon_map, quip_feed, main_feed
- Trigger notifications for beacon interactions and cross-post comments
- Push notification logic with proper content type detection

##  Phase 4: The Great Supabase Purge
- Delete function_proxy.go and remove /functions/:name route
- Remove SupabaseURL, SupabaseKey from config.go
- Remove SupabaseID field from User model
- Clean all Supabase imports and dependencies
- Sanitize codebase of legacy Supabase references

##  Phase 5: Flutter Frontend Integration
- Implement vouchBeacon(), reportBeacon(), removeBeaconVote() in ApiService
- Replace TODO delay in video_comments_sheet.dart with actual publishComment call
- Fix compilation errors (named parameters, orphaned child properties)
- Complete frontend integration with Go API endpoints

##  Additional Improvements
- Fix compilation errors in threaded_comment_widget.dart (orphaned child property)
- Update video_comments_sheet.dart to use proper named parameters
- Comprehensive error handling and validation
- Production-ready notification system with deep linking

##  Migration Status: 100% Complete
- Backend: Fully migrated from Supabase to custom Go/Gin API
- Frontend: Integrated with new Go endpoints
- Notifications: Complete FCM integration with smart routing
- Database: Clean of all Supabase dependencies
- Features: All functionality preserved and enhanced

Ready for VPS deployment and production testing!
2026-01-30 09:24:31 -06:00

384 lines
8.1 KiB
Markdown

# Sojorn Seeding Setup Guide
## Prerequisites
- Supabase project deployed
- Categories seeded (run `seed_categories.sql`)
- At least one real user account created (for testing)
## Setup Order
Run these scripts in order in your Supabase SQL Editor:
https://app.supabase.com/project/zwkihedetedlatyvplyz/sql/new
### Step 1: Add is_official Column
**File:** `supabase/migrations/add_is_official_column.sql`
**Purpose:** Adds `is_official` boolean column to profiles table
**What it does:**
- Adds `is_official BOOLEAN DEFAULT false` to profiles
- Creates index for performance
- Adds documentation comment
**Run this:**
```sql
-- Paste contents of add_is_official_column.sql
```
**Verify:**
```sql
SELECT column_name, data_type, column_default
FROM information_schema.columns
WHERE table_name = 'profiles' AND column_name = 'is_official';
-- Should return:
-- column_name | data_type | column_default
-- is_official | boolean | false
```
---
### Step 2: Create Official Accounts
**File:** `supabase/seed/seed_official_accounts.sql`
**Purpose:** Creates 3 official Sojorn accounts
**What it does:**
- Creates @sojorn (platform announcements)
- Creates @sojorn_read (reading content)
- Creates @sojorn_write (writing prompts)
- Sets disabled passwords (cannot log in)
- Marks `is_official = true`
- Creates trust_state records
- Adds RLS policies
**Run this:**
```sql
-- Paste contents of seed_official_accounts.sql
```
**Verify:**
```sql
SELECT handle, display_name, is_official, bio
FROM profiles
WHERE is_official = true;
-- Should return 3 rows:
-- sojorn | Sojorn | true | Official Sojorn account • Platform updates...
-- sojorn_read | Sojorn Reading | true | Excerpts, quotes, and reading prompts...
-- sojorn_write | Sojorn Writing | true | Writing prompts and gentle reflections
```
**Expected output:**
```
NOTICE: Official accounts created successfully
NOTICE: @sojorn: [UUID]
NOTICE: @sojorn_read: [UUID]
NOTICE: @sojorn_write: [UUID]
```
---
### Step 3: Seed Content
**File:** `supabase/seed/seed_content.sql`
**Purpose:** Creates ~55 posts from official accounts
**What it does:**
- Inserts platform transparency posts
- Inserts public domain poetry
- Inserts reading reflections
- Inserts writing prompts
- Inserts observational content
- Backdates posts over 14 days
- Sets all engagement metrics to 0
**Run this:**
```sql
-- Paste contents of seed_content.sql
```
**Verify:**
```sql
SELECT
p.handle,
COUNT(posts.*) as post_count
FROM posts
JOIN profiles p ON p.id = posts.author_id
WHERE p.is_official = true
GROUP BY p.handle
ORDER BY p.handle;
-- Should return approximately:
-- sojorn | 5
-- sojorn_read | 20-25
-- sojorn_write | 25-30
```
**Check timestamp distribution:**
```sql
SELECT
DATE(created_at) as post_date,
COUNT(*) as posts
FROM posts
JOIN profiles p ON p.id = posts.author_id
WHERE p.is_official = true
GROUP BY DATE(created_at)
ORDER BY post_date;
-- Should show posts spread over ~14 days
```
**Check engagement (should all be 0):**
```sql
SELECT
like_count,
save_count,
comment_count,
view_count,
COUNT(*) as posts_with_these_values
FROM post_metrics pm
JOIN posts ON posts.id = pm.post_id
JOIN profiles p ON p.id = posts.author_id
WHERE p.is_official = true
GROUP BY like_count, save_count, comment_count, view_count;
-- Should return:
-- 0 | 0 | 0 | 0 | [total_count]
```
**Expected output:**
```
NOTICE: Seed content created successfully
NOTICE: Posts span 14 days, backdated from NOW
NOTICE: All engagement metrics set to 0 (no fake activity)
```
---
## Testing in Flutter App
### 1. Update Flutter Dependencies
Make sure you've pulled the latest code with the updated Profile model:
```dart
// lib/models/profile.dart should include:
final bool isOfficial;
```
### 2. Run the App
```bash
cd sojorn_app
flutter run -d chrome
```
### 3. Verify Official Badge
- Navigate to the Sojorn feed
- Look for posts from official accounts
- Should see **[SOJORN]** badge next to author name
- Badge should be soft blue (AppTheme.info)
- Badge should be small (8px font)
### 4. Verify No Fake Engagement
- Official posts should show 0 likes, 0 saves, 0 comments
- No "trending" or "recommended" language
- Just the content and the [SOJORN] badge
---
## Troubleshooting
### Error: "column is_official does not exist"
**Cause:** Step 1 (migration) was skipped
**Fix:**
```sql
-- Run add_is_official_column.sql first
ALTER TABLE profiles
ADD COLUMN IF NOT EXISTS is_official BOOLEAN DEFAULT false;
```
### Error: "No users found" in seed_content.sql
**Cause:** Official accounts not created yet
**Fix:** Run Step 2 (seed_official_accounts.sql) first
### Error: "duplicate key value violates unique constraint"
**Cause:** Official accounts already exist
**Fix:** Either:
1. Delete and recreate:
```sql
DELETE FROM profiles WHERE is_official = true;
-- Then re-run seed_official_accounts.sql
```
2. Or skip seed_official_accounts.sql if already done
### Official badge not showing in Flutter
**Cause:** Profile model not updated or API not returning is_official
**Fix:**
1. Check Profile model includes `isOfficial` field
2. Check API query includes `is_official` in SELECT:
```typescript
.select('*, author:profiles(*)')
// Make sure profiles(*) includes is_official
```
---
## Post-Seeding Checks
### Feed Distribution
Check how much of your feed is official content:
```sql
WITH feed_stats AS (
SELECT
p.is_official,
COUNT(*) as count
FROM posts
JOIN profiles p ON p.id = posts.author_id
WHERE posts.status = 'active'
GROUP BY p.is_official
)
SELECT
CASE
WHEN is_official THEN 'Official'
ELSE 'User'
END as account_type,
count,
ROUND(100.0 * count / SUM(count) OVER (), 1) as percentage
FROM feed_stats;
-- Expected (day 1):
-- Official | 55 | 100.0%
-- User | 0 | 0.0%
-- Expected (after users join):
-- Official | 55 | ~50-80%
-- User | XX | ~20-50%
```
### Content by Category
```sql
SELECT
c.name as category,
COUNT(*) as posts
FROM posts
JOIN profiles p ON p.id = posts.author_id
JOIN categories c ON c.id = posts.category_id
WHERE p.is_official = true
GROUP BY c.name
ORDER BY posts DESC;
-- Should show balanced distribution across categories
```
---
## Monthly Maintenance
### Check Official Content Ratio
Run monthly to ensure official content isn't dominating:
```sql
SELECT
DATE_TRUNC('week', created_at) as week,
SUM(CASE WHEN p.is_official THEN 1 ELSE 0 END) as official_posts,
SUM(CASE WHEN NOT p.is_official THEN 1 ELSE 0 END) as user_posts,
ROUND(
100.0 * SUM(CASE WHEN p.is_official THEN 1 ELSE 0 END) / COUNT(*),
1
) as pct_official
FROM posts
JOIN profiles p ON p.id = posts.author_id
WHERE posts.status = 'active'
AND created_at >= NOW() - INTERVAL '4 weeks'
GROUP BY week
ORDER BY week DESC;
```
**Target ratios:**
- Week 1-2: 80-100% official (okay, platform is new)
- Week 3-4: 50-80% official (user content growing)
- Month 2+: 10-30% official (user content dominant)
- Month 6+: 0-10% official (archive old posts)
### Archive Old Official Posts (After 6 Months)
```sql
-- Optional: Move old official posts to archived status
UPDATE posts
SET status = 'archived'
WHERE author_id IN (
SELECT id FROM profiles WHERE is_official = true
)
AND created_at < NOW() - INTERVAL '6 months'
AND status = 'active';
```
---
## Rollback (If Needed)
### Remove All Seed Content
```sql
-- Delete seed posts
DELETE FROM posts
WHERE author_id IN (
SELECT id FROM profiles WHERE is_official = true
);
-- Delete official accounts
DELETE FROM profiles WHERE is_official = true;
-- Remove column (optional)
ALTER TABLE profiles DROP COLUMN IF EXISTS is_official;
```
---
## Summary
**What you should have after seeding:**
✅ 3 official accounts (@sojorn, @sojorn_read, @sojorn_write)
✅ ~55 posts backdated over 14 days
✅ 0 fake engagement on all posts
✅ Clear [SOJORN] badge in UI
✅ Balanced content across categories
✅ New users see content immediately
✅ Trust preserved through transparency
**What you should NOT have:**
❌ Fake user personas
❌ Inflated metrics
❌ Hidden origin
❌ Synthetic conversations
❌ Deceptive language
---
**Philosophy:** Honest hospitality, not deception.
**Next:** Monitor feed ratio monthly and plan archival after 6 months.