# 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?