# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is an ATProto OAuth application monorepo with separate frontend and backend packages. The backend is an XRPC server built with Elysia, and the frontend is built with React Router v7 (SSR) handling OAuth authentication. **Current Status**: Core functionality implemented. OAuth authentication working on client-side (SSR), XRPC server operational, post creation and storage functional. This is a full-stack ATProto microblogging application with ATProto-native architecture. ## Monorepo Structure This project is organized as a Bun workspace monorepo: ``` watproto/ ├── packages/ │ ├── server/ # XRPC API server (ATProto endpoints, post storage) │ │ ├── src/ # Server source code │ │ │ ├── db/ # Database migrations and schema │ │ │ └── lib/ # XRPC server, ID resolver, utilities │ │ ├── data/ # SQLite database files │ │ ├── CLAUDE.md # Server-specific documentation │ │ └── package.json # Server dependencies │ ├── client/ # React Router v7 frontend (SSR with OAuth) │ │ ├── app/ # React Router application code │ │ │ ├── routes/ # File-based routes (login, editor, oauth) │ │ │ ├── components/ # React components (Header, PostFeed, etc.) │ │ │ └── lib/ # OAuth client, XRPC client, DB, utilities │ │ ├── data/ # SQLite database (OAuth state storage) │ │ ├── CLAUDE.md # Client-specific documentation │ │ └── package.json # Client dependencies │ └── lexicon/ # ATProto lexicon type definitions │ ├── types/ # Generated TypeScript types │ ├── index.ts # Lexicon exports │ └── package.json # Package configuration ├── lexicons/ # ATProto lexicon schemas (JSON) ├── lex.config.js # Lexicon generation configuration ├── lexicons.json # Lexicon metadata ├── package.json # Workspace root configuration ├── tsconfig.root.json # Base TypeScript configuration ├── CLAUDE.md # This file (monorepo-wide documentation) └── README.md # Project setup and usage instructions ``` **Current Architecture**: ``` React Router Frontend (SSR) - packages/client ├── OAuth Client (ATProto OAuth flow) ├── Session Management (SQLite state DB) └── XRPC Client ↓ XRPC calls (ATProto RPC protocol) XRPC Server - packages/server ├── Post Storage (public/private posts, tags) ├── Account Management └── ID Resolution ↓ ATProto operations ATProto Network ``` ## Common Commands ### Typical Development Workflow 1. **Terminal 1** (Server): `cd packages/server && bun run dev` 2. **Terminal 2** (Client): `cd packages/client && bun run dev` 3. **Access**: Open http://127.0.0.1:5173 in browser ### Workspace Commands (from root) - `bun install` - Install dependencies for all packages - `bun run dev` - Start both server and client in development mode - `bun run dev:server` - Start server only (port 3000) - `bun run dev:client` - Start client only (port 5173) - `bun run build` - Build client for production - `bun run typecheck` - Type check all packages - `bun run lex` - Generate TypeScript types from ATProto lexicons ### Server Commands (from packages/server) - `bun run dev` - Start development server with hot reload on port 3000 - `bun run start` - Start production server - `bun run debug` - Start server with Bun debugger - `bun run db:codegen` - Regenerate database schema types from database - `bun run db:migrate` - Run database migrations manually - `bun run typecheck` - Run TypeScript type checking ### Client Commands (from packages/client) - `bun run dev` - Start development server with hot reload (port 5173) - `bun run build` - Build production bundle - `bun run start` - Start production server - `bun run lint` - Run ESLint - `bun run typecheck` - Run TypeScript type checking ## Architecture ### Core Stack **Backend (packages/server)**: - **Runtime**: Bun - **Web Framework**: Elysia (type-safe, fast web framework) - **Protocol**: XRPC (ATProto RPC) via @atcute/xrpc-server - **Database**: SQLite with Kysely query builder - **Features**: Post storage, account management, ID resolution - **TypeScript**: Strict mode enabled with path aliases **Frontend (packages/client)**: - **Runtime**: Bun - **Framework**: React Router v7 (file-based routing, SSR) - **OAuth**: ATProto OAuth Client (Node implementation) - runs in SSR - **Database**: SQLite for OAuth session state (server-side) - **Protocol**: XRPC client via @atcute/client - **Identity Resolution**: @atcute/identity-resolver + @atcute/identity (DID/handle resolution) - **UI Library**: React 19 - **Styling**: Tailwind CSS v4 + DaisyUI - **Build Tool**: Vite - **TypeScript**: Strict mode enabled with path aliases **Shared (packages/lexicon)**: - **Purpose**: ATProto lexicon type definitions - **Generator**: @atcute/lex-cli - **Source**: Lexicon schemas in `lexicons/` directory **Deployment Strategy**: - Client: SSR deployment (Vercel, Netlify with SSR, Cloudflare Pages) - Note: Requires SSR support due to OAuth and database - Server: Node/Bun hosting (Fly.io, Railway, etc.) - Communication: XRPC protocol (not REST) ### OAuth Flow Architecture **Client implements ATProto OAuth in SSR** (see `packages/client/CLAUDE.md` for details): 1. **Login**: User visits `/login` route, enters handle 2. **OAuth Flow**: React Router SSR initiates OAuth with ATProto 3. **Callback**: `/oauth/$` route handles callback, stores session in SQLite 4. **Session**: Session stored in client's database (data/state.db) 5. **Protected Routes**: Loader functions check session before rendering **Architecture Notes**: - OAuth client runs in React Router's SSR layer (Node.js context) - Session state stored in SQLite database on client server - Uses @atproto/oauth-client-node for ATProto OAuth flow - XRPC client uses authenticated sessions for API calls to server ### Database Architecture **Server Database** (`packages/server/data/`): - **Location**: SQLite with WAL mode - **Tables**: - `accounts` - User accounts with DID, handle, metadata - `public_posts` - Public posts visible to all - `private_posts` - Private posts for account holders - `tags` - Tag associations for posts - **Details**: See `packages/server/CLAUDE.md` for full schema **Client Database** (`packages/client/data/`): - **Location**: SQLite database for OAuth state - **Purpose**: Store OAuth sessions, states, and tokens - **Implementation**: Managed by @atproto/oauth-client-node - **Details**: See `packages/client/CLAUDE.md` for session management ### Environment Variables **Server** (`packages/server/.env.local`): - `PORT` - Server port (default: 3000) - `DATABASE_URL` - SQLite database path (default: ':memory:') - `SERVICE_DID` - DID that points to this service (required) **Client** (`packages/client/.env.local`): - `CLIENT_URL` - Client URL (optional) - `API_URL` - XRPC server API URL (required, e.g., http://localhost:3000) - `DEFAULT_PDS_URL` - Default PDS URL for OAuth (required) - `DB_PATH` - SQLite database path (default: './data/state.db') - `PORT` - Client server port (default: 5173) - `AUTH_SECRET` - Secret for session encryption (required) - `KEYSERVER_DID` - DID that poins to a [Keyserver](https://tangled.org/@djara.dev/atp-keyserver) for encryption / decryption (required) ## Package-Specific Documentation For detailed implementation information, refer to the package-specific CLAUDE.md files: - **Server**: `packages/server/CLAUDE.md` - XRPC server implementation - Database patterns and migrations - Post storage and retrieval - Social graph (follow relationships) - Profile management (wafrn-specific + caching) - Account management (operational data) - ID resolution - **Client**: `packages/client/CLAUDE.md` - React Router v7 routing patterns - OAuth authentication flow (SSR) - XRPC client integration - Component architecture - Session management - Styling with Tailwind CSS + DaisyUI - **Lexicon**: `packages/lexicon/` - ATProto lexicon type definitions - Generated from schemas in `lexicons/` directory - Shared types across server and client ## Working with the Monorepo ### Adding New Features **Backend API Endpoint**: 1. Navigate to `packages/server` 2. Create route handler in `src/` (or add to existing routes) 3. Test with `bun run dev` 4. See `packages/server/CLAUDE.md` for patterns **Frontend Feature**: 1. Navigate to `packages/client` 2. Create route in `app/routes/` (file-based routing) 3. Create components in `app/components/` 4. Test with `bun run dev` 5. See `packages/client/CLAUDE.md` for patterns ### Path Aliases The monorepo uses TypeScript path aliases for cleaner imports: **Configured in `tsconfig.root.json`:** - `@api/*` → `packages/server/src/*` - Server internal imports - `@www/*` → `packages/client/app/*` - Client internal imports **Server Usage** (`packages/server`): ```typescript import { db } from '@api/db/db' import env from '@api/lib/env' import { createOrUpdateAccount } from '@api/lib/account' import { xrpcServer } from '@api/lib/xrpcServer' ``` **Client Usage** (`packages/client`): ```typescript // Client internal imports import { Header } from '@www/components/Header' import { xrpcClient } from '@www/lib/xrpcClient' // Import server types (type-only imports) import type { Account } from '@api/db/schema' ``` **Lexicon Usage** (both packages): ```typescript import { Watproto } from '@watproto/lexicon' ``` **Benefits:** - Clean, consistent import paths across the monorepo - No relative path traversal (`../../..`) - Type sharing between packages via workspace dependencies - Vite and Bun automatically resolve these paths **Note:** Lexicon package is a workspace dependency used by both server and client. ## Current Features & Future Expansion ### Implemented - ✅ ATProto OAuth authentication (client-side SSR) - ✅ Session management with SQLite - ✅ XRPC server and client - ✅ Post creation and storage (public and private) - ✅ Post deletion (transactional, removes post and associated tags) - ✅ Tag system for posts - ✅ User authentication flow - ✅ UI components - Header, PostFeed, UserMenu - GlobalSpinner (navigation state feedback) - Delete post button (visible to post authors only) - ✅ Lexicon type generation - ✅ Social graph (follow relationships) - Follow/unfollow operations with transaction-safe count updates - Follower and following list queries (returns DIDs for batch enrichment) - Denormalized follow counts for fast profile queries - Federation-friendly (no foreign key constraints) - ✅ Profile system (separated architecture) - Operational account data (roles, status, moderation) - Wafrn-specific profile customization (HTML bio, custom fields) - Optional standard profile caching for performance - Batch profile queries for efficient rendering ### Planned Features - **Job Queue & Workers**: Background processing for posts, firehose consumption, timelines - **Real-time Features**: WebSocket support for notifications and live updates - **Media Upload**: Image and video upload with ATProto blob storage - **Timeline Algorithm**: Personalized feed ranking and filtering - **Search**: Full-text search for posts and user profiles - **Multi-Account Support**: Support being logged in to more than one account at the same time See package-specific CLAUDE.md files for detailed implementation plans. ## Getting Started with your local copy 1. **Clone and install**: ```bash git clone cd watproto bun install ``` 2. **Configure environment variables**: use the examples in this file 3. **Start development**: ```bash # Terminal 1: Start server cd packages/server bun run dev # Terminal 2: Start client cd packages/client bun run dev ``` 4. **Access the application**: - Client: http://127.0.0.1:5173 - Server API: http://localhost:4000 - API Docs: http://localhost:4000/openapi ## Troubleshooting - **Port conflicts**: Change `PORT` in server .env.local or client will use next available port - **CORS errors**: Ensure server CORS is configured to allow client origin - **Type errors**: Run `bun install` at root to sync workspace dependencies - **Database issues**: If your local `packages/server/data/*.db*` files do not have important information you can just delete them and restart your server. Database files will be created from scratch. For package-specific issues, see the CLAUDE.md file in that package.