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#
- Terminal 1 (Server):
cd packages/server && bun run dev - Terminal 2 (Client):
cd packages/client && bun run dev - Access: Open http://127.0.0.1:5173 in browser
Workspace Commands (from root)#
bun install- Install dependencies for all packagesbun run dev- Start both server and client in development modebun run dev:server- Start server only (port 3000)bun run dev:client- Start client only (port 5173)bun run build- Build client for productionbun run typecheck- Type check all packagesbun run lex- Generate TypeScript types from ATProto lexicons
Server Commands (from packages/server)#
bun run dev- Start development server with hot reload on port 3000bun run start- Start production serverbun run debug- Start server with Bun debuggerbun run db:codegen- Regenerate database schema types from databasebun run db:migrate- Run database migrations manuallybun 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 bundlebun run start- Start production serverbun run lint- Run ESLintbun 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):
- Login: User visits
/loginroute, enters handle - OAuth Flow: React Router SSR initiates OAuth with ATProto
- Callback:
/oauth/$route handles callback, stores session in SQLite - Session: Session stored in client's database (data/state.db)
- 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, metadatapublic_posts- Public posts visible to allprivate_posts- Private posts for account holderstags- Tag associations for posts
- Details: See
packages/server/CLAUDE.mdfor 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.mdfor 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 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:
- Navigate to
packages/server - Create route handler in
src/(or add to existing routes) - Test with
bun run dev - See
packages/server/CLAUDE.mdfor patterns
Frontend Feature:
- Navigate to
packages/client - Create route in
app/routes/(file-based routing) - Create components in
app/components/ - Test with
bun run dev - See
packages/client/CLAUDE.mdfor 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):
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):
// 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):
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#
-
Clone and install:
git clone <repo-url> cd watproto bun install -
Configure environment variables: use the examples in this file
-
Start development:
# Terminal 1: Start server cd packages/server bun run dev # Terminal 2: Start client cd packages/client bun run dev -
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
PORTin 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 installat 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.