CLAUDE.md 5.8 KB

CLAUDE.md — smartbotic-vectorapi

C++20 REST API fronting smartbotic-database (gRPC) for n8n + other clients. Stores RAG vectors + JSON, organized into projects with multi-key per-project-grant auth. React admin UI. Ships as Debian .debs.

Build / test / run

# Backend + web UI (Release)
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_WEBUI=ON -S .
cmake --build build -j"$(nproc)"

# Tests (GoogleTest). Integration tests need a running smartbotic-database on localhost:9004;
# they GTEST_SKIP() cleanly if it's unreachable. BUILD_WEBUI=OFF to skip the npm build during test cycles.
cmake -B build -G Ninja -DBUILD_TESTS=ON -DBUILD_WEBUI=OFF -S . && cmake --build build -j"$(nproc)"
ctest --test-dir build --output-on-failure

# Run locally (use the repo's api/ for /openapi.json,/llms.txt,/docs and the built UI)
SMARTBOTIC_VECTORAPI_KEY=dev ./build/src/smartbotic-vectorapi \
  --config config/config.json --share-dir "$PWD/api" --webui-dir "$PWD/build/webui/dist"

# Web UI only
cd webui && npm install && npm run build   # → webui/dist ; `npm run dev` for the :3000 proxy dev server

Architecture (where things live)

  • src/ — the server. vectorapi_core static lib + main.cpp. Namespace svapi. Flat headers, quoted includes.
    • db_gateway (qualify(project,coll) + DbGateway over smartbotic::database::Client), settings_store (global settings, hot-reload), key_store (API keys, hot-reload, bootstrap admin key), collection_registry (per-project metadata), embeddings (OpenAI), auth (sessions, bearer/cookie), server (ApiServer + auth helpers), handlers/* (one file per route group).
    • Auth model: pre-routing authenticates /api/* (401); each handler authorizes via requireKeyrequireAdmin / requireProjectAccess (403). Keys are referenced by a stable id (not the secret).
  • webui/ — React 19 + Vite + TS (strict, erasableSyntaxOnly) + Tailwind + Monaco. Cookie-session auth (credentials:'include'). Pages read currentProject/admin from useAuthStore; all calls go through src/api/client.ts.
  • api/openapi.json (3.1), llms.txt (llmstxt.org), docs/ (Redoc page). Served at /openapi.json, /llms.txt, /docs. Shipped in the server .deb. Keep these in sync when changing routes.
  • packaging/build.sh (--local + Docker trixie), deb/create-debs.sh, control templates, systemd unit, maintainer scripts. docs/superpowers/ — design spec (esp. Addendum A) + the 3 implementation plans.

Conventions

  • C++20, nlohmann/json, spdlog, cpp-httplib (FetchContent, OpenSSL on). Handlers throw svapi::ApiError; a global exception handler maps to {error:{code,message}} + HTTP status (errors.hpp: 400/401/403/404/422/503/500).
  • Filters: field:op:value (op ∈ eq/ne/gt/gte/lt/lte/in/contains/exists/regex/search).
  • TS: no any, no TS enum, no constructor parameter-property shorthand (tsconfig erasableSyntaxOnly). Iterating parsed JSON: bind to a named var first (range-for over nlohmann::json::parse(...)[...] dangles).
  • Commits: conventional prefixes (feat/fix/build/docs/test). Branch for feature work; main is pushed to ssh://git.smartbotics.ai:10022/fszontagh/smartbotic-vectorapi.git.

Data model & runtime config

  • Bootstrap config.json is minimal: log_level, http.{bind_address,port}, database.address. Everything else lives in the DB and hot-reloads (subscribe + atomic snapshot swap).
  • Global service collections (DB default project, no leading underscore — see gotcha): vectorapi_keys, vectorapi_settings. Per-project registry: <project>:vectorapi_collections. The vectorapi_ prefix is reserved (collection-create rejects _ and vectorapi_).
  • First run with no keys generates an admin key (projects:["*"], admin:true) and logs it once; SMARTBOTIC_VECTORAPI_KEY seeds it, OPENAI_API_KEY seeds embeddings.

⚠️ Gotchas (hard-won — don't relearn these)

  • DB v2.3.1: _-prefixed collections misroute when project-qualified. Writes land in MemoryStore (mirror skips _-names) but reads of default:_foo route to LMDB → null. → service collections use no leading underscore (vectorapi_*). Suspected DB bug.
  • DB v2.3.1: dropProject does not physically purge collection data. A recycled project name is otherwise blocked by stale collections/registry → the project-delete handler drops the registry + collections first, and collection-create drops invisible orphans (after the registry "exists" check).
  • DB client strips an id field from stored doc bodies. So API keys store their stable id as key_id in the body (exposed as id externally); document handlers strip id before insert and use the separate id param.
  • Debian 13 (trixie) gRPC cmake config is broken unless protobuf-compiler-grpc + libgrpc++-dev + libprotobuf-dev are installed — find_package(gRPC CONFIG) (used transitively by smartbotic-db-clientConfig.cmake) fails on a gRPCTargets.cmake referencing missing plugin files. The Docker base installs them.
  • Abseil ABI: smartbotic-database/client debs must be built against the system's current Abseil; a stale build crash-loops on libabsl_*.so.<old>. Rebuild the DB if it won't start.
  • Monaco is bundled locally (webui/src/monacoSetup.ts) so the editor works offline — do not revert to the CDN loader.
  • systemd unit is Type=notify; the binary must be built with libsystemd (it is, when libsystemd-dev is present) or change to Type=exec.

Deploy / publish

./packaging/build.sh                                # Debian-13 .debs → dist/debian13/
./packaging/build.sh --repo --suite trixie --sync   # + publish to repository.smartbotics.ai (outward-facing!)

Publishing uploads to the live apt repo — only with explicit confirmation. The deb-repo tooling is /data/smartbotics-deb-repo/scripts/.