# Lumvise Account & Project API Base: `https://app.lumvise.com` (web) — the same endpoints serve the desktop app. ## Authentication Single sign-on via AWS Cognito (OIDC, Authorization Code + PKCE, public client — no client secret). One app client serves both the website and the desktop app. - **Web**: redirect to `https://eu-north-1lvplz48hz.auth.eu-north-1.amazoncognito.com/oauth2/authorize` with `response_type=code`, `scope=openid email profile`, S256 code challenge. Redirect target: `https://app.lumvise.com/auth/callback` (the app subdomain, per the "Allowed callback URLs" below). - **Desktop**: same flow with a loopback redirect (`http://127.0.0.1:<port>/callback`); exchange the code at `https://eu-north-1lvplz48hz.auth.eu-north-1.amazoncognito.com/oauth2/token` with the PKCE verifier. - **Renewal**: use the Cognito refresh token at `/oauth2/token` (`grant_type=refresh_token`). Fully local work needs no session at all. Every API call sends the **ID token** as `Authorization: Bearer <id_token>`. The server verifies it against the pool JWKS (issuer, signature, expiry, audience) and maps `sub` to the user's profile. Clients never receive database or graph-database credentials. ## Concepts - **Personal space**: every user automatically has a private space; it is just the set of projects they own plus projects shared with them. - **Project**: a knowledge graph plus relational content. Owned by exactly one user; shareable with others as `viewer` or `editor`. - **Centralized project**: a project whose graph lives in FalkorDB (`lumvise_p_<projectId>`). Local-only projects stay fully supported. - **Publication**: an optional public page for a project (`/p/<slug>`). ## Endpoints (RPC, JSON over POST) All endpoints are TanStack server functions; the desktop app calls them as `POST /_serverFn/<id>` with a JSON body `{ "data": ... }` and the bearer token. | Function | Input | Auth | Description | |---|---|---|---| | `getAccount` | — | user | Profile + owned projects + projects shared with the caller | | `createProject` | `{ name, description? }` | user | Creates a project in the caller's space | | `renameProject` | `{ projectId, name }` | owner | Renames a project | | `deleteProject` | `{ projectId }` | owner | Deletes project, memberships, publication (graph drop: see contract) | | `shareProject` | `{ projectId, email, role }` | owner | Shares with an existing account (`viewer`/`editor`) | | `unshareProject` | `{ projectId, memberId }` | owner | Removes a member | | `listProjectMembers` | `{ projectId }` | owner | Lists members | | `publishProject` | `{ projectId, title, summary? }` | owner | Creates/updates the public page, returns `slug` | | `unpublishProject` | `{ projectId }` | owner | Removes the public page | | `listPublications` | — | public | Latest public projects | | `centralizeProject` | `{ projectId }` | owner | Provisions the FalkorDB graph for a local project | Errors: `401` missing/invalid token, `403` not permitted, `404` not found, `400` invalid input (zod-validated). ## Graph API Node/edge read/write endpoints are **not yet implemented** — they follow the graph-storage contract in `docs/graph-contract.md`, which we agree on before the desktop adapter is built. ## Graph gateway `/api/public/v1/projects/{projectId}/graph/{op}`. Send `Authorization: Bearer <Cognito id or access token>`. You can leave the token out only to read published projects. The gateway handles each request in this order: check the token, look up the caller's role on the project in PostgreSQL, check that role against the operation, then run it on that project's FalkorDB graph only. A private or unknown project returns `404`, so outsiders can't tell whether it exists. | op | Method | Minimum role | Body | |---|---|---|---| | `query` | POST | public | `{ cypher, params? }`, read-only (`GRAPH.RO_QUERY`), 5 s timeout | | `export` | GET | public | | | `putNodes` | POST | editor | `{ nodes: Node[] }` (≤500); `rev` must match the stored value, otherwise `409` lists the conflicts | | `deleteNodes` | POST | editor | `{ ids }` (≤1000) | | `putEdges` | POST | editor | `{ edges: {id,type,from,to,created_at?}[] }` (≤2000) | | `deleteEdges` | POST | editor | `{ ids }` | | `import` | POST | owner | `{ mode: "replace"\|"merge", nodes, edges }` (≤10k / 50k) | `kind` and `type` must be lowercase identifiers. Requests are limited to 8 MB and `body` to 256 KB per node. The project must be centralized first; otherwise the gateway returns `409`. ## Desktop sign-in The desktop app signs in through the browser using authorization code + PKCE. Its callback is `http://localhost:8787/callback`. It then sends the resulting tokens to the gateway and renews them with the refresh token.