|
@@ -1,9 +1,10 @@
|
|
|
# smartbotic-vectorapi — Design Spec
|
|
# smartbotic-vectorapi — Design Spec
|
|
|
|
|
|
|
|
- **Date:** 2026-05-31
|
|
- **Date:** 2026-05-31
|
|
|
-- **Status:** Approved (pre-implementation)
|
|
|
|
|
|
|
+- **Status:** Approved; **§4.2/§4.3/§5/§6 superseded by Addendum A** (multi-project + multi-key auth, added after the DB shipped v2.3.0 multi-project namespaces)
|
|
|
- **Repo:** `ssh://git@git.smartbotics.ai:10022/fszontagh/smartbotic-vectorapi.git`
|
|
- **Repo:** `ssh://git@git.smartbotics.ai:10022/fszontagh/smartbotic-vectorapi.git`
|
|
|
- **Version:** 0.1.0
|
|
- **Version:** 0.1.0
|
|
|
|
|
+- **DB dependency:** `libsmartbotic-db-client (>= 2.3.0)` (v2.3 adds project namespaces + `listProjects`/`createProject`/`dropProject`)
|
|
|
|
|
|
|
|
## 1. Purpose
|
|
## 1. Purpose
|
|
|
|
|
|
|
@@ -309,6 +310,111 @@ mocked with a local httplib server) → similarity search returns ranked results
|
|
|
|
|
|
|
|
## 13. Open setup items
|
|
## 13. Open setup items
|
|
|
|
|
|
|
|
-- Local dev/test uses the already-installed `smartbotic-database` (v2.2.1) on
|
|
|
|
|
|
|
+- Local dev/test uses the locally-installed `smartbotic-database` (v2.3.0) on
|
|
|
`localhost:9004`.
|
|
`localhost:9004`.
|
|
|
- Git remote configured but no push until the user requests it.
|
|
- Git remote configured but no push until the user requests it.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# Addendum A — Multi-project namespaces + multi-key authorization
|
|
|
|
|
+
|
|
|
|
|
+Added 2026-05-31 after `smartbotic-database` v2.3.0 shipped **project namespaces**
|
|
|
|
|
+(separated collections per project, MySQL-database-like). This addendum
|
|
|
|
|
+**supersedes §4.2, §4.3, §5, and §6**. Everything else in the spec stands.
|
|
|
|
|
+
|
|
|
|
|
+## A.1 Concepts
|
|
|
|
|
+
|
|
|
|
|
+- **Project** — a DB namespace (the client addresses it via `Config::project` or a
|
|
|
|
|
+ per-call `<project>:<collection>` qualified name; the qualified form wins). The
|
|
|
|
|
+ DB exposes `listProjects()` / `createProject(name)` / `dropProject(name)`. Names
|
|
|
|
|
+ match `^[a-zA-Z_][a-zA-Z0-9_-]{0,62}$`; `"default"` always exists and cannot be
|
|
|
|
|
+ dropped. Projects are addressed in the REST API as a **URL path segment**.
|
|
|
|
|
+- **API key** — a bearer credential with **grants**: a set of project names it may
|
|
|
|
|
+ access (or `"*"` for all), plus an `admin` flag. This mirrors MySQL user→database
|
|
|
|
|
+ rights. There is no longer a single global key.
|
|
|
|
|
+
|
|
|
|
|
+## A.2 Authorization model
|
|
|
|
|
+
|
|
|
|
|
+A key record: `{ key, label, projects: ["*"] | ["p1", ...], admin: bool, created_at }`.
|
|
|
|
|
+
|
|
|
|
|
+- `admin: true` → may manage projects and keys, and access **all** projects.
|
|
|
|
|
+- A non-admin key may access exactly the projects listed in `projects` (or all if it
|
|
|
|
|
+ contains `"*"`).
|
|
|
|
|
+- **Project-scoped routes** (`/api/v1/projects/{project}/…`): the key must be admin,
|
|
|
|
|
+ hold `"*"`, or list `{project}` → else **403**. Unknown/absent key → **401**.
|
|
|
|
|
+- **Management routes** (`POST/DELETE /api/v1/projects`, all `/api/v1/keys`, global
|
|
|
|
|
+ `/api/v1/stats`): require `admin` → else **403**.
|
|
|
|
|
+- Web UI login posts a key; the session cookie carries that key's identity, so the UI
|
|
|
|
|
+ exposes exactly the projects/management the key is granted.
|
|
|
|
|
+
|
|
|
|
|
+## A.3 Bootstrap (replaces §4.3)
|
|
|
|
|
+
|
|
|
|
|
+On first start, if **no keys exist**, generate one **admin** key
|
|
|
|
|
+(`{admin: true, projects: ["*"]}`), store it, and log it once at WARN. `SMARTBOTIC_VECTORAPI_KEY`
|
|
|
|
|
+seeds this initial admin key's value when set. The key is never logged again.
|
|
|
|
|
+
|
|
|
|
|
+## A.4 Data model & scoping (replaces §5)
|
|
|
|
|
+
|
|
|
|
|
+- **Global** (stored unqualified, i.e. in the DB `default` project):
|
|
|
|
|
+ - `_vectorapi_keys` — one doc per key (doc id = the key string); encrypted.
|
|
|
|
|
+ - `_vectorapi_settings` — global settings doc `current`; encrypted. **No `api_key`
|
|
|
|
|
+ field anymore** — keys live in `_vectorapi_keys`.
|
|
|
|
|
+- **Per project `P`** (qualified `P:<name>`):
|
|
|
|
|
+ - `P:_vectorapi_collections` — the collection registry for that project.
|
|
|
|
|
+ - `P:<userCollection>` — user JSON / vector collections.
|
|
|
|
|
+- The gateway exposes `qualify(project, collection)`; global service collections are
|
|
|
|
|
+ used unqualified. Projects referenced by a request are `createProject`-ensured
|
|
|
|
|
+ (idempotent) on first granted use.
|
|
|
|
|
+
|
|
|
|
|
+## A.5 REST API (replaces §6)
|
|
|
|
|
+
|
|
|
|
|
+All `/api/v1/*` require a valid key (bearer or session cookie). Public: `/healthz`,
|
|
|
|
|
+`/readyz`, `/openapi.json`, `/llms.txt`, static UI, `POST /ui/login`.
|
|
|
|
|
+
|
|
|
|
|
+**Projects**
|
|
|
|
|
+- `GET /api/v1/projects` — list projects the key may access (admin → all).
|
|
|
|
|
+- `POST /api/v1/projects` `{name}` — create (admin).
|
|
|
|
|
+- `GET /api/v1/projects/{project}` — info (collection/doc counts).
|
|
|
|
|
+- `DELETE /api/v1/projects/{project}` — drop (admin; not `default`).
|
|
|
|
|
+
|
|
|
|
|
+**Keys** (all admin-only)
|
|
|
|
|
+- `GET /api/v1/keys` — list (secret masked: show label, projects, admin, created_at,
|
|
|
|
|
+ and a short key prefix).
|
|
|
|
|
+- `POST /api/v1/keys` `{label, projects:[...], admin?:bool}` — generate; returns the
|
|
|
|
|
+ new key value **once**.
|
|
|
|
|
+- `PATCH /api/v1/keys/{key}` `{label?, projects?, admin?}` — update grants.
|
|
|
|
|
+- `DELETE /api/v1/keys/{key}` — revoke.
|
|
|
|
|
+
|
|
|
|
|
+**Collections** (project-scoped) — `…/projects/{project}/collections`
|
|
|
|
|
+- `POST` create `{name, kind:"json"|"vector", vector_dimension?, embedding_model?}`,
|
|
|
|
|
+ `GET` list, `GET /{name}`, `DELETE /{name}`.
|
|
|
|
|
+
|
|
|
|
|
+**JSON documents** — `…/projects/{project}/collections/{name}/documents`
|
|
|
|
|
+- `POST` insert, `GET /{id}`, `GET` find (`filter`/`limit`/`offset`/`sort`/`desc`),
|
|
|
|
|
+ `PATCH /{id}`, `PUT /{id}`, `DELETE /{id}`.
|
|
|
|
|
+
|
|
|
|
|
+**Vectors / RAG** — `…/projects/{project}/collections/{name}`
|
|
|
|
|
+- `POST /vectors` `{id?, text?, vector?, metadata?}`; `POST /search`
|
|
|
|
|
+ `{query_text?|query_vector?, top_k, min_score, filters?}`.
|
|
|
|
|
+
|
|
|
|
|
+**Stats**
|
|
|
|
|
+- `GET /api/v1/projects/{project}/stats` — project-scoped (any key granted the project).
|
|
|
|
|
+- `GET /api/v1/stats` — server-wide (admin).
|
|
|
|
|
+
|
|
|
|
|
+**Errors** unchanged from §6.6, plus **403** `forbidden` for a valid key lacking the
|
|
|
|
|
+required grant.
|
|
|
|
|
+
|
|
|
|
|
+## A.6 Settings (replaces §4.2)
|
|
|
|
|
+
|
|
|
|
|
+`_vectorapi_settings` (encrypted, global): `openai_api_base`, `openai_api_key`,
|
|
|
|
|
+`default_embedding_model`, `cors_origins`, `session_ttl_minutes`, `webui_enabled`.
|
|
|
|
|
+Bootstrap `config.json` is unchanged (log level, http bind/port, DB address). The
|
|
|
|
|
+**default project** the UI/clients land on when none is given may also live here as
|
|
|
|
|
+`default_project` (defaults to `"default"`).
|
|
|
|
|
+
|
|
|
|
|
+## A.7 Web UI deltas
|
|
|
|
|
+
|
|
|
|
|
+Login with a key → session. A **project selector** (only granted projects). Admin
|
|
|
|
|
+keys additionally get **Projects** (create/drop) and **Keys** (create/revoke/edit
|
|
|
|
|
+grants) screens. All collection/document/vector/search/stats views operate within the
|
|
|
|
|
+selected project.
|