docs(api): define REST boundary and point management routes
Why: - Establish the versioned FastAPI boundary for authentication, tenant isolation, chat runs, file ingestion, point management, and health checks. Changes: - Define /v1 routers, bearer-token authentication, scopes, response envelopes, error conventions, and job-shaped ingestion responses. - Rename the older indicative /chunks routes to /points while preserving the existing Qdrant payload and CRUD semantics. - Define tenant injection and concurrency requirements at the HTTP boundary. Impact: - The REST API is owned by ADR-0008 when older endpoint examples differ. - Clients should use /v1/points and /v1/threads resource paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,11 @@
|
||||
|
||||
Accepted
|
||||
|
||||
Route naming note: ADR-0008 owns the REST API surface and renames the
|
||||
indicative endpoint examples in this ADR from `/chunks/...` to `/points/...`.
|
||||
The CRUD semantics, Qdrant primitives, payload schema, soft-delete behavior,
|
||||
and tenant-isolation rules in this ADR remain accepted.
|
||||
|
||||
## Context
|
||||
|
||||
Beyond bulk ingestion ([0001](0001-ingestion-pipeline-and-collection-schema.md)),
|
||||
@@ -24,16 +29,16 @@ the `chunks` collection and payload schema from ADR-0001:
|
||||
|
||||
| Operation | FastAPI endpoint (indicative) | Qdrant primitive |
|
||||
|---|---|---|
|
||||
| Create a chunk | `POST /chunks` | upsert (single point) |
|
||||
| Update a chunk's vectors/content | `PUT /chunks/{chunk_id}` | upsert (`update_only` mode) |
|
||||
| Partially update payload | `PATCH /chunks/{chunk_id}/payload` | `set_payload` / `overwrite_payload` |
|
||||
| Delete one chunk | `DELETE /chunks/{chunk_id}` | delete by ID |
|
||||
| Delete many chunks | `DELETE /chunks?file_id=...` | delete by filter |
|
||||
| List/paginate chunks, in order | `GET /chunks?file_id=...` | `scroll` with filter + pagination, `order_by: order_id` |
|
||||
| Reorder/insert a chunk | `PATCH /chunks/{chunk_id}/order` | `set_payload` on `order_id` only |
|
||||
| Count chunks | `GET /chunks/count` | `count` |
|
||||
| Keyword search | `GET /chunks/search?q=...` | full-text payload index on `content` (match, not semantic) |
|
||||
| Bulk multi-op edits | `POST /chunks/batch` | Qdrant `points/batch` |
|
||||
| Create a point | `POST /points` | upsert (single point) |
|
||||
| Update a point's vectors/content | `PUT /points/{point_id}` | upsert (`update_only` mode) |
|
||||
| Partially update payload | `PATCH /points/{point_id}/payload` | `set_payload` / `overwrite_payload` |
|
||||
| Delete one point | `DELETE /points/{point_id}` | delete by ID |
|
||||
| Delete many points | `DELETE /points?file_id=...` | delete by filter |
|
||||
| List/paginate points, in order | `GET /points?file_id=...` | `scroll` with filter + pagination, `order_by: order_id` |
|
||||
| Reorder/insert a point | `PATCH /points/{point_id}/order` | `set_payload` on `order_id` only |
|
||||
| Count points | `GET /points/count` | `count` |
|
||||
| Keyword search | `GET /points/search?q=...` | full-text payload index on `content` (match, not semantic) |
|
||||
| Bulk multi-op edits | `POST /points/batch` | Qdrant `points/batch` |
|
||||
|
||||
### Ordering and reordering
|
||||
|
||||
@@ -45,7 +50,7 @@ inserting a chunk only requires assigning it a new value between its two new
|
||||
neighbors — no renumbering of siblings, and no effect on the chunk's stable
|
||||
point ID (which is derived from the immutable `chunk_index`, not `order_id`).
|
||||
|
||||
`PATCH /chunks/{chunk_id}/order` does more than set one field, though: since
|
||||
`PATCH /points/{point_id}/order` does more than set one field, though: since
|
||||
ADR-0001 also maintains `previous_chunk_id`/`next_chunk_id` pointers for O(1)
|
||||
adjacency lookups, a single reorder touches **up to four chunks** in one
|
||||
`points/batch` call:
|
||||
@@ -62,7 +67,7 @@ go stale.
|
||||
|
||||
### Keyword search is not semantic search
|
||||
|
||||
`GET /chunks/search` matches against the full-text payload index on
|
||||
`GET /points/search` matches against the full-text payload index on
|
||||
`content` (and structured filters on `tenant_id`, `domain`, `file_id`,
|
||||
etc.) — it is filter/match-based keyword search, not embedding-based
|
||||
retrieval. This is deliberately distinct from the hybrid dense+sparse
|
||||
@@ -72,11 +77,11 @@ context) and should not be conflated in the API or in future discussion.
|
||||
|
||||
### Delete is soft by default
|
||||
|
||||
`DELETE /chunks/{chunk_id}` and `DELETE /chunks?file_id=...` set
|
||||
`DELETE /points/{point_id}` and `DELETE /points?file_id=...` set
|
||||
`is_active: false` and `deleted_at` (via `set_payload`) rather than removing
|
||||
the point from Qdrant — consistent with ADR-0001's soft-delete fields. This
|
||||
keeps deleted chunks available for audit and lets `GET /chunks` and
|
||||
`GET /chunks/search` filter them out by default (`is_active: true` implied
|
||||
keeps deleted points available for audit and lets `GET /points` and
|
||||
`GET /points/search` filter them out by default (`is_active: true` implied
|
||||
unless the caller explicitly asks to include inactive chunks). A hard delete
|
||||
(actual point removal, e.g. `points/delete`) is available separately for
|
||||
compliance-driven purges, not as the default CRUD behavior. Either way, the
|
||||
|
||||
Reference in New Issue
Block a user