From a2081b2796acd8232b6d16523e033014c72081e9 Mon Sep 17 00:00:00 2001 From: Rassl Date: Wed, 23 Sep 2026 22:56:33 +0400 Subject: [PATCH 1/2] refactor: move schema store and audit to the /v2/schema API The /schema blueprint is deprecated in jarvis-backend; every route has a /v2/schema successor served by the same service methods, so the payload shape is unchanged. Reads go to GET /v2/schema (was /schema/all), type and relationship CRUD to /v2/schema and /v2/schema/edge, audit to /v2/schema/audit. Boltwall already gates all /v2/schema/* writes. --- CLAUDE.md | 2 +- src/app/admin/domains/page.tsx | 2 +- src/app/admin/ontology/mock-small.ts | 2 +- src/lib/__tests__/schema-store.test.ts | 10 +++++----- src/lib/graph-api.ts | 2 +- src/lib/schema-icons.ts | 2 +- src/lib/schema-types.ts | 2 +- src/stores/schema-store.ts | 14 +++++++------- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2cf6e50c..b36bcd98 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ Knowledge graph explorer frontend. Rebuilds the core of sphinx-nav-fiber with Ne ## Backend Services - **jarvis-boltwall**: Auth gateway (isAdmin, feature flags, L402 payments, radar/sources) -- **jarvis-backend**: Graph data (v2/nodes, v2/edges, schema/all, stats, about) +- **jarvis-backend**: Graph data (v2/nodes, v2/edges, v2/schema, stats, about) - Boltwall proxies most requests to jarvis-backend; schema endpoints go direct ## Transaction History diff --git a/src/app/admin/domains/page.tsx b/src/app/admin/domains/page.tsx index 90f8b9d1..4b4d8efb 100644 --- a/src/app/admin/domains/page.tsx +++ b/src/app/admin/domains/page.tsx @@ -116,7 +116,7 @@ export default function DomainsPage() { // --- Write helpers ------------------------------------------------------ - // Reassign a set of types to `domainValue` (PUT /schema each), then relabel + // Reassign a set of types to `domainValue` (PUT /v2/schema each), then relabel // existing nodes in the background. const assignTypesToDomain = useCallback( async (typeNames: string[], domainValue: string) => { diff --git a/src/app/admin/ontology/mock-small.ts b/src/app/admin/ontology/mock-small.ts index dafc7f15..292e53a1 100644 --- a/src/app/admin/ontology/mock-small.ts +++ b/src/app/admin/ontology/mock-small.ts @@ -1,6 +1,6 @@ import type { SchemaNode, SchemaEdge } from "@/lib/schema-types" -// Trimmed from real /schema/all response +// Trimmed from real /v2/schema response export const SMALL_SCHEMAS: SchemaNode[] = [ { ref_id: "9e96b53a-c8ba-4f2a-9d4a-ced714d57e43", diff --git a/src/lib/__tests__/schema-store.test.ts b/src/lib/__tests__/schema-store.test.ts index 6d6cd589..f941e9e5 100644 --- a/src/lib/__tests__/schema-store.test.ts +++ b/src/lib/__tests__/schema-store.test.ts @@ -238,13 +238,13 @@ describe("schema-store – endpoints", () => { useSchemaStore.setState({ schemas: [makeSchema()], edges: [], loading: false }) }) - it("fetches the ontology from /schema/all", async () => { + it("fetches the ontology from /v2/schema", async () => { mockGet.mockResolvedValueOnce({ schemas: [], edges: [] }) await useSchemaStore.getState().fetchAll() - expect(mockGet).toHaveBeenCalledWith("/schema/all") + expect(mockGet).toHaveBeenCalledWith("/v2/schema") }) - it("sends type and relationship writes to /schema", async () => { + it("sends type and relationship writes to /v2/schema", async () => { mockPut.mockResolvedValueOnce({}).mockResolvedValueOnce({}) mockPost.mockResolvedValueOnce({}).mockResolvedValueOnce({}) const store = useSchemaStore.getState() @@ -254,7 +254,7 @@ describe("schema-store – endpoints", () => { await store.addEdge({ ref_id: "e-1", source: "a", target: "b", source_type: "A", target_type: "B", edge_type: "LINKS" }) await store.updateEdge({ ref_id: "e-1", source: "a", target: "b", edge_type: "LINKS" }) - expect(mockPut.mock.calls.map(([path]) => path)).toEqual(["/schema/test-1", "/schema/edge/e-1"]) - expect(mockPost.mock.calls.map(([path]) => path)).toEqual(["/schema", "/schema/edge"]) + expect(mockPut.mock.calls.map(([path]) => path)).toEqual(["/v2/schema/test-1", "/v2/schema/edge/e-1"]) + expect(mockPost.mock.calls.map(([path]) => path)).toEqual(["/v2/schema", "/v2/schema/edge"]) }) }) diff --git a/src/lib/graph-api.ts b/src/lib/graph-api.ts index 8b51a581..88abd8c7 100644 --- a/src/lib/graph-api.ts +++ b/src/lib/graph-api.ts @@ -1377,7 +1377,7 @@ export async function dismissReview( } export async function getSchemaAudit(): Promise { - return api.get("/schema/audit") + return api.get("/v2/schema/audit") } // ── Legal document ingestion ───────────────────────────────────────────────── diff --git a/src/lib/schema-icons.ts b/src/lib/schema-icons.ts index a700b65d..67798120 100644 --- a/src/lib/schema-icons.ts +++ b/src/lib/schema-icons.ts @@ -21,7 +21,7 @@ import type { LucideIcon } from "lucide-react" /** * Maps jarvis schema icon names to lucide-react components. - * Icon names come from the /schema/all API response (e.g. "TwitterIcon", "VideoIcon"). + * Icon names come from the /v2/schema API response (e.g. "TwitterIcon", "VideoIcon"). */ const SCHEMA_ICON_MAP: Record = { NodesIcon: CircleDot, diff --git a/src/lib/schema-types.ts b/src/lib/schema-types.ts index d373741a..de7c717f 100644 --- a/src/lib/schema-types.ts +++ b/src/lib/schema-types.ts @@ -49,6 +49,6 @@ export interface SchemaEdge { target_type?: string // Attribute definitions for this edge type, e.g. { since: "?datetime", // role: "string" }. A leading "?" marks the attribute optional. Present on - // the live /schema/all payload; absent on some mock fixtures. + // the live /v2/schema payload; absent on some mock fixtures. attributes?: Record } diff --git a/src/stores/schema-store.ts b/src/stores/schema-store.ts index ffad8b9d..5fa730e4 100644 --- a/src/stores/schema-store.ts +++ b/src/stores/schema-store.ts @@ -62,7 +62,7 @@ export const useSchemaStore = create((set) => ({ if (isMocksEnabled()) return try { - await api.put(`/schema/${updated.ref_id}`, { + await api.put(`/v2/schema/${updated.ref_id}`, { type: updated.type, parent: updated.parent, primary_color: updated.color, @@ -93,7 +93,7 @@ export const useSchemaStore = create((set) => ({ if (isMocksEnabled()) return schema.ref_id try { - const res = await api.post<{ ref_id?: string }>("/schema", { + const res = await api.post<{ ref_id?: string }>("/v2/schema", { type: schema.type, parent: schema.parent, primary_color: schema.color, @@ -129,7 +129,7 @@ export const useSchemaStore = create((set) => ({ if (isMocksEnabled()) return try { - await api.delete(`/schema/${refId}`) + await api.delete(`/v2/schema/${refId}`) } catch (err) { console.error("Failed to delete schema:", err) // Rollback @@ -145,7 +145,7 @@ export const useSchemaStore = create((set) => ({ try { // The backend keys edge schemas off type NAMES, not ref_ids. - const res = await api.post<{ ref_id?: string }>("/schema/edge", { + const res = await api.post<{ ref_id?: string }>("/v2/schema/edge", { source: edge.source_type ?? edge.source, target: edge.target_type ?? edge.target, edge_type: edge.edge_type, @@ -182,7 +182,7 @@ export const useSchemaStore = create((set) => ({ if (isMocksEnabled()) return try { - await api.put(`/schema/edge/${edge.ref_id}`, { + await api.put(`/v2/schema/edge/${edge.ref_id}`, { edge_type: edge.edge_type, attributes: edge.attributes ?? {}, }) @@ -204,7 +204,7 @@ export const useSchemaStore = create((set) => ({ if (isMocksEnabled()) return try { - await api.delete(`/schema/edge/${refId}`) + await api.delete(`/v2/schema/edge/${refId}`) } catch (err) { console.error("Failed to delete relationship:", err) // Rollback @@ -235,7 +235,7 @@ export const useSchemaStore = create((set) => ({ centrality?: number }> edges: SchemaEdge[] - }>("/schema/all") + }>("/v2/schema") const schemas: SchemaNode[] = (res.schemas ?? []).map((s) => ({ ref_id: s.ref_id, From 6be1d81abfbeb86d6844e944387492fc9abee251 Mon Sep 17 00:00:00 2001 From: Rassl Date: Wed, 23 Sep 2026 23:29:13 +0400 Subject: [PATCH 2/2] docs: point agent guides at GET /v2/schema for the full ontology llms.txt, agents.txt and the README named the deprecated /schema (v1) route. The v2 route is public again on boltwall and takes ?domains= to scope the payload; note that concise/include_attributes drop parent. --- README.md | 2 +- public/agents.txt | 5 ++++- public/llms.txt | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b13e1ac9..f68f5736 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ src/ - `GET /isAdmin` — auth + feature flags (boltwall) - `GET /v2/nodes` — search/list nodes (jarvis-backend) -- `GET /schema/all` — ontology schemas + edges (jarvis-backend) +- `GET /v2/schema` — ontology schemas + edges, `?domains=` to scope (jarvis-backend) - `POST /radar` — add content source (boltwall) - `POST /boost` — boost a node with Lightning (boltwall) - `GET /about` — graph metadata (jarvis-backend) diff --git a/public/agents.txt b/public/agents.txt index fffd82c3..085d6f92 100644 --- a/public/agents.txt +++ b/public/agents.txt @@ -255,7 +255,9 @@ When the human says… | Hit this endpoint | `BELOW_MINIMUM` with the figure in `message`. | See "Withdrawing" below. "open this node" / "show details" | `GET /api/v2/nodes/?expand=edges` -"what node types exist" | `GET /api/v2/schema/domains` (free) or `GET /schema` +"what node types exist" | `GET /api/v2/schema/domains` (free) or + / "show the ontology" | `GET /api/v2/schema?domains=,` (free; + | types with `parent` + relationship schemas) "how many nodes / topics / people" | `GET /api/stats` (free) "subscribe to this RSS / channel" | `POST /radar` with `{source, source_type}` — / "follow this handle" | `source_type` ∈ `twitter_handle`, `youtube_channel`, @@ -373,6 +375,7 @@ asking the human to fund a token: - `GET /api/stats` - `GET /api/about` - `GET /api/v2/schema/domains` +- `GET /api/v2/schema?domains=,` — full ontology, scoped by domain - `GET /api/v2/nodes/topic-check?name=` - `GET /api/v2/nodes/check?node_type=&key=` diff --git a/public/llms.txt b/public/llms.txt index 63449b89..adb3ad93 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -12,6 +12,9 @@ 2. Explore for free first (no auth required): - `GET /api/getPrice` — current price in sats of every paid route - `GET /api/stats`, `GET /api/about`, `GET /api/v2/schema/domains` + - `GET /api/v2/schema?domains=,` — full ontology (types with + `parent` inheritance + relationship schemas), optionally scoped + to a domain list from `/api/v2/schema/domains` - `GET /api/v2/nodes/topic-check?name=` - `GET /api/v2/nodes/check?node_type=&key=` 3. For paid actions (search, node lookup, content add): @@ -86,7 +89,7 @@ direct LN-node check (see `/agents.txt`). Any non-empty string after | GET | `/api/v2/content?sort_by=date&limit=100` | **List the caller's own content / "my content" / "what I added".** Server-filtered by the LSAT identity in your `Authorization` header — never fetch `/api/v2/nodes` and filter client-side. Returns `{nodes, totalCount, totalProcessing}` where `totalProcessing` counts your submissions still being ingested. | | GET | `/api/v2/reviews?status=&type=&sort=&skip=&limit=` | Pending content reviews. | | GET | `/api/v2/schema/domains` | Domain roots, hidden_types, hidden_domains. | -| GET | `/schema` | Full ontology. | +| GET | `/api/v2/schema?domains=,` | Full ontology: `{schemas, edges}`. Each schema has `type`, `parent` (CHILD_OF inheritance), `domain`, `node_key`, `attributes`, `inherited_attributes`; each edge has `source`, `target`, `edge_type`. `domains` scopes to a comma-separated list. Do **not** pass `concise=true` or `include_attributes=false` — both drop `parent`. Replaces the deprecated `/schema/all`. | | GET | `/stats` | `{num_nodes, num_episodes, num_people, num_audio, num_video, num_tweet, num_documents, …}`. | | GET | `/about` | Graph identity (title, description). | | GET | `/balance` | Caller's sats balance. |