From e6a2ea24101bf40b78b6750cef2c098141d6838c Mon Sep 17 00:00:00 2001 From: sun-970 <3843544764@qq.com> Date: Sat, 19 Sep 2026 06:29:09 +0000 Subject: [PATCH 1/2] docs: document content search, time range, and sort params for host apps (#73) Rebased onto current main after #69. --- CHANGELOG.md | 1 + docs/API.md | 43 ++++++++++- docs/CAPABILITIES.md | 18 ++--- docs/host-app-integration.md | 134 +++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 docs/host-app-integration.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c06b1d..1413c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ All notable changes to `doc` are documented here. (case-insensitive). New `after` / `before` (ISO 8601) filter by `updatedAt`; `sort` accepts `updated_desc` (default), `updated_asc`, `created_desc`, `created_asc`. Shared query parser (`src/lib/doc-query.ts`) keeps the two routes consistent; invalid dates/sort return 400. +- Document host-app integration guide for search, time range, and sort params (#73). - Adoption of the shared `@fullstack-ai-infra/ui` design system for the first document workflow: workspace shell (responsive sidebar with compact mode), editor chrome, and diff --git a/docs/API.md b/docs/API.md index dcfb59f..909f92e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -74,13 +74,54 @@ The response contains `authenticated`, `userId`, and the token's `scopes`. ### List documents ```http -GET /api/v1/documents?limit=50&cursor=...&query=...&starred=true&trash=false +GET /api/v1/documents?limit=50&cursor=...&query=...&starred=true&trash=false&after=...&before=...&sort=... ``` The list contains documents owned by the token's user. `limit` defaults to `50` and must be from `1` to `100`. Follow `meta.nextCursor` until it is `null`; cursors are opaque. `starred` and `trash` accept only `true` or `false`. `query` is limited to 200 characters. +#### Search + +`query` searches both document **title** and **content** (case-insensitive). A document matches +when either field contains the keyword. The search uses `OR` semantics — a match in the title, +the body, or both all return the document. + +#### Time range filters + +- `after` — return documents updated strictly after this ISO 8601 date (e.g. `2026-09-01` or + `2026-09-01T00:00:00.000Z`). +- `before` — return documents updated strictly before this ISO 8601 date. + +Both are optional and can be combined. Invalid dates return `400 invalid_query`. + +#### Sort + +`sort` controls result ordering. Accepted values: + +| Value | Order | +| -------------- | ------------------------------------- | +| `updated_desc` | Most recently updated first (default) | +| `updated_asc` | Least recently updated first | +| `created_desc` | Newest created first | +| `created_asc` | Oldest created first | + +Invalid values return `400 invalid_query`. Cursor pagination (`cursor` param) is only compatible +with `updated_*` sort orders; combining `cursor` with `created_*` returns `400 invalid_cursor`. + +#### Examples + +```http +# Search content and title for "runbook", updated in September 2026 +GET /api/v1/documents?query=runbook&after=2026-09-01&before=2026-09-30 + +# Oldest documents first +GET /api/v1/documents?sort=created_asc + +# Recently updated documents matching "deployment" +GET /api/v1/documents?query=deployment&sort=updated_desc +``` + ```json { "data": [ diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 889673f..5746a01 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -81,15 +81,15 @@ Primary implementation paths: ## Identity, governance, and product surface -| Capability | Status | Current implementation | -| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ | -| Authentication | available | GitHub OAuth, email sign-in, and scoped personal access tokens with expiry, revocation, and one-time secret display | -| Document API v1 | available | Bearer-only token inspection, owner listing, authorized reads, canonical creation, and ETag-guarded metadata updates | -| Document authorization | experimental | Browser routes, API v1, publication, and collaboration entry points enforce persisted ownership and READ/WRITE relations | -| User settings | available | User name and avatar | -| Admin governance | available | Overview, user/admin management, document filtering, restore/delete, and publication moderation | -| Localization and theme | available | Chinese/English plus dark, light, and system themes | -| Object storage | experimental | Uploads use the current Ali OSS client; a provider-neutral S3 interface is not implemented | +| Capability | Status | Current implementation | +| ---------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Authentication | available | GitHub OAuth, email sign-in, and scoped personal access tokens with expiry, revocation, and one-time secret display | +| Document API v1 | available | Bearer-only token inspection, owner listing with content search, time range filters, sort options, authorized reads, canonical creation, and ETag-guarded metadata updates | +| Document authorization | experimental | Browser routes, API v1, publication, and collaboration entry points enforce persisted ownership and READ/WRITE relations | +| User settings | available | User name and avatar | +| Admin governance | available | Overview, user/admin management, document filtering, restore/delete, and publication moderation | +| Localization and theme | available | Chinese/English plus dark, light, and system themes | +| Object storage | experimental | Uploads use the current Ali OSS client; a provider-neutral S3 interface is not implemented | Primary implementation paths: diff --git a/docs/host-app-integration.md b/docs/host-app-integration.md new file mode 100644 index 0000000..97c4d5d --- /dev/null +++ b/docs/host-app-integration.md @@ -0,0 +1,134 @@ +# Host app integration guide + +Host applications that embed `doc` as a read-only knowledge source (e.g. RoleWeave Memory & +Collaboration panel) consume documents through the API v1 list endpoint. This guide describes +how to use the search, time range, and sort parameters effectively. + +## Base endpoint + +```http +GET /api/v1/documents +Authorization: Bearer doc_pat_... +``` + +A token with `documents:read` scope is required. See [API.md](API.md) for authentication details. + +## Search across title and content + +The `query` parameter searches both document title and body content with OR semantics. A document +is returned if the keyword appears in either field. + +```http +GET /api/v1/documents?query=deployment+procedure +``` + +The search is case-insensitive and uses substring matching (`ILIKE`-style). For host apps that +need to show where the match was found, there is currently no `matchField` indicator in the API +response — the host app should fetch individual documents (`GET /api/v1/documents/{id}`) and +inspect the content if highlight positioning is needed. + +## Filter by time range + +Use `after` and `before` to narrow results to a specific update window. Both filter on +`updatedAt`. + +```http +# Documents updated in the last 7 days +GET /api/v1/documents?after=2026-09-11T00:00:00.000Z + +# Documents updated in September 2026 +GET /api/v1/documents?after=2026-09-01&before=2026-09-30 +``` + +Dates accept any ISO 8601 format. Invalid dates return `400 invalid_query`. + +## Sort results + +Control ordering with the `sort` parameter: + +```http +# Most recently created first +GET /api/v1/documents?sort=created_desc + +# Alphabetical by update time (oldest first) +GET /api/v1/documents?sort=updated_asc +``` + +Default is `updated_desc`. When using cursor-based pagination (`cursor` param), only `updated_*` +sort orders are supported — `created_*` sorts with a cursor return `400 invalid_cursor`. + +## Pagination + +The endpoint uses cursor-based pagination. Always follow `meta.nextCursor` until it is `null`: + +``` +Page 1: GET /api/v1/documents?limit=50&query=runbook + → meta.nextCursor = "eyJ1cGRhdGVkQXQi..." + +Page 2: GET /api/v1/documents?limit=50&query=runbook&cursor=eyJ1cGRhdGVkQXQi... + → meta.nextCursor = null (done) +``` + +Cursor pagination is tied to `(updatedAt, id)`. If you need `created_*` ordering, you must fetch +all results (no cursor) and sort client-side, or use offset-based logic with `after`/`before`. + +## Combining parameters + +All parameters can be combined: + +```http +GET /api/v1/documents?query=onboarding&after=2026-08-01&sort=created_desc&limit=20 +``` + +This returns documents matching "onboarding" in title or content, updated after August 1 2026, +ordered by creation date descending, 20 per page. + +## Internal API (browser session) + +The internal `GET /api/doc` endpoint used by the doc web UI also supports the same search and +filter parameters, using `keyword` instead of `query`: + +```http +GET /api/doc?keyword=runbook&after=2026-09-01&sort=updated_desc +``` + +This endpoint uses the browser session cookie for authentication and is not intended for host app +integration — use API v1 with a PAT instead. + +## Error handling + +| Status | Code | Meaning | +| ------ | -------------------- | --------------------------------------------- | +| 400 | `invalid_query` | Invalid `after`/`before` date or `sort` value | +| 400 | `invalid_cursor` | Cursor used with `created_*` sort | +| 401 | `unauthorized` | Missing or invalid PAT | +| 403 | `insufficient_scope` | Token lacks `documents:read` | + +## Testing the date range filter + +Host apps should verify that `after` and `before` filter on `updatedAt`, not `createdAt`. A +document edited today but created last month will appear in an `after=last-week` query. + +```typescript +const res = await fetch( + `${DOC_ORIGIN}/api/v1/documents?after=2026-09-11T00:00:00.000Z&before=2026-09-18T00:00:00.000Z`, + { headers: { Authorization: `Bearer ${token}` } } +) + +const { data, requestId } = await res.json() + +// Every returned document must have updatedAt within the range +for (const doc of data) { + const updated = new Date(doc.updatedAt) + console.assert(updated > new Date('2026-09-11T00:00:00.000Z'), `${doc.id} updatedAt out of range`) + console.assert(updated < new Date('2026-09-18T00:00:00.000Z'), `${doc.id} updatedAt out of range`) +} + +// Invalid date returns 400 +const bad = await fetch(`${DOC_ORIGIN}/api/v1/documents?after=not-a-date`, { + headers: { Authorization: `Bearer ${token}` }, +}) +console.assert(bad.status === 400) +const body = await bad.json() +console.assert(body.error.code === 'invalid_query') +``` From f12cfe89f0f0771150c647cb1e433ab28138de28 Mon Sep 17 00:00:00 2001 From: sun-970 <3843544764@qq.com> Date: Sat, 19 Sep 2026 07:24:22 +0000 Subject: [PATCH 2/2] docs: clarify host-app search is one substring and updated_asc ordering (#73) query=deployment+procedure is a single ILIKE substring (plus is a space), not two OR terms. updated_asc is least-recently-updated, not alphabetical. --- docs/host-app-integration.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/host-app-integration.md b/docs/host-app-integration.md index 97c4d5d..a864798 100644 --- a/docs/host-app-integration.md +++ b/docs/host-app-integration.md @@ -19,9 +19,14 @@ The `query` parameter searches both document title and body content with OR sema is returned if the keyword appears in either field. ```http -GET /api/v1/documents?query=deployment+procedure +GET /api/v1/documents?query=deployment%20procedure ``` +`query` is a **single substring**, not a list of OR terms. `deployment%20procedure` (a space) +matches documents whose title or body contains the 21-character string `deployment procedure`. +It does not match a document that has `deployment` in the title and `procedure` only in the +body as two separate words. `+` in the query string is a space, not a boolean operator. + The search is case-insensitive and uses substring matching (`ILIKE`-style). For host apps that need to show where the match was found, there is currently no `matchField` indicator in the API response — the host app should fetch individual documents (`GET /api/v1/documents/{id}`) and @@ -50,7 +55,7 @@ Control ordering with the `sort` parameter: # Most recently created first GET /api/v1/documents?sort=created_desc -# Alphabetical by update time (oldest first) +# Least recently updated first GET /api/v1/documents?sort=updated_asc ```