1# ATProto OAuth Application
2
3A full-stack ATProto microblogging application with OAuth authentication. Built with Elysia (backend) and React Router v7 (frontend) in a Bun workspace monorepo.
4
5## Project Structure
6
7```
8watproto/
9├── packages/
10│ ├── server/ # XRPC API server
11│ │ ├── src/ # Server source code
12│ │ ├── data/ # SQLite database
13│ │ └── CLAUDE.md # Server documentation
14│ ├── client/ # React Router v7 frontend (SSR)
15│ │ ├── app/ # React Router app
16│ │ ├── data/ # OAuth state database
17│ │ └── CLAUDE.md # Client documentation
18│ └── lexicon/ # ATProto lexicon types
19│ ├── types/ # Generated types
20│ └── index.ts # Type exports
21├── lexicons/ # Lexicon schemas
22├── package.json # Workspace configuration
23└── CLAUDE.md # Project-wide documentation
24```
25
26## Tech Stack
27
28**Backend (Server)**:
29- Bun runtime
30- Elysia web framework
31- XRPC protocol (@atcute/xrpc-server)
32- SQLite + Kysely ORM
33
34**Frontend (Client)**:
35- React Router v7 (SSR)
36- ATProto OAuth (@atproto/oauth-client-node)
37- XRPC client (@atcute/client)
38- React 19
39- Tailwind CSS v4 + DaisyUI
40- Vite
41
42**Shared**:
43- @watproto/lexicon - Lexicon type definitions and utils generated from lexicon schemas
44
45## Quick Start
46
47### Prerequisites
48- [Bun](https://bun.sh) v1.0+
49
50### Installation
51
521. Clone the repository:
53 ```bash
54 git clone <repository-url>
55 cd watproto
56 ```
57
582. Install dependencies:
59 ```bash
60 bun install
61 ```
62
633. Create files for environment variables:
64
65 **Server** (`packages/server/.env.local`):
66 ```env
67 PORT=3000
68 DATABASE_URL=./data/dev.db
69 SERVICE_DID=did:web:localhost:3000
70 ```
71
72 **Client** (`packages/client/.env.local`):
73 ```env
74 CLIENT_URL=http://your.client.host
75 API_URL=http://localhost:3000
76 DEFAULT_PDS_URL=https://your.pds.host
77 DB_PATH=./data/state.db
78 PORT=5173
79 AUTH_SECRET=your-random-secret-key-here
80 KEYSERVER_DID=did:web:your.keyserver.host
81 ```
82
83 Generate `AUTH_SECRET` with: `openssl rand -base64 32`
84
85 To use OAuth in `localhost` do not define a `CLIENT_URL` here
86
87 More on environment variables [below](#environment-variables)
88
89### Development
90
91Run both server and client in separate terminals:
92
93**Terminal 1 - Server**:
94```bash
95cd packages/server
96bun run dev
97```
98
99**Terminal 2 - Client**:
100```bash
101cd packages/client
102bun run dev
103```
104
105Then you can open:
106- **Frontend**: http://127.0.0.1:5173
107- **XRPC Server**: http://localhost:3000
108
109### Alternative: Run from Root
110
111You can also use workspace scripts from the root:
112
113```bash
114# Start server only
115bun run dev
116
117# Start client only
118bun run dev:client
119
120# Build both packages
121bun run build
122
123# Type check all packages
124bun run typecheck
125```
126
127This has the advantage of being slightly easier to run, but logs will be slightly more cluttered.
128
129## Project Commands
130
131### Root Commands
132```bash
133bun install # Install all workspace dependencies
134bun run dev # Start both server and client
135bun run dev:server # Start server only
136bun run dev:client # Start client only
137bun run build # Build client for production
138bun run typecheck # Type check all packages
139bun run lex # Generate TypeScript types from lexicon schemas
140```
141
142### Server Commands (packages/server)
143```bash
144bun run dev # Start development server (port 3000)
145bun run start # Start production server
146bun run debug # Start with debugger
147bun run db:codegen # Regenerate database types
148bun run db:migrate # Run database migrations
149bun run typecheck # Type check
150```
151
152### Client Commands (packages/client)
153```bash
154bun run dev # Start development server (port 5173)
155bun run build # Build for production
156bun run start # Start production server
157bun run lint # Run ESLint
158bun run typecheck # Type check
159```
160
161## Features
162
163### Current
164- ✅ ATProto OAuth authentication (client-side SSR)
165- ✅ Session management with SQLite
166- ✅ XRPC server and client communication
167- ✅ Post creation and storage (public and private)
168- ✅ Tag system for posts
169- ✅ User authentication UI (login flow)
170- ✅ Basic UI components (Header, PostFeed, UserMenu)
171- ✅ Lexicon type generation
172- ✅ React Router v7 frontend with SSR
173- ✅ Tailwind CSS + DaisyUI styling
174- ✅ TypeScript throughout
175
176### Planned
177- 🚧 ATProto feed aggregation and timeline
178- 🚧 User profile pages
179- 🚧 Media upload (images/videos)
180- 🚧 Real-time updates via WebSockets
181- 🚧 Background job processing
182- 🚧 Full-text search
183- 🚧 Multi-account support
184
185## Architecture
186
187### Backend (packages/server)
188- **Framework**: Elysia (fast, type-safe web framework)
189- **Protocol**: XRPC (ATProto RPC protocol)
190- **Database**: SQLite with Kysely query builder
191- **Features**: Post storage, account management, ID resolution
192
193### Frontend (packages/client)
194- **Framework**: React Router v7 (with SSR)
195- **OAuth**: ATProto OAuth Client (server-side)
196- **Database**: SQLite for OAuth state
197- **Routing**: File-based routes in `app/routes/`
198- **Styling**: Tailwind CSS v4 + DaisyUI
199- **Build**: Vite
200
201### Shared (packages/lexicon)
202- **Purpose**: ATProto lexicon type definitions
203- **Generator**: @atcute/lex-cli
204- **Usage**: Shared types across server and client
205
206### Communication
207- Client ↔ Server: XRPC protocol over HTTP
208- Authentication: OAuth managed by client SSR
209- Session: SQLite database with httpOnly cookies
210
211## Deployment
212
213### Server
214Deploy to Node/Bun compatible hosting:
215- [Fly.io](https://fly.io)
216- [Railway](https://railway.app)
217- [Render](https://render.com)
218
219### Client
220Deploy to static hosting:
221- [Vercel](https://vercel.com)
222- [Netlify](https://netlify.com)
223- [Cloudflare Pages](https://pages.cloudflare.com)
224
225### Environment Variables
226Configure production environment variables in your hosting provider:
227
228**Server**:
229- `PORT` - Server port (default: 3000)
230- `DATABASE_URL` - SQLite database path
231- `SERVICE_DID` - DID that points to this service (required)
232
233**Client**:
234- `API_URL` - XRPC server URL (required)
235- `DEFAULT_PDS_URL` - Default PDS URL for OAuth (required)
236- `AUTH_SECRET` - Session encryption secret (required)
237- `KEYSERVER_DID` - DID that poins to a [Keyserver](https://tangled.org/@djara.dev/atp-keyserver) for encryption / decryption (required)
238- Optional: `CLIENT_URL`, `DB_PATH`, `PORT`
239
240**Important**: Client requires SSR-capable hosting with writable filesystem for OAuth database
241
242## Documentation
243
244Detailed documentation is available in CLAUDE.md files:
245- **Root**: `CLAUDE.md` - Monorepo overview and workflow
246- **Server**: `packages/server/CLAUDE.md` - Backend architecture and patterns
247- **Client**: `packages/client/CLAUDE.md` - Frontend architecture and patterns
248
249## Development Workflow
250
251### Adding a Backend Feature
2521. Navigate to `packages/server`
2532. Create/modify XRPC procedures in `src/`
2543. Add database migrations if needed
2554. Test with `bun run dev`
2565. See `packages/server/CLAUDE.md` for patterns
257
258### Adding a Frontend Feature
2591. Navigate to `packages/client`
2602. Create route file in `app/routes/`
2613. Create components as needed
2624. Style with Tailwind CSS + DaisyUI
2635. Test with `bun run dev`
2646. See `packages/client/CLAUDE.md` for patterns
265
266### Working with Lexicons
267```bash
268# Add or modify lexicon schemas in lexicons/ directory
269# Then regenerate TypeScript types:
270bun run lex
271
272# Types are generated in packages/lexicon/types/
273# Available via: import { Watproto } from '@watproto/lexicon'
274```
275
276### Database Migrations
277```bash
278cd packages/server
279
280# Create migration file manually in src/db/migrations/
281# Then regenerate types:
282bun run db:codegen
283```
284
285## Troubleshooting
286
287**Port already in use**:
288- Change `PORT` in `packages/server/.env.local`
289- Client will auto-increment port if 5173 is taken
290
291**CORS errors**:
292- Ensure server CORS allows client origin
293- Check `API_URL` in client environment variables matches server URL
294
295**Type errors**:
296- Run `bun install` at root to sync workspace
297- Run `bun run typecheck` to find issues
298
299**Database issues**:
300- Delete `packages/server/data/*.db*` files
301- Restart server to recreate database
302
303## License
304
305MIT
306
307## Contributing
308
309See CLAUDE.md for development guidelines and architecture patterns.