Barazo Docker Compose templates for self-hosting barazo.forum
at main 591 lines 31 kB view raw
1#!/usr/bin/env bash 2# Barazo Staging Seed Script 3# 4# Populates the staging database with test data for development and QA. 5# Run after reset-staging.sh or on a fresh staging deployment. 6# 7# Usage: 8# ./scripts/seed-staging.sh # Seed all test data 9# ./scripts/seed-staging.sh --minimal # Seed only categories (faster) 10# 11# What it creates: 12# - 5 top-level categories + 7 subcategories (12 total) 13# - 5 test users (admin, moderator, 3 members) with known DIDs 14# - 10 sample topics across categories 15# - 18 flat replies across topics 16# - 15-level deep reply thread (Raspberry Pi self-hosting topic) 17# - 1 forum-wide pinned topic + 1 category-pinned topic + 1 locked topic 18# - Moderation data: queue items, action log, word filter 19# 20# Prerequisites: 21# - Staging services must be running 22# - Database must have migrations applied (API does this on startup) 23# - COMMUNITY_DID must be set in .env 24# 25# Environment: 26# COMPOSE_CMD Docker Compose command override 27# COMMUNITY_DID AT Protocol community DID (required, loaded from .env) 28 29set -euo pipefail 30 31COMPOSE_CMD="${COMPOSE_CMD:-docker compose -f docker-compose.yml -f docker-compose.staging.yml}" 32MINIMAL=false 33 34# Parse arguments 35for arg in "$@"; do 36 case "$arg" in 37 --minimal) MINIMAL=true ;; 38 --help|-h) 39 echo "Usage: $0 [--minimal]" 40 echo "" 41 echo "Seeds the staging database with test data." 42 echo "" 43 echo "Options:" 44 echo " --minimal Only create categories (skip users, topics, replies)" 45 exit 0 46 ;; 47 *) 48 echo "Unknown argument: $arg" >&2 49 exit 1 50 ;; 51 esac 52done 53 54# Load .env for database credentials and COMMUNITY_DID 55if [ -f .env ]; then 56 # shellcheck disable=SC2046 57 export $(grep -v '^#' .env | grep -v '^\s*$' | xargs) 58fi 59 60DB_NAME="${POSTGRES_DB:-barazo_staging}" 61DB_USER="${POSTGRES_USER:-barazo}" 62 63if [ -z "${COMMUNITY_DID:-}" ]; then 64 echo "Error: COMMUNITY_DID is not set. Add it to .env or export it." >&2 65 exit 1 66fi 67 68echo "Using COMMUNITY_DID: $COMMUNITY_DID" 69 70# Verify PostgreSQL is running 71if ! $COMPOSE_CMD exec -T postgres pg_isready -U "$DB_USER" &>/dev/null; then 72 echo "Error: PostgreSQL is not running. Start services first:" >&2 73 echo " docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d" >&2 74 exit 1 75fi 76 77# Helper: run psql with COMMUNITY_DID available as a psql variable 78run_psql() { 79 $COMPOSE_CMD exec -T postgres psql -U "$DB_USER" -d "$DB_NAME" \ 80 -v community_did="'$COMMUNITY_DID'" 81} 82 83echo "Seeding staging database..." 84echo "" 85 86# --- Categories (with subcategories) --- 87echo "Creating categories..." 88run_psql <<'SQL' 89-- Top-level categories 90INSERT INTO categories (id, slug, name, description, parent_id, sort_order, community_did, maturity_rating, created_at, updated_at) 91VALUES 92 ('cat-general', 'general', 'General', 'General discussion about anything', NULL, 1, :community_did, 'safe', NOW(), NOW()), 93 ('cat-feedback', 'feedback', 'Feedback', 'Feature requests, bug reports, and suggestions', NULL, 2, :community_did, 'safe', NOW(), NOW()), 94 ('cat-development', 'development', 'Development', 'Technical discussions about building with Barazo', NULL, 3, :community_did, 'safe', NOW(), NOW()), 95 ('cat-atproto', 'atproto', 'AT Protocol', 'AT Protocol ecosystem, standards, and tooling', NULL, 4, :community_did, 'safe', NOW(), NOW()), 96 ('cat-off-topic', 'off-topic', 'Off-Topic', 'Casual conversations and community hangout', NULL, 5, :community_did, 'safe', NOW(), NOW()) 97ON CONFLICT DO NOTHING; 98 99-- Subcategories under Development 100INSERT INTO categories (id, slug, name, description, parent_id, sort_order, community_did, maturity_rating, created_at, updated_at) 101VALUES 102 ('cat-dev-frontend', 'frontend', 'Frontend', 'UI, components, and client-side development', 'cat-development', 1, :community_did, 'safe', NOW(), NOW()), 103 ('cat-dev-backend', 'backend', 'Backend', 'API, database, and server-side development', 'cat-development', 2, :community_did, 'safe', NOW(), NOW()), 104 ('cat-dev-infra', 'infra', 'Infrastructure', 'Deployment, Docker, CI/CD, and hosting', 'cat-development', 3, :community_did, 'safe', NOW(), NOW()) 105ON CONFLICT DO NOTHING; 106 107-- Subcategories under Feedback 108INSERT INTO categories (id, slug, name, description, parent_id, sort_order, community_did, maturity_rating, created_at, updated_at) 109VALUES 110 ('cat-fb-features', 'feature-requests', 'Feature Requests', 'Suggest new features and improvements', 'cat-feedback', 1, :community_did, 'safe', NOW(), NOW()), 111 ('cat-fb-bugs', 'bug-reports', 'Bug Reports', 'Report bugs and unexpected behavior', 'cat-feedback', 2, :community_did, 'safe', NOW(), NOW()) 112ON CONFLICT DO NOTHING; 113 114-- Subcategories under AT Protocol 115INSERT INTO categories (id, slug, name, description, parent_id, sort_order, community_did, maturity_rating, created_at, updated_at) 116VALUES 117 ('cat-atp-lexicons', 'lexicons', 'Lexicons', 'Schema definitions and data model discussions', 'cat-atproto', 1, :community_did, 'safe', NOW(), NOW()), 118 ('cat-atp-identity', 'identity', 'Identity', 'DIDs, handles, and portable identity', 'cat-atproto', 2, :community_did, 'safe', NOW(), NOW()) 119ON CONFLICT DO NOTHING; 120SQL 121echo " Categories and subcategories created." 122 123if [ "$MINIMAL" = true ]; then 124 echo "" 125 echo "Minimal seed complete (categories only)." 126 exit 0 127fi 128 129# --- Test Users --- 130# Users table has no community_did (global across communities) 131echo "Creating test users..." 132run_psql <<'SQL' 133INSERT INTO users (did, handle, display_name, role, first_seen_at, last_active_at) 134VALUES 135 ('did:plc:staging-admin-001', 'staging-admin.bsky.social', 'Staging Admin', 'admin', NOW(), NOW()), 136 ('did:plc:staging-moderator-001', 'staging-mod.bsky.social', 'Staging Moderator', 'moderator', NOW(), NOW()), 137 ('did:plc:staging-member-001', 'staging-member.bsky.social', 'Staging Member', 'user', NOW(), NOW()), 138 ('did:plc:staging-member-002', 'staging-member2.bsky.social', 'Test User Two', 'user', NOW(), NOW()), 139 ('did:plc:staging-member-003', 'staging-member3.bsky.social', 'Test User Three', 'user', NOW(), NOW()) 140ON CONFLICT (did) DO NOTHING; 141SQL 142echo " Test users created." 143 144# --- Topics --- 145# AT Protocol style: uri is the primary key, references author by DID, category by slug 146echo "Creating sample topics..." 147run_psql <<'SQL' 148INSERT INTO topics (uri, rkey, author_did, title, content, category, community_did, cid, reply_count, created_at, last_activity_at, is_pinned, pinned_at, pinned_scope, is_locked) 149VALUES 150 -- Forum-wide pinned announcement 151 ('at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 152 '3seed001', 'did:plc:staging-admin-001', 153 'Welcome to Barazo Staging', 154 'This is the staging instance of Barazo, used for testing and development. Feel free to create topics and test features.', 155 'general', :community_did, 'bafyseed-t01', 3, 156 NOW() - INTERVAL '7 days', NOW() - INTERVAL '6 days 18 hours', 157 true, NOW() - INTERVAL '7 days', 'forum', false), 158 159 -- Category-pinned in feedback + locked 160 ('at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 161 '3seed002', 'did:plc:staging-admin-001', 162 'How to report bugs', 163 'Found a bug? Describe what you expected to happen, what actually happened, and steps to reproduce.', 164 'feedback', :community_did, 'bafyseed-t02', 3, 165 NOW() - INTERVAL '6 days', NOW() - INTERVAL '5 days 18 hours', 166 true, NOW() - INTERVAL '6 days', 'category', true), 167 168 ('at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 169 '3seed003', 'did:plc:staging-moderator-001', 170 'Getting started with the Barazo API', 171 'The Barazo API is a RESTful API built with Fastify. You can explore the API documentation at /docs.', 172 'development', :community_did, 'bafyseed-t03', 3, 173 NOW() - INTERVAL '5 days', NOW() - INTERVAL '4 days 14 hours', 174 false, NULL, NULL, false), 175 176 ('at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 177 '3seed004', 'did:plc:staging-moderator-001', 178 'AT Protocol identity and portability', 179 'One of the key features of building on AT Protocol is portable identity. Your DID stays with you across communities.', 180 'atproto', :community_did, 'bafyseed-t04', 3, 181 NOW() - INTERVAL '4 days', NOW() - INTERVAL '3 days 14 hours', 182 false, NULL, NULL, false), 183 184 ('at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 185 '3seed005', 'did:plc:staging-member-001', 186 'Favorite open source projects?', 187 'What open source projects are you excited about right now? Share your favorites!', 188 'off-topic', :community_did, 'bafyseed-t05', 3, 189 NOW() - INTERVAL '3 days', NOW() - INTERVAL '2 days 12 hours', 190 false, NULL, NULL, false), 191 192 ('at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 193 '3seed006', 'did:plc:staging-member-001', 194 'Feature request: dark mode improvements', 195 'The dark mode is great but could use some contrast improvements in the sidebar and category labels.', 196 'feedback', :community_did, 'bafyseed-t06', 3, 197 NOW() - INTERVAL '2 days', NOW() - INTERVAL '1 day 12 hours', 198 false, NULL, NULL, false), 199 200 ('at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed007', 201 '3seed007', 'did:plc:staging-admin-001', 202 'Understanding the firehose and Tap', 203 'Tap filters the AT Protocol firehose for forum.barazo.* records. Here is how it works and why it matters.', 204 'development', :community_did, 'bafyseed-t07', 0, 205 NOW() - INTERVAL '2 days', NOW() - INTERVAL '2 days', 206 false, NULL, NULL, false), 207 208 ('at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed008', 209 '3seed008', 'did:plc:staging-moderator-001', 210 'Cross-community reputation design', 211 'How should reputation work across multiple Barazo communities? Let us discuss the design considerations.', 212 'atproto', :community_did, 'bafyseed-t08', 0, 213 NOW() - INTERVAL '1 day', NOW() - INTERVAL '1 day', 214 false, NULL, NULL, false), 215 216 ('at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 217 '3seed009', 'did:plc:staging-member-001', 218 'Self-hosting Barazo on a Raspberry Pi', 219 'Has anyone tried running Barazo on a Raspberry Pi? Curious about the performance on ARM hardware.', 220 'general', :community_did, 'bafyseed-t09', 15, 221 NOW() - INTERVAL '12 hours', NOW() - INTERVAL '1 hour', 222 false, NULL, NULL, false), 223 224 ('at://did:plc:staging-member-001/forum.barazo.topic.post/3seed010', 225 '3seed010', 'did:plc:staging-member-001', 226 'Weekend project ideas', 227 'Looking for weekend project ideas that integrate with AT Protocol. What are you building?', 228 'off-topic', :community_did, 'bafyseed-t10', 0, 229 NOW() - INTERVAL '6 hours', NOW() - INTERVAL '6 hours', 230 false, NULL, NULL, false) 231ON CONFLICT DO NOTHING; 232SQL 233echo " Sample topics created." 234 235# --- Flat Replies (depth 1, across multiple topics) --- 236echo "Creating sample replies..." 237run_psql <<'SQL' 238-- Welcome topic replies (flat, depth 1) 239INSERT INTO replies (uri, rkey, author_did, content, root_uri, root_cid, parent_uri, parent_cid, community_did, cid, depth, created_at) 240VALUES 241 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seedr01', 242 '3seedr01', 'did:plc:staging-moderator-001', 243 'Great to see the staging environment up and running!', 244 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 245 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 246 :community_did, 'bafyseed-r01', 1, NOW() - INTERVAL '6 days 23 hours'), 247 248 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seedr02', 249 '3seedr02', 'did:plc:staging-member-001', 250 'Testing the reply functionality. Markdown **bold** and *italic* work well.', 251 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 252 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 253 :community_did, 'bafyseed-r02', 1, NOW() - INTERVAL '6 days 20 hours'), 254 255 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seedr03', 256 '3seedr03', 'did:plc:staging-member-002', 257 'Confirmed everything looks good on mobile too.', 258 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 259 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 'bafyseed-t01', 260 :community_did, 'bafyseed-r03', 1, NOW() - INTERVAL '6 days 18 hours'), 261 262 -- Bug report topic replies 263 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seedr04', 264 '3seedr04', 'did:plc:staging-moderator-001', 265 'I can help triage bugs as they come in.', 266 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 267 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 268 :community_did, 'bafyseed-r04', 1, NOW() - INTERVAL '5 days 22 hours'), 269 270 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seedr05', 271 '3seedr05', 'did:plc:staging-member-001', 272 'Is there a template for bug reports?', 273 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 274 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 275 :community_did, 'bafyseed-r05', 1, NOW() - INTERVAL '5 days 20 hours'), 276 277 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seedr06', 278 '3seedr06', 'did:plc:staging-admin-001', 279 'Not yet, but that is a good idea. Will add one.', 280 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 281 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 'bafyseed-t02', 282 :community_did, 'bafyseed-r06', 1, NOW() - INTERVAL '5 days 18 hours'), 283 284 -- API topic replies 285 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seedr07', 286 '3seedr07', 'did:plc:staging-member-001', 287 'The Fastify integration is really clean. Love the Zod validation.', 288 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 289 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 290 :community_did, 'bafyseed-r07', 1, NOW() - INTERVAL '4 days 20 hours'), 291 292 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seedr08', 293 '3seedr08', 'did:plc:staging-member-002', 294 'How does rate limiting work on the API?', 295 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 296 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 297 :community_did, 'bafyseed-r08', 1, NOW() - INTERVAL '4 days 16 hours'), 298 299 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seedr09', 300 '3seedr09', 'did:plc:staging-admin-001', 301 'Rate limiting uses a sliding window stored in Valkey. Configurable per endpoint.', 302 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 303 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed003', 'bafyseed-t03', 304 :community_did, 'bafyseed-r09', 1, NOW() - INTERVAL '4 days 14 hours'), 305 306 -- Identity topic replies 307 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seedr10', 308 '3seedr10', 'did:plc:staging-member-001', 309 'This is the killer feature of AT Protocol-based forums.', 310 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 311 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 312 :community_did, 'bafyseed-r10', 1, NOW() - INTERVAL '3 days 20 hours'), 313 314 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seedr11', 315 '3seedr11', 'did:plc:staging-member-003', 316 'Can I use my existing Bluesky handle to sign in?', 317 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 318 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 319 :community_did, 'bafyseed-r11', 1, NOW() - INTERVAL '3 days 16 hours'), 320 321 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seedr12', 322 '3seedr12', 'did:plc:staging-moderator-001', 323 'Yes! Any AT Protocol account works via OAuth. Bluesky, Blacksky, self-hosted PDS, all supported.', 324 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 325 'at://did:plc:staging-moderator-001/forum.barazo.topic.post/3seed004', 'bafyseed-t04', 326 :community_did, 'bafyseed-r12', 1, NOW() - INTERVAL '3 days 14 hours'), 327 328 -- OSS topic replies 329 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seedr13', 330 '3seedr13', 'did:plc:staging-moderator-001', 331 'Valkey has been great as a Redis replacement.', 332 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 333 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 334 :community_did, 'bafyseed-r13', 1, NOW() - INTERVAL '2 days 20 hours'), 335 336 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seedr14', 337 '3seedr14', 'did:plc:staging-member-002', 338 'I have been enjoying Caddy for reverse proxy. So much simpler than nginx.', 339 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 340 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 341 :community_did, 'bafyseed-r14', 1, NOW() - INTERVAL '2 days 16 hours'), 342 343 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seedr15', 344 '3seedr15', 'did:plc:staging-admin-001', 345 'Drizzle ORM is another good one. TypeScript-first database queries.', 346 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 347 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed005', 'bafyseed-t05', 348 :community_did, 'bafyseed-r15', 1, NOW() - INTERVAL '2 days 12 hours'), 349 350 -- Dark mode topic replies 351 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seedr16', 352 '3seedr16', 'did:plc:staging-moderator-001', 353 'Agreed on the sidebar contrast. The category pills are hard to read in dark mode.', 354 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 355 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 356 :community_did, 'bafyseed-r16', 1, NOW() - INTERVAL '1 day 20 hours'), 357 358 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seedr17', 359 '3seedr17', 'did:plc:staging-admin-001', 360 'We use Radix Colors which should handle this well. Will investigate.', 361 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 362 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 363 :community_did, 'bafyseed-r17', 1, NOW() - INTERVAL '1 day 16 hours'), 364 365 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seedr18', 366 '3seedr18', 'did:plc:staging-member-003', 367 'Maybe the Flexoki accent hues need adjustment for the dark palette.', 368 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 369 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed006', 'bafyseed-t06', 370 :community_did, 'bafyseed-r18', 1, NOW() - INTERVAL '1 day 12 hours') 371ON CONFLICT DO NOTHING; 372SQL 373echo " Flat replies created." 374 375# --- Deep Thread (15 levels) on the Raspberry Pi topic --- 376# A single chain of replies where each is a child of the previous one. 377# Cycles through all 5 test users for realistic variety. 378echo "Creating deep reply thread (15 levels)..." 379run_psql <<'SQL' 380-- Raspberry Pi self-hosting topic: deep threaded conversation 381-- Topic URI: at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009 382-- Each reply is a child of the previous, forming a single chain depth 1-15. 383 384-- Users cycle: admin(001), mod(001), member(001), member(002), member(003), admin, mod, ... 385INSERT INTO replies (uri, rkey, author_did, content, root_uri, root_cid, parent_uri, parent_cid, community_did, cid, depth, created_at) 386VALUES 387 -- Depth 1: member-002 replies to topic 388 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep01', 389 '3seeddeep01', 'did:plc:staging-member-002', 390 'I actually have it running on a Pi 4 with 8GB RAM. Works surprisingly well.', 391 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 392 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 393 :community_did, 'bafyseed-d01', 1, NOW() - INTERVAL '11 hours'), 394 395 -- Depth 2: member-003 replies to depth 1 396 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep02', 397 '3seeddeep02', 'did:plc:staging-member-003', 398 'What about the database? PostgreSQL on a Pi seems heavy.', 399 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 400 'at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep01', 'bafyseed-d01', 401 :community_did, 'bafyseed-d02', 2, NOW() - INTERVAL '10 hours'), 402 403 -- Depth 3: admin replies to depth 2 404 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep03', 405 '3seeddeep03', 'did:plc:staging-admin-001', 406 'SQLite would be lighter but you lose concurrent writes. PostgreSQL is fine with proper tuning.', 407 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 408 'at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep02', 'bafyseed-d02', 409 :community_did, 'bafyseed-d03', 3, NOW() - INTERVAL '9 hours'), 410 411 -- Depth 4: member-002 replies to depth 3 412 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep04', 413 '3seeddeep04', 'did:plc:staging-member-002', 414 'What pg settings did you change? I keep running out of shared memory.', 415 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 416 'at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep03', 'bafyseed-d03', 417 :community_did, 'bafyseed-d04', 4, NOW() - INTERVAL '8 hours 30 minutes'), 418 419 -- Depth 5: mod replies to depth 4 420 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep05', 421 '3seeddeep05', 'did:plc:staging-moderator-001', 422 'Set shared_buffers to 256MB and work_mem to 16MB. Also reduce max_connections to 20.', 423 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 424 'at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep04', 'bafyseed-d04', 425 :community_did, 'bafyseed-d05', 5, NOW() - INTERVAL '8 hours'), 426 427 -- Depth 6: member-002 replies to depth 5 428 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep06', 429 '3seeddeep06', 'did:plc:staging-member-002', 430 'That helped a lot, thanks! But now the firehose consumer is lagging behind.', 431 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 432 'at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep05', 'bafyseed-d05', 433 :community_did, 'bafyseed-d06', 6, NOW() - INTERVAL '7 hours'), 434 435 -- Depth 7: admin replies to depth 6 436 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep07', 437 '3seeddeep07', 'did:plc:staging-admin-001', 438 'The firehose needs dedicated resources. Consider running it as a separate service.', 439 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 440 'at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep06', 'bafyseed-d06', 441 :community_did, 'bafyseed-d07', 7, NOW() - INTERVAL '6 hours 30 minutes'), 442 443 -- Depth 8: member-003 replies to depth 7 444 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep08', 445 '3seeddeep08', 'did:plc:staging-member-003', 446 'Separate service means another container though. The Pi is already running 4.', 447 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 448 'at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep07', 'bafyseed-d07', 449 :community_did, 'bafyseed-d08', 8, NOW() - INTERVAL '6 hours'), 450 451 -- Depth 9: mod replies to depth 8 452 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep09', 453 '3seeddeep09', 'did:plc:staging-moderator-001', 454 'You could use a lightweight process manager instead of Docker for some services.', 455 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 456 'at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep08', 'bafyseed-d08', 457 :community_did, 'bafyseed-d09', 9, NOW() - INTERVAL '5 hours'), 458 459 -- Depth 10: member-001 (topic author) replies to depth 9 460 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seeddeep10', 461 '3seeddeep10', 'did:plc:staging-member-001', 462 'PM2 or systemd? I tried PM2 but it added 100MB of memory overhead.', 463 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 464 'at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep09', 'bafyseed-d09', 465 :community_did, 'bafyseed-d10', 10, NOW() - INTERVAL '4 hours 30 minutes'), 466 467 -- Depth 11: admin replies to depth 10 468 ('at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep11', 469 '3seeddeep11', 'did:plc:staging-admin-001', 470 'systemd is the way to go. Zero overhead and it handles restarts natively.', 471 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 472 'at://did:plc:staging-member-001/forum.barazo.reply.post/3seeddeep10', 'bafyseed-d10', 473 :community_did, 'bafyseed-d11', 11, NOW() - INTERVAL '4 hours'), 474 475 -- Depth 12: member-002 replies to depth 11 476 ('at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep12', 477 '3seeddeep12', 'did:plc:staging-member-002', 478 'Good call. One more question -- how do you handle SSL termination?', 479 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 480 'at://did:plc:staging-admin-001/forum.barazo.reply.post/3seeddeep11', 'bafyseed-d11', 481 :community_did, 'bafyseed-d12', 12, NOW() - INTERVAL '3 hours'), 482 483 -- Depth 13: mod replies to depth 12 484 ('at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep13', 485 '3seeddeep13', 'did:plc:staging-moderator-001', 486 'Caddy is perfect for this. Auto-HTTPS with minimal config and low resource usage.', 487 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 488 'at://did:plc:staging-member-002/forum.barazo.reply.post/3seeddeep12', 'bafyseed-d12', 489 :community_did, 'bafyseed-d13', 13, NOW() - INTERVAL '2 hours 30 minutes'), 490 491 -- Depth 14: member-003 replies to depth 13 492 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep14', 493 '3seeddeep14', 'did:plc:staging-member-003', 494 'Has anyone benchmarked Caddy vs nginx on ARM? Curious about the TLS handshake overhead.', 495 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 496 'at://did:plc:staging-moderator-001/forum.barazo.reply.post/3seeddeep13', 'bafyseed-d13', 497 :community_did, 'bafyseed-d14', 14, NOW() - INTERVAL '2 hours'), 498 499 -- Depth 15: member-001 (topic author) wraps it up 500 ('at://did:plc:staging-member-001/forum.barazo.reply.post/3seeddeep15', 501 '3seeddeep15', 'did:plc:staging-member-001', 502 'This whole thread is gold. Someone should turn this into a self-hosting guide.', 503 'at://did:plc:staging-member-001/forum.barazo.topic.post/3seed009', 'bafyseed-t09', 504 'at://did:plc:staging-member-003/forum.barazo.reply.post/3seeddeep14', 'bafyseed-d14', 505 :community_did, 'bafyseed-d15', 15, NOW() - INTERVAL '1 hour') 506ON CONFLICT DO NOTHING; 507SQL 508echo " Deep thread created (15 levels)." 509 510# --- Moderation Data --- 511echo "Creating moderation data..." 512run_psql <<'SQL' 513-- Word filter: add sample words to community settings 514UPDATE community_settings 515SET word_filter = '["spam", "scam", "free money", "buy now"]'::jsonb 516WHERE community_did = :community_did; 517 518-- Moderation action log: record the pin, lock, and a topic deletion 519INSERT INTO moderation_actions (action, target_uri, moderator_did, community_did, reason, created_at) 520VALUES 521 ('pin', 522 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed001', 523 'did:plc:staging-admin-001', :community_did, 524 'Pinned forum-wide as welcome announcement', 525 NOW() - INTERVAL '7 days'), 526 ('pin', 527 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 528 'did:plc:staging-moderator-001', :community_did, 529 'Pinned in feedback category for visibility', 530 NOW() - INTERVAL '6 days'), 531 ('lock', 532 'at://did:plc:staging-admin-001/forum.barazo.topic.post/3seed002', 533 'did:plc:staging-moderator-001', :community_did, 534 'Locked to keep bug reporting instructions stable', 535 NOW() - INTERVAL '6 days'), 536 ('delete', 537 'at://did:plc:staging-member-003/forum.barazo.topic.post/3seedmod01', 538 'did:plc:staging-moderator-001', :community_did, 539 'Removed spam content', 540 NOW() - INTERVAL '2 days') 541ON CONFLICT DO NOTHING; 542 543-- Moderation queue: sample items in different states 544-- 1. Pending item (word filter match) - a reply that's waiting for review 545INSERT INTO moderation_queue (content_uri, content_type, author_did, community_did, queue_reason, matched_words, status, created_at) 546VALUES 547 ('at://did:plc:staging-member-003/forum.barazo.reply.post/3seedheld01', 548 'reply', 'did:plc:staging-member-003', :community_did, 549 'word_filter', '["free money"]', 550 'pending', NOW() - INTERVAL '3 hours') 551ON CONFLICT DO NOTHING; 552 553-- 2. Approved item (first post by new user) 554INSERT INTO moderation_queue (content_uri, content_type, author_did, community_did, queue_reason, status, reviewed_by, created_at, reviewed_at) 555VALUES 556 ('at://did:plc:staging-member-002/forum.barazo.topic.post/3seed005', 557 'topic', 'did:plc:staging-member-002', :community_did, 558 'first_post', 559 'approved', 'did:plc:staging-moderator-001', 560 NOW() - INTERVAL '4 days', NOW() - INTERVAL '4 days' + INTERVAL '15 minutes') 561ON CONFLICT DO NOTHING; 562 563-- 3. Rejected item (word filter match on a deleted topic) 564INSERT INTO moderation_queue (content_uri, content_type, author_did, community_did, queue_reason, matched_words, status, reviewed_by, created_at, reviewed_at) 565VALUES 566 ('at://did:plc:staging-member-003/forum.barazo.topic.post/3seedmod01', 567 'topic', 'did:plc:staging-member-003', :community_did, 568 'word_filter', '["scam", "buy now"]', 569 'rejected', 'did:plc:staging-moderator-001', 570 NOW() - INTERVAL '2 days', NOW() - INTERVAL '2 days' + INTERVAL '30 minutes') 571ON CONFLICT DO NOTHING; 572SQL 573echo " Moderation data created (word filter, action log, queue items)." 574 575echo "" 576echo "Staging seed complete." 577echo "" 578echo "Test users:" 579echo " Admin: did:plc:staging-admin-001 (staging-admin.bsky.social)" 580echo " Moderator: did:plc:staging-moderator-001 (staging-mod.bsky.social)" 581echo " Member: did:plc:staging-member-001 (staging-member.bsky.social)" 582echo " Member 2: did:plc:staging-member-002 (staging-member2.bsky.social)" 583echo " Member 3: did:plc:staging-member-003 (staging-member3.bsky.social)" 584echo "" 585echo "Categories: 5 top-level + 7 subcategories (12 total)" 586echo "Topics: 10 | Flat replies: 18 | Deep thread: 15 replies (depth 1-15)" 587echo "Pinned: 'Welcome' (forum-wide) + 'How to report bugs' (category, locked)" 588echo "Moderation: 3 queue items (1 pending, 1 approved, 1 rejected) + 4 action log entries" 589echo "Word filter: spam, scam, free money, buy now" 590echo "" 591echo "Deep thread topic: 'Self-hosting Barazo on a Raspberry Pi'"