# ATProto OAuth Application A full-stack ATProto microblogging application with OAuth authentication. Built with Elysia (backend) and React Router v7 (frontend) in a Bun workspace monorepo. ## Project Structure ``` watproto/ ├── packages/ │ ├── server/ # XRPC API server │ │ ├── src/ # Server source code │ │ ├── data/ # SQLite database │ │ └── CLAUDE.md # Server documentation │ ├── client/ # React Router v7 frontend (SSR) │ │ ├── app/ # React Router app │ │ ├── data/ # OAuth state database │ │ └── CLAUDE.md # Client documentation │ └── lexicon/ # ATProto lexicon types │ ├── types/ # Generated types │ └── index.ts # Type exports ├── lexicons/ # Lexicon schemas ├── package.json # Workspace configuration └── CLAUDE.md # Project-wide documentation ``` ## Tech Stack **Backend (Server)**: - Bun runtime - Elysia web framework - XRPC protocol (@atcute/xrpc-server) - SQLite + Kysely ORM **Frontend (Client)**: - React Router v7 (SSR) - ATProto OAuth (@atproto/oauth-client-node) - XRPC client (@atcute/client) - React 19 - Tailwind CSS v4 + DaisyUI - Vite **Shared**: - @watproto/lexicon - Lexicon type definitions and utils generated from lexicon schemas ## Quick Start ### Prerequisites - [Bun](https://bun.sh) v1.0+ ### Installation 1. Clone the repository: ```bash git clone cd watproto ``` 2. Install dependencies: ```bash bun install ``` 3. Create files for environment variables: **Server** (`packages/server/.env.local`): ```env PORT=3000 DATABASE_URL=./data/dev.db SERVICE_DID=did:web:localhost:3000 ``` **Client** (`packages/client/.env.local`): ```env CLIENT_URL=http://your.client.host API_URL=http://localhost:3000 DEFAULT_PDS_URL=https://your.pds.host DB_PATH=./data/state.db PORT=5173 AUTH_SECRET=your-random-secret-key-here KEYSERVER_DID=did:web:your.keyserver.host ``` Generate `AUTH_SECRET` with: `openssl rand -base64 32` To use OAuth in `localhost` do not define a `CLIENT_URL` here More on environment variables [below](#environment-variables) ### Development Run both server and client in separate terminals: **Terminal 1 - Server**: ```bash cd packages/server bun run dev ``` **Terminal 2 - Client**: ```bash cd packages/client bun run dev ``` Then you can open: - **Frontend**: http://127.0.0.1:5173 - **XRPC Server**: http://localhost:3000 ### Alternative: Run from Root You can also use workspace scripts from the root: ```bash # Start server only bun run dev # Start client only bun run dev:client # Build both packages bun run build # Type check all packages bun run typecheck ``` This has the advantage of being slightly easier to run, but logs will be slightly more cluttered. ## Project Commands ### Root Commands ```bash bun install # Install all workspace dependencies bun run dev # Start both server and client bun run dev:server # Start server only bun run dev:client # Start client only bun run build # Build client for production bun run typecheck # Type check all packages bun run lex # Generate TypeScript types from lexicon schemas ``` ### Server Commands (packages/server) ```bash bun run dev # Start development server (port 3000) bun run start # Start production server bun run debug # Start with debugger bun run db:codegen # Regenerate database types bun run db:migrate # Run database migrations bun run typecheck # Type check ``` ### Client Commands (packages/client) ```bash bun run dev # Start development server (port 5173) bun run build # Build for production bun run start # Start production server bun run lint # Run ESLint bun run typecheck # Type check ``` ## Features ### Current - ✅ ATProto OAuth authentication (client-side SSR) - ✅ Session management with SQLite - ✅ XRPC server and client communication - ✅ Post creation and storage (public and private) - ✅ Tag system for posts - ✅ User authentication UI (login flow) - ✅ Basic UI components (Header, PostFeed, UserMenu) - ✅ Lexicon type generation - ✅ React Router v7 frontend with SSR - ✅ Tailwind CSS + DaisyUI styling - ✅ TypeScript throughout ### Planned - 🚧 ATProto feed aggregation and timeline - 🚧 User profile pages - 🚧 Media upload (images/videos) - 🚧 Real-time updates via WebSockets - 🚧 Background job processing - 🚧 Full-text search - 🚧 Multi-account support ## Architecture ### Backend (packages/server) - **Framework**: Elysia (fast, type-safe web framework) - **Protocol**: XRPC (ATProto RPC protocol) - **Database**: SQLite with Kysely query builder - **Features**: Post storage, account management, ID resolution ### Frontend (packages/client) - **Framework**: React Router v7 (with SSR) - **OAuth**: ATProto OAuth Client (server-side) - **Database**: SQLite for OAuth state - **Routing**: File-based routes in `app/routes/` - **Styling**: Tailwind CSS v4 + DaisyUI - **Build**: Vite ### Shared (packages/lexicon) - **Purpose**: ATProto lexicon type definitions - **Generator**: @atcute/lex-cli - **Usage**: Shared types across server and client ### Communication - Client ↔ Server: XRPC protocol over HTTP - Authentication: OAuth managed by client SSR - Session: SQLite database with httpOnly cookies ## Deployment ### Server Deploy to Node/Bun compatible hosting: - [Fly.io](https://fly.io) - [Railway](https://railway.app) - [Render](https://render.com) ### Client Deploy to static hosting: - [Vercel](https://vercel.com) - [Netlify](https://netlify.com) - [Cloudflare Pages](https://pages.cloudflare.com) ### Environment Variables Configure production environment variables in your hosting provider: **Server**: - `PORT` - Server port (default: 3000) - `DATABASE_URL` - SQLite database path - `SERVICE_DID` - DID that points to this service (required) **Client**: - `API_URL` - XRPC server URL (required) - `DEFAULT_PDS_URL` - Default PDS URL for OAuth (required) - `AUTH_SECRET` - Session encryption secret (required) - `KEYSERVER_DID` - DID that poins to a [Keyserver](https://tangled.org/@djara.dev/atp-keyserver) for encryption / decryption (required) - Optional: `CLIENT_URL`, `DB_PATH`, `PORT` **Important**: Client requires SSR-capable hosting with writable filesystem for OAuth database ## Documentation Detailed documentation is available in CLAUDE.md files: - **Root**: `CLAUDE.md` - Monorepo overview and workflow - **Server**: `packages/server/CLAUDE.md` - Backend architecture and patterns - **Client**: `packages/client/CLAUDE.md` - Frontend architecture and patterns ## Development Workflow ### Adding a Backend Feature 1. Navigate to `packages/server` 2. Create/modify XRPC procedures in `src/` 3. Add database migrations if needed 4. Test with `bun run dev` 5. See `packages/server/CLAUDE.md` for patterns ### Adding a Frontend Feature 1. Navigate to `packages/client` 2. Create route file in `app/routes/` 3. Create components as needed 4. Style with Tailwind CSS + DaisyUI 5. Test with `bun run dev` 6. See `packages/client/CLAUDE.md` for patterns ### Working with Lexicons ```bash # Add or modify lexicon schemas in lexicons/ directory # Then regenerate TypeScript types: bun run lex # Types are generated in packages/lexicon/types/ # Available via: import { Watproto } from '@watproto/lexicon' ``` ### Database Migrations ```bash cd packages/server # Create migration file manually in src/db/migrations/ # Then regenerate types: bun run db:codegen ``` ## Troubleshooting **Port already in use**: - Change `PORT` in `packages/server/.env.local` - Client will auto-increment port if 5173 is taken **CORS errors**: - Ensure server CORS allows client origin - Check `API_URL` in client environment variables matches server URL **Type errors**: - Run `bun install` at root to sync workspace - Run `bun run typecheck` to find issues **Database issues**: - Delete `packages/server/data/*.db*` files - Restart server to recreate database ## License MIT ## Contributing See CLAUDE.md for development guidelines and architecture patterns.