Barazo Docker Compose templates for self-hosting
barazo.forum
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'"