learn and share notes on atproto (wip) 🦉
malfestio.stormlightlabs.org/
readability
solid
axum
atproto
srs
1# Local Development
2
3## Prerequisites
4
5### Required Tools
6
7- Rust (latest stable)
8- Node.js 18+ and pnpm
9- PostgreSQL 14+
10- Docker (optional, for containerized Postgres)
11
12### Bluesky Account Setup
13
141. Create a Bluesky account at <https://bsky.app> (you'll use this for OAuth testing)
15
16### Environment Configuration
17
18Copy the template and configure for your environment:
19
20```bash
21cp .env.example .env
22```
23
24For local development, the defaults in `.env.example` work out of the box. You only need to ensure your PostgreSQL connection string is correct.
25
26## Testing OAuth Flow
27
28### Step-by-Step
29
301. **Start PostgreSQL**
31
32 ```bash
33 # Using Docker
34 docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:14
35
36 # Or use your local PostgreSQL installation
37 ```
38
392. **Run migrations**
40
41 ```bash
42 just migrate
43 ```
44
453. **Start backend**
46
47 ```bash
48 just start
49 ```
50
51 Server runs on <http://localhost:8080>
52
534. **Start frontend**
54
55 ```bash
56 just web-dev
57 ```
58
59 Frontend runs on <http://localhost:3000>
60
615. **Test OAuth login**
62 - Navigate to <http://localhost:3000/login>
63 - Enter your Bluesky handle (e.g., `thunderbot.bsky.social`)
64 - Authorize the application on bsky.social
65 - Verify redirect back to app with successful login
66
67### OAuth Flow Details
68
69When you enter a handle like `thunderbot.bsky.social`, the system:
70
711. **Handle Resolution**: DNS TXT lookup at `_atproto.thunderbot.bsky.social` or HTTP `https://thunderbot.bsky.social/.well-known/atproto-did`
722. **DID Resolution**: Resolved DID (e.g., `did:plc:...`) queries `https://plc.directory` for PDS endpoint
733. **OAuth Discovery**: `https://bsky.social/.well-known/oauth-authorization-server` fetched for endpoints
744. **Authorization**: User redirected to PDS authorization page with PKCE challenge
755. **Token Exchange**: Authorization code exchanged for access/refresh tokens with DPoP binding
766. **Storage**: Tokens stored in database with encrypted DPoP keypair
77
78## Testing Record Publishing
79
80After successful OAuth login:
81
821. Create a deck or note in the UI
832. Click "Publish" to publish to your PDS
843. Check your Bluesky profile at <https://bsky.app> to see the published record
854. Verify record appears in your AT Protocol repository
86
87## Verifying Your Setup
88
89### Check OAuth Tokens
90
91After successful login, verify tokens were stored:
92
93```sql
94SELECT
95 did,
96 pds_url,
97 LEFT(access_token, 20) || '...' as token_preview,
98 created_at,
99 updated_at
100FROM oauth_tokens
101WHERE did = 'your-did-here';
102```
103
104Replace `'your-did-here'` with the DID from your login success page.
105
106### Check Indexed Records
107
108After publishing content, verify firehose indexing:
109
110```sql
111-- Check indexed decks
112SELECT at_uri, title, indexed_at
113FROM indexed_decks
114WHERE did = 'your-did-here'
115ORDER BY indexed_at DESC
116LIMIT 10;
117
118-- Check indexed cards
119SELECT at_uri, front_content, indexed_at
120FROM indexed_cards
121WHERE did = 'your-did-here'
122ORDER BY indexed_at DESC
123LIMIT 10;
124```
125
126Note: Indexing may take 5-10 seconds after publishing.
127
128### Diagnostic Command
129
130Run this command to check handle resolution and database state:
131
132```bash
133just verify your-handle.bsky.social
134```
135
136This will verify:
137
138- Database connection
139- Handle → DID resolution
140- DID → PDS URL resolution
141- OAuth token status
142- Indexed content count
143
144## Environment Variables Reference
145
146### Required
147
148```bash
149DB_URL="postgres://postgres:postgres@localhost:5432/malfestio_dev?sslmode=disable"
150```
151
152### Optional
153
154```bash
155# OAuth Client Configuration
156APP_URL=http://localhost:3000 # OAuth callback URL
157APP_NAME=Malfestio # App display name
158
159# Server Configuration
160SERVER_HOST=127.0.0.1
161SERVER_PORT=8080
162
163# Frontend Configuration
164VITE_API_URL=http://localhost:8080
165
166# Logging
167RUST_LOG=info,malfestio_server=debug
168```
169
170See `.env.example` for a complete template.
171
172## Additional Resources
173
174- [AT Protocol OAuth Guide](https://docs.bsky.app/blog/oauth-atproto)
175- [OAuth Client Implementation](https://docs.bsky.app/docs/advanced-guides/oauth-client)
176- [PDS Self-Hosting](https://atproto.com/guides/self-hosting)
177- [AT Protocol Specifications](https://atproto.com)