# Lumvise Graph-Storage Contract (DRAFT — for agreement before implementation) Status: **implemented in the graph gateway (see docs/api.md); open questions below still apply**. Lumvise server and the desktop app for storing project knowledge graphs in FalkorDB. Nothing here is final until both sides sign off. ## 1. Topology - One FalkorDB graph per project: `lumvise_p_<projectId>` (project UUID without dashes). Created by `centralizeProject`, dropped on project deletion. - Clients never connect to FalkorDB directly. All graph traffic goes through the server API, which enforces Cognito auth + owner/member roles. ## 2. Node model Every node carries these properties: | Property | Type | Notes | |---|---|---| | `id` | string (UUID) | Stable across exports; assigned by the client | | `kind` | string | e.g. `document`, `entity`, `concept`, `file` — open enum | | `title` | string | Display name | | `body` | string? | Text content (may be large; see §6 limits) | | `created_at` / `updated_at` | int (epoch ms) | Client clock, server overwrites `updated_at` on write | | `rev` | int | Optimistic-concurrency revision, server-incremented | Labels: one label per `kind` plus a common `:Node` label. ## 3. Edge model | Property | Type | Notes | |---|---|---| | `id` | string (UUID) | | | `type` | string | e.g. `references`, `contains`, `relates_to` — open enum | | `created_at` | int | | Edges are directed; undirected relations are stored as two edges. ## 4. Operations (proposed endpoints) | Operation | Input | Semantics | |---|---|---| | `graph.putNodes` | `{ projectId, nodes: Node[] }` | Upsert by `id`; `rev` must match for update, else `409` | | `graph.deleteNodes` | `{ projectId, ids: string[] }` | Deletes nodes + attached edges | | `graph.putEdges` | `{ projectId, edges: Edge[] }` | Upsert by `id` | | `graph.deleteEdges` | `{ projectId, ids: string[] }` | | | `graph.query` | `{ projectId, cypher, params? }` | Read-only Cypher; server rejects write clauses | | `graph.export` | `{ projectId }` | Full graph as `.pz`-compatible JSON (round-trip with the desktop export) | | `graph.import` | `{ projectId, graph, mode: "replace" \| "merge" }` | Bulk load; `replace` wipes the graph first | ## 5. Sync model (desktop) - The desktop app is the source of truth while local. Centralizing copies the graph up via `graph.import` (`replace`). - After centralization, edits go through `graph.put*` with revision checks; the desktop keeps a local cache and can always re-export. - Conflict rule: last writer wins at node granularity, guarded by `rev` so a stale client gets `409` and must re-read. ## 6. Limits (proposed) - 10k nodes / 50k edges per project on the current plan (soft limit). - `body` ≤ 256 KB per node; larger content belongs in object storage (future). - `graph.query` is read-only and time-boxed (5 s). ## 7. Open questions for you 1. Do the `kind`/`type` enums match what the desktop workspace actually produces, or should the contract carry your exact taxonomy? 2. Is the `.pz` export format the right bulk interchange, or do you want a streaming format for very large graphs? 3. Should shared `editor`s have full graph write access, or a subset (e.g. no deletes)? 4. Do you need per-node ACLs later, or is project-level sharing enough?