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

Merge pull request #5 from malpercio-dev/claude/reorganize-monorepo-structure-mDKmb

refactor: reorganize monorepo into apps/ and packages/ directories

authored by

Malpercio and committed by
GitHub
eae0f515 43c8564c

+139 -67
+19 -7
CLAUDE.md
··· 4 4 5 5 The master project plan with MVP phases and progress tracking lives at `docs/atproto-forum-plan.md`. 6 6 7 - ## Packages 7 + ## Apps & Packages 8 8 9 - | Package | Description | Port | 10 - |---------|-------------|------| 11 - | `@atbb/lexicon` | AT Proto lexicon definitions (YAML) + generated TypeScript types | — | 9 + ### Apps (`apps/`) 10 + 11 + Servers and applications that are deployed or run as services. 12 + 13 + | App | Description | Port | 14 + |-----|-------------|------| 12 15 | `@atbb/appview` | Hono JSON API server — indexes forum data, serves API | 3000 | 13 16 | `@atbb/web` | Hono JSX + HTMX server-rendered web UI — calls appview API | 3001 | 14 - | `@atbb/spike` | PDS read/write test script for validating AT Proto operations | — | 15 17 16 - **Dependency chain:** `@atbb/lexicon` builds first (generates types), then `@atbb/appview` and `@atbb/web` build in parallel. Turbo handles this via `^build`. 18 + ### Packages (`packages/`) 19 + 20 + Shared libraries, tools, and utilities consumed by apps or used standalone. 21 + 22 + | Package | Description | 23 + |---------|-------------| 24 + | `@atbb/db` | Drizzle ORM schema and connection factory for PostgreSQL | 25 + | `@atbb/lexicon` | AT Proto lexicon definitions (YAML) + generated TypeScript types | 26 + | `@atbb/spike` | PDS read/write test script for validating AT Proto operations | 27 + 28 + **Dependency chain:** `@atbb/lexicon` and `@atbb/db` build first, then `@atbb/appview` and `@atbb/web` build in parallel. Turbo handles this via `^build`. 17 29 18 30 ## Development 19 31 ··· 68 80 69 81 - **`@types/node` is required** as a devDependency in every package that uses `process.env` or other Node APIs. `tsx` doesn't need it at runtime, but `tsc` builds will fail without it. 70 82 - **Hono JSX `children`:** Use `PropsWithChildren<T>` from `hono/jsx` for components that accept children. Unlike React, Hono's `FC<T>` does not include `children` implicitly. 71 - - **HTMX attributes in JSX:** The `typed-htmx` package provides types for `hx-*` attributes. See `packages/web/src/global.d.ts` for the augmentation. 83 + - **HTMX attributes in JSX:** The `typed-htmx` package provides types for `hx-*` attributes. See `apps/web/src/global.d.ts` for the augmentation. 72 84 - **Glob expansion in npm scripts:** `@atproto/lex-cli` needs file paths, not globs. Use `bash -c 'shopt -s globstar && ...'` to expand `**/*.json` in npm scripts. 73 85 - **`.env` loading:** Dev and spike scripts use Node's `--env-file=../../.env` flag to load the root `.env` file. No `dotenv` dependency needed. 74 86
+11 -3
README.md
··· 26 26 27 27 User-generated content (posts, reactions, memberships) lives on each user's PDS. Forum metadata (categories, roles, mod actions) lives on a dedicated Forum Service Account. The AppView indexes both into a unified view. 28 28 29 - ## Packages 29 + ## Apps & Packages 30 30 31 31 This is a [Turborepo](https://turbo.build/) monorepo with [pnpm](https://pnpm.io/) workspaces. 32 32 33 + ### Apps (`apps/`) 34 + 35 + | App | Description | 36 + |-----|-------------| 37 + | [`apps/appview`](apps/appview) | Hono-based JSON API server | 38 + | [`apps/web`](apps/web) | Server-rendered web UI (Hono JSX + HTMX) | 39 + 40 + ### Packages (`packages/`) 41 + 33 42 | Package | Description | 34 43 |---------|-------------| 44 + | [`packages/db`](packages/db) | Drizzle ORM schema and connection factory for PostgreSQL | 35 45 | [`packages/lexicon`](packages/lexicon) | AT Proto lexicon schemas (YAML) and generated TypeScript types | 36 - | [`packages/appview`](packages/appview) | Hono-based JSON API server | 37 - | [`packages/web`](packages/web) | Server-rendered web UI (Hono JSX + HTMX) | 38 46 | [`packages/spike`](packages/spike) | PDS read/write test script | 39 47 40 48 ## Getting Started
+1 -1
docs/atproto-forum-plan.md
··· 139 139 - [x] Audit existing `space.atbb.*` lexicons — **Result:** 2 existing (`forum.forum`, `post`), 5 new needed for MVP. No separate topic type; unified post model with reply refs. 140 140 - [x] Review prior Rust AppView — **Result:** Axum/SQLx scaffold with jetstream-oxide firehose, minimal DB schema. Reference for route structure and Docker setup; MVP will be Node/TS rewrite. 141 141 - [x] Define new lexicons in YAML: `forum.category`, `forum.role`, `membership`, `reaction`, `modAction` — **Result:** All 5 defined in `packages/lexicon/lexicons/`, with YAML→JSON→TypeScript build pipeline via `@atproto/lex-cli`. 142 - - [x] Set up project scaffolding: monorepo with `packages/lexicon`, `packages/appview`, `packages/web` — **Result:** Turborepo + pnpm workspaces, devenv for Nix toolchain. AppView (Hono JSON API, port 3000), Web (Hono JSX + HTMX, port 3001), plus `packages/spike` for PDS testing. 142 + - [x] Set up project scaffolding: monorepo with `packages/lexicon`, `apps/appview`, `apps/web` — **Result:** Turborepo + pnpm workspaces, devenv for Nix toolchain. AppView (Hono JSON API, port 3000), Web (Hono JSX + HTMX, port 3001), plus `packages/spike` for PDS testing. Apps live in `apps/`, shared libraries in `packages/`. 143 143 - [ ] Create Forum Service Account (generate DID, set up PDS or use existing hosting) 144 144 - [ ] Spike: write a test record to a PDS, read it back via AT Proto API — **Note:** Script written in `packages/spike`, ready to run once PDS credentials are configured in `.env`. 145 145
+22 -22
docs/plans/2026-02-06-database-schema-design.md
··· 13 13 ### Task 1: Install Drizzle dependencies 14 14 15 15 **Files:** 16 - - Modify: `packages/appview/package.json` 16 + - Modify: `apps/appview/package.json` 17 17 18 18 **Step 1: Add runtime dependencies** 19 19 ··· 46 46 **Step 4: Commit** 47 47 48 48 ```bash 49 - git add packages/appview/package.json pnpm-lock.yaml 49 + git add apps/appview/package.json pnpm-lock.yaml 50 50 git commit -m "feat(appview): add drizzle-orm and postgres dependencies" 51 51 ``` 52 52 ··· 55 55 ### Task 2: Define the database schema 56 56 57 57 **Files:** 58 - - Create: `packages/appview/src/db/schema.ts` 58 + - Create: `apps/appview/src/db/schema.ts` 59 59 60 60 **Step 1: Create the schema file** 61 61 62 - Create `packages/appview/src/db/schema.ts` with the full schema: 62 + Create `apps/appview/src/db/schema.ts` with the full schema: 63 63 64 64 ```typescript 65 65 import { ··· 223 223 **Step 3: Commit** 224 224 225 225 ```bash 226 - git add packages/appview/src/db/schema.ts 226 + git add apps/appview/src/db/schema.ts 227 227 git commit -m "feat(appview): define database schema for all 6 tables" 228 228 ``` 229 229 ··· 232 232 ### Task 3: Create the database connection module 233 233 234 234 **Files:** 235 - - Create: `packages/appview/src/db/index.ts` 236 - - Modify: `packages/appview/src/lib/config.ts` 235 + - Create: `apps/appview/src/db/index.ts` 236 + - Modify: `apps/appview/src/lib/config.ts` 237 237 238 238 **Step 1: Add DATABASE_URL to config** 239 239 240 - Modify `packages/appview/src/lib/config.ts` to add `databaseUrl`: 240 + Modify `apps/appview/src/lib/config.ts` to add `databaseUrl`: 241 241 242 242 ```typescript 243 243 export interface AppConfig { ··· 259 259 260 260 **Step 2: Create the database connection module** 261 261 262 - Create `packages/appview/src/db/index.ts`: 262 + Create `apps/appview/src/db/index.ts`: 263 263 264 264 ```typescript 265 265 import { drizzle } from "drizzle-orm/postgres-js"; ··· 287 287 **Step 4: Commit** 288 288 289 289 ```bash 290 - git add packages/appview/src/db/index.ts packages/appview/src/lib/config.ts 290 + git add apps/appview/src/db/index.ts apps/appview/src/lib/config.ts 291 291 git commit -m "feat(appview): add database connection module and DATABASE_URL config" 292 292 ``` 293 293 ··· 296 296 ### Task 4: Configure drizzle-kit and generate migrations 297 297 298 298 **Files:** 299 - - Create: `packages/appview/drizzle.config.ts` 299 + - Create: `apps/appview/drizzle.config.ts` 300 300 301 301 **Step 1: Create drizzle-kit config** 302 302 303 - Create `packages/appview/drizzle.config.ts`: 303 + Create `apps/appview/drizzle.config.ts`: 304 304 305 305 ```typescript 306 306 import { defineConfig } from "drizzle-kit"; ··· 314 314 315 315 **Step 2: Add migration scripts to package.json** 316 316 317 - Add to `packages/appview/package.json` scripts: 317 + Add to `apps/appview/package.json` scripts: 318 318 319 319 ```json 320 320 { ··· 331 331 pnpm --filter @atbb/appview db:generate 332 332 ``` 333 333 334 - Expected: a migration SQL file appears in `packages/appview/drizzle/` with CREATE TABLE statements for all 6 tables. 334 + Expected: a migration SQL file appears in `apps/appview/drizzle/` with CREATE TABLE statements for all 6 tables. 335 335 336 336 **Step 4: Inspect the generated SQL** 337 337 338 - Read the generated `.sql` file in `packages/appview/drizzle/` and verify it contains: 338 + Read the generated `.sql` file in `apps/appview/drizzle/` and verify it contains: 339 339 - 6 CREATE TABLE statements (forums, categories, users, memberships, posts, mod_actions) 340 340 - All UNIQUE indexes on (did, rkey) 341 341 - All additional indexes (posts.forum_uri, posts.root_post_id, memberships.did) ··· 344 344 **Step 5: Commit** 345 345 346 346 ```bash 347 - git add packages/appview/drizzle.config.ts packages/appview/drizzle/ packages/appview/package.json 347 + git add apps/appview/drizzle.config.ts apps/appview/drizzle/ apps/appview/package.json 348 348 git commit -m "feat(appview): add drizzle-kit config and generate initial migration" 349 349 ``` 350 350 ··· 446 446 447 447 | Action | File | 448 448 |--------|------| 449 - | Modify | `packages/appview/package.json` (deps + scripts) | 450 - | Create | `packages/appview/src/db/schema.ts` | 451 - | Create | `packages/appview/src/db/index.ts` | 452 - | Modify | `packages/appview/src/lib/config.ts` | 453 - | Create | `packages/appview/drizzle.config.ts` | 454 - | Create | `packages/appview/drizzle/*.sql` (generated) | 449 + | Modify | `apps/appview/package.json` (deps + scripts) | 450 + | Create | `apps/appview/src/db/schema.ts` | 451 + | Create | `apps/appview/src/db/index.ts` | 452 + | Modify | `apps/appview/src/lib/config.ts` | 453 + | Create | `apps/appview/drizzle.config.ts` | 454 + | Create | `apps/appview/drizzle/*.sql` (generated) | 455 455 | Modify | `.env.example` | 456 456 | Create | `docs/plans/2026-02-06-database-schema-design.md` |
+1 -1
packages/appview/drizzle.config.ts apps/appview/drizzle.config.ts
··· 1 1 import { defineConfig } from "drizzle-kit"; 2 2 3 3 export default defineConfig({ 4 - schema: "./src/db/schema.ts", 4 + schema: "../../packages/db/src/schema.ts", 5 5 out: "./drizzle", 6 6 dialect: "postgresql", 7 7 dbCredentials: {
packages/appview/drizzle/0000_lovely_roland_deschain.sql apps/appview/drizzle/0000_lovely_roland_deschain.sql
packages/appview/drizzle/meta/0000_snapshot.json apps/appview/drizzle/meta/0000_snapshot.json
packages/appview/drizzle/meta/_journal.json apps/appview/drizzle/meta/_journal.json
+2 -3
packages/appview/package.json apps/appview/package.json
··· 13 13 "db:migrate": "drizzle-kit migrate" 14 14 }, 15 15 "dependencies": { 16 + "@atbb/db": "workspace:*", 16 17 "@atbb/lexicon": "workspace:*", 17 18 "@atproto/api": "^0.15.0", 18 19 "@atproto/common-web": "^0.4.0", 19 20 "@hono/node-server": "^1.14.0", 20 - "drizzle-orm": "^0.45.1", 21 - "hono": "^4.7.0", 22 - "postgres": "^3.4.8" 21 + "hono": "^4.7.0" 23 22 }, 24 23 "devDependencies": { 25 24 "@types/node": "^22.0.0",
packages/appview/src/db/index.ts packages/db/src/index.ts
packages/appview/src/db/schema.ts packages/db/src/schema.ts
packages/appview/src/index.ts apps/appview/src/index.ts
packages/appview/src/lib/atproto.ts apps/appview/src/lib/atproto.ts
packages/appview/src/lib/config.ts apps/appview/src/lib/config.ts
packages/appview/src/routes/categories.ts apps/appview/src/routes/categories.ts
packages/appview/src/routes/forum.ts apps/appview/src/routes/forum.ts
packages/appview/src/routes/health.ts apps/appview/src/routes/health.ts
packages/appview/src/routes/index.ts apps/appview/src/routes/index.ts
packages/appview/src/routes/posts.ts apps/appview/src/routes/posts.ts
packages/appview/src/routes/topics.ts apps/appview/src/routes/topics.ts
packages/appview/tsconfig.json apps/appview/tsconfig.json
+31
packages/db/package.json
··· 1 + { 2 + "name": "@atbb/db", 3 + "version": "0.1.0", 4 + "private": true, 5 + "type": "module", 6 + "main": "./dist/index.js", 7 + "types": "./dist/index.d.ts", 8 + "exports": { 9 + ".": { 10 + "types": "./dist/index.d.ts", 11 + "default": "./dist/index.js" 12 + }, 13 + "./schema": { 14 + "types": "./dist/schema.d.ts", 15 + "default": "./dist/schema.js" 16 + } 17 + }, 18 + "scripts": { 19 + "build": "tsc", 20 + "lint": "tsc --noEmit", 21 + "clean": "rm -rf dist" 22 + }, 23 + "dependencies": { 24 + "drizzle-orm": "^0.45.1", 25 + "postgres": "^3.4.8" 26 + }, 27 + "devDependencies": { 28 + "@types/node": "^22.0.0", 29 + "typescript": "^5.7.0" 30 + } 31 + }
+8
packages/db/tsconfig.json
··· 1 + { 2 + "extends": "../../tsconfig.base.json", 3 + "compilerOptions": { 4 + "outDir": "./dist", 5 + "rootDir": "./src" 6 + }, 7 + "include": ["src/**/*.ts"] 8 + }
packages/web/package.json apps/web/package.json
packages/web/src/global.d.ts apps/web/src/global.d.ts
packages/web/src/index.ts apps/web/src/index.ts
packages/web/src/layouts/base.tsx apps/web/src/layouts/base.tsx
packages/web/src/lib/api.ts apps/web/src/lib/api.ts
packages/web/src/lib/config.ts apps/web/src/lib/config.ts
packages/web/src/routes/home.tsx apps/web/src/routes/home.tsx
packages/web/src/routes/index.ts apps/web/src/routes/index.ts
packages/web/tsconfig.json apps/web/tsconfig.json
+43 -30
pnpm-lock.yaml
··· 15 15 specifier: ^5.7.0 16 16 version: 5.9.3 17 17 18 - packages/appview: 18 + apps/appview: 19 19 dependencies: 20 + '@atbb/db': 21 + specifier: workspace:* 22 + version: link:../../packages/db 20 23 '@atbb/lexicon': 21 24 specifier: workspace:* 22 - version: link:../lexicon 25 + version: link:../../packages/lexicon 23 26 '@atproto/api': 24 27 specifier: ^0.15.0 25 28 version: 0.15.27 ··· 29 32 '@hono/node-server': 30 33 specifier: ^1.14.0 31 34 version: 1.19.9(hono@4.11.8) 32 - drizzle-orm: 33 - specifier: ^0.45.1 34 - version: 0.45.1(postgres@3.4.8) 35 35 hono: 36 36 specifier: ^4.7.0 37 37 version: 4.11.8 38 - postgres: 39 - specifier: ^3.4.8 40 - version: 3.4.8 41 38 devDependencies: 42 39 '@types/node': 43 40 specifier: ^22.0.0 ··· 52 49 specifier: ^5.7.0 53 50 version: 5.9.3 54 51 52 + apps/web: 53 + dependencies: 54 + '@hono/node-server': 55 + specifier: ^1.14.0 56 + version: 1.19.9(hono@4.11.8) 57 + hono: 58 + specifier: ^4.7.0 59 + version: 4.11.8 60 + devDependencies: 61 + '@types/node': 62 + specifier: ^22.0.0 63 + version: 22.19.9 64 + tsx: 65 + specifier: ^4.0.0 66 + version: 4.21.0 67 + typed-htmx: 68 + specifier: ^0.3.0 69 + version: 0.3.1 70 + typescript: 71 + specifier: ^5.7.0 72 + version: 5.9.3 73 + 74 + packages/db: 75 + dependencies: 76 + drizzle-orm: 77 + specifier: ^0.45.1 78 + version: 0.45.1(postgres@3.4.8) 79 + postgres: 80 + specifier: ^3.4.8 81 + version: 3.4.8 82 + devDependencies: 83 + '@types/node': 84 + specifier: ^22.0.0 85 + version: 22.19.9 86 + typescript: 87 + specifier: ^5.7.0 88 + version: 5.9.3 89 + 55 90 packages/lexicon: 56 91 devDependencies: 57 92 '@atproto/lex-cli': ··· 85 120 tsx: 86 121 specifier: ^4.0.0 87 122 version: 4.21.0 88 - typescript: 89 - specifier: ^5.7.0 90 - version: 5.9.3 91 - 92 - packages/web: 93 - dependencies: 94 - '@hono/node-server': 95 - specifier: ^1.14.0 96 - version: 1.19.9(hono@4.11.8) 97 - hono: 98 - specifier: ^4.7.0 99 - version: 4.11.8 100 - devDependencies: 101 - '@types/node': 102 - specifier: ^22.0.0 103 - version: 22.19.9 104 - tsx: 105 - specifier: ^4.0.0 106 - version: 4.21.0 107 - typed-htmx: 108 - specifier: ^0.3.0 109 - version: 0.3.1 110 123 typescript: 111 124 specifier: ^5.7.0 112 125 version: 5.9.3
+1
pnpm-workspace.yaml
··· 1 1 packages: 2 + - "apps/*" 2 3 - "packages/*"