Kaynağa Gözat

docs(spec): Addendum A — multi-project namespaces + multi-key (project-grant) auth

DB shipped v2.3.0 project namespaces. Supersedes the single-key/§5/§6 design:
projects as URL path segments, API keys with MySQL-style per-project grants,
project + key management via API/UI, per-project collection registries.
Fszontagh 2 ay önce
ebeveyn
işleme
70267f3592

+ 108 - 2
docs/superpowers/specs/2026-05-31-smartbotic-vectorapi-design.md

@@ -1,9 +1,10 @@
 # smartbotic-vectorapi — Design Spec
 
 - **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`
 - **Version:** 0.1.0
+- **DB dependency:** `libsmartbotic-db-client (>= 2.3.0)` (v2.3 adds project namespaces + `listProjects`/`createProject`/`dropProject`)
 
 ## 1. Purpose
 
@@ -309,6 +310,111 @@ mocked with a local httplib server) → similarity search returns ranked results
 
 ## 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`.
 - 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.