WIP! A BB-style forum, on the ATmosphere!
We're still working... we'll be back soon when we have something to show off!
node
typescript
hono
htmx
atproto
1# Bootstrap CLI Design
2
3**Date:** 2026-02-18
4**Status:** Approved
5
6## Problem
7
8atBB has a bootstrapping gap. After deploying the appview and database, operators must manually create the forum record on the Forum DID's PDS and assign themselves the Owner role via raw AT Proto API calls. There is no automated first-time setup flow.
9
10Existing automation covers only part of the picture:
11- Role seeding (Owner/Admin/Moderator/Member) runs on appview startup
12- ForumAgent authenticates as the Forum DID on startup
13- Database migrations exist but must be run manually
14
15What remains manual:
161. Creating the `space.atbb.forum.forum/self` record on the Forum PDS
172. Assigning the Owner role to the operator's AT Proto identity
183. Verifying the environment is correctly configured before first launch
19
20## Solution
21
22A CLI tool (`atbb init`) that bootstraps a new forum instance in one command. It handles environment validation, forum record creation, role seeding, and first-owner assignment.
23
24### Audience
25
26Both server operators (Docker deployments) and developer-operators (running from source). The CLI works as a pnpm workspace script during development and as a Docker exec command in production.
27
28### Scope
29
30Bootstrap only. Ongoing admin operations (categories, boards, bans) go through the web admin UI. The CLI handles one-time setup that must happen before the web UI is functional.
31
32## Architecture
33
34### New packages
35
36**`packages/cli` (`@atbb/cli`)** — The CLI tool itself. Ships the `atbb` command with the `init` subcommand.
37
38**`packages/atproto` (`@atbb/atproto`)** — Shared AT Protocol utilities extracted from the appview. Contains `ForumAgent`, error classification helpers, and identity resolution.
39
40### Code extraction from appview
41
42| What | From | To |
43|---|---|---|
44| `ForumAgent` class | `apps/appview/src/lib/forum-agent.ts` | `packages/atproto/src/forum-agent.ts` |
45| `isAuthError` / `isNetworkError` | same file | `packages/atproto/src/errors.ts` |
46| `isProgrammingError` | `apps/appview` (various) | `packages/atproto/src/errors.ts` |
47
48New in `packages/atproto`:
49- `resolveIdentity(input, pdsUrl)` — resolves a handle or DID string to a confirmed DID
50
51What stays in appview:
52- `AppContext` (ties together DB + ForumAgent + OAuth + firehose)
53- `loadConfig()` (appview-specific env vars)
54- `seed-roles.ts` (depends on AppContext; CLI has its own step)
55
56### Updated dependency chain
57
58```
59@atbb/lexicon ──┐
60@atbb/db ──┼──→ @atbb/appview
61@atbb/atproto ──┘
62 ┌──→ @atbb/cli
63@atbb/db ──┤
64@atbb/atproto ──┘
65```
66
67Turbo build order: `lexicon` + `db` + `atproto` (independent), then `appview` + `web` + `cli` (parallel).
68
69## Command Design: `atbb init`
70
71### Bootstrap sequence
72
731. **Preflight checks** — Validate required env vars (DATABASE_URL, FORUM_DID, PDS_URL, FORUM_HANDLE, FORUM_PASSWORD). Fail immediately with a clear message listing what is missing.
742. **Database connection** — Verify connectivity. Confirm migrations are applied.
753. **PDS authentication** — Authenticate ForumAgent. Distinguish auth errors from network errors.
764. **Create forum record** — Prompt for forum name and description (or accept via flags). Create `space.atbb.forum.forum/self` on the Forum PDS. Skip if already exists.
775. **Seed default roles** — Create Owner/Admin/Moderator/Member role records on the Forum PDS. Skip any that already exist.
786. **Assign owner** — Prompt for owner handle or DID (or accept via flag). Resolve handle to DID if needed. Assign the Owner role. Skip if already assigned.
797. **Print summary** — Display what was created/skipped and next steps.
80
81### Interaction model
82
83Interactive by default with flag overrides for scripted use:
84
85```sh
86# Interactive (prompts for each value)
87atbb init
88
89# Scripted (no prompts)
90atbb init --forum-name "My Forum" --forum-description "A cool forum" --owner alice.bsky.social
91```
92
93When all required flags are provided, no prompts appear.
94
95### Idempotency
96
97Every step checks before acting:
98- Forum record: checks if `space.atbb.forum.forum/self` exists on PDS
99- Role seeding: checks DB for existing roles by name
100- Owner assignment: checks if user already has Owner role
101
102Safe to run multiple times. Important for Docker containers that restart.
103
104### Error handling
105
106- Missing env vars: fail immediately before any prompts
107- PDS auth errors: "check your FORUM_PASSWORD" (no retry for bad credentials)
108- PDS network errors: "can't reach PDS at https://..." (suggest checking PDS_URL)
109- Handle resolution failure: "Could not resolve 'alice.bsky.social'"
110- Partial completion: each step is independent; re-running picks up where it left off
111
112## Package Structure
113
114### `packages/atproto`
115
116```
117packages/atproto/
118├── package.json
119├── tsconfig.json
120└── src/
121 ├── index.ts # Public exports
122 ├── forum-agent.ts # ForumAgent class (moved from appview)
123 ├── errors.ts # isAuthError, isNetworkError, isProgrammingError
124 └── resolve-identity.ts # Handle/DID resolution
125```
126
127### `packages/cli`
128
129```
130packages/cli/
131├── package.json
132├── tsconfig.json
133└── src/
134 ├── index.ts # CLI entrypoint (citty main)
135 ├── commands/
136 │ └── init.ts # The init command
137 ├── lib/
138 │ ├── config.ts # CLI-specific config loader
139 │ ├── preflight.ts # Env var checks, DB/PDS connectivity
140 │ └── steps/
141 │ ├── create-forum.ts # Step 1: create forum record
142 │ ├── seed-roles.ts # Step 2: seed default roles
143 │ └── assign-owner.ts # Step 3: assign owner role
144 └── __tests__/
145 ├── preflight.test.ts
146 ├── create-forum.test.ts
147 ├── seed-roles.test.ts
148 ├── assign-owner.test.ts
149 └── resolve-identity.test.ts
150```
151
152## Dependencies
153
154| Package | Purpose |
155|---|---|
156| `citty` | Lightweight CLI framework (UnJS). Arg parsing, subcommands. |
157| `consola` | Styled console output (UnJS). Spinners, colored prefixes. |
158| `@inquirer/prompts` | Interactive prompts (text input, confirmations). Tree-shakeable. |
159| `@atproto/api` | AT Proto client. Already in workspace. |
160| `@atbb/db` | Database access. Workspace dependency. |
161| `@atbb/atproto` | ForumAgent + identity resolution. Workspace dependency. |
162
163## Testing Strategy
164
165Each step is a pure function taking explicit dependencies (DB, AtpAgent, config). No global state.
166
167- **preflight.test.ts** — env var validation, missing vars, invalid formats
168- **create-forum.test.ts** — idempotency (record exists -> skip), PDS write success/failure
169- **seed-roles.test.ts** — role creation, duplicate detection, PDS errors
170- **assign-owner.test.ts** — handle resolution, DID passthrough, role assignment, already-owner skip
171- **resolve-identity.test.ts** — handle->DID resolution, DID passthrough, invalid handle errors
172
173All PDS calls mocked. Database calls use existing test harness patterns.
174
175## Appview Changes
176
177After extraction, the appview changes are minimal:
178- `forum-agent.ts` deleted, replaced with `import { ForumAgent } from "@atbb/atproto"`
179- Error helpers imported from `@atbb/atproto` instead of local definitions
180- No behavioral changes — all existing tests should pass as-is