an app to share curated trails sidetrail.app
1

Configure Feed

Select the types of activity you want to include in your feed.

at bug-repro 135 lines 3.7 kB View raw View rendered
1# Sidetrail 2 3[Sidetrail](https://sidetrail.app/) is an app to create and share "trails". Create sequential paths with 2-24 stops, walk through them one step at a time, and share them with others. 4 5Built on [AT](https://atproto.com/) protocol: trails, walks, and completions are stored in users' repositories and synced via Jetstream. 6 7## Architecture 8 9Three services: 10 11- **Next.js app** — Web frontend + API. Reads from PostgreSQL, writes to users' ATProto repos via OAuth. 12- **Ingester** — Subscribes to [Jetstream](https://docs.bsky.app/blog/jetstream) and indexes `app.sidetrail.*` records into PostgreSQL. 13- **Realtime** — Rebroadcasts Jetstream events to browser clients for real-time updates on some pages. 14 15## Local Development 16 17### Prerequisites 18 19- Node.js 22.16.0+ 20- PostgreSQL 21- Redis 22 23### Setup 24 25```bash 26# Install dependencies 27npm install 28 29# Start Redis 30brew services start redis 31 32# Create the database 33createdb sidetrail 34 35# Copy environment file and configure DATABASE_URL and REDIS_URL 36cp .env.example .env 37 38# Push database schema 39npm run db:push 40 41# Populate the database from the live network (see Syncing below) 42npm run sync 43 44# Start all services (run in separate terminals) 45npm run dev # Next.js app on :3000 46npm run dev:ingester # Jetstream ingester 47npm run dev:realtime # Realtime server 48``` 49 50Then open `127.0.0.1:3000` (it has to be `127.0.0.1`, not `localhost`). 51 52### Syncing 53 54The ingester only indexes records as they stream past on Jetstream, and 55Jetstream's replay window is only a few days. Any fresh database — or one 56whose ingester was down for longer than the window — has drifted from the 57network. 58 59`npm run sync` reconciles: it asks the relay which repos contain 60`app.sidetrail.*` records, fetches them from each user's PDS, and makes the 61index mirror the lexicon-valid records currently on the network — adding 62what's missing and pruning what was deleted or doesn't validate. Repos it 63fails to reach are left untouched. Idempotent, safe to rerun anytime 64(including after changing a lexicon). 65 66```bash 67npm run sync # local DB (.env) 68DATABASE_URL=postgres://... npm run sync # any other DB 69``` 70 71### Environment Variables 72 73See `.env.example`. For local development, `DATABASE_URL` and `REDIS_URL` are required. 74 75Production requires: 76 77- `PUBLIC_URL` - Your app's public URL 78- `PRIVATE_KEY_ES256` - OAuth signing key (generate with `node scripts/gen-jwk.mjs`) 79- `COOKIE_SECRET` - Session encryption (32+ chars) 80 81## Lexicons 82 83Sidetrail uses three ATProto record types: 84 85- `app.sidetrail.trail` - Trail with embedded stops 86- `app.sidetrail.walk` - User's current walk state (deleted on completion) 87- `app.sidetrail.completion` - Permanent completion record 88 89See [lexicons/LEXICONS.md](lexicons/LEXICONS.md) for details. 90 91## Testing 92 93```bash 94# Create test database (one-time) 95psql -c "CREATE DATABASE sidetrail_test" 96 97npm test 98``` 99 100## Scripts 101 102```bash 103npm run dev # Start Next.js dev server 104npm run dev:ingester # Start Jetstream ingester 105npm run dev:realtime # Start realtime server 106 107npm run build # Production build 108npm run db:push # Push schema to database 109npm run db:studio # Open Drizzle Studio 110 111npm run test # Run tests 112npm run check # Lint + typecheck 113npm run sync # Sync the index with the live network 114``` 115 116## Deployment 117 118Uses [Railway](https://railway.app/) with three services. One-time setup: 119 120```bash 121railway link --project sidetrail 122``` 123 124Then deploy with: 125 126```bash 127npm run deploy:app 128npm run deploy:ingester 129npm run deploy:realtime 130npm run deploy:all # all three, sequentially 131``` 132 133## License 134 135MIT