···11-# atBB Monorepo
22-33-**atBB** is a decentralized BB-style forum built on the AT Protocol. Users own their posts on their own PDS; the forum's AppView indexes and serves them. Lexicon namespace: `space.atbb.*` (domain `atbb.space` is owned). License: AGPL-3.0.
44-55-The master project plan with MVP phases and progress tracking lives at `docs/atproto-forum-plan.md`.
66-77-## Apps & Packages
88-99-### Apps (`apps/`)
1010-1111-Servers and applications that are deployed or run as services.
1212-1313-| App | Description | Port |
1414-|-----|-------------|------|
1515-| `@atbb/appview` | Hono JSON API server — indexes forum data, serves API | 3000 |
1616-| `@atbb/web` | Hono JSX + HTMX server-rendered web UI — calls appview API | 3001 |
11+# Claude.md
1721818-### Packages (`packages/`)
1919-2020-Shared libraries, tools, and utilities consumed by apps or used standalone.
2121-2222-| Package | Description |
2323-|---------|-------------|
2424-| `@atbb/db` | Drizzle ORM schema and connection factory for PostgreSQL |
2525-| `@atbb/lexicon` | AT Proto lexicon definitions (YAML) + generated TypeScript types |
33+The role of this file is to describe common mistakes and confusion points that agents might encounter as they work in this project. If you ever encounter something in the project that surprises you, please alert the developer working with you and indicate that this is the case in the Claude.md file to help prevent future agents from having the same issue.
2642727-**Dependency chain:** `@atbb/lexicon` and `@atbb/db` build first, then `@atbb/appview` and `@atbb/web` build in parallel. Turbo handles this via `^build`.
55+This project is greenfield. It is okay to change the schema entirely or make what might be breaking changes. We will sort out any backfill or backwards compatibility requirements when they are actually needed.
286297## Development
308···3614cp .env.example .env # configure environment variables
3715```
38163939-### Commands
4040-4141-```sh
4242-pnpm build # build all packages (lexicon → appview + web)
4343-pnpm dev # start all dev servers with hot reload
4444-pnpm test # run all tests across all packages
4545-pnpm clean # remove all dist/ directories
4646-devenv up # start appview + web servers via process manager
4747-pnpm --filter @atbb/appview db:migrate # run database migrations
4848-pnpm --filter @atbb/appview dev # run a single package
4949-pnpm --filter @atbb/appview test # run tests for a single package
5050-```
5151-5252-### Environment Variables
5353-5454-See `.env.example`. Key variables:
5555-5656-- `PORT` — server port (appview: 3000, web: 3001)
5757-- `FORUM_DID` — the forum's AT Proto DID
5858-- `PDS_URL` — URL of the forum's PDS
5959-- `APPVIEW_URL` — URL the web package uses to reach the appview API
6060-- `FORUM_HANDLE`, `FORUM_PASSWORD` — forum service account credentials
6161-6262-**OAuth & session management (required for production):**
6363-- `OAUTH_PUBLIC_URL` — public URL where AppView is accessible (used for client_id and redirect_uri)
6464-- `SESSION_SECRET` — signing key for session tokens (generate with `openssl rand -hex 32`)
6565-- `SESSION_TTL_DAYS` — session lifetime in days (default: 7)
6666-- `REDIS_URL` — optional Redis URL for session storage (recommended for multi-instance deployments)
6767-6868-## Deployment
6969-7070-### Docker
7171-7272-The project includes production-ready Docker infrastructure for single-container deployment:
7373-7474-```sh
7575-# Build the Docker image
7676-docker build -t atbb:latest .
7777-7878-# Run with docker-compose (recommended)
7979-cp docker-compose.example.yml docker-compose.yml
8080-# Edit docker-compose.yml with your DATABASE_URL, FORUM_DID, etc.
8181-docker compose up -d
8282-```
8383-8484-**What's included:**
8585-- Multi-stage Dockerfile (Node 22 Alpine, ~200MB final image)
8686-- Nginx reverse proxy serving both appview (port 3000) and web (port 3001) on port 80
8787-- Non-root user (`atbb:atbb`) for security
8888-- Health checks on `/api/healthz`
8989-- Production-ready entrypoint script
9090-9191-**Key files:**
9292-- `Dockerfile` — multi-stage build definition
9393-- `entrypoint.sh` — startup script (nginx + node servers)
9494-- `nginx.conf` — reverse proxy configuration
9595-- `docker-compose.example.yml` — orchestration template
9696-- `docs/deployment-guide.md` — comprehensive deployment instructions
9797-9898-**Database migrations:** The container does NOT auto-run migrations. Run manually before starting:
9999-```sh
100100-docker compose run --rm atbb pnpm --filter @atbb/appview db:migrate
101101-```
102102-103103-## Pre-Commit Checks
104104-105105-Every commit automatically runs three checks in parallel via lefthook:
106106-107107-1. **Lint** — oxlint scans staged TypeScript/JavaScript files for code quality issues
108108-2. **Typecheck** — `pnpm turbo lint` runs type checking on affected packages
109109-3. **Test** — Vitest runs tests in packages with staged changes
110110-11117### Auto-Fixing Lint Issues
1121811319Before committing, auto-fix safe lint violations:
···12026pnpm --filter @atbb/appview lint:fix
12127```
12228123123-### Bypassing Hooks (Emergency Only)
124124-125125-In urgent situations, bypass hooks with:
126126-127127-```sh
128128-git commit --no-verify -m "emergency: your message"
129129-```
130130-131131-Use sparingly — hooks catch issues that would fail in CI.
132132-133133-## CI/CD
134134-135135-### GitHub Actions Workflows
136136-137137-**`.github/workflows/ci.yml`** — Runs on all pull requests (parallel jobs):
138138-- **Lint:** `pnpm exec oxlint .` — catches code quality issues
139139-- **Type Check:** `pnpm turbo lint` — verifies TypeScript types across all packages
140140-- **Test:** `pnpm test` — runs all tests with PostgreSQL 17 service container
141141-- **Build:** `pnpm build` — verifies compilation succeeds
142142-143143-**`.github/workflows/publish.yml`** — Runs on pushes to `main` branch:
144144-- Builds Docker image and publishes to GitHub Container Registry (GHCR)
145145-- Tags: `latest` (main branch) and `sha-<commit>` (specific commit)
146146-- Image: `ghcr.io/atbb-community/atbb:latest`
147147-148148-**All checks must pass before merging a PR.**
149149-150150-### How Hooks Work
151151-152152-- **Lefthook** manages git hooks (`lefthook.yml`)
153153-- **Oxlint** provides fast linting (`.oxlintrc.json`)
154154-- **Turbo** filters checks to affected packages only
155155-- Hooks auto-install after `pnpm install` via `prepare` script
156156-15729## Testing Standards
1583015931**CRITICAL: Always run tests before committing code or requesting code review.**
160160-161161-### Running Tests
162162-163163-```sh
164164-# Run all tests
165165-pnpm test
166166-167167-# Run tests for a specific package
168168-pnpm --filter @atbb/appview test
169169-170170-# Run tests in watch mode during development
171171-pnpm --filter @atbb/appview test --watch
172172-173173-# Run a specific test file
174174-pnpm --filter @atbb/appview test src/lib/__tests__/config.test.ts
175175-```
1763217733### Environment Variables in Tests
17834···277133278134**If you're unsure how to test something:** Leave a `// TODO: Add test for X` comment and create a Linear issue. Never commit a stub test that pretends to test something.
279135280280-### Example Test Structure
281281-282282-```typescript
283283-describe("createForumRoutes", () => {
284284- it("returns forum metadata when forum exists", async () => {
285285- // Arrange: Set up test context with mock data
286286- const ctx = await createTestContext();
287287-288288- // Act: Call the endpoint
289289- const res = await app.request("/api/forum");
290290-291291- // Assert: Verify response
292292- expect(res.status).toBe(200);
293293- const data = await res.json();
294294- expect(data.name).toBe("Test Forum");
295295- });
296296-297297- it("returns 404 when forum does not exist", async () => {
298298- // Test error case
299299- const ctx = await createTestContext({ emptyDb: true });
300300- const res = await app.request("/api/forum");
301301- expect(res.status).toBe(404);
302302- });
303303-});
304304-```
305136306137### Test Coverage Expectations
307138