From 0122088cd11ec952b88e27ec7728c0a51a17f73d Mon Sep 17 00:00:00 2001 From: Trezy Date: Fri, 27 Feb 2026 00:05:34 -0600 Subject: [PATCH] docs: update links to work on Github --- docs/README.md | 8 +++--- docs/getting-started/authentication.md | 4 +-- docs/getting-started/configuration.md | 4 +-- docs/getting-started/dashboard.md | 6 ++--- docs/getting-started/deployment/docker.md | 2 +- docs/getting-started/deployment/other.md | 6 ++--- docs/getting-started/quickstart.md | 22 +++++++-------- docs/guides/backfill.md | 12 ++++----- docs/guides/lexicons.md | 16 +++++------ docs/guides/scripting.md | 30 ++++++++++----------- docs/reference/admin-api.md | 6 ++--- docs/reference/architecture.md | 2 +- docs/reference/glossary.md | 10 +++---- docs/reference/production-deployment.md | 10 +++---- docs/reference/scripts/batch-save.md | 4 +-- docs/reference/scripts/cascading-delete.md | 2 +- docs/reference/scripts/complex-mutations.md | 4 +-- docs/reference/scripts/create-record.md | 2 +- docs/reference/scripts/expanded-query.md | 2 +- docs/reference/scripts/get-record.md | 2 +- docs/reference/scripts/list-or-fetch.md | 4 +-- docs/reference/scripts/paginated-list.md | 2 +- docs/reference/scripts/sidecar-records.md | 4 +-- docs/reference/scripts/update-or-delete.md | 4 +-- docs/reference/scripts/upsert-record.md | 4 +-- docs/reference/troubleshooting.md | 14 +++++----- docs/reference/xrpc-api.md | 16 +++++------ docs/tutorials/statusphere.md | 18 ++++++------- 28 files changed, 110 insertions(+), 110 deletions(-) diff --git a/docs/README.md b/docs/README.md index bf8b38f..6dad911 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # HappyView -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#at-protocol-terms) schemas and get a fully functional AppView, complete with [XRPC](reference/glossary#at-protocol-terms) endpoints, OAuth, real-time network sync, and historical [backfill](guides/backfill), without writing a single line of server code. +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#at-protocol-terms) schemas and get a fully functional AppView, complete with [XRPC](reference/glossary.md#at-protocol-terms) endpoints, OAuth, real-time network sync, and historical [backfill](guides/backfill.md), without writing a single line of server code. Building an AppView from scratch means wiring up firehose connections, 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. @@ -27,6 +27,6 @@ Building an AppView from scratch means wiring up firehose connections, record st ## Next Steps -- [Quickstart](getting-started/deployment/railway): Deploy HappyView on Railway or run it locally -- [Lexicons](guides/lexicons): Upload lexicon schemas and start indexing records -- [Lua Scripting](guides/scripting): Write custom query and procedure logic +- [Quickstart](getting-started/deployment/railway.md): Deploy HappyView on Railway or run it locally +- [Lexicons](guides/lexicons.md): Upload lexicon schemas and start indexing records +- [Lua Scripting](guides/scripting.md): Write custom query and procedure logic diff --git a/docs/getting-started/authentication.md b/docs/getting-started/authentication.md index 708a9fd..a963af4 100644 --- a/docs/getting-started/authentication.md +++ b/docs/getting-started/authentication.md @@ -19,7 +19,7 @@ Authorization: Bearer ## Getting a token from the dashboard -The easiest way to get a token for CLI or curl usage is through the [web dashboard](dashboard): +The easiest way to get a token for CLI or curl usage is through the [web dashboard](dashboard.md): 1. Open the dashboard and log in with your AT Protocol identity 2. Open your browser's developer tools (F12 or Cmd+Shift+I) @@ -62,4 +62,4 @@ Token validation happens on every request; there is no local token caching. Admin endpoints require the authenticated user's DID to exist in the `admins` table. If the table is empty (fresh deployment), the first authenticated request to any admin endpoint auto-bootstraps that user as the initial admin. -To add more admins, use `POST /admin/admins` or the [dashboard](dashboard). See [Admin API](../reference/admin-api#admin-management) for details. +To add more admins, use `POST /admin/admins` or the [dashboard](dashboard.md). See [Admin API](../reference/admin-api.md#admin-management) for details. diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index ce2fc48..8364cbc 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -1,6 +1,6 @@ # Configuration -HappyView is configured via environment variables. A `.env` file in the project root is loaded automatically on startup. See [Deployment](deployment/docker) for local setup or [Production Deployment](../reference/production-deployment) for production setup. +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. ## Environment variables @@ -12,7 +12,7 @@ HappyView is configured via environment variables. A `.env` file in the project | `PORT` | no | `3000` | Bind port | | `TAP_URL` | no | `http://localhost:2480` | [Tap](https://github.com/bluesky-social/indigo/tree/main/cmd/tap) instance URL for real-time record streaming and backfill | | `TAP_ADMIN_PASSWORD` | no | --- | Shared secret for authenticating with Tap's admin endpoints | -| `RELAY_URL` | no | `https://bsky.network` | Relay URL for [backfill](../guides/backfill) repo discovery | +| `RELAY_URL` | no | `https://bsky.network` | Relay URL for [backfill](../guides/backfill.md) repo discovery | | `PLC_URL` | no | `https://plc.directory` | [PLC directory](https://github.com/did-method-plc/did-method-plc) URL for DID resolution | | `RUST_LOG` | no | `happyview=debug,tower_http=debug` | Log filter (uses `tracing_subscriber::EnvFilter`) | diff --git a/docs/getting-started/dashboard.md b/docs/getting-started/dashboard.md index 77bbf77..fca8154 100644 --- a/docs/getting-started/dashboard.md +++ b/docs/getting-started/dashboard.md @@ -1,6 +1,6 @@ # Dashboard -HappyView ships with a web dashboard that provides a visual interface for everything the [admin API](../reference/admin-api) offers: managing lexicons, viewing indexed records, and monitoring backfill jobs. It runs as a separate Next.js application alongside the Rust backend. +HappyView ships with a web dashboard that provides a visual interface for everything the [admin API](../reference/admin-api.md) offers: managing lexicons, viewing indexed records, and monitoring backfill jobs. It runs as a separate Next.js application alongside the Rust backend. ## Logging in for the first time @@ -21,7 +21,7 @@ A default Lua script is auto-generated when you first set the type to query or p Toggle **Enable backfill** to index historical records when uploading a record-type lexicon. -**Network** lexicons are fetched from the AT Protocol 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 Tap. See [Lexicons - Network lexicons](../guides/lexicons#network-lexicons) for how resolution works. +**Network** lexicons are fetched from the AT Protocol 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 Tap. See [Lexicons - Network lexicons](../guides/lexicons.md#network-lexicons) for how resolution works. ### JSON editor @@ -35,4 +35,4 @@ The JSON editor provides real-time validation against the AT Protocol Lexicon v1 The Lua editor provides context-aware code completions, including suggestions for the `Record`, `db`, `input`, and `params` APIs as well as Lua keywords, builtins, and standard library functions. It also offers snippet templates for common constructs like `if`, `for`, and `function`. -See [Lua Scripting](../guides/scripting) for the full runtime reference and examples. +See [Lua Scripting](../guides/scripting.md) for the full runtime reference and examples. diff --git a/docs/getting-started/deployment/docker.md b/docs/getting-started/deployment/docker.md index 94402ac..bcaaccc 100644 --- a/docs/getting-started/deployment/docker.md +++ b/docs/getting-started/deployment/docker.md @@ -46,4 +46,4 @@ HappyView runs migrations automatically on startup. The first build will take a ## Next steps -Your HappyView stack is running. Follow the [Statusphere tutorial](../../tutorials/statusphere) to upload lexicons, add custom query logic, and start indexing records from the network. +Your HappyView stack is running. Follow the [Statusphere tutorial](../../tutorials/statusphere.md) to upload lexicons, add custom query logic, and start indexing records from the network. diff --git a/docs/getting-started/deployment/other.md b/docs/getting-started/deployment/other.md index 3d55f47..1efa0fe 100644 --- a/docs/getting-started/deployment/other.md +++ b/docs/getting-started/deployment/other.md @@ -1,6 +1,6 @@ # Local Development from Source -This guide runs HappyView directly with `cargo run`, with you managing Postgres, AIP, and Tap separately. If you'd rather use Docker Compose to run everything together, see [Local Development with Docker](docker). +This guide runs HappyView directly with `cargo run`, with you managing Postgres, AIP, and Tap separately. If you'd rather use Docker Compose to run everything together, see [Local Development with Docker](docker.md). ## Prerequisites @@ -26,7 +26,7 @@ TAP_URL=http://localhost:2480 TAP_ADMIN_PASSWORD=your-secret-here ``` -See [Configuration](../configuration) for all available variables. +See [Configuration](../configuration.md) for all available variables. ## 2. Create the database @@ -52,4 +52,4 @@ HappyView starts on port 3000 (configurable via the `PORT` environment variable) ## Next steps -Your HappyView instance is running. Follow the [Statusphere tutorial](../../tutorials/statusphere) to upload lexicons, add custom query logic, and start indexing records from the network. +Your HappyView instance is running. Follow the [Statusphere tutorial](../../tutorials/statusphere.md) to upload lexicons, add custom query logic, and start indexing records from the network. diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index 3d324f7..0824ff3 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -8,15 +8,15 @@ Pick whichever option fits your situation: | Option | Best for | |--------|----------| -| [**Railway**](deployment/railway) | Fastest path — one-click deploy of the full stack (HappyView + AIP + Tap + Postgres) | -| [**Docker Compose**](deployment/docker) | Local development with the full stack running in containers | -| [**From source**](deployment/other) | Running HappyView with `cargo run` and managing dependencies yourself | +| [**Railway**](deployment/railway.md) | Fastest path — one-click deploy of the full stack (HappyView + AIP + Tap + Postgres) | +| [**Docker Compose**](deployment/docker.md) | Local development with the full stack running in containers | +| [**From source**](deployment/other.md) | Running HappyView with `cargo run` and managing dependencies yourself | If you're just trying HappyView for the first time, start with Railway. ## 2. Log in to the dashboard -Open your HappyView instance in a browser. The built-in [dashboard](dashboard) is served at the root URL. +Open your HappyView instance in a browser. The built-in [dashboard](dashboard.md) is served at the root URL. Click **Log in** and authenticate with your AT Protocol identity. On a fresh deployment with no admins configured, the first authenticated request to any admin endpoint automatically bootstraps that user as an admin. @@ -31,7 +31,7 @@ Lexicons tell HappyView what data to index and what endpoints to serve. The quic HappyView immediately starts indexing records for that collection. A backfill job is created to fetch historical records, and new records stream in via Tap in real time. -You can also upload lexicons manually via the dashboard or the [admin API](../reference/admin-api). See [Lexicons](../guides/lexicons) for the full details. +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. ## 4. Verify records are being indexed @@ -49,14 +49,14 @@ Without a Lua script, HappyView generates a default query endpoint that supports GET /xrpc/xyz.statusphere.listStatuses?limit=5 ``` -For custom query logic, attach a [Lua script](../guides/scripting). +For custom query logic, attach a [Lua script](../guides/scripting.md). ## Next steps You now have a working AppView. Here's where to go from here: -- [**Statusphere tutorial**](../tutorials/statusphere): end-to-end walkthrough building a complete AppView with record, query, and procedure lexicons -- [**Lexicons guide**](../guides/lexicons): target collections, backfill flag, network lexicons -- [**Lua Scripting**](../guides/scripting): custom query and procedure logic -- [**Configuration**](configuration): environment variables and tuning -- [**Authentication**](authentication): how OAuth works and how to get API tokens +- [**Statusphere tutorial**](../tutorials/statusphere.md): end-to-end walkthrough building a complete AppView with record, query, and procedure lexicons +- [**Lexicons guide**](../guides/lexicons.md): target collections, backfill flag, network lexicons +- [**Lua Scripting**](../guides/scripting.md): custom query and procedure logic +- [**Configuration**](configuration.md): environment variables and tuning +- [**Authentication**](authentication.md): how OAuth works and how to get API tokens diff --git a/docs/guides/backfill.md b/docs/guides/backfill.md index 341bc59..5493a7e 100644 --- a/docs/guides/backfill.md +++ b/docs/guides/backfill.md @@ -4,10 +4,10 @@ When you add a new record-type lexicon, HappyView starts indexing new records fr ## When backfill runs -- **Automatically** when a record-type lexicon is uploaded with `backfill: true` (the default). See [Lexicons - Backfill flag](lexicons#backfill-flag). -- **Manually** via `POST /admin/backfill` or the [dashboard](../getting-started/dashboard). You can scope a manual backfill to a specific collection, a specific DID, or both. +- **Automatically** when a record-type lexicon is uploaded with `backfill: true` (the default). See [Lexicons - Backfill flag](lexicons.md#backfill-flag). +- **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. -See the [admin API](../reference/admin-api#backfill) for endpoint details. +See the [admin API](../reference/admin-api.md#backfill) for endpoint details. ## How it works @@ -32,6 +32,6 @@ Deleting records from HappyView (via the dashboard or API) only removes them fro ## Next steps -- [Lexicons](lexicons#backfill-flag): Control whether lexicons trigger backfill on upload -- [Admin API](../reference/admin-api#backfill): Full reference for backfill endpoints -- [Admin API - Tap Stats](../reference/admin-api#tap-stats): Monitor Tap's processing progress +- [Lexicons](lexicons.md#backfill-flag): Control whether lexicons trigger backfill on upload +- [Admin API](../reference/admin-api.md#backfill): Full reference for backfill endpoints +- [Admin API - Tap Stats](../reference/admin-api.md#tap-stats): Monitor Tap's processing progress diff --git a/docs/guides/lexicons.md b/docs/guides/lexicons.md index 27faa60..79958cf 100644 --- a/docs/guides/lexicons.md +++ b/docs/guides/lexicons.md @@ -2,7 +2,7 @@ Lexicons are the core building block of HappyView. They're [AT Protocol 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. -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-api#lexicons) or [dashboard](../getting-started/dashboard), or fetching them directly from the AT Protocol network via [DNS authority resolution](#network-lexicons). +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-api.md#lexicons) or [dashboard](../getting-started/dashboard.md), or fetching them directly from the AT Protocol network via [DNS authority resolution](#network-lexicons). ## Supported lexicon types @@ -13,7 +13,7 @@ You don't write route handlers or database queries; you upload a lexicon and Hap | `procedure` | Registers a `POST /xrpc/{nsid}` endpoint that proxies writes to the user's PDS | | `definitions` | Stored but does not generate routes or subscriptions | -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) walks through this pattern end-to-end. +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. ## Target collection @@ -21,7 +21,7 @@ Query and procedure lexicons don't store data themselves. They operate on record For example, a query lexicon `xyz.statusphere.listStatuses` would set `target_collection` to `xyz.statusphere.status` to read from that record collection. -See the [admin API](../reference/admin-api#upload--upsert-a-lexicon) for how to set `target_collection` when uploading. +See the [admin API](../reference/admin-api.md#upload--upsert-a-lexicon) for how to set `target_collection` when uploading. :::note The `target_collection` is available in Lua scripts as the `collection` global, but it is not required if your endpoint uses a Lua script. @@ -35,7 +35,7 @@ When uploading a record-type lexicon, HappyView automatically creates a backfill When record-type lexicons change (uploaded or deleted), HappyView automatically syncs the updated collection filter to Tap. HappyView always includes `com.atproto.lexicon.schema` in the filter to track network lexicon updates. -Deleting a lexicon updates Tap's collection filters (stopping live indexing for that collection) but does **not** remove previously indexed repos or their cached state from Tap. To fully reset a collection's state, delete the lexicon, re-add it, and run a [backfill](backfill). +Deleting a lexicon updates Tap's collection filters (stopping live indexing for that collection) but does **not** remove previously indexed repos or their cached state from Tap. To fully reset a collection's state, delete the lexicon, re-add it, and run a [backfill](backfill.md). ## Network lexicons @@ -78,7 +78,7 @@ On every startup, HappyView re-fetches all network lexicons from their respectiv ## Next steps -- [Lua Scripting](scripting): Add custom query and procedure logic to your endpoints -- [XRPC API](../reference/xrpc-api): Understand how the generated endpoints behave -- [Backfill](backfill): Learn how historical records are indexed -- [Admin API](../reference/admin-api): Full reference for lexicon management endpoints +- [Lua Scripting](scripting.md): Add custom query and procedure logic to your endpoints +- [XRPC API](../reference/xrpc-api.md): Understand how the generated endpoints behave +- [Backfill](backfill.md): Learn how historical records are indexed +- [Admin API](../reference/admin-api.md): Full reference for lexicon management endpoints diff --git a/docs/guides/scripting.md b/docs/guides/scripting.md index 571889d..ef3f681 100644 --- a/docs/guides/scripting.md +++ b/docs/guides/scripting.md @@ -270,7 +270,7 @@ function handle() end ``` -To see log output, make sure your `RUST_LOG` environment variable includes debug level for HappyView (the default `happyview=debug` works). See [Configuration](../getting-started/configuration). +To see log output, make sure your `RUST_LOG` environment variable includes debug level for HappyView (the default `happyview=debug` works). See [Configuration](../getting-started/configuration.md). ### Error messages @@ -293,22 +293,22 @@ The **full error message** is logged server-side at error level. Check the serve See the example script references for complete, ready-to-use scripts: **Queries:** -- [Get a record](../reference/scripts/get-record) — fetch a single record by AT URI -- [Paginated list](../reference/scripts/paginated-list) — list records with cursor-based pagination and DID filtering -- [List or fetch](../reference/scripts/list-or-fetch) — combined single-record lookup and paginated listing -- [Expanded query](../reference/scripts/expanded-query) — list statuses with user profiles in a single response +- [Get a record](../reference/scripts/get-record.md) — fetch a single record by AT URI +- [Paginated list](../reference/scripts/paginated-list.md) — list records with cursor-based pagination and DID filtering +- [List or fetch](../reference/scripts/list-or-fetch.md) — combined single-record lookup and paginated listing +- [Expanded query](../reference/scripts/expanded-query.md) — list statuses with user profiles in a single response **Procedures:** -- [Create a record](../reference/scripts/create-record) — simple write that saves input as a record -- [Upsert a record](../reference/scripts/upsert-record) — create or update using a deterministic rkey -- [Update or delete](../reference/scripts/update-or-delete) — single endpoint handling create, update, and delete -- [Batch save](../reference/scripts/batch-save) — create multiple records in parallel with `Record.save_all()` -- [Sidecar records](../reference/scripts/sidecar-records) — create linked records across collections with a shared rkey -- [Cascading delete](../reference/scripts/cascading-delete) — delete a record and all related records -- [Complex mutations](../reference/scripts/complex-mutations) — load, transform, and save a record with multiple field changes +- [Create a record](../reference/scripts/create-record.md) — simple write that saves input as a record +- [Upsert a record](../reference/scripts/upsert-record.md) — create or update using a deterministic rkey +- [Update or delete](../reference/scripts/update-or-delete.md) — single endpoint handling create, update, and delete +- [Batch save](../reference/scripts/batch-save.md) — create multiple records in parallel with `Record.save_all()` +- [Sidecar records](../reference/scripts/sidecar-records.md) — create linked records across collections with a shared rkey +- [Cascading delete](../reference/scripts/cascading-delete.md) — delete a record and all related records +- [Complex mutations](../reference/scripts/complex-mutations.md) — load, transform, and save a record with multiple field changes ## Next steps -- [Lexicons](lexicons): Understand how record, query, and procedure lexicons work together -- [XRPC API](../reference/xrpc-api): See how endpoints behave with and without Lua scripts -- [Dashboard](../getting-started/dashboard#lua-editor): Use the web editor with context-aware completions +- [Lexicons](lexicons.md): Understand how record, query, and procedure lexicons work together +- [XRPC API](../reference/xrpc-api.md): See how endpoints behave with and without Lua scripts +- [Dashboard](../getting-started/dashboard.md#lua-editor): Use the web editor with context-aware completions diff --git a/docs/reference/admin-api.md b/docs/reference/admin-api.md index 3ff602b..d4b9443 100644 --- a/docs/reference/admin-api.md +++ b/docs/reference/admin-api.md @@ -1,6 +1,6 @@ # Admin API -The admin API lets you manage lexicons, monitor records, run backfill jobs, and control admin access. All endpoints live under `/admin` and require an [AIP](https://github.com/graze-social/aip)-issued Bearer token from a DID that exists in the `admins` table. You can also manage all of this through the [web dashboard](../getting-started/dashboard). +The admin API lets you manage lexicons, monitor records, run backfill jobs, and control admin access. All endpoints live under `/admin` and require an [AIP](https://github.com/graze-social/aip)-issued Bearer token from a DID that exists in the `admins` table. You can also manage all of this through the [web dashboard](../getting-started/dashboard.md). ## Auth @@ -115,7 +115,7 @@ curl -X DELETE http://localhost:3000/admin/lexicons/xyz.statusphere.status -H "$ ## Network Lexicons -Network lexicons are fetched from the AT Protocol network via DNS TXT resolution and kept updated via Tap. See [Lexicons - Network lexicons](../guides/lexicons#network-lexicons) for background. +Network lexicons are fetched from the AT Protocol network via DNS TXT resolution and kept updated via Tap. See [Lexicons - Network lexicons](../guides/lexicons.md#network-lexicons) for background. ### Add a network lexicon @@ -212,7 +212,7 @@ curl http://localhost:3000/admin/stats -H "$AUTH" ## Tap Stats -Aggregate stats from the [Tap](https://github.com/bluesky-social/indigo/tree/main/cmd/tap) instance. Useful for monitoring backfill progress. See [Backfill - Job lifecycle](../guides/backfill#job-lifecycle) for context. +Aggregate stats from the [Tap](https://github.com/bluesky-social/indigo/tree/main/cmd/tap) instance. Useful for monitoring backfill progress. See [Backfill - Job lifecycle](../guides/backfill.md#job-lifecycle) for context. ### Get Tap stats diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md index c9dff94..70ac429 100644 --- a/docs/reference/architecture.md +++ b/docs/reference/architecture.md @@ -1,6 +1,6 @@ # Architecture -Guide for contributors working on HappyView itself. For a user-facing overview, see the [Introduction](/). +Guide for contributors working on HappyView itself. For a user-facing overview, see the [Introduction](/README.md). ## System overview diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index 4c0b6ff..1559a1f 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -12,7 +12,7 @@ Key terms used throughout the HappyView documentation. For a broader introductio **Handle** — A human-readable name for an account (e.g. `user.bsky.social`). Handles resolve to a DID via DNS or the PLC directory. -**Lexicon** — A schema definition for AT Protocol data types and API methods. Lexicons define what records look like, what endpoints exist, and what parameters they accept. See [Lexicons](../guides/lexicons). +**Lexicon** — A schema definition for AT Protocol data types and API methods. Lexicons define what records look like, what endpoints exist, and what parameters they accept. See [Lexicons](../guides/lexicons.md). **NSID** (Namespaced Identifier) — A reverse-DNS identifier for a lexicon (e.g. `xyz.statusphere.status`). The authority is everything except the last segment. @@ -22,21 +22,21 @@ Key terms used throughout the HappyView documentation. For a broader introductio **Record** — A single piece of data in an AT Protocol repository, identified by an AT URI (e.g. `at://did:plc:abc/xyz.statusphere.status/abc123`). -**Relay** — A network service that aggregates repository data from many PDSes. HappyView queries the relay during [backfill](../guides/backfill) to discover which repos contain records for a given collection, then delegates the actual record fetching to Tap. +**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 delegates the actual record fetching to Tap. **rkey** (Record Key) — The unique key for a record within a collection and repo. These are most commonly TIDs (timestamp-based) or NSIDs. **TID** (Timestamp Identifier) — A 13-character sortable identifier used as a record key. Generated from the current timestamp. -**XRPC** — The HTTP-based RPC protocol used by the AT Protocol. Query methods map to GET requests, procedure methods map to POST requests. See [XRPC API](xrpc-api). +**XRPC** — The HTTP-based RPC protocol used by the AT Protocol. Query methods map to GET requests, procedure methods map to POST requests. See [XRPC API](xrpc-api.md). ## HappyView-specific terms **AIP** — [Authentication and Identity Provider](https://github.com/graze-social/aip). An external service that handles AT Protocol OAuth for HappyView. Issues Bearer tokens used for authentication. -**Backfill** — The process of bulk-indexing existing records from the network. HappyView discovers repos via the relay and delegates record fetching to Tap. Runs when a new record-type lexicon is uploaded or triggered manually. See [Backfill](../guides/backfill). +**Backfill** — The process of bulk-indexing existing records from the network. HappyView discovers repos via the relay and delegates record fetching to Tap. Runs when a new record-type lexicon is uploaded or triggered manually. See [Backfill](../guides/backfill.md). -**Network lexicon** — A lexicon fetched directly from the AT Protocol network via DNS authority resolution, rather than uploaded manually. See [Lexicons - Network lexicons](../guides/lexicons#network-lexicons). +**Network lexicon** — A lexicon fetched directly from the AT Protocol network via DNS authority resolution, rather than uploaded manually. See [Lexicons - Network lexicons](../guides/lexicons.md#network-lexicons). **Tap** — A [firehose consumer and backfill worker](https://github.com/bluesky-social/indigo/tree/main/cmd/tap) that handles real-time record streaming, cryptographic verification, and historical record fetching. HappyView connects to Tap via WebSocket to receive record events, and delegates backfill work to Tap via its HTTP API. diff --git a/docs/reference/production-deployment.md b/docs/reference/production-deployment.md index dac3067..6cd6d26 100644 --- a/docs/reference/production-deployment.md +++ b/docs/reference/production-deployment.md @@ -1,6 +1,6 @@ # Deployment -HappyView requires a Postgres database and an [AIP](https://github.com/graze-social/aip) instance for OAuth. The [Quickstart](../getting-started/deployment/railway) covers the fastest path with Railway. This page covers other deployment options. +HappyView requires a Postgres database and an [AIP](https://github.com/graze-social/aip) instance for OAuth. The [Quickstart](../getting-started/deployment/railway.md) covers the fastest path with Railway. This page covers other deployment options. ## Docker @@ -10,7 +10,7 @@ Build the image: docker build -t happyview . ``` -For local development, see [Docker deployment](../getting-started/deployment/docker). +For local development, see [Docker deployment](../getting-started/deployment/docker.md). ### Production Compose example @@ -50,12 +50,12 @@ The general process for any hosting platform: 1. Provision a Postgres 17+ database 2. Deploy an [AIP](https://github.com/graze-social/aip) instance (handles OAuth for your AppView) -3. Set `DATABASE_URL` and `AIP_URL` environment variables (see [Configuration](../getting-started/configuration) for all options) +3. Set `DATABASE_URL` and `AIP_URL` environment variables (see [Configuration](../getting-started/configuration.md) for all options) 4. Deploy the Docker image or build from source 5. HappyView listens on `PORT` (default `3000`) 6. Health check: `GET /health` returns `ok` -For Railway specifically, the [Quickstart](../getting-started/deployment/railway) template handles all of this with a single click. +For Railway specifically, the [Quickstart](../getting-started/deployment/railway.md) template handles all of this with a single click. ## Database @@ -67,4 +67,4 @@ HappyView does not terminate TLS. Put it behind a reverse proxy (nginx, Caddy, C ## Logging -HappyView uses the `RUST_LOG` environment variable to control log output. The default (`happyview=debug,tower_http=debug`) logs all HappyView activity and HTTP requests. For production, consider `happyview=info,tower_http=info` to reduce noise. See [Configuration](../getting-started/configuration) for details. +HappyView uses the `RUST_LOG` environment variable to control log output. The default (`happyview=debug,tower_http=debug`) logs all HappyView activity and HTTP requests. For production, consider `happyview=info,tower_http=info` to reduce noise. See [Configuration](../getting-started/configuration.md) for details. diff --git a/docs/reference/scripts/batch-save.md b/docs/reference/scripts/batch-save.md index 137c930..5989529 100644 --- a/docs/reference/scripts/batch-save.md +++ b/docs/reference/scripts/batch-save.md @@ -23,8 +23,8 @@ end ## How it works -1. Iterate over `input.items` and create a [`Record`](../../guides/scripting#record-api) instance for each item. -2. Call [`Record.save_all()`](../../guides/scripting#static-methods) to save all records in parallel, rather than one at a time. +1. Iterate over `input.items` and create a [`Record`](../../guides/scripting.md#record-api) instance for each item. +2. Call [`Record.save_all()`](../../guides/scripting.md#static-methods) to save all records in parallel, rather than one at a time. 3. Collect the resulting AT URIs and return them. ## Usage diff --git a/docs/reference/scripts/cascading-delete.md b/docs/reference/scripts/cascading-delete.md index c109ac4..c790944 100644 --- a/docs/reference/scripts/cascading-delete.md +++ b/docs/reference/scripts/cascading-delete.md @@ -49,7 +49,7 @@ end 1. Load the primary record by URI. Return early if it doesn't exist. 2. Query for related records, in this example comments by the same user that reference the primary record's URI. -3. Load each related record with [`Record.load`](../../guides/scripting#static-methods) to get a deletable `Record` instance. +3. Load each related record with [`Record.load`](../../guides/scripting.md#static-methods) to get a deletable `Record` instance. 4. Delete everything. Each `r:delete()` removes the record from the user's PDS and the local index. ## Usage diff --git a/docs/reference/scripts/complex-mutations.md b/docs/reference/scripts/complex-mutations.md index f2e98f2..a57be9e 100644 --- a/docs/reference/scripts/complex-mutations.md +++ b/docs/reference/scripts/complex-mutations.md @@ -56,12 +56,12 @@ end ## How it works -1. Load the existing record with [`Record.load`](../../guides/scripting#static-methods). This gives you a mutable `Record` instance with all the current field values. +1. Load the existing record with [`Record.load`](../../guides/scripting.md#static-methods). This gives you a mutable `Record` instance with all the current field values. 2. Apply transformations directly on the record's fields: - **Increment a counter**: use `or 0` to handle the field being `nil` on first access. - **Merge tags**: iterate over `input.tags`, skip duplicates already in `r.tags`, append new ones, then trim the list to 10. - **Normalize a string**: use `string.gsub` to trim whitespace. - - **Set a timestamp**: use [`now()`](../../guides/scripting#utility-globals) for UTC ISO 8601. + - **Set a timestamp**: use [`now()`](../../guides/scripting.md#utility-globals) for UTC ISO 8601. 3. Call `r:save()`. Since `_uri` is set (from the load), this calls `putRecord` to update the record on the user's PDS. ## Usage diff --git a/docs/reference/scripts/create-record.md b/docs/reference/scripts/create-record.md index dea0f59..158ed6e 100644 --- a/docs/reference/scripts/create-record.md +++ b/docs/reference/scripts/create-record.md @@ -14,7 +14,7 @@ end ## How it works -1. Create a new [`Record`](../../guides/scripting#record-api) instance from the target collection, populated with the fields from the request body. +1. Create a new [`Record`](../../guides/scripting.md#record-api) instance from the target collection, populated with the fields from the request body. 2. Call `r:save()`, which creates the record on the caller's PDS and indexes it locally. 3. Return the AT URI and CID of the newly created record. diff --git a/docs/reference/scripts/expanded-query.md b/docs/reference/scripts/expanded-query.md index 703eaa6..abfe50b 100644 --- a/docs/reference/scripts/expanded-query.md +++ b/docs/reference/scripts/expanded-query.md @@ -51,7 +51,7 @@ end 1. Query statuses from the target collection with pagination, same as a normal list query. 2. Extract the unique DIDs from the returned status URIs using `string.match`. 3. Build an AT URI for each DID's `app.bsky.actor.profile/self` record (this is where Bluesky profiles live). -4. Load all profiles in parallel with [`Record.load_all`](../../guides/scripting#static-methods). Profiles that aren't indexed locally return `nil` and are skipped. +4. Load all profiles in parallel with [`Record.load_all`](../../guides/scripting.md#static-methods). Profiles that aren't indexed locally return `nil` and are skipped. 5. Return statuses and profiles as separate keys, with the cursor from the status query. ## Usage diff --git a/docs/reference/scripts/get-record.md b/docs/reference/scripts/get-record.md index 1f990e6..9476aa0 100644 --- a/docs/reference/scripts/get-record.md +++ b/docs/reference/scripts/get-record.md @@ -22,7 +22,7 @@ end ## How it works 1. Check that the `uri` query parameter is present. Return a structured error if missing. -2. Look up the record with [`db.get`](../../guides/scripting#dbget), which returns the record table or `nil`. +2. Look up the record with [`db.get`](../../guides/scripting.md#dbget), which returns the record table or `nil`. 3. Return the record wrapped in an object. ## Usage diff --git a/docs/reference/scripts/list-or-fetch.md b/docs/reference/scripts/list-or-fetch.md index caa0ebd..b2053cb 100644 --- a/docs/reference/scripts/list-or-fetch.md +++ b/docs/reference/scripts/list-or-fetch.md @@ -25,8 +25,8 @@ end ## How it works -1. If a `uri` query parameter is provided, fetch that single record with [`db.get`](../../guides/scripting#dbget) and return it. If it doesn't exist, return a structured error (using `error()` would trigger a 500 response). -2. Otherwise, list records from the target collection using [`db.query`](../../guides/scripting#dbquery), with optional filtering by `did` and pagination via `limit`/`offset`. Since query parameters arrive as strings, `tonumber()` converts them to numbers. +1. If a `uri` query parameter is provided, fetch that single record with [`db.get`](../../guides/scripting.md#dbget) and return it. If it doesn't exist, return a structured error (using `error()` would trigger a 500 response). +2. Otherwise, list records from the target collection using [`db.query`](../../guides/scripting.md#dbquery), with optional filtering by `did` and pagination via `limit`/`offset`. Since query parameters arrive as strings, `tonumber()` converts them to numbers. ## Usage diff --git a/docs/reference/scripts/paginated-list.md b/docs/reference/scripts/paginated-list.md index 6f1553c..01a67d3 100644 --- a/docs/reference/scripts/paginated-list.md +++ b/docs/reference/scripts/paginated-list.md @@ -23,7 +23,7 @@ end ## How it works 1. Parse `limit` from the query string, defaulting to 20 and capping at 100. -2. Call [`db.query`](../../guides/scripting#dbquery) with the target collection, optional DID filter, and offset-based pagination. +2. Call [`db.query`](../../guides/scripting.md#dbquery) with the target collection, optional DID filter, and offset-based pagination. 3. Return the result directly. `db.query` returns `{ records = [...], cursor = "..." }` where `cursor` is present when more records exist. ## Usage diff --git a/docs/reference/scripts/sidecar-records.md b/docs/reference/scripts/sidecar-records.md index 36a17df..337b55c 100644 --- a/docs/reference/scripts/sidecar-records.md +++ b/docs/reference/scripts/sidecar-records.md @@ -32,9 +32,9 @@ end ## How it works -1. Generate a single [`TID()`](../../guides/scripting#utility-globals) to use as the rkey for both records. +1. Generate a single [`TID()`](../../guides/scripting.md#utility-globals) to use as the rkey for both records. 2. Create a `Record` for each collection and call `r:set_rkey()` with the shared rkey. -3. Save both records in parallel with [`Record.save_all()`](../../guides/scripting#static-methods). +3. Save both records in parallel with [`Record.save_all()`](../../guides/scripting.md#static-methods). 4. Return both URIs so the client knows the identity of each record. ## Usage diff --git a/docs/reference/scripts/update-or-delete.md b/docs/reference/scripts/update-or-delete.md index 4972e34..fb83f8f 100644 --- a/docs/reference/scripts/update-or-delete.md +++ b/docs/reference/scripts/update-or-delete.md @@ -30,8 +30,8 @@ end ## How it works -1. If `input.delete` is truthy and `input.uri` is provided, load the record with [`Record.load`](../../guides/scripting#static-methods) and delete it. -2. If only `input.uri` is provided, load the existing record with [`Record.load`](../../guides/scripting#static-methods), update its fields, and save it back. Since `_uri` is already set, `r:save()` calls `putRecord` instead of `createRecord`. +1. If `input.delete` is truthy and `input.uri` is provided, load the record with [`Record.load`](../../guides/scripting.md#static-methods) and delete it. +2. If only `input.uri` is provided, load the existing record with [`Record.load`](../../guides/scripting.md#static-methods), update its fields, and save it back. Since `_uri` is already set, `r:save()` calls `putRecord` instead of `createRecord`. 3. If neither condition matches, create a new record from the input. ## Usage diff --git a/docs/reference/scripts/upsert-record.md b/docs/reference/scripts/upsert-record.md index fcdc825..2164df2 100644 --- a/docs/reference/scripts/upsert-record.md +++ b/docs/reference/scripts/upsert-record.md @@ -32,8 +32,8 @@ end ## How it works -1. Use the client-provided `input.rkey` if present, otherwise generate a new [`TID()`](../../guides/scripting#utility-globals). This means omitting `rkey` always creates, while providing one enables updates. -2. Build the AT URI from the caller's DID, the target collection, and the rkey, then try to load it with [`Record.load`](../../guides/scripting#static-methods). +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. +2. Build the AT URI from the caller's DID, the target collection, and the rkey, then try to load it with [`Record.load`](../../guides/scripting.md#static-methods). 3. If the record exists, update its fields and save. Since `_uri` is already set, `r:save()` calls `putRecord`. 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. diff --git a/docs/reference/troubleshooting.md b/docs/reference/troubleshooting.md index 3989ca5..131a36c 100644 --- a/docs/reference/troubleshooting.md +++ b/docs/reference/troubleshooting.md @@ -8,7 +8,7 @@ Common issues and how to resolve them. **Causes**: -- The lexicon hasn't been uploaded yet. Check with `GET /admin/lexicons` or the [dashboard](../getting-started/dashboard). +- The lexicon hasn't been uploaded yet. Check with `GET /admin/lexicons` or the [dashboard](../getting-started/dashboard.md). - The lexicon's `defs.main.type` doesn't match the HTTP method. Queries are `GET`, procedures are `POST`. - The NSID in the URL doesn't match the `id` field in the uploaded lexicon JSON. @@ -18,9 +18,9 @@ Common issues and how to resolve them. **Causes**: -- 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#target-collection). +- 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). - The record-type lexicon hasn't finished backfilling. Check backfill status with `GET /admin/backfill/status` or the dashboard. -- Records exist on the network but HappyView hasn't indexed them yet. Tap only picks up new events from when the collection filter was added. Use [backfill](../guides/backfill) for historical records. +- Records exist on the network but HappyView hasn't indexed them yet. Tap only picks up new events from when the collection filter was added. Use [backfill](../guides/backfill.md) for historical records. ## Procedure returns 401 Unauthorized @@ -51,9 +51,9 @@ For AIP-specific issues, see the [AIP documentation](https://github.com/graze-so 1. Check the server logs: the full error message is logged at error level but not exposed to the client. 2. Use `log("message")` in your script to trace execution. Output appears in server logs at debug level (requires `RUST_LOG` to include debug). -3. If you hit the execution limit, your script likely has an infinite loop or is processing too much data. See [Lua Scripting - Sandbox](../guides/scripting#sandbox). +3. If you hit the execution limit, your script likely has an infinite loop or is processing too much data. See [Lua Scripting - Sandbox](../guides/scripting.md#sandbox). -See [Lua Scripting - Debugging](../guides/scripting#debugging) for more. +See [Lua Scripting - Debugging](../guides/scripting.md#debugging) for more. ## Backfill job stuck in "pending" or "running" @@ -65,7 +65,7 @@ See [Lua Scripting - Debugging](../guides/scripting#debugging) for more. - The relay (`RELAY_URL`) may be unreachable or slow to respond. Check connectivity. - Individual PDS fetches can fail silently. The worker logs warnings and continues. Check server logs for details. -See [Backfill](../guides/backfill) for how the process works. +See [Backfill](../guides/backfill.md) for how the process works. ## Records not appearing in real time @@ -97,4 +97,4 @@ See the [AIP documentation](https://github.com/graze-social/aip) for setup and d - The database user doesn't have sufficient permissions. HappyView needs to create tables (migrations run automatically on startup). - Postgres version is too old. HappyView requires Postgres 17+. -See [Configuration](../getting-started/configuration) for environment variable details. +See [Configuration](../getting-started/configuration.md) for environment variable details. diff --git a/docs/reference/xrpc-api.md b/docs/reference/xrpc-api.md index 0e5fb1e..8954ad2 100644 --- a/docs/reference/xrpc-api.md +++ b/docs/reference/xrpc-api.md @@ -1,8 +1,8 @@ # XRPC API -[XRPC](https://atproto.com/specs/xrpc) is the HTTP-based RPC protocol used by the AT Protocol. HappyView dynamically registers XRPC endpoints based on your uploaded [lexicons](../guides/lexicons): query lexicons become `GET /xrpc/{nsid}` routes, procedure lexicons become `POST /xrpc/{nsid}` routes. +[XRPC](https://atproto.com/specs/xrpc) is the HTTP-based RPC protocol used by the AT Protocol. 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. -If a query or procedure lexicon has a [Lua script](../guides/scripting) attached, the script handles the request. Otherwise, HappyView uses built-in default behavior (described below). +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). ## Auth @@ -71,7 +71,7 @@ curl -X POST http://localhost:3000/xrpc/com.atproto.repo.uploadBlob \ ## Dynamic query endpoints -Query endpoints are generated from lexicons with `type: "query"`. Without a [Lua script](../guides/scripting), they support two built-in modes depending on whether a `uri` parameter is provided. +Query endpoints are generated from lexicons with `type: "query"`. Without a [Lua script](../guides/scripting.md), they support two built-in modes depending on whether a `uri` parameter is provided. ### Single record @@ -133,7 +133,7 @@ The `cursor` field is present only when more records exist. ## Dynamic procedure endpoints -Procedure endpoints are generated from lexicons with `type: "procedure"`. Without a [Lua script](../guides/scripting), HappyView auto-detects create vs update based on whether the request body contains a `uri` field. +Procedure endpoints are generated from lexicons with `type: "procedure"`. Without a [Lua script](../guides/scripting.md), HappyView auto-detects create vs update based on whether the request body contains a `uri` field. ### Create a record @@ -195,7 +195,7 @@ When a Lua script fails, the response is `500` with one of: - `{"error": "script execution failed"}`: syntax error, runtime error, or missing `handle()` function - `{"error": "script exceeded execution time limit"}`: the script hit the 1,000,000 instruction limit -The full error details are logged server-side but not exposed to the client. See [Lua Scripting - Debugging](../guides/scripting#debugging) for how to diagnose script issues. +The full error details are logged server-side but not exposed to the client. See [Lua Scripting - Debugging](../guides/scripting.md#debugging) for how to diagnose script issues. ### PDS errors @@ -203,6 +203,6 @@ When a procedure proxies a write to the user's PDS and the PDS returns an error, ## Next steps -- [Lua Scripting](../guides/scripting): Override the default query and procedure behavior with custom logic -- [Lexicons](../guides/lexicons): Understand how lexicons generate these endpoints -- [Admin API](admin-api): Manage lexicons and monitor your instance +- [Lua Scripting](../guides/scripting.md): Override the default query and procedure behavior with custom logic +- [Lexicons](../guides/lexicons.md): Understand how lexicons generate these endpoints +- [Admin API](admin-api.md): Manage lexicons and monitor your instance diff --git a/docs/tutorials/statusphere.md b/docs/tutorials/statusphere.md index adccb73..3894e89 100644 --- a/docs/tutorials/statusphere.md +++ b/docs/tutorials/statusphere.md @@ -5,7 +5,7 @@ In this tutorial, you'll set up HappyView to act as the AppView for Statusphere. By the end, you'll have automatically indexed records and automatically generated XPRC endpoints. :::tip -This tutorial assumes you have a running HappyView instance. If you don't, start with the [Quickstart](../getting-started/deployment/railway) or one of the local development guides ([Docker](../getting-started/deployment/docker), [from source](../getting-started/deployment/other)). +This tutorial assumes you have a running HappyView instance. If you don't, start with the [Quickstart](../getting-started/deployment/railway.md) or one of the local development guides ([Docker](../getting-started/deployment/docker.md), [from source](../getting-started/deployment/other.md)). ::: ## The Statusphere lexicon @@ -23,7 +23,7 @@ For more background on how the app works, see the [ATProto Statusphere guide](ht First, upload the `xyz.statusphere.status` lexicon to HappyView. This tells HappyView to start indexing Statusphere records from across the network as they're created, updated, or deleted. -The examples below use `$TOKEN` as a placeholder for an AIP-issued access token. See [Authentication](../getting-started/authentication) for how to get one. +The examples below use `$TOKEN` as a placeholder for an AIP-issued access token. See [Authentication](../getting-started/authentication.md) for how to get one. ```sh curl -X POST http://localhost:3000/admin/lexicons \ @@ -52,10 +52,10 @@ curl -X POST http://localhost:3000/admin/lexicons \ }' ``` -HappyView now subscribes to `xyz.statusphere.status` via Tap. The `backfill` flag tells HappyView to also index existing status records from the network. You can monitor progress with `GET /admin/backfill/status` or the [dashboard](../getting-started/dashboard). +HappyView now subscribes to `xyz.statusphere.status` via Tap. The `backfill` flag tells HappyView to also index existing status records from the network. You can monitor progress with `GET /admin/backfill/status` or the [dashboard](../getting-started/dashboard.md). :::tip -Since the `xyz.statusphere.status` lexicon is [published on the AT Protocol network](../guides/lexicons#network-lexicons), you can also add it as a network lexicon instead of uploading the JSON manually: +Since the `xyz.statusphere.status` lexicon is [published on the AT Protocol network](../guides/lexicons.md#network-lexicons), you can also add it as a network lexicon instead of uploading the JSON manually: ```sh curl -X POST http://localhost:3000/admin/network-lexicons \ @@ -129,11 +129,11 @@ curl "http://localhost:3000/xrpc/xyz.statusphere.listStatuses?limit=5" } ``` -See [XRPC API](../reference/xrpc-api) for the full default query behavior. +See [XRPC API](../reference/xrpc-api.md) for the full default query behavior. ## Step 4: Enhance the query with a Lua script -The default query behavior works, but let's customize it with a [Lua script](../guides/scripting). Here's a script that handles single-record lookups by URI and paginated listing with an optional DID filter: +The default query behavior works, but let's customize it with a [Lua script](../guides/scripting.md). Here's a script that handles single-record lookups by URI and paginated listing with an optional DID filter: ```lua function handle() @@ -298,8 +298,8 @@ With three lexicon uploads and a few lines of Lua, you have a complete Statusphe ## Next steps -- [Lua Scripting](../guides/scripting): Explore the full Record and database APIs to build more complex queries -- [Lexicons](../guides/lexicons): Learn about network lexicons, the backfill flag, and target collections -- [XRPC API](../reference/xrpc-api): Understand how the generated endpoints behave +- [Lua Scripting](../guides/scripting.md): Explore the full Record and database APIs to build more complex queries +- [Lexicons](../guides/lexicons.md): Learn about network lexicons, the backfill flag, and target collections +- [XRPC API](../reference/xrpc-api.md): Understand how the generated endpoints behave - [Statusphere example app](https://github.com/bluesky-social/statusphere-example-app): See the full Statusphere frontend - [ATProto Statusphere guide](https://atproto.com/guides/applications): Deep dive into how the app works at the protocol level -- 2.51.2