A lexicon-driven AppView for ATProto. happyview.dev
backfill firehose jetstream atproto appview oauth lexicon
8
fork

Configure Feed

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

docs: add migration guide for v1 to v2

Trezy e9385ea6 b94af6e8

+215
+210
packages/docs/docs/guides/upgrading-to-v2.md
··· 1 + # Migrating from v1 2 + 3 + v2 consolidates HappyView, [Tap](https://github.com/bluesky-social/indigo/tree/main/cmd/tap), and [AIP](https://github.com/graze-social/aip) into a single binary. Real-time indexing, backfill, and OAuth are now built in — there are no companion services to deploy. 4 + 5 + This guide covers every breaking change and the steps to migrate. 6 + 7 + ## Architecture changes 8 + 9 + | v1 | v2 | 10 + |----|-----| 11 + | HappyView + Tap + AIP (3 services) | Single HappyView binary | 12 + | Postgres only | SQLite (default) or Postgres | 13 + | AIP handles OAuth | Built-in atproto OAuth with DPoP | 14 + | Tap handles indexing + backfill | Built-in Jetstream streaming + backfill | 15 + | Offset-based pagination | Cursor-based pagination | 16 + | Admin bootstrapping via config | First authenticated user becomes admin | 17 + 18 + ## 1. Remove Tap and AIP 19 + 20 + Tap and AIP are no longer needed. Remove them from your `docker-compose.yml` (or equivalent) and delete any associated containers/volumes. 21 + 22 + **Environment variables to remove:** 23 + 24 + | Variable | Reason | 25 + |----------|--------| 26 + | `AIP_URL` | OAuth is now built in | 27 + | `AIP_PUBLIC_URL` | No longer needed | 28 + | `TAP_URL` | Indexing is now built in | 29 + | `TAP_ADMIN_PASSWORD` | No longer needed | 30 + | `TAP_DATABASE_URL` | Tap no longer exists | 31 + | `TAP_RELAY_URL` | Use `RELAY_URL` on HappyView directly | 32 + | `TAP_PLC_URL` | Use `PLC_URL` on HappyView directly | 33 + | `TAP_COLLECTION_FILTERS` | Collection filtering now uses lexicon config | 34 + | `TAP_SIGNAL_COLLECTIONS` | Collection filtering now uses lexicon config | 35 + 36 + ## 2. Update environment variables 37 + 38 + **New required variables:** 39 + 40 + | Variable | Description | 41 + |----------|-------------| 42 + | `PUBLIC_URL` | Public-facing URL (e.g. `https://happyview.example.com`). Used for OAuth callbacks | 43 + | `SESSION_SECRET` | Secret key for signing session cookies (at least 64 chars). **Must be set in production** | 44 + 45 + **New optional variables:** 46 + 47 + | Variable | Default | Description | 48 + |----------|---------|-------------| 49 + | `DATABASE_BACKEND` | auto-detected | Force `sqlite` or `postgres` | 50 + | `JETSTREAM_URL` | `wss://jetstream1.us-east.bsky.network` | Replaces Tap's Jetstream connection | 51 + | `STATIC_DIR` | `./web/out` | Dashboard static assets directory | 52 + | `TOKEN_ENCRYPTION_KEY` | --- | Base64-encoded 32-byte key for encrypting stored OAuth tokens. **Strongly recommended in production** | 53 + | `DEFAULT_RATE_LIMIT_CAPACITY` | `100` | Default token bucket capacity for new API clients | 54 + | `DEFAULT_RATE_LIMIT_REFILL_RATE` | `2.0` | Default refill rate (tokens/sec) for new API clients | 55 + | `APP_NAME` | --- | App name shown on OAuth screens | 56 + | `LOGO_URI` | --- | Logo URL for OAuth screens | 57 + | `TOS_URI` | --- | Terms of service URL | 58 + | `POLICY_URI` | --- | Privacy policy URL | 59 + 60 + **Unchanged variables:** `DATABASE_URL`, `HOST`, `PORT`, `RELAY_URL`, `PLC_URL`, `EVENT_LOG_RETENTION_DAYS`, `RUST_LOG`. 61 + 62 + See [Configuration](../getting-started/configuration.md) for the full reference. 63 + 64 + ## 3. Choose your database 65 + 66 + v2 defaults to SQLite. If you're running Postgres in v1, you have two options: 67 + 68 + **Keep Postgres** — no changes needed. Your `DATABASE_URL` stays the same and v2 auto-detects the backend from the connection string. 69 + 70 + **Migrate to SQLite** — follow the [Postgres to SQLite migration guide](database/postgres-to-sqlite-migration.md). SQLite is simpler to operate (no separate database server) and is the recommended default for most deployments. 71 + 72 + ## 4. Update Lua scripts 73 + 74 + ### Cursor-based pagination (breaking change) 75 + 76 + `db.query` no longer supports `offset`. Replace offset-based pagination with cursors: 77 + 78 + **Before (v1):** 79 + 80 + ```lua 81 + local result = db.query({ 82 + collection = collection, 83 + limit = limit, 84 + offset = page * limit, 85 + }) 86 + ``` 87 + 88 + **After (v2):** 89 + 90 + ```lua 91 + local result = db.query({ 92 + collection = collection, 93 + limit = limit, 94 + cursor = params.cursor, 95 + }) 96 + 97 + -- result.cursor is an opaque string; pass it back as ?cursor= for the next page 98 + ``` 99 + 100 + Clients should pass the `cursor` value from the response as a query parameter to fetch the next page. Don't parse or construct cursors — they're opaque. 101 + 102 + ### New APIs available 103 + 104 + v2 adds several new Lua APIs that you can optionally adopt: 105 + 106 + - [`atproto.resolve_service_endpoint`](../reference/lua/atproto-api.md) — resolve a DID to its PDS endpoint 107 + - [`atproto.get_labels`](../reference/lua/atproto-api.md) / [`atproto.get_labels_batch`](../reference/lua/atproto-api.md) — fetch content labels from subscribed labelers 108 + - [`os.time`](../reference/lua/standard-libraries.md), `os.date`, `os.difftime`, `os.clock` — safe `os` subset 109 + 110 + ## 5. Update API key prefixes 111 + 112 + v1 API keys used the `hv_` prefix. v2 keeps existing `hv_` keys working but new keys use the `hv_` prefix as well. No migration needed. 113 + 114 + v2 also adds **API clients** for third-party OAuth apps, which use the `hvc_` prefix. These are separate from API keys — see the [API Clients guide](features/api-clients.md). 115 + 116 + ## 6. Update the dashboard URL 117 + 118 + The dashboard has moved from the root path to `/dashboard`: 119 + 120 + | v1 | v2 | 121 + |----|-----| 122 + | `/` | `/dashboard` | 123 + | `/lexicons` | `/dashboard/lexicons` | 124 + | `/records` | `/dashboard/records` | 125 + | `/settings` | `/dashboard/settings` | 126 + 127 + Update any bookmarks or internal links. 128 + 129 + ## 7. User permissions 130 + 131 + v2 introduces granular user permissions. After upgrading: 132 + 133 + 1. The first user to authenticate becomes the **super user** (full access). 134 + 2. Additional users are created with no permissions by default. 135 + 3. Assign permissions or use a template (Viewer, Operator, Manager, Full Access). 136 + 137 + See the [Permissions guide](admin/permissions.md) for details. 138 + 139 + ## 8. Docker Compose (example) 140 + 141 + **Before (v1):** 142 + 143 + ```yaml 144 + services: 145 + postgres: 146 + image: postgres:17 147 + # ... 148 + 149 + tap: 150 + image: ghcr.io/bluesky-social/indigo/tap:latest 151 + environment: 152 + TAP_DATABASE_URL: postgres://... 153 + TAP_RELAY_URL: https://bsky.network 154 + TAP_ADMIN_PASSWORD: secret 155 + depends_on: [postgres] 156 + 157 + happyview: 158 + image: ghcr.io/gamesgamesgamesgamesgames/happyview:latest 159 + environment: 160 + DATABASE_URL: postgres://... 161 + AIP_URL: http://aip:8080 162 + TAP_URL: http://tap:2480 163 + TAP_ADMIN_PASSWORD: secret 164 + depends_on: [postgres, tap] 165 + ``` 166 + 167 + **After (v2):** 168 + 169 + ```yaml 170 + services: 171 + happyview: 172 + image: ghcr.io/gamesgamesgamesgamesgames/happyview:latest 173 + environment: 174 + DATABASE_URL: sqlite://data/happyview.db?mode=rwc 175 + PUBLIC_URL: https://happyview.example.com 176 + SESSION_SECRET: your-64-char-secret 177 + volumes: 178 + - data:/app/data 179 + 180 + volumes: 181 + data: 182 + ``` 183 + 184 + Or with Postgres: 185 + 186 + ```yaml 187 + services: 188 + postgres: 189 + image: postgres:17 190 + # ... 191 + 192 + happyview: 193 + image: ghcr.io/gamesgamesgamesgamesgames/happyview:latest 194 + environment: 195 + DATABASE_URL: postgres://happyview:happyview@postgres/happyview 196 + PUBLIC_URL: https://happyview.example.com 197 + SESSION_SECRET: your-64-char-secret 198 + depends_on: [postgres] 199 + ``` 200 + 201 + ## Checklist 202 + 203 + - [ ] Remove Tap and AIP services 204 + - [ ] Remove old environment variables (`AIP_URL`, `TAP_URL`, `TAP_ADMIN_PASSWORD`, etc.) 205 + - [ ] Add `PUBLIC_URL` and `SESSION_SECRET` 206 + - [ ] Add `TOKEN_ENCRYPTION_KEY` (recommended for production) 207 + - [ ] Decide on SQLite (default) or keep Postgres 208 + - [ ] Update Lua scripts to use cursor-based pagination instead of offsets 209 + - [ ] Update any bookmarks/links to use `/dashboard` prefix 210 + - [ ] Set up user permissions after first login
+5
packages/docs/sidebars.ts
··· 75 75 label: "Guides", 76 76 items: [ 77 77 { 78 + type: "doc", 79 + id: "guides/upgrading-to-v2", 80 + label: "Migrating from v1", 81 + }, 82 + { 78 83 type: "category", 79 84 label: "Features", 80 85 items: [