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: fix broken links

Trezy fe04731f 05e86d3d

+208 -208
+11 -11
packages/docs/docs/README.md
··· 1 1 # HappyView 2 2 3 - HappyView is the best way to build an [AppView](https://atproto.com/guides/glossary#app-view) for the [AT Protocol](https://atproto.com). Upload your [lexicon](reference/glossary.md#atproto-terms) schemas and get a fully functional AppView, complete with [XRPC](reference/glossary.md#atproto-terms) endpoints, OAuth, real-time network sync, and historical [backfill](guides/backfill.md), without writing a single line of server code. 3 + HappyView is the best way to build an [AppView](https://atproto.com/guides/glossary#app-view) for the [AT Protocol](https://atproto.com). Upload your [lexicon](reference/glossary.md#atproto-terms) schemas and get a fully functional AppView, complete with [XRPC](reference/glossary.md#atproto-terms) endpoints, OAuth, real-time network sync, and historical [backfill](guides/indexing/backfill.md), without writing a single line of server code. 4 4 5 5 Building an AppView from scratch means wiring up real-time event streams, record storage, XRPC routing, OAuth flows, and PDS write proxying before you can even think about your application. HappyView handles all of that. Define your data model with lexicons, add custom logic with Lua scripts when you need it, and ship your app. 6 6 7 7 ## Features 8 8 9 - - **Schema-driven endpoints:** Upload a [lexicon](guides/lexicons.md) and HappyView generates XRPC query and procedure routes, storage, and indexing from it — updatable at runtime with no restart. 9 + - **Schema-driven endpoints:** Upload a [lexicon](guides/indexing/lexicons.md) and HappyView generates XRPC query and procedure routes, storage, and indexing from it — updatable at runtime with no restart. 10 10 11 - - **Network sync built in:** Real-time record streaming via [Jetstream](https://github.com/bluesky-social/jetstream), historical [backfill](guides/backfill.md) from each user's PDS, and atproto OAuth with DPoP-bound proxy writes back to the PDS. 11 + - **Network sync built in:** Real-time record streaming via [Jetstream](https://github.com/bluesky-social/jetstream), historical [backfill](guides/indexing/backfill.md) from each user's PDS, and atproto OAuth with DPoP-bound proxy writes back to the PDS. 12 12 13 - - **Customize with Lua, hooks, and plugins:** [Lua scripts](guides/scripting.md) for query and procedure logic, [index hooks](guides/index-hooks.md) that fire on every record change, WASM [plugins](guides/plugins.md) for external platform integration, and [labeler](guides/labelers.md) subscriptions for content moderation. 13 + - **Customize with Lua, hooks, and plugins:** [Lua scripts](guides/scripting.md) for query and procedure logic, [index hooks](guides/indexing/index-hooks.md) that fire on every record change, WASM [plugins](guides/features/plugins.md) for external platform integration, and [labeler](guides/features/labelers.md) subscriptions for content moderation. 14 14 15 - - **Protocol-native:** Works with any PDS, resolves DIDs through the directory, and fetches [network lexicons](guides/lexicons.md#network-lexicons) via DNS authority resolution. 15 + - **Protocol-native:** Works with any PDS, resolves DIDs through the directory, and fetches [network lexicons](guides/indexing/lexicons.md#network-lexicons) via DNS authority resolution. 16 16 17 - - **Full admin surface:** Built-in [dashboard](getting-started/dashboard.md) and [admin API](reference/admin-api.md) for managing lexicons, users, API keys, API clients, backfill jobs, and plugins. 17 + - **Full admin surface:** Built-in [dashboard](getting-started/dashboard.md) and [admin API](reference/admin/admin-api.md) for managing lexicons, users, API keys, API clients, backfill jobs, and plugins. 18 18 19 19 ## Design Principles 20 20 ··· 29 29 ## Next Steps 30 30 31 31 - [Quickstart](getting-started/deployment/railway.md): Deploy HappyView on Railway or run it locally 32 - - [Lexicons](guides/lexicons.md): Upload lexicon schemas and start indexing records 32 + - [Lexicons](guides/indexing/lexicons.md): Upload lexicon schemas and start indexing records 33 33 - [Lua Scripting](guides/scripting.md): Write custom query and procedure logic 34 - - [Index Hooks](guides/index-hooks.md): React to record changes in real time 35 - - [Labelers](guides/labelers.md): Subscribe to external labelers and manage content labels 36 - - [Plugins](guides/plugins.md): Integrate with external platforms using WASM plugins 37 - - [Event Logs](guides/event-logs.md): Monitor system activity, debug script errors, and audit admin actions 34 + - [Index Hooks](guides/indexing/index-hooks.md): React to record changes in real time 35 + - [Labelers](guides/features/labelers.md): Subscribe to external labelers and manage content labels 36 + - [Plugins](guides/features/plugins.md): Integrate with external platforms using WASM plugins 37 + - [Event Logs](guides/admin/event-logs.md): Monitor system activity, debug script errors, and audit admin actions
+5 -5
packages/docs/docs/getting-started/authentication.md
··· 3 3 HappyView has two distinct authentication surfaces: 4 4 5 5 - **XRPC** (`/xrpc/*`) — client-level identification via an **API client key** on every request, plus optional user-level atproto OAuth for endpoints that need a specific user's identity (e.g. procedures that write to a PDS). 6 - - **Admin API** (`/admin/*`) — user-level authentication via admin API keys or service auth JWTs, gated by [permissions](../guides/permissions.md). 6 + - **Admin API** (`/admin/*`) — user-level authentication via admin API keys or service auth JWTs, gated by [permissions](../guides/admin/permissions.md). 7 7 8 8 ## Which endpoints require what? 9 9 ··· 11 11 | ---------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------- | 12 12 | Queries (`GET /xrpc/{method}`) | `X-Client-Key` required | Optional — DPoP auth if the query needs to know who the user is | 13 13 | Procedures (`POST /xrpc/{method}`) | `X-Client-Key` required | Required — DPoP auth so HappyView can proxy writes to the user's PDS | 14 - | Admin API (`/admin/*`) | — | Required — admin API key or service auth JWT with the right [permissions](../guides/permissions.md) | 14 + | Admin API (`/admin/*`) | — | Required — admin API key or service auth JWT with the right [permissions](../guides/admin/permissions.md) | 15 15 | Health check (`GET /health`) | — | — | 16 16 17 17 ## XRPC: API client identification ··· 91 91 92 92 ### Admin API key 93 93 94 - For automation — CI/CD, monitoring, cron jobs — create an [admin API key](../guides/api-keys.md) at **Settings > API Keys** or via `POST /admin/api-keys` and pass it as a bearer token: 94 + For automation — CI/CD, monitoring, cron jobs — create an [admin API key](../guides/admin/api-keys.md) at **Settings > API Keys** or via `POST /admin/api-keys` and pass it as a bearer token: 95 95 96 96 ```sh 97 97 export TOKEN="hv_your-api-key-here" ··· 315 315 ## Next steps 316 316 317 317 - [JavaScript SDK](../sdk/overview.md) — authenticate and make XRPC calls from JavaScript 318 - - [Permissions](../guides/permissions.md) — full list of permissions and what each one grants 319 - - [API Keys](../guides/api-keys.md) — create scoped admin API keys for automation 318 + - [Permissions](../guides/admin/permissions.md) — full list of permissions and what each one grants 319 + - [API Keys](../guides/admin/api-keys.md) — create scoped admin API keys for automation 320 320 - [Admin API — API Clients](../reference/admin/api-clients.md) — register API clients and configure rate limits
+3 -3
packages/docs/docs/getting-started/configuration.md
··· 1 1 # Configuration 2 2 3 - HappyView is configured via environment variables. A `.env` file in the project root is loaded automatically on startup. See [Deployment](deployment/docker.md) for local setup or [Production Deployment](../reference/production-deployment.md) for production setup. 3 + HappyView is configured via environment variables. A `.env` file in the project root is loaded automatically on startup. See [Deployment](deployment/docker.md) for local setup or [Production Deployment](production-deployment.md) for production setup. 4 4 5 5 ## Environment variables 6 6 ··· 13 13 | `HOST` | no | `0.0.0.0` | Bind host | 14 14 | `PORT` | no | `3000` | Bind port | 15 15 | `JETSTREAM_URL` | no | `wss://jetstream1.us-east.bsky.network` | Jetstream WebSocket URL for real-time record streaming | 16 - | `RELAY_URL` | no | `https://bsky.network` | Relay URL for [backfill](../guides/backfill.md) repo discovery | 16 + | `RELAY_URL` | no | `https://bsky.network` | Relay URL for [backfill](../guides/indexing/backfill.md) repo discovery | 17 17 | `PLC_URL` | no | `https://plc.directory` | [PLC directory](https://github.com/did-method-plc/did-method-plc) URL for DID resolution | 18 18 | `STATIC_DIR` | no | `./web/out` | Directory containing the built dashboard static assets | 19 19 | `EVENT_LOG_RETENTION_DAYS` | no | `30` | Number of days to keep event logs before automatic cleanup. Set to `0` to disable cleanup | ··· 59 59 60 60 - [Authentication](authentication.md) — set up OAuth and admin users 61 61 - [Dashboard](dashboard.md) — explore the admin dashboard 62 - - [Production deployment](../reference/production-deployment.md) — deploy HappyView to production 62 + - [Production deployment](production-deployment.md) — deploy HappyView to production
+9 -9
packages/docs/docs/getting-started/dashboard.md
··· 1 1 # Dashboard 2 2 3 - HappyView ships with a web dashboard that provides a visual interface for everything the [admin API](../reference/admin-api.md) offers. It runs as a separate Next.js application alongside the Rust backend and authenticates via atproto OAuth. 3 + HappyView ships with a web dashboard that provides a visual interface for everything the [admin API](../reference/admin/admin-api.md) offers. It runs as a separate Next.js application alongside the Rust backend and authenticates via atproto OAuth. 4 4 5 5 On a fresh deployment with no users in the database, the first person to log in to the dashboard is automatically bootstrapped as the super user with all permissions — so log in with the handle you want to own the instance first. 6 6 ··· 23 23 24 24 Toggle **Enable backfill** to index historical records when uploading a record-type lexicon. 25 25 26 - **Network** lexicons are fetched from the atproto network. Enter an NSID (e.g. `xyz.statusphere.status`) and HappyView resolves the schema automatically. If found, the lexicon JSON is displayed in a read-only editor. Click **Add** to track it. Network lexicons are kept up to date via the Jetstream subscription. See [Lexicons - Network lexicons](../guides/lexicons.md#network-lexicons) for how resolution works. 26 + **Network** lexicons are fetched from the atproto network. Enter an NSID (e.g. `xyz.statusphere.status`) and HappyView resolves the schema automatically. If found, the lexicon JSON is displayed in a read-only editor. Click **Add** to track it. Network lexicons are kept up to date via the Jetstream subscription. See [Lexicons - Network lexicons](../guides/indexing/lexicons.md#network-lexicons) for how resolution works. 27 27 28 28 ### JSON editor 29 29 ··· 45 45 46 46 ## Backfill 47 47 48 - Navigate to **Backfill** to view and manage backfill jobs. You can start a new backfill for any record-type lexicon to import historical records from the network. The page shows job status, progress (repos processed / total), and record counts. See [Backfill](../guides/backfill.md) for how the process works. 48 + Navigate to **Backfill** to view and manage backfill jobs. You can start a new backfill for any record-type lexicon to import historical records from the network. The page shows job status, progress (repos processed / total), and record counts. See [Backfill](../guides/indexing/backfill.md) for how the process works. 49 49 50 50 ## Users 51 51 52 - Navigate to **Users** to manage who can access the admin API and dashboard. You can add users by DID, assign permissions individually or via a template (`viewer`, `operator`, `manager`, `full_access`), and remove users. The super user is highlighted and has all permissions by default. See [Permissions](../guides/permissions.md) for what each permission grants. 52 + Navigate to **Users** to manage who can access the admin API and dashboard. You can add users by DID, assign permissions individually or via a template (`viewer`, `operator`, `manager`, `full_access`), and remove users. The super user is highlighted and has all permissions by default. See [Permissions](../guides/admin/permissions.md) for what each permission grants. 53 53 54 54 ## Events 55 55 ··· 69 69 70 70 ### API Keys 71 71 72 - Create and revoke admin API keys for automation. Each key is scoped to specific permissions and tied to the creating user. See [API Keys](../guides/api-keys.md) for details. 72 + Create and revoke admin API keys for automation. Each key is scoped to specific permissions and tied to the creating user. See [API Keys](../guides/admin/api-keys.md) for details. 73 73 74 74 ### Users 75 75 ··· 77 77 78 78 ### Plugins 79 79 80 - Manage installed plugins and configure plugin secrets. Plugins extend HappyView with additional functionality. Plugin secrets are encrypted at rest when `TOKEN_ENCRYPTION_KEY` is configured. See [Plugins](../guides/plugins.md) for details. 80 + Manage installed plugins and configure plugin secrets. Plugins extend HappyView with additional functionality. Plugin secrets are encrypted at rest when `TOKEN_ENCRYPTION_KEY` is configured. See [Plugins](../guides/features/plugins.md) for details. 81 81 82 82 ### Labelers 83 83 84 - Configure labeler subscriptions for content labeling. See [Labelers](../guides/labelers.md) for details. 84 + Configure labeler subscriptions for content labeling. See [Labelers](../guides/features/labelers.md) for details. 85 85 86 86 ### Environment Variables 87 87 ··· 93 93 94 94 ## Next steps 95 95 96 - - [Lexicons](../guides/lexicons.md) — how lexicons drive HappyView's indexing and routing 96 + - [Lexicons](../guides/indexing/lexicons.md) — how lexicons drive HappyView's indexing and routing 97 97 - [Lua Scripting](../guides/scripting.md) — write custom query and procedure logic 98 - - [Permissions](../guides/permissions.md) — manage user access to admin features 98 + - [Permissions](../guides/admin/permissions.md) — manage user access to admin features 99 99 - [Configuration](configuration.md) — full list of environment variables
+1 -1
packages/docs/docs/getting-started/deployment/docker.md
··· 34 34 The `happyview` container serves its own bundled dashboard at `http://localhost:3000`, but that copy is baked in at container build time and only updates when you rebuild the image. For day-to-day development, use the dev dashboard at `http://localhost:3001` — it hot-reloads on changes to the `web/` source. 35 35 36 36 :::tip 37 - SQLite is the default and requires no extra services. To use Postgres instead, uncomment the `postgres` service in `docker-compose.yml` and update `DATABASE_URL` in `.env`. See the [database setup guide](../../guides/database-setup.md). 37 + SQLite is the default and requires no extra services. To use Postgres instead, uncomment the `postgres` service in `docker-compose.yml` and update `DATABASE_URL` in `.env`. See the [database setup guide](../../guides/database/database-setup.md). 38 38 ::: 39 39 40 40 ## Next steps
+1 -1
packages/docs/docs/getting-started/deployment/other.md
··· 30 30 DATABASE_URL=postgres://happyview:happyview@localhost/happyview 31 31 ``` 32 32 33 - See [Configuration](../configuration.md) for all available variables and the [database setup guide](../../guides/database-setup.md) for details on both backends. 33 + See [Configuration](../configuration.md) for all available variables and the [database setup guide](../../guides/database/database-setup.md) for details on both backends. 34 34 35 35 ## 2. Create the database (Postgres only) 36 36
+1 -1
packages/docs/docs/getting-started/deployment/railway.md
··· 24 24 25 25 - [Configuration](../configuration.md) — full list of environment variables 26 26 - [Dashboard](../dashboard.md) — manage lexicons, users, and plugins via the web UI 27 - - [Production deployment](../../reference/production-deployment.md) — hardening checklist for production instances 27 + - [Production deployment](../production-deployment.md) — hardening checklist for production instances
+8 -8
packages/docs/docs/getting-started/production-deployment.md
··· 14 14 15 15 ## Token encryption key 16 16 17 - If you use [plugins](../guides/plugins.md) that require secrets (API keys, OAuth credentials), set `TOKEN_ENCRYPTION_KEY` to a base64-encoded 32-byte key. This encrypts plugin secrets at rest using AES-256-GCM: 17 + If you use [plugins](../guides/features/plugins.md) that require secrets (API keys, OAuth credentials), set `TOKEN_ENCRYPTION_KEY` to a base64-encoded 32-byte key. This encrypts plugin secrets at rest using AES-256-GCM: 18 18 19 19 ```sh 20 20 openssl rand -base64 32 ··· 40 40 - Larger-than-memory working sets 41 41 - External tools that need direct read access to the records table 42 42 43 - See the [database setup guide](../guides/database-setup.md) for configuration details and [Postgres → SQLite migration](../guides/postgres-to-sqlite-migration.md) if you're moving the other direction. Migrations run automatically on startup regardless of backend. 43 + See the [database setup guide](../guides/database/database-setup.md) for configuration details and [Postgres → SQLite migration](../guides/database/postgres-to-sqlite-migration.md) if you're moving the other direction. Migrations run automatically on startup regardless of backend. 44 44 45 45 ## Rate limits 46 46 47 - HappyView has a per-client token-bucket rate limiter for XRPC endpoints. The defaults (set via `DEFAULT_RATE_LIMIT_CAPACITY` and `DEFAULT_RATE_LIMIT_REFILL_RATE`) apply to any [API client](../guides/api-keys.md) that doesn't have per-client overrides. Raise the defaults cautiously — they exist so one misbehaving integrator can't saturate the server. 47 + HappyView has a per-client token-bucket rate limiter for XRPC endpoints. The defaults (set via `DEFAULT_RATE_LIMIT_CAPACITY` and `DEFAULT_RATE_LIMIT_REFILL_RATE`) apply to any [API client](../guides/admin/api-keys.md) that doesn't have per-client overrides. Raise the defaults cautiously — they exist so one misbehaving integrator can't saturate the server. 48 48 49 - Per-client overrides are set at client creation or via `PUT /admin/api-clients/{id}` (see [Admin API — API Clients](admin/api-clients.md)). 49 + Per-client overrides are set at client creation or via `PUT /admin/api-clients/{id}` (see [Admin API — API Clients](../reference/admin/api-clients.md)). 50 50 51 51 ## Logging 52 52 ··· 60 60 61 61 ## Event log retention 62 62 63 - The admin [event log](../guides/event-logs.md) is stored in the same database as records. `EVENT_LOG_RETENTION_DAYS` (default `30`) controls automatic cleanup. Set to `0` to keep events indefinitely — useful for compliance-sensitive deployments, but plan for database growth. 63 + The admin [event log](../guides/admin/event-logs.md) is stored in the same database as records. `EVENT_LOG_RETENTION_DAYS` (default `30`) controls automatic cleanup. Set to `0` to keep events indefinitely — useful for compliance-sensitive deployments, but plan for database growth. 64 64 65 65 ## Health checks 66 66 ··· 73 73 - **SQLite**: back up the database file (e.g. `data/happyview.db`) plus its `-wal` and `-shm` sidecar files. Use `sqlite3 happyview.db ".backup '/path/backup.db'"` for a consistent snapshot while HappyView is running. 74 74 - **Postgres**: standard `pg_dump` / managed-Postgres snapshots. 75 75 76 - Most of what HappyView stores is derivable from the network — lost records can be re-indexed via [backfill](../guides/backfill.md). You can't recover from the network: user accounts and permissions, API keys, API clients, plugin secrets, and the Jetstream cursor. Prioritize those in your backup plan. 76 + Most of what HappyView stores is derivable from the network — lost records can be re-indexed via [backfill](../guides/indexing/backfill.md). You can't recover from the network: user accounts and permissions, API keys, API clients, plugin secrets, and the Jetstream cursor. Prioritize those in your backup plan. 77 77 78 78 ## Next steps 79 79 80 80 - [Configuration](../getting-started/configuration.md) — full environment variable reference 81 - - [Permissions](../guides/permissions.md) — lock down admin access before exposing the dashboard publicly 82 - - [Troubleshooting](troubleshooting.md) — diagnose issues with a running instance 81 + - [Permissions](../guides/admin/permissions.md) — lock down admin access before exposing the dashboard publicly 82 + - [Troubleshooting](../reference/troubleshooting.md) — diagnose issues with a running instance
+2 -2
packages/docs/docs/getting-started/quickstart.md
··· 29 29 30 30 HappyView starts indexing records for that collection. A backfill job fetches historical records, and new records stream in via Jetstream. 31 31 32 - You can also upload lexicons manually via the dashboard or the [admin API](../reference/admin-api.md). See [Lexicons](../guides/lexicons.md) for the full details. 32 + You can also upload lexicons manually via the dashboard or the [admin API](../reference/admin/admin-api.md). See [Lexicons](../guides/indexing/lexicons.md) for the full details. 33 33 34 34 ## 4. Verify records are being indexed 35 35 ··· 50 50 ## Next steps 51 51 52 52 - [**Statusphere tutorial**](../tutorials/statusphere.md): full walkthrough building a complete AppView with record, query, and procedure lexicons 53 - - [**Lexicons guide**](../guides/lexicons.md): target collections, backfill flag, network lexicons 53 + - [**Lexicons guide**](../guides/indexing/lexicons.md): target collections, backfill flag, network lexicons 54 54 - [**Lua Scripting**](../guides/scripting.md): custom query and procedure logic 55 55 - [**Configuration**](configuration.md): environment variables and tuning 56 56 - [**Authentication**](authentication.md): how OAuth works and how to get API tokens
+4 -4
packages/docs/docs/guides/admin/api-keys.md
··· 31 31 -H "Authorization: Bearer hv_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" 32 32 ``` 33 33 34 - This works for all [admin API](../reference/admin-api.md) endpoints that the key has permissions for. Unlike OAuth tokens which carry the user's full permissions, API keys are limited to the specific permissions assigned at creation time. 34 + This works for all [admin API](../../reference/admin/admin-api.md) endpoints that the key has permissions for. Unlike OAuth tokens which carry the user's full permissions, API keys are limited to the specific permissions assigned at creation time. 35 35 36 36 ## Revoking a key 37 37 ··· 55 55 56 56 ## Next steps 57 57 58 - - [Admin API reference](../reference/admin-api.md) — full endpoint documentation 59 - - [Scripting](scripting.md) — automate record processing with Lua scripts 60 - - [Index hooks](index-hooks.md) — push records to external services on write 58 + - [Admin API reference](../../reference/admin/admin-api.md) — full endpoint documentation 59 + - [Scripting](../scripting.md) — automate record processing with Lua scripts 60 + - [Index hooks](../indexing/index-hooks.md) — push records to external services on write
+9 -9
packages/docs/docs/guides/admin/event-logs.md
··· 1 1 # Event Logs 2 2 3 - HappyView maintains an internal event log that records system activity — lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the [admin API](../reference/admin/events.md). 3 + HappyView maintains an internal event log that records system activity — lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the [admin API](../../reference/admin/events.md). 4 4 5 5 ## Event types 6 6 ··· 14 14 | `lexicon.updated` | info | Lexicon NSID | `revision`, `has_script`, `source` | 15 15 | `lexicon.deleted` | info | Lexicon NSID | — | 16 16 17 - Logged when lexicons are uploaded, updated, or deleted via the [admin API](../reference/admin/lexicons.md). The `actor_did` is the user who performed the action. 17 + Logged when lexicons are uploaded, updated, or deleted via the [admin API](../../reference/admin/lexicons.md). The `actor_did` is the user who performed the action. 18 18 19 19 ### Record events 20 20 ··· 48 48 | `user.permissions_updated` | info | User ID | `granted`, `revoked` | 49 49 | `user.super_transferred` | warn | New super user ID | `from_user_id` | 50 50 51 - The `user.bootstrapped` event is logged when the first user is auto-promoted to super user (see [Auth - Auto-bootstrap](../reference/admin-api.md#auth)). 51 + The `user.bootstrapped` event is logged when the first user is auto-promoted to super user (see [Auth - Auto-bootstrap](../../reference/admin/admin-api.md#auth)). 52 52 53 53 ### Auth events 54 54 ··· 79 79 | `hook.executed` | info | Record AT URI | `lexicon_id` | 80 80 | `hook.dead_lettered` | error | Record AT URI | `lexicon_id`, `error` | 81 81 82 - Logged when [index hooks](index-hooks.md) run. Dead-lettered events indicate a hook failed all retry attempts. You can manage dead letters from the **Data > Dead Letters** page in the dashboard — see [Dead Letters](#dead-letters) below. 82 + Logged when [index hooks](../indexing/index-hooks.md) run. Dead-lettered events indicate a hook failed all retry attempts. You can manage dead letters from the **Data > Dead Letters** page in the dashboard — see [Dead Letters](#dead-letters) below. 83 83 84 84 ### Backfill events 85 85 ··· 89 89 | `backfill.completed` | info | Collection NSID | `job_id`, `total_repos` | 90 90 | `backfill.failed` | error | Collection NSID | `job_id`, `error` | 91 91 92 - See [Backfill](backfill.md) for background on backfill jobs. 92 + See [Backfill](../indexing/backfill.md) for background on backfill jobs. 93 93 94 94 ### Jetstream events 95 95 ··· 118 118 curl "http://localhost:3000/admin/events?limit=20&cursor=2026-03-01T11:59:00Z" -H "$AUTH" 119 119 ``` 120 120 121 - See the [Admin API reference](../reference/admin/events.md#list-event-logs) for full parameter documentation. 121 + See the [Admin API reference](../../reference/admin/events.md#list-event-logs) for full parameter documentation. 122 122 123 123 ## Retention 124 124 ··· 126 126 127 127 Set `EVENT_LOG_RETENTION_DAYS=0` to disable automatic cleanup and keep logs indefinitely. 128 128 129 - See [Configuration](../getting-started/configuration.md) for all environment variables. 129 + See [Configuration](../../getting-started/configuration.md) for all environment variables. 130 130 131 131 ## Dead Letters 132 132 ··· 142 142 143 143 ## Next steps 144 144 145 - - [Admin API — Event Logs](../reference/admin/events.md) — full query parameters and response format 145 + - [Admin API — Event Logs](../../reference/admin/events.md) — full query parameters and response format 146 146 - [Permissions](permissions.md) — control which users can read event logs 147 - - [Troubleshooting](../reference/troubleshooting.md) — using event logs to diagnose issues 147 + - [Troubleshooting](../../reference/troubleshooting.md) — using event logs to diagnose issues
+2 -2
packages/docs/docs/guides/admin/permissions.md
··· 132 132 - `PATCH /admin/users/{id}/permissions` — grant or revoke individual permissions 133 133 - `POST /admin/users/transfer-super` — transfer super user status (super user only) 134 134 135 - See the [Admin API — Users](../reference/admin/users.md) for full details. 135 + See the [Admin API — Users](../../reference/admin/users.md) for full details. 136 136 137 137 ## Next steps 138 138 139 - - [Admin API reference](../reference/admin-api.md) — endpoint documentation with required permissions 139 + - [Admin API reference](../../reference/admin/admin-api.md) — endpoint documentation with required permissions 140 140 - [API Keys](api-keys.md) — creating scoped API keys 141 141 - [Event Logs](event-logs.md) — permission-denied events are logged for auditing
+2 -2
packages/docs/docs/guides/database/database-setup.md
··· 74 74 75 75 - [SQLite → Postgres migration](sqlite-to-postgres-migration.md) — switch an existing instance from SQLite to Postgres 76 76 - [Postgres → SQLite migration](postgres-to-sqlite-migration.md) — switch an existing instance from Postgres to SQLite 77 - - [Lua scripting](scripting.md) — write queries that target either backend 78 - - [Configuration](../getting-started/configuration.md) — `DATABASE_URL` and related variables 77 + - [Lua scripting](../scripting.md) — write queries that target either backend 78 + - [Configuration](../../getting-started/configuration.md) — `DATABASE_URL` and related variables
+2 -2
packages/docs/docs/guides/database/postgres-to-sqlite-migration.md
··· 87 87 88 88 - [SQLite → Postgres migration](sqlite-to-postgres-migration.md) — migrate in the opposite direction 89 89 - [Database setup](database-setup.md) — choose between SQLite and Postgres for new instances 90 - - [Backfill](backfill.md) — re-index records from the network after switching backends 91 - - [Lua scripting](scripting.md) — write SQL that works against either backend 90 + - [Backfill](../indexing/backfill.md) — re-index records from the network after switching backends 91 + - [Lua scripting](../scripting.md) — write SQL that works against either backend
+2 -2
packages/docs/docs/guides/database/sqlite-to-postgres-migration.md
··· 84 84 85 85 - [Postgres → SQLite migration](postgres-to-sqlite-migration.md) — migrate in the opposite direction 86 86 - [Database setup](database-setup.md) — choose between SQLite and Postgres for new instances 87 - - [Backfill](backfill.md) — re-index records from the network after switching backends 88 - - [Lua scripting](scripting.md) — write SQL that works against either backend 87 + - [Backfill](../indexing/backfill.md) — re-index records from the network after switching backends 88 + - [Lua scripting](../scripting.md) — write SQL that works against either backend
+9 -9
packages/docs/docs/guides/features/api-clients.md
··· 2 2 3 3 API clients identify your application to a HappyView instance. Every XRPC request — even unauthenticated queries — must include a client key. This guide walks through creating a client, choosing between public and confidential types, and authenticating users. 4 4 5 - For the admin CRUD endpoints, see the [API reference](../reference/admin/api-clients.md). For the JavaScript SDK, see the [SDK docs](../sdk/overview.md). 5 + For the admin CRUD endpoints, see the [API reference](../../reference/admin/api-clients.md). For the JavaScript SDK, see the [SDK docs](../../sdk/overview.md). 6 6 7 7 ## Concepts 8 8 ··· 63 63 }' 64 64 ``` 65 65 66 - See the [API reference](../reference/admin/api-clients.md#create-an-api-client) for all fields. 66 + See the [API reference](../../reference/admin/api-clients.md#create-an-api-client) for all fields. 67 67 68 68 ## Using your client key 69 69 ··· 91 91 92 92 ### Authenticated requests (user identity) 93 93 94 - Procedures — and queries whose scripts need to know who the caller is — require a user's OAuth session. This uses [DPoP authentication](../getting-started/authentication.md#dpop-key-provisioning-for-third-party-apps), where each request includes a cryptographic proof that the caller holds the right key. 94 + Procedures — and queries whose scripts need to know who the caller is — require a user's OAuth session. This uses [DPoP authentication](../../getting-started/authentication.md#dpop-key-provisioning-for-third-party-apps), where each request includes a cryptographic proof that the caller holds the right key. 95 95 96 96 ```sh 97 97 curl -X POST 'https://happyview.example.com/xrpc/com.example.createPost' \ ··· 141 141 } 142 142 ``` 143 143 144 - For server-side Node.js apps, use the core [`@happyview/oauth-client`](../sdk/oauth-client.md) package with a confidential client. For type-safe XRPC calls, pair either client with [`@happyview/lex-agent`](../sdk/lex-agent.md). 144 + For server-side Node.js apps, use the core [`@happyview/oauth-client`](../../sdk/oauth-client.md) package with a confidential client. For type-safe XRPC calls, pair either client with [`@happyview/lex-agent`](../../sdk/lex-agent.md). 145 145 146 146 ### Manual DPoP flow 147 147 ··· 348 348 | `RateLimit-Reset` | Unix timestamp when the bucket will be full | 349 349 | `Retry-After` | Seconds to wait (only on `429` responses) | 350 350 351 - Adjust per-client rate limits via the dashboard or the [admin API](../reference/admin/api-clients.md#update-an-api-client). 351 + Adjust per-client rate limits via the dashboard or the [admin API](../../reference/admin/api-clients.md#update-an-api-client). 352 352 353 353 ## Security notes 354 354 ··· 359 359 360 360 ## Next steps 361 361 362 - - [Authentication](../getting-started/authentication.md) — full protocol details and security model 363 - - [JavaScript SDK](../sdk/overview.md) — get started with the SDK 364 - - [Admin API — API Clients](../reference/admin/api-clients.md) — CRUD endpoints 365 - - [Permissions](permissions.md) — control who can manage API clients 362 + - [Authentication](../../getting-started/authentication.md) — full protocol details and security model 363 + - [JavaScript SDK](../../sdk/overview.md) — get started with the SDK 364 + - [Admin API — API Clients](../../reference/admin/api-clients.md) — CRUD endpoints 365 + - [Permissions](../admin/permissions.md) — control who can manage API clients
+2 -2
packages/docs/docs/guides/features/developing-plugins.md
··· 101 101 102 102 - [Official plugins repository](https://github.com/gamesgamesgamesgamesgames/happyview-plugins) — ready-to-use plugins and the plugin SDK 103 103 - [Plugins guide](plugins.md) — install and configure plugins 104 - - [API Keys](api-keys.md) — authenticate programmatic access to admin endpoints 105 - - [Permissions](permissions.md) — configure user access to plugin management 104 + - [API Keys](../admin/api-keys.md) — authenticate programmatic access to admin endpoints 105 + - [Permissions](../admin/permissions.md) — configure user access to plugin management
+4 -4
packages/docs/docs/guides/features/labelers.md
··· 65 65 66 66 Self-labels (applied by the record author) use an outline badge style to distinguish them from external labels. Hover over a badge to see the source labeler's DID. 67 67 68 - Labels are also available in the records API response and in Lua scripts via the [`atproto.get_labels` and `atproto.get_labels_batch`](../reference/lua/atproto-api.md#atprotoget_labels) functions. 68 + Labels are also available in the records API response and in Lua scripts via the [`atproto.get_labels` and `atproto.get_labels_batch`](../../reference/lua/atproto-api.md#atprotoget_labels) functions. 69 69 70 70 ## Using labels in your AppView 71 71 ··· 85 85 86 86 ## Next steps 87 87 88 - - [Admin API — Labelers](../reference/admin/labelers.md) — full endpoint documentation 89 - - [atproto API](../reference/lua/atproto-api.md) — access labels in Lua scripts with `get_labels` and `get_labels_batch` 90 - - [Permissions](permissions.md) — manage user access to labeler operations 88 + - [Admin API — Labelers](../../reference/admin/labelers.md) — full endpoint documentation 89 + - [atproto API](../../reference/lua/atproto-api.md) — access labels in Lua scripts with `get_labels` and `get_labels_batch` 90 + - [Permissions](../admin/permissions.md) — manage user access to labeler operations
+2 -2
packages/docs/docs/guides/features/plugins.md
··· 75 75 76 76 - [Developing Plugins](developing-plugins.md) — create your own plugins with the WASM plugin API 77 77 - [Official plugins repository](https://github.com/gamesgamesgamesgamesgames/happyview-plugins) — ready-to-use plugins for Steam, Xbox, itch.io, and more 78 - - [API Keys](api-keys.md) — authenticate programmatic access to admin endpoints 79 - - [Permissions](permissions.md) — configure user access to plugin management 78 + - [API Keys](../admin/api-keys.md) — authenticate programmatic access to admin endpoints 79 + - [Permissions](../admin/permissions.md) — configure user access to plugin management
+3 -3
packages/docs/docs/guides/indexing/backfill.md
··· 5 5 ## When backfill runs 6 6 7 7 - **Automatically** when a record-type lexicon is uploaded with `backfill: true` (the default). See [Lexicons - Backfill flag](lexicons.md#backfill-flag). 8 - - **Manually** via `POST /admin/backfill` or the [dashboard](../getting-started/dashboard.md). You can scope a manual backfill to a specific collection, a specific DID, or both. 8 + - **Manually** via `POST /admin/backfill` or the [dashboard](../../getting-started/dashboard.md). You can scope a manual backfill to a specific collection, a specific DID, or both. 9 9 10 - See the [admin API](../reference/admin/backfill.md) for endpoint details. 10 + See the [admin API](../../reference/admin/backfill.md) for endpoint details. 11 11 12 12 ## How it works 13 13 ··· 34 34 ## Next steps 35 35 36 36 - [Lexicons](lexicons.md#backfill-flag): Control whether lexicons trigger backfill on upload 37 - - [Admin API — Backfill](../reference/admin/backfill.md): Full reference for backfill endpoints 37 + - [Admin API — Backfill](../../reference/admin/backfill.md): Full reference for backfill endpoints
+11 -11
packages/docs/docs/guides/indexing/index-hooks.md
··· 2 2 3 3 Index hooks are Lua scripts that run whenever a record in a collection is created, updated, or deleted. They run **before** the record is indexed, giving you the ability to filter out unwanted records, transform record data before storage, or trigger side effects like syncing with external services. 4 4 5 - Index hooks fire on **all** record events for the collection — including records created by HappyView procedure endpoints, not just events from the network. Unlike [query and procedure scripts](scripting.md) that run in response to XRPC requests, index hooks are triggered by incoming Jetstream events (which include events caused by HappyView's own PDS writes). 5 + Index hooks fire on **all** record events for the collection — including records created by HappyView procedure endpoints, not just events from the network. Unlike [query and procedure scripts](../scripting.md) that run in response to XRPC requests, index hooks are triggered by incoming Jetstream events (which include events caused by HappyView's own PDS writes). 6 6 7 7 ## Attaching a hook 8 8 9 - Each record-type lexicon can have one index hook. You can add it through the [dashboard](../getting-started/dashboard.md) (click "Add Index Hook" on any record lexicon's detail page) or via the [admin API](../reference/admin/lexicons.md#upload--upsert-a-lexicon) by including the `index_hook` field when uploading a lexicon. 9 + Each record-type lexicon can have one index hook. You can add it through the [dashboard](../../getting-started/dashboard.md) (click "Add Index Hook" on any record lexicon's detail page) or via the [admin API](../../reference/admin/lexicons.md#upload--upsert-a-lexicon) by including the `index_hook` field when uploading a lexicon. 10 10 11 11 ## Script structure 12 12 ··· 57 57 58 58 Index hooks have access to: 59 59 60 - - **[Database API](../reference/lua/database-api.md)** — `db.query`, `db.get`, `db.search`, `db.backlinks`, `db.count`, `db.raw` 61 - - **[HTTP API](../reference/lua/http-api.md)** — `http.get`, `http.post`, `http.put`, `http.patch`, `http.delete`, `http.head` 62 - - **[JSON API](../reference/lua/json-api.md)** — `json.encode`, `json.decode` 63 - - **[Utility globals](scripting.md#utility-globals)** — `log()`, `now()`, `TID()`, `toarray()` 60 + - **[Database API](../../reference/lua/database-api.md)** — `db.query`, `db.get`, `db.search`, `db.backlinks`, `db.count`, `db.raw` 61 + - **[HTTP API](../../reference/lua/http-api.md)** — `http.get`, `http.post`, `http.put`, `http.patch`, `http.delete`, `http.head` 62 + - **[JSON API](../../reference/lua/json-api.md)** — `json.encode`, `json.decode` 63 + - **[Utility globals](../scripting.md#utility-globals)** — `log()`, `now()`, `TID()`, `toarray()` 64 64 65 65 ## Error handling and retries 66 66 ··· 70 70 2. If all retries are exhausted, the failed event is inserted into the `dead_letter_hooks` table for later inspection. 71 71 3. On failure the system **fails open** — the original record is stored as-is so indexing is not permanently blocked. 72 72 73 - Failed hooks are logged as errors. Check the [event logs](event-logs.md) or query the `dead_letter_hooks` table directly to find and replay failures. 73 + Failed hooks are logged as errors. Check the [event logs](../admin/event-logs.md) or query the `dead_letter_hooks` table directly to find and replay failures. 74 74 75 75 ### Performance considerations 76 76 ··· 178 178 end 179 179 ``` 180 180 181 - See the full [Algolia sync reference](../reference/scripts/algolia-sync.md) for more detail. 181 + See the full [Algolia sync reference](../scripting/algolia-sync.md) for more detail. 182 182 183 183 ### Sync to Meilisearch 184 184 ··· 213 213 end 214 214 ``` 215 215 216 - See the full [Meilisearch sync reference](../reference/scripts/meilisearch-sync.md) for more detail. 216 + See the full [Meilisearch sync reference](../scripting/meilisearch-sync.md) for more detail. 217 217 218 218 ## Next steps 219 219 220 - - [Lua Scripting](scripting.md): Full reference for the sandbox, APIs, and debugging 220 + - [Lua Scripting](../scripting.md): Full reference for the sandbox, APIs, and debugging 221 221 - [Lexicons](lexicons.md): Understand how record, query, and procedure lexicons work together 222 - - [Admin API — Lexicons](../reference/admin/lexicons.md#upload--upsert-a-lexicon): Upload lexicons with index hooks via the API 222 + - [Admin API — Lexicons](../../reference/admin/lexicons.md#upload--upsert-a-lexicon): Upload lexicons with index hooks via the API
+7 -7
packages/docs/docs/guides/indexing/lexicons.md
··· 2 2 3 3 Lexicons are the core building block of HappyView. They're [atproto schema definitions](https://atproto.com/specs/lexicon) that describe your data model, and HappyView uses them to decide which records to index from the network and what XRPC endpoints to serve. 4 4 5 - You don't write route handlers or database queries; you upload a lexicon and HappyView generates the infrastructure from it. There are two ways to add lexicons: uploading them via the [admin API](../reference/admin/lexicons.md) or [dashboard](../getting-started/dashboard.md), or fetching them directly from the atproto network via [DNS authority resolution](#network-lexicons). 5 + You don't write route handlers or database queries; you upload a lexicon and HappyView generates the infrastructure from it. There are two ways to add lexicons: uploading them via the [admin API](../../reference/admin/lexicons.md) or [dashboard](../../getting-started/dashboard.md), or fetching them directly from the atproto network via [DNS authority resolution](#network-lexicons). 6 6 7 7 ## Supported lexicon types 8 8 ··· 13 13 | `procedure` | Registers a `POST /xrpc/{nsid}` endpoint that proxies writes to the user's PDS | 14 14 | `definitions` | Stored but does not generate routes or subscriptions | 15 15 16 - A typical setup has three lexicons working together: a **record** lexicon that defines the data and triggers indexing, a **query** lexicon that exposes a read endpoint, and a **procedure** lexicon that exposes a write endpoint. The [Statusphere tutorial](../tutorials/statusphere.md) walks through this pattern end-to-end. 16 + A typical setup has three lexicons working together: a **record** lexicon that defines the data and triggers indexing, a **query** lexicon that exposes a read endpoint, and a **procedure** lexicon that exposes a write endpoint. The [Statusphere tutorial](../../tutorials/statusphere.md) walks through this pattern end-to-end. 17 17 18 18 ## Target collection 19 19 ··· 21 21 22 22 For example, a query lexicon `xyz.statusphere.listStatuses` would set `target_collection` to `xyz.statusphere.status` to read from that record collection. 23 23 24 - See the [admin API](../reference/admin/lexicons.md#upload--upsert-a-lexicon) for how to set `target_collection` when uploading. 24 + See the [admin API](../../reference/admin/lexicons.md#upload--upsert-a-lexicon) for how to set `target_collection` when uploading. 25 25 26 26 :::note 27 27 The `target_collection` is available in Lua scripts as the `collection` global, but it is not required if your endpoint uses a Lua script. ··· 89 89 A few things to note: 90 90 91 91 - HappyView does **not** proxy to the reversed hostname directly. `foo.example.com` is only the DNS host for the TXT record — the actual XRPC request goes to whatever PDS endpoint the authority DID resolves to. 92 - - Proxying applies equally to queries and procedures. For procedures, HappyView uses the caller's OAuth session to attach a DPoP-bound access token (see [Authentication](../getting-started/authentication.md#proxying-procedures-to-the-users-pds)). 92 + - Proxying applies equally to queries and procedures. For procedures, HappyView uses the caller's OAuth session to attach a DPoP-bound access token (see [Authentication](../../getting-started/authentication.md#proxying-procedures-to-the-users-pds)). 93 93 - If authority resolution fails — no TXT record, unresolvable DID, or the target PDS doesn't support the method — the client gets an error back. HappyView does not fall back to any other routing strategy. 94 94 - Tracking a network lexicon does **not** make HappyView handle requests for that NSID locally. Network lexicons are only about indexing record collections and keeping the schema up to date. If a client calls a query NSID that you've tracked as a network lexicon but haven't uploaded a local query lexicon for, HappyView still proxies the request out — it won't query your local record table. To serve a method locally, upload a local query or procedure lexicon with a matching `target_collection`. 95 95 ··· 97 97 98 98 ## Next steps 99 99 100 - - [Lua Scripting](scripting.md): Add custom query and procedure logic to your endpoints 100 + - [Lua Scripting](../scripting.md): Add custom query and procedure logic to your endpoints 101 101 - [Index Hooks](index-hooks.md): Run Lua scripts when records are indexed from the network 102 - - [XRPC API](../reference/xrpc-api.md): Understand how the generated endpoints behave 102 + - [XRPC API](../../reference/xrpc-api.md): Understand how the generated endpoints behave 103 103 - [Backfill](backfill.md): Learn how historical records are indexed 104 - - [Admin API](../reference/admin-api.md): Full reference for lexicon management endpoints 104 + - [Admin API](../../reference/admin/admin-api.md): Full reference for lexicon management endpoints
+15 -15
packages/docs/docs/guides/scripting.md
··· 10 10 11 11 Scripts are attached to query and procedure lexicons and run in a sandboxed Lua VM with access to the [Record API](#record-api), a [database API](#database-api), an [HTTP client API](#http-api), a [JSON API](#json-api), and a set of [context globals](#context-globals). 12 12 13 - For scripts that react to record changes from the network (rather than XRPC requests), see [Index Hooks](index-hooks.md). 13 + For scripts that react to record changes from the network (rather than XRPC requests), see [Index Hooks](indexing/index-hooks.md). 14 14 15 15 ## Script structure 16 16 ··· 177 177 See the example script references for complete, ready-to-use scripts: 178 178 179 179 **Queries:** 180 - - [Get a record](../reference/scripts/get-record.md) — fetch a single record by AT URI 181 - - [Paginated list](../reference/scripts/paginated-list.md) — list records with cursor-based pagination and DID filtering 182 - - [List or fetch](../reference/scripts/list-or-fetch.md) — combined single-record lookup and paginated listing 183 - - [Expanded query](../reference/scripts/expanded-query.md) — list statuses with user profiles in a single response 180 + - [Get a record](scripting/get-record.md) — fetch a single record by AT URI 181 + - [Paginated list](scripting/paginated-list.md) — list records with cursor-based pagination and DID filtering 182 + - [List or fetch](scripting/list-or-fetch.md) — combined single-record lookup and paginated listing 183 + - [Expanded query](scripting/expanded-query.md) — list statuses with user profiles in a single response 184 184 185 185 **Procedures:** 186 - - [Create a record](../reference/scripts/create-record.md) — simple write that saves input as a record 187 - - [Upsert a record](../reference/scripts/upsert-record.md) — create or update using a deterministic rkey 188 - - [Update or delete](../reference/scripts/update-or-delete.md) — single endpoint handling create, update, and delete 189 - - [Batch save](../reference/scripts/batch-save.md) — create multiple records in parallel with `Record.save_all()` 190 - - [Sidecar records](../reference/scripts/sidecar-records.md) — create linked records across collections with a shared rkey 191 - - [Cascading delete](../reference/scripts/cascading-delete.md) — delete a record and all related records 192 - - [Complex mutations](../reference/scripts/complex-mutations.md) — load, transform, and save a record with multiple field changes 186 + - [Create a record](scripting/create-record.md) — simple write that saves input as a record 187 + - [Upsert a record](scripting/upsert-record.md) — create or update using a deterministic rkey 188 + - [Update or delete](scripting/update-or-delete.md) — single endpoint handling create, update, and delete 189 + - [Batch save](scripting/batch-save.md) — create multiple records in parallel with `Record.save_all()` 190 + - [Sidecar records](scripting/sidecar-records.md) — create linked records across collections with a shared rkey 191 + - [Cascading delete](scripting/cascading-delete.md) — delete a record and all related records 192 + - [Complex mutations](scripting/complex-mutations.md) — load, transform, and save a record with multiple field changes 193 193 194 194 **Index Hooks:** 195 - - [Algolia sync](../reference/scripts/algolia-sync.md) — push records to an Algolia search index on create/update/delete 195 + - [Algolia sync](scripting/algolia-sync.md) — push records to an Algolia search index on create/update/delete 196 196 197 197 ## Next steps 198 198 199 - - [Index Hooks](index-hooks.md): React to record changes from the network in real time 200 - - [Lexicons](lexicons.md): Understand how record, query, and procedure lexicons work together 199 + - [Index Hooks](indexing/index-hooks.md): React to record changes from the network in real time 200 + - [Lexicons](indexing/lexicons.md): Understand how record, query, and procedure lexicons work together 201 201 - [XRPC API](../reference/xrpc-api.md): See how endpoints behave with and without Lua scripts 202 202 - [Dashboard](../getting-started/dashboard.md#lua-editor): Use the web editor with context-aware completions
+1 -1
packages/docs/docs/guides/scripting/algolia-sync.md
··· 37 37 1. On **create** or **update**: sends a `PUT` request to Algolia's index API with the record data, using the AT URI as the `objectID`. Algolia upserts the object — if it already exists, it's replaced. 38 38 2. On **delete**: sends a `DELETE` request to remove the object from the index by its AT URI. 39 39 40 - The `json.encode()` function converts the Lua table into a JSON string for the request body. See [JSON API](../../guides/index-hooks.md#json-api). 40 + The `json.encode()` function converts the Lua table into a JSON string for the request body. See [JSON API](../../reference/lua/json-api.md). 41 41 42 42 ## Configuration 43 43
+2 -2
packages/docs/docs/guides/scripting/batch-save.md
··· 23 23 24 24 ## How it works 25 25 26 - 1. Iterate over `input.items` and create a [`Record`](../lua/record-api.md) instance for each item. 27 - 2. Call [`Record.save_all()`](../lua/record-api.md#static-methods) to save all records in parallel, rather than one at a time. 26 + 1. Iterate over `input.items` and create a [`Record`](../../reference/lua/record-api.md) instance for each item. 27 + 2. Call [`Record.save_all()`](../../reference/lua/record-api.md#static-methods) to save all records in parallel, rather than one at a time. 28 28 3. Collect the resulting AT URIs and return them. 29 29 30 30 ## Usage
+1 -1
packages/docs/docs/guides/scripting/cascading-delete.md
··· 49 49 50 50 1. Load the primary record by URI. Return early if it doesn't exist. 51 51 2. Query for related records, in this example comments by the same user that reference the primary record's URI. 52 - 3. Load each related record with [`Record.load`](../lua/record-api.md#static-methods) to get a deletable `Record` instance. 52 + 3. Load each related record with [`Record.load`](../../reference/lua/record-api.md#static-methods) to get a deletable `Record` instance. 53 53 4. Delete everything. Each `r:delete()` removes the record from the user's PDS and the local index. 54 54 55 55 ## Usage
+1 -1
packages/docs/docs/guides/scripting/complex-mutations.md
··· 56 56 57 57 ## How it works 58 58 59 - 1. Load the existing record with [`Record.load`](../lua/record-api.md#static-methods). This gives you a mutable `Record` instance with all the current field values. 59 + 1. Load the existing record with [`Record.load`](../../reference/lua/record-api.md#static-methods). This gives you a mutable `Record` instance with all the current field values. 60 60 2. Apply transformations directly on the record's fields: 61 61 - **Increment a counter**: use `or 0` to handle the field being `nil` on first access. 62 62 - **Merge tags**: iterate over `input.tags`, skip duplicates already in `r.tags`, append new ones, then trim the list to 10.
+1 -1
packages/docs/docs/guides/scripting/create-record.md
··· 14 14 15 15 ## How it works 16 16 17 - 1. Create a new [`Record`](../lua/record-api.md) instance from the target collection, populated with the fields from the request body. 17 + 1. Create a new [`Record`](../../reference/lua/record-api.md) instance from the target collection, populated with the fields from the request body. 18 18 2. Call `r:save()`, which creates the record on the caller's PDS and indexes it locally. 19 19 3. Return the AT URI and CID of the newly created record. 20 20
+1 -1
packages/docs/docs/guides/scripting/expanded-query.md
··· 51 51 1. Query statuses from the target collection with pagination, same as a normal list query. 52 52 2. Extract the unique DIDs from the returned status URIs using `string.match`. 53 53 3. Build an AT URI for each DID's `app.bsky.actor.profile/self` record (this is where Bluesky profiles live). 54 - 4. Load all profiles in parallel with [`Record.load_all`](../lua/record-api.md#static-methods). Profiles that aren't indexed locally return `nil` and are skipped. 54 + 4. Load all profiles in parallel with [`Record.load_all`](../../reference/lua/record-api.md#static-methods). Profiles that aren't indexed locally return `nil` and are skipped. 55 55 5. Return statuses and profiles as separate keys, with the cursor from the status query. 56 56 57 57 ## Usage
+1 -1
packages/docs/docs/guides/scripting/get-record.md
··· 22 22 ## How it works 23 23 24 24 1. Check that the `uri` query parameter is present. Return a structured error if missing. 25 - 2. Look up the record with [`db.get`](../lua/database-api.md#dbget), which returns the record table or `nil`. 25 + 2. Look up the record with [`db.get`](../../reference/lua/database-api.md#dbget), which returns the record table or `nil`. 26 26 3. Return the record wrapped in an object. 27 27 28 28 ## Usage
+2 -2
packages/docs/docs/guides/scripting/list-or-fetch.md
··· 25 25 26 26 ## How it works 27 27 28 - 1. If a `uri` query parameter is provided, fetch that single record with [`db.get`](../lua/database-api.md#dbget) and return it. If it doesn't exist, return a structured error (using `error()` would trigger a 500 response). 29 - 2. Otherwise, list records from the target collection using [`db.query`](../lua/database-api.md#dbquery), with optional filtering by `did` and cursor-based pagination. The `cursor` is an opaque string from a previous response — pass it through directly. Since `limit` arrives as a string, `tonumber()` converts it to a number. 28 + 1. If a `uri` query parameter is provided, fetch that single record with [`db.get`](../../reference/lua/database-api.md#dbget) and return it. If it doesn't exist, return a structured error (using `error()` would trigger a 500 response). 29 + 2. Otherwise, list records from the target collection using [`db.query`](../../reference/lua/database-api.md#dbquery), with optional filtering by `did` and cursor-based pagination. The `cursor` is an opaque string from a previous response — pass it through directly. Since `limit` arrives as a string, `tonumber()` converts it to a number. 30 30 31 31 ## Usage 32 32
+2 -2
packages/docs/docs/guides/scripting/meilisearch-sync.md
··· 38 38 1. On **create** or **update**: sends a `POST` request to Meilisearch's document API with the record data wrapped in an array. Meilisearch upserts by `id` — if a document with the same AT URI already exists, it's replaced. 39 39 2. On **delete**: sends a `DELETE` request to remove the document from the index by its AT URI. 40 40 41 - The `toarray()` function ensures the table is encoded as a JSON array (Meilisearch expects an array of documents). See [JSON API](../../guides/index-hooks.md#json-api). 41 + The `toarray()` function ensures the table is encoded as a JSON array (Meilisearch expects an array of documents). See [JSON API](../../reference/lua/json-api.md). 42 42 43 43 ## Configuration 44 44 45 - This script uses [script variables](../../guides/scripting.md) instead of hardcoded values. Set these via the [admin API](../../reference/admin-api.md) or dashboard: 45 + This script uses [script variables](../../guides/scripting.md) instead of hardcoded values. Set these via the [admin API](../../reference/admin/admin-api.md) or dashboard: 46 46 47 47 | Variable | Value | 48 48 | --------------------- | ------------------------------------------------------------------------------ |
+1 -1
packages/docs/docs/guides/scripting/paginated-list.md
··· 23 23 ## How it works 24 24 25 25 1. Parse `limit` from the query string, defaulting to 20 and capping at 100. 26 - 2. Call [`db.query`](../lua/database-api.md#dbquery) with the target collection, optional DID filter, and cursor for pagination. 26 + 2. Call [`db.query`](../../reference/lua/database-api.md#dbquery) with the target collection, optional DID filter, and cursor for pagination. 27 27 3. Return the result directly. `db.query` returns `{ records = [...], cursor = "..." }` where `cursor` is an opaque string present when more records exist. 28 28 29 29 ## Usage
+1 -1
packages/docs/docs/guides/scripting/sidecar-records.md
··· 34 34 35 35 1. Generate a single [`TID()`](../../guides/scripting.md#utility-globals) to use as the rkey for both records. 36 36 2. Create a `Record` for each collection and call `r:set_rkey()` with the shared rkey. 37 - 3. Save both records in parallel with [`Record.save_all()`](../lua/record-api.md#static-methods). 37 + 3. Save both records in parallel with [`Record.save_all()`](../../reference/lua/record-api.md#static-methods). 38 38 4. Return both URIs so the client knows the identity of each record. 39 39 40 40 ## Usage
+2 -2
packages/docs/docs/guides/scripting/update-or-delete.md
··· 30 30 31 31 ## How it works 32 32 33 - 1. If `input.delete` is truthy and `input.uri` is provided, load the record with [`Record.load`](../lua/record-api.md#static-methods) and delete it. 34 - 2. If only `input.uri` is provided, load the existing record with [`Record.load`](../lua/record-api.md#static-methods), update its fields, and save it back. Since `_uri` is already set, `r:save()` calls `putRecord` instead of `createRecord`. 33 + 1. If `input.delete` is truthy and `input.uri` is provided, load the record with [`Record.load`](../../reference/lua/record-api.md#static-methods) and delete it. 34 + 2. If only `input.uri` is provided, load the existing record with [`Record.load`](../../reference/lua/record-api.md#static-methods), update its fields, and save it back. Since `_uri` is already set, `r:save()` calls `putRecord` instead of `createRecord`. 35 35 3. If neither condition matches, create a new record from the input. 36 36 37 37 ## Usage
+1 -1
packages/docs/docs/guides/scripting/upsert-record.md
··· 33 33 ## How it works 34 34 35 35 1. Use the client-provided `input.rkey` if present, otherwise generate a new [`TID()`](../../guides/scripting.md#utility-globals). This means omitting `rkey` always creates, while providing one enables updates. 36 - 2. Build the AT URI from the caller's DID, the target collection, and the rkey, then try to load it with [`Record.load`](../lua/record-api.md#static-methods). 36 + 2. Build the AT URI from the caller's DID, the target collection, and the rkey, then try to load it with [`Record.load`](../../reference/lua/record-api.md#static-methods). 37 37 3. If the record exists, update its fields and save. Since `_uri` is already set, `r:save()` calls `putRecord`. 38 38 4. If it doesn't exist, create a new record, set the rkey explicitly with `r:set_rkey()`, and save. This calls `createRecord` with the specified rkey. 39 39
+15 -15
packages/docs/docs/reference/admin/admin-api.md
··· 1 1 # Admin API 2 2 3 - The admin API lets you manage lexicons, monitor records, run backfill jobs, and control user access. All endpoints live under `/admin` and require authentication from a DID that exists in the `users` table, with the appropriate [permissions](../guides/permissions.md) for the endpoint being called. You can also manage all of this through the [web dashboard](../getting-started/dashboard.md). 3 + The admin API lets you manage lexicons, monitor records, run backfill jobs, and control user access. All endpoints live under `/admin` and require authentication from a DID that exists in the `users` table, with the appropriate [permissions](../../guides/admin/permissions.md) for the endpoint being called. You can also manage all of this through the [web dashboard](../../getting-started/dashboard.md). 4 4 5 5 ## Auth 6 6 7 7 The admin API supports two authentication methods: 8 8 9 - 1. **API keys** — read/write tokens starting with `hv_`, passed as `Authorization: Bearer hv_...`. See the [API Keys guide](../guides/api-keys.md) for details. 9 + 1. **API keys** — read/write tokens starting with `hv_`, passed as `Authorization: Bearer hv_...`. See the [API Keys guide](../../guides/admin/api-keys.md) for details. 10 10 2. **Service auth JWT** — atproto inter-service authentication via signed JWTs. 11 11 12 12 In all cases the resolved DID is checked against the `users` table, and the user's permissions are loaded to authorize the request. ··· 41 41 42 42 | Group | Description | 43 43 | ----- | ----------- | 44 - | [Lexicons](admin/lexicons.md) | Upload, list, get, and delete lexicons and network lexicons | 45 - | [Stats](admin/stats.md) | Record counts by collection | 46 - | [Backfill](admin/backfill.md) | Create and monitor historical backfill jobs | 47 - | [Event Logs](admin/events.md) | Query the audit trail of system events | 48 - | [API Keys](admin/api-keys.md) | Create, list, and revoke API keys | 49 - | [Users](admin/users.md) | Create, list, update, and delete admin users | 50 - | [Labelers](admin/labelers.md) | Manage external labeler subscriptions | 51 - | [Instance Settings](admin/settings.md) | Configure app name, logo, and policy URLs | 52 - | [Domains](admin/domains.md) | Manage domains and their OAuth client identities | 53 - | [Script Variables](admin/script-variables.md) | Encrypted key/value pairs for Lua scripts | 54 - | [API Clients](admin/api-clients.md) | Register and manage third-party XRPC clients | 55 - | [Plugins](admin/plugins.md) | Install, configure, and manage WASM plugins | 44 + | [Lexicons](lexicons.md) | Upload, list, get, and delete lexicons and network lexicons | 45 + | [Stats](stats.md) | Record counts by collection | 46 + | [Backfill](backfill.md) | Create and monitor historical backfill jobs | 47 + | [Event Logs](events.md) | Query the audit trail of system events | 48 + | [API Keys](api-keys.md) | Create, list, and revoke API keys | 49 + | [Users](users.md) | Create, list, update, and delete admin users | 50 + | [Labelers](labelers.md) | Manage external labeler subscriptions | 51 + | [Instance Settings](settings.md) | Configure app name, logo, and policy URLs | 52 + | [Domains](domains.md) | Manage domains and their OAuth client identities | 53 + | [Script Variables](script-variables.md) | Encrypted key/value pairs for Lua scripts | 54 + | [API Clients](api-clients.md) | Register and manage third-party XRPC clients | 55 + | [Plugins](plugins.md) | Install, configure, and manage WASM plugins | 56 56 57 57 ## Permissions 58 58 59 - Each admin API endpoint requires a specific permission. See the [Permissions guide](../guides/permissions.md) for the full list of permissions and templates. 59 + Each admin API endpoint requires a specific permission. See the [Permissions guide](../../guides/admin/permissions.md) for the full list of permissions and templates. 60 60 61 61 | Endpoint | Required Permission | 62 62 | ---------------------------------------- | -------------------------- |
+1 -1
packages/docs/docs/reference/admin/api-clients.md
··· 4 4 5 5 A single API client represents your application, not individual users. Create one client for your app and use the same client key across all instances. Users authenticate separately via OAuth — the client key identifies _your app_, not _who is using it_. 6 6 7 - Each client has an `hvc_`-prefixed client key and an `hvs_`-prefixed client secret. The secret is only returned at creation and is sha256-hashed in the database. Server-to-server callers pass the secret as `X-Client-Secret`. Browser callers use the `Origin` header, which is matched against the client's `client_uri`. Mismatches currently log warnings rather than rejecting the request, but rate limiting applies either way. See [Authentication — XRPC](../../getting-started/authentication.md#xrpc-api-client-identification) for the client-side view, and the [API Keys guide](../../guides/api-keys.md) for how admin API keys differ from API clients. 7 + Each client has an `hvc_`-prefixed client key and an `hvs_`-prefixed client secret. The secret is only returned at creation and is sha256-hashed in the database. Server-to-server callers pass the secret as `X-Client-Secret`. Browser callers use the `Origin` header, which is matched against the client's `client_uri`. Mismatches currently log warnings rather than rejecting the request, but rate limiting applies either way. See [Authentication — XRPC](../../getting-started/authentication.md#xrpc-api-client-identification) for the client-side view, and the [API Keys guide](../../guides/admin/api-keys.md) for how admin API keys differ from API clients. 8 8 9 9 ```sh 10 10 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/admin/api-keys.md
··· 1 1 # Admin API: API Keys 2 2 3 - Manage API keys for programmatic access. See the [API Keys guide](../../guides/api-keys.md) for usage details. 3 + Manage API keys for programmatic access. See the [API Keys guide](../../guides/admin/api-keys.md) for usage details. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/admin/backfill.md
··· 1 1 # Admin API: Backfill 2 2 3 - Create and monitor historical backfill jobs. See the [Backfill guide](../../guides/backfill.md) for background. 3 + Create and monitor historical backfill jobs. See the [Backfill guide](../../guides/indexing/backfill.md) for background. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/admin/events.md
··· 1 1 # Admin API: Event Logs 2 2 3 - HappyView logs system events — lexicon changes, record operations, script errors, user actions, and more. See the [Event Logs guide](../../guides/event-logs.md) for details on event types and retention. 3 + HappyView logs system events — lexicon changes, record operations, script errors, user actions, and more. See the [Event Logs guide](../../guides/admin/event-logs.md) for details on event types and retention. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/admin/labelers.md
··· 1 1 # Admin API: Labelers 2 2 3 - Manage external labeler subscriptions. See the [Labelers guide](../../guides/labelers.md) for background. 3 + Manage external labeler subscriptions. See the [Labelers guide](../../guides/features/labelers.md) for background. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+3 -3
packages/docs/docs/reference/admin/lexicons.md
··· 1 1 # Admin API: Lexicons 2 2 3 - Manage lexicons and network lexicons. See the [Lexicons guide](../../guides/lexicons.md) for background on how lexicons drive indexing and XRPC routing. 3 + Manage lexicons and network lexicons. See the [Lexicons guide](../../guides/indexing/lexicons.md) for background on how lexicons drive indexing and XRPC routing. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...) ··· 30 30 | `backfill` | boolean | no | Whether uploading triggers historical backfill (default `true`) | 31 31 | `target_collection` | string | no | For query/procedure lexicons, the record collection they operate on | 32 32 | `script` | string | no | Lua script for query/procedure endpoints | 33 - | `index_hook` | string | no | [Index hook](../../guides/index-hooks.md) Lua script for record lexicons | 33 + | `index_hook` | string | no | [Index hook](../../guides/indexing/index-hooks.md) Lua script for record lexicons | 34 34 35 35 **Response**: `201 Created` (new) or `200 OK` (upsert) 36 36 ··· 92 92 93 93 ## Network Lexicons 94 94 95 - Network lexicons are fetched from the atproto network via DNS TXT resolution and kept updated via the Jetstream subscription. See [Lexicons - Network lexicons](../../guides/lexicons.md#network-lexicons) for background. 95 + Network lexicons are fetched from the atproto network via DNS TXT resolution and kept updated via the Jetstream subscription. See [Lexicons - Network lexicons](../../guides/indexing/lexicons.md#network-lexicons) for background. 96 96 97 97 ### Add a network lexicon 98 98
+1 -1
packages/docs/docs/reference/admin/plugins.md
··· 1 1 # Admin API: Plugins 2 2 3 - Plugins extend HappyView with WebAssembly modules sourced from the [official plugin registry](../../guides/plugins.md) or any URL serving a `manifest.json`. Most endpoints take a plugin manifest URL and load (or reload) the plugin in place — no restart needed. Encrypted plugin secrets require `TOKEN_ENCRYPTION_KEY` to be configured. 3 + Plugins extend HappyView with WebAssembly modules sourced from the [official plugin registry](../../guides/features/plugins.md) or any URL serving a `manifest.json`. Most endpoints take a plugin manifest URL and load (or reload) the plugin in place — no restart needed. Encrypted plugin secrets require `TOKEN_ENCRYPTION_KEY` to be configured. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/admin/users.md
··· 1 1 # Admin API: Users 2 2 3 - Manage admin users and their permissions. See the [Permissions guide](../../guides/permissions.md) for available permissions and templates. 3 + Manage admin users and their permissions. See the [Permissions guide](../../guides/admin/permissions.md) for available permissions and templates. 4 4 5 5 ```sh 6 6 # All examples assume $TOKEN is an API key (hv_...)
+1 -1
packages/docs/docs/reference/architecture.md
··· 31 31 Labeler["Labeler<br/><small>WebSocket (out-of-band)</small>"] -->|label events| DB 32 32 ``` 33 33 34 - Queries go through the query handler to the database (SQLite by default, or Postgres). Writes go through the procedure handler to the user's PDS, then HappyView indexes the record locally. Real-time record events stream in via [Jetstream](https://github.com/bluesky-social/jetstream); historical records are backfilled in-process by discovering repos via the relay's `listReposByCollection` and fetching records directly from each PDS. [Labelers](../guides/labelers.md) are external services that emit content labels over a direct WebSocket connection — they operate out-of-band, outside the relay/repo system. 34 + Queries go through the query handler to the database (SQLite by default, or Postgres). Writes go through the procedure handler to the user's PDS, then HappyView indexes the record locally. Real-time record events stream in via [Jetstream](https://github.com/bluesky-social/jetstream); historical records are backfilled in-process by discovering repos via the relay's `listReposByCollection` and fetching records directly from each PDS. [Labelers](../guides/features/labelers.md) are external services that emit content labels over a direct WebSocket connection — they operate out-of-band, outside the relay/repo system. 35 35 36 36 ## Request flow 37 37
+5 -5
packages/docs/docs/reference/glossary.md
··· 12 12 13 13 **Handle** — A human-readable name for an account (e.g. `user.bsky.social`). Handles resolve to a DID via a DNS TXT record or an HTTP `.well-known/atproto-did` lookup. 14 14 15 - **Lexicon** — A schema definition for atproto data types and API methods. Lexicons define what records look like, what endpoints exist, and what parameters they accept. See [Lexicons](../guides/lexicons.md). 15 + **Lexicon** — A schema definition for atproto data types and API methods. Lexicons define what records look like, what endpoints exist, and what parameters they accept. See [Lexicons](../guides/indexing/lexicons.md). 16 16 17 17 **NSID** (Namespaced Identifier) — A reverse-DNS identifier for a lexicon (e.g. `xyz.statusphere.status`). The authority is everything except the last segment. 18 18 ··· 22 22 23 23 **Record** — A single piece of data in an atproto repository, identified by an AT URI (e.g. `at://did:plc:abc/xyz.statusphere.status/abc123`). 24 24 25 - **Relay** — A network service that aggregates repository data from many PDSes. HappyView queries the relay during [backfill](../guides/backfill.md) to discover which repos contain records for a given collection, then fetches each repo's records directly from its PDS. 25 + **Relay** — A network service that aggregates repository data from many PDSes. HappyView queries the relay during [backfill](../guides/indexing/backfill.md) to discover which repos contain records for a given collection, then fetches each repo's records directly from its PDS. 26 26 27 27 **rkey** (Record Key) — The unique key for a record within a collection and repo. These are most commonly TIDs (timestamp-based) or NSIDs. 28 28 ··· 34 34 35 35 ## HappyView-specific terms 36 36 37 - **Backfill** — The process of bulk-indexing existing records from the network. HappyView discovers repos via the relay and fetches each repo's records directly from its PDS. Runs when a new record-type lexicon is uploaded or triggered manually. See [Backfill](../guides/backfill.md). 37 + **Backfill** — The process of bulk-indexing existing records from the network. HappyView discovers repos via the relay and fetches each repo's records directly from its PDS. Runs when a new record-type lexicon is uploaded or triggered manually. See [Backfill](../guides/indexing/backfill.md). 38 38 39 - **Network lexicon** — A lexicon fetched directly from the atproto network via DNS authority resolution, rather than uploaded manually. See [Lexicons - Network lexicons](../guides/lexicons.md#network-lexicons). 39 + **Network lexicon** — A lexicon fetched directly from the atproto network via DNS authority resolution, rather than uploaded manually. See [Lexicons - Network lexicons](../guides/indexing/lexicons.md#network-lexicons). 40 40 41 - **Permission** — A granular access control right that authorizes a specific action in the admin API. HappyView defines 20 permissions organized by category (e.g. `lexicons:create`, `users:read`). See [Permissions](../guides/permissions.md). 41 + **Permission** — A granular access control right that authorizes a specific action in the admin API. HappyView defines 20 permissions organized by category (e.g. `lexicons:create`, `users:read`). See [Permissions](../guides/admin/permissions.md). 42 42 43 43 **Permission template** — A predefined set of permissions that can be applied when creating a user. Templates are: **Viewer** (read-only access), **Operator** (viewer + backfill and API key management), **Manager** (operator + lexicon and record management), and **Full Access** (all 20 permissions). 44 44
+1 -1
packages/docs/docs/reference/lua/atproto-api.md
··· 1 1 # atproto API 2 2 3 - The `atproto` table provides atproto utility functions. Available in queries, procedures, and [index hooks](../../guides/index-hooks.md). 3 + The `atproto` table provides atproto utility functions. Available in queries, procedures, and [index hooks](../../guides/indexing/index-hooks.md). 4 4 5 5 ## atproto.resolve_service_endpoint 6 6
+2 -2
packages/docs/docs/reference/lua/database-api.md
··· 1 1 # Database API 2 2 3 - The `db` table provides access to the database. Available in queries, procedures, and [index hooks](../../guides/index-hooks.md). 3 + The `db` table provides access to the database. Available in queries, procedures, and [index hooks](../../guides/indexing/index-hooks.md). 4 4 5 5 ## db.query 6 6 ··· 95 95 96 96 ### SQL dialect 97 97 98 - Write SQL in **SQLite syntax** — HappyView translates it to Postgres at runtime if you're using Postgres. See [Database Setup](../../guides/database-setup.md) for details on what gets translated. If you need database-specific SQL that can't be translated, check `db.is_postgres()` at runtime. 98 + Write SQL in **SQLite syntax** — HappyView translates it to Postgres at runtime if you're using Postgres. See [Database Setup](../../guides/database/database-setup.md) for details on what gets translated. If you need database-specific SQL that can't be translated, check `db.is_postgres()` at runtime. 99 99 100 100 ### Column type mapping 101 101
+1 -1
packages/docs/docs/reference/lua/http-api.md
··· 1 1 # HTTP API 2 2 3 - The `http` table provides async HTTP client functions. Available in queries, procedures, and [index hooks](../../guides/index-hooks.md). 3 + The `http` table provides async HTTP client functions. Available in queries, procedures, and [index hooks](../../guides/indexing/index-hooks.md). 4 4 5 5 ## Methods 6 6
+1 -1
packages/docs/docs/reference/lua/json-api.md
··· 1 1 # JSON API 2 2 3 - The `json` global provides JSON serialization and deserialization. Available in queries, procedures, and [index hooks](../../guides/index-hooks.md). 3 + The `json` global provides JSON serialization and deserialization. Available in queries, procedures, and [index hooks](../../guides/indexing/index-hooks.md). 4 4 5 5 ## json.encode 6 6
+1 -1
packages/docs/docs/reference/lua/utility-globals.md
··· 1 1 # Utility Globals 2 2 3 - Global functions available in queries, procedures, and [index hooks](../../guides/index-hooks.md). These don't belong to a specific API table — they're available at the top level of any Lua script. 3 + Global functions available in queries, procedures, and [index hooks](../../guides/indexing/index-hooks.md). These don't belong to a specific API table — they're available at the top level of any Lua script. 4 4 5 5 ## now 6 6
+6 -6
packages/docs/docs/reference/troubleshooting.md
··· 18 18 19 19 **Causes**: 20 20 21 - - The query lexicon is missing a `target_collection`. Without it, the query doesn't know which records to read. See [Lexicons - target_collection](../guides/lexicons.md#target-collection). 21 + - The query lexicon is missing a `target_collection`. Without it, the query doesn't know which records to read. See [Lexicons - target_collection](../guides/indexing/lexicons.md#target-collection). 22 22 - The record-type lexicon hasn't finished backfilling. Check backfill status with `GET /admin/backfill/status` or the dashboard. 23 - - Records exist on the network but HappyView hasn't indexed them yet. Jetstream only delivers events from after the collection was added to the filter. Use [backfill](../guides/backfill.md) to import historical records. 23 + - Records exist on the network but HappyView hasn't indexed them yet. Jetstream only delivers events from after the collection was added to the filter. Use [backfill](../guides/indexing/backfill.md) to import historical records. 24 24 25 25 ## Procedure returns 401 Unauthorized 26 26 ··· 48 48 49 49 **Causes**: 50 50 51 - - Your user account doesn't have the specific permission required by the endpoint. Each endpoint requires a specific permission — see the [permissions table](admin-api.md#permissions). 51 + - Your user account doesn't have the specific permission required by the endpoint. Each endpoint requires a specific permission — see the [permissions table](admin/admin-api.md#permissions). 52 52 - If using an API key, the key's effective permissions are the intersection of the key's permissions and your user permissions. A key can never have more access than the user who created it. 53 53 - Only the super user can call `POST /admin/users/transfer-super`. This endpoint cannot be accessed with any permission — it requires super user status. 54 54 ··· 74 74 - The relay (`RELAY_URL`) may be unreachable or slow to respond. Check connectivity. 75 75 - Individual PDS fetches can fail silently. The worker logs warnings and continues. Check server logs for details. 76 76 77 - See [Backfill](../guides/backfill.md) for how the process works. 77 + See [Backfill](../guides/indexing/backfill.md) for how the process works. 78 78 79 79 ## Records not appearing in real time 80 80 ··· 102 102 103 103 **Causes**: 104 104 105 - - `TOKEN_ENCRYPTION_KEY` is not set. Plugin secrets are encrypted at rest and cannot be read without this key. See [Plugins - Configuration](../guides/plugins.md#plugin-configuration). 105 + - `TOKEN_ENCRYPTION_KEY` is not set. Plugin secrets are encrypted at rest and cannot be read without this key. See [Plugins - Configuration](../guides/features/plugins.md#plugin-configuration). 106 106 - If `TOKEN_ENCRYPTION_KEY` changed since the secrets were saved, the existing encrypted values are unreadable. Re-enter the secrets via the dashboard or `PUT /admin/plugins/{id}/secrets`. 107 107 - Environment variable secrets (`PLUGIN_<ID>_<KEY>`) are overridden by dashboard-configured secrets. If you've set both, the dashboard values take precedence. 108 108 ··· 143 143 144 144 **Explanation**: Each database is independent. Switching `DATABASE_URL` points HappyView at a fresh database. Your old data is still in the previous database file or Postgres instance. 145 145 146 - **Recovery**: Re-upload your lexicons and run backfills to re-index records from the network. Admin settings, users, and API keys need to be re-created manually. See the [SQLite → Postgres](../guides/sqlite-to-postgres-migration.md) or [Postgres → SQLite](../guides/postgres-to-sqlite-migration.md) migration guides. 146 + **Recovery**: Re-upload your lexicons and run backfills to re-index records from the network. Admin settings, users, and API keys need to be re-created manually. See the [SQLite → Postgres](../guides/database/sqlite-to-postgres-migration.md) or [Postgres → SQLite](../guides/database/postgres-to-sqlite-migration.md) migration guides. 147 147 148 148 ## Jetstream disconnects frequently 149 149
+3 -3
packages/docs/docs/reference/xrpc-api.md
··· 1 1 # XRPC API 2 2 3 - [XRPC](https://atproto.com/specs/xrpc) is the HTTP-based RPC protocol used by the atproto. HappyView dynamically registers XRPC endpoints based on your uploaded [lexicons](../guides/lexicons.md): query lexicons become `GET /xrpc/{nsid}` routes, procedure lexicons become `POST /xrpc/{nsid}` routes. 3 + [XRPC](https://atproto.com/specs/xrpc) is the HTTP-based RPC protocol used by the atproto. HappyView dynamically registers XRPC endpoints based on your uploaded [lexicons](../guides/indexing/lexicons.md): query lexicons become `GET /xrpc/{nsid}` routes, procedure lexicons become `POST /xrpc/{nsid}` routes. 4 4 5 5 If a query or procedure lexicon has a [Lua script](../guides/scripting.md) attached, the script handles the request. Otherwise, HappyView uses built-in default behavior (described below). 6 6 ··· 210 210 ## Next steps 211 211 212 212 - [Lua Scripting](../guides/scripting.md): Override the default query and procedure behavior with custom logic 213 - - [Lexicons](../guides/lexicons.md): Understand how lexicons generate these endpoints 214 - - [Admin API](admin-api.md): Manage lexicons and monitor your instance 213 + - [Lexicons](../guides/indexing/lexicons.md): Understand how lexicons generate these endpoints 214 + - [Admin API](admin/admin-api.md): Manage lexicons and monitor your instance
+4 -4
packages/docs/docs/tutorials/statusphere.md
··· 21 21 22 22 ## Step 1: Add the record lexicon 23 23 24 - First, tell HappyView to start indexing Statusphere records. Since `xyz.statusphere.status` is [published on the atproto network](../guides/lexicons.md#network-lexicons), you can add it directly from the dashboard: 24 + First, tell HappyView to start indexing Statusphere records. Since `xyz.statusphere.status` is [published on the atproto network](../guides/indexing/lexicons.md#network-lexicons), you can add it directly from the dashboard: 25 25 26 26 1. Go to **Lexicons > Add Lexicon > Network** 27 27 2. Enter `xyz.statusphere.status` ··· 207 207 - **A query endpoint** (`xyz.statusphere.listStatuses`) with filtering, pagination, and single-record lookups 208 208 - **A write endpoint** (`xyz.statusphere.setStatus`) that creates records on the user's PDS and indexes them locally 209 209 210 - Everything was done through the dashboard — no server restarts, no config files, no deploys. For automation and CI/CD, the same operations are available via the [admin API](../reference/admin-api.md). 210 + Everything was done through the dashboard — no server restarts, no config files, no deploys. For automation and CI/CD, the same operations are available via the [admin API](../reference/admin/admin-api.md). 211 211 212 212 ## Next steps 213 213 214 214 - [Lua Scripting](../guides/scripting.md): Explore the full Record and database APIs to build more complex queries 215 - - [Lexicons](../guides/lexicons.md): Learn about network lexicons, the backfill flag, and target collections 215 + - [Lexicons](../guides/indexing/lexicons.md): Learn about network lexicons, the backfill flag, and target collections 216 216 - [XRPC API](../reference/xrpc-api.md): Understand how the generated endpoints behave 217 - - [Admin API](../reference/admin-api.md): Automate lexicon management via the API 217 + - [Admin API](../reference/admin/admin-api.md): Automate lexicon management via the API 218 218 - [Statusphere example app](https://github.com/bluesky-social/statusphere-example-app): See the full Statusphere frontend 219 219 - [ATProto Statusphere guide](https://atproto.com/guides/applications): How the app works at the protocol level
+26 -26
packages/docs/sidebars.ts
··· 76 76 items: [ 77 77 { 78 78 type: "category", 79 + label: "Features", 80 + items: [ 81 + { 82 + type: "doc", 83 + id: "guides/features/api-clients", 84 + label: "API Clients", 85 + }, 86 + { 87 + type: "doc", 88 + id: "guides/features/labelers", 89 + label: "Labelers", 90 + }, 91 + { 92 + type: "doc", 93 + id: "guides/features/plugins", 94 + label: "Plugins", 95 + }, 96 + { 97 + type: "doc", 98 + id: "guides/features/developing-plugins", 99 + label: "Developing Plugins", 100 + }, 101 + ], 102 + }, 103 + { 104 + type: "category", 79 105 label: "Indexing", 80 106 items: [ 81 107 { ··· 174 200 label: "Meilisearch Sync", 175 201 }, 176 202 ], 177 - }, 178 - ], 179 - }, 180 - { 181 - type: "category", 182 - label: "Features", 183 - items: [ 184 - { 185 - type: "doc", 186 - id: "guides/features/api-clients", 187 - label: "API Clients", 188 - }, 189 - { 190 - type: "doc", 191 - id: "guides/features/labelers", 192 - label: "Labelers", 193 - }, 194 - { 195 - type: "doc", 196 - id: "guides/features/plugins", 197 - label: "Plugins", 198 - }, 199 - { 200 - type: "doc", 201 - id: "guides/features/developing-plugins", 202 - label: "Developing Plugins", 203 203 }, 204 204 ], 205 205 },