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## Testing Sync Flow 88 89The app supports offline-first editing with automatic sync when online. 90 91### Local Storage (IndexedDB) 92 93All decks, notes, and cards are stored locally in IndexedDB via Dexie.js. You can view this data: 94 951. Navigate to Settings page 962. Scroll to "Local Sync Data" section 973. Use the Records/Queue tabs to view stored data 98 99### Testing Offline Mode 100 1011. Create or edit a deck while online → syncs immediately 1022. Disconnect network (DevTools → Network → Offline) 1033. Create/edit content → stored locally with "local_only" or "pending_push" status 1044. Reconnect → content auto-syncs when online status changes 105 106### Sync Statuses 107 108| Status | Meaning | 109| -------------- | -------------------------------- | 110| `local_only` | New content, never synced | 111| `synced` | Content matches PDS | 112| `pending_push` | Local changes waiting to sync | 113| `conflict` | Local and remote versions differ | 114 115### Conflict Resolution 116 117When conflicts occur: 118 1191. Settings → Local Sync Data shows records with "conflict" status 1202. Click "Keep Local" to overwrite remote with local version 1213. Or use the API: `POST /api/sync/resolve/:type/:id` with strategy 122 123## Verifying Your Setup 124 125### Check OAuth Tokens 126 127After successful login, verify tokens were stored: 128 129```sql 130SELECT 131 did, 132 pds_url, 133 LEFT(access_token, 20) || '...' as token_preview, 134 created_at, 135 updated_at 136FROM oauth_tokens 137WHERE did = 'your-did-here'; 138``` 139 140Replace `'your-did-here'` with the DID from your login success page. 141 142### Check Indexed Records 143 144After publishing content, verify firehose indexing: 145 146```sql 147-- Check indexed decks 148SELECT at_uri, title, indexed_at 149FROM indexed_decks 150WHERE did = 'your-did-here' 151ORDER BY indexed_at DESC 152LIMIT 10; 153 154-- Check indexed cards 155SELECT at_uri, front_content, indexed_at 156FROM indexed_cards 157WHERE did = 'your-did-here' 158ORDER BY indexed_at DESC 159LIMIT 10; 160``` 161 162Note: Indexing may take 5-10 seconds after publishing. 163 164### Diagnostic Command 165 166Run this command to check handle resolution and database state: 167 168```bash 169just verify your-handle.bsky.social 170``` 171 172This will verify: 173 174- Database connection 175- Handle → DID resolution 176- DID → PDS URL resolution 177- OAuth token status 178- Indexed content count 179 180## Environment Variables Reference 181 182### Required 183 184```bash 185DB_URL="postgres://postgres:postgres@localhost:5432/malfestio_dev?sslmode=disable" 186``` 187 188### Optional 189 190```bash 191# OAuth Client Configuration 192APP_URL=http://localhost:3000 # OAuth callback URL 193APP_NAME=Malfestio # App display name 194 195# Server Configuration 196SERVER_HOST=127.0.0.1 197SERVER_PORT=8080 198 199# Frontend Configuration 200VITE_API_URL=http://localhost:8080 201 202# Logging 203RUST_LOG=info,malfestio_server=debug 204``` 205 206See `.env.example` for a complete template. 207 208## Additional Resources 209 210- [AT Protocol OAuth Guide](https://docs.bsky.app/blog/oauth-atproto) 211- [OAuth Client Implementation](https://docs.bsky.app/docs/advanced-guides/oauth-client) 212- [PDS Self-Hosting](https://atproto.com/guides/self-hosting) 213- [AT Protocol Specifications](https://atproto.com)