docs: NextGraph multi-user data model — stores, auth matrix, inbox fork plan

Capture the multi-user design exploration as project knowledge + briefs:
- knowledge: NextGraph store types/permissions (+ inbox at protocol, SDK
  exposure, local repo path); integration model (iframe, where the verifier
  runs, generic JS plumbing, ngd stateful, build-time broker target)
- briefs: multi-store refactor; authorization matrix + query inventory +
  derived store partitions; temporary fork to expose the inbox (3 layers:
  SDK fork, Coolify self-hosting, Festipod integration; libs via build:ng)
- fix stale @ng-org versions (alpha.11 -> alpha.13) and a broken
  decision-record link in data-layer.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-05-21 17:38:51 +02:00
parent ffda889f34
commit 445a448031
7 changed files with 468 additions and 40 deletions
@@ -0,0 +1,75 @@
# Modèle d'intégration et de déploiement NextGraph
Comment une app web tierce s'intègre à NextGraph, et où tourne le moteur (verifier).
## Overview
NextGraph s'utilise depuis une app web via un **proxy iframe** (`@ng-org/web`) : l'app tierce ne contient pas le moteur, elle délègue à un ng-app hébergé (par défaut `nextgraph.net`) qui exécute le moteur dans une iframe. Comprendre ce découpage est nécessaire pour savoir ce qu'on peut modifier sans auto-héberger. Vérifié dans `nextgraph-rs` le 2026-05-21 (voir [chemin du repo local](./nextgraph-stores-permissions.md#code-source-local)).
## Les paquets JS
- **`@ng-org/web`** — paquet **publié**. Proxy postMessage léger (aucun wasm embarqué). C'est **le** chemin d'intégration d'une app web tierce. `@ng-org/orm` et tous les exemples officiels (expense-tracker…) en dépendent. **Festipod l'utilise.**
- **`@ng-org/api-web`** — paquet **privé** (`"private": true`, non publié). Moteur navigateur complet : charge `@ng-org/lib-wasm` dans un Web Worker (`?worker&inline`), utilise `sessionStorage`/`Worker`. Consommé uniquement par `app/nextgraph` (le frontend ng-app) et `engine/broker/auth`. C'est le moteur **interne** de l'app NextGraph, **pas** une cible d'intégration tierce.
- **`@ng-org/lib-wasm`** — le moteur compilé en wasm (contient le verifier via la dépendance `nextgraph` / `local_broker`). Source : `sdk/js/lib-wasm/`.
- **`nextgraph`** (npm) — l'API **NodeJS** (build `pkg-node` de lib-wasm).
- **`@ng-org/orm`** — l'ORM réactif (`useShape`…), bâti sur `@ng-org/web`.
## Où tourne le verifier
Dans le modèle web standard (iframe), le verifier tourne **dans l'iframe** : `app/nextgraph` charge `api-web``lib-wasm` dans un Web Worker, côté navigateur. Le broker (`ngd`) ne fait que **le transport et le stockage**.
**Conséquence** : modifier la logique du verifier (ex. `request_processor`, `inbox_processor`) = reconstruire le **ng-app**, pas le broker.
## Le modèle iframe (intégration tierce)
- `@ng-org/web` redirige vers le ng-app hébergé, qui recharge l'app tierce dans une iframe après authentification, puis relaie les appels par `postMessage`.
- **Reciblable au build** via variables d'env (fichier `sdk/js/web/src/index.ts`) :
| Variable | Cible |
|---|---|
| `NG_REDIR_SERVER` | défaut `nextgraph.net` |
| `NG_DEV3` | `127.0.0.1:3033` |
| `NG_DEV` | `localhost:14402` (redir) / `14404` (origin) |
| `NG_DEV_LOCAL_BROKER` | `localhost:1421` |
Une app tierce peut donc pointer `@ng-org/web` vers un ng-app **auto-hébergé** sans changer son code, juste en rebuildant avec ces variables.
## Build pipeline lib-wasm
Scripts cargo dans `sdk/js/lib-wasm/Cargo.toml` (`[package.metadata.scripts]`) :
- `web` / `webdev``wasm-pack build --target web`
- `node` / `nodedev``wasm-pack build -t nodejs`
- `app` / `appdev``wasm-pack build --target bundler`
Post-traités par `prepare-web.js` / `prepare-node.js`.
## Plomberie proxy ↔ iframe ↔ worker (générique)
Le chemin d'appel d'une méthode du moteur est **entièrement générique** — aucune allowlist :
- `@ng-org/web` (proxy) : un `Proxy` JS qui relaie *n'importe quel* nom de méthode à l'iframe par `postMessage` (`apply``postMessage({method, args})`). Seules les méthodes *streamées* ont une entrée dans une table interne (positions d'arguments) ; les autres passent en simple requête/réponse.
- `app/nextgraph``api-web/wasm-worker.js` : dispatch générique `Reflect.apply(ng[method], null, args)` (la table `mapping` est commentée/inutilisée).
**Conséquence** : une nouvelle fonction wasm en **requête/réponse simple** est *atteignable* de bout en bout via ce forwarding générique sans modifier le JS. Mais c'est un mécanisme de relais, **pas un substitut à une API typée** : l'appeler ainsi est un appel string non typé/non documenté (hack de test). Pour une intégration propre, on ajoute la méthode à la surface d'API du paquet (`@ng-org/web`) et à ses `.d.ts`, et éventuellement à `@ng-org/orm` (qui, lui, n'est **pas** un forwarder générique).
Cas **streamé** : une méthode en flux exige une entrée dans la table de streaming **des deux côtés**`E` dans `@ng-org/web` (`ngweb.js`) **et** `streamed_api` dans `api-web/main.ts`. (Méthodes streamées actuelles : `doc_subscribe`, `orm_start_graph`, `orm_start_discrete`, `file_get`, `app_request_stream`.)
## Ciblage du broker : build-time uniquement
La cible (broker/ng-app) est figée **au build** de `@ng-org/web` via `import.meta.env` (`sdk/js/web/src/index.ts`) — **pas d'override runtime**, et `init()` ne prend pas d'URL de broker. Pour pointer une app vers un ng-app auto-hébergé, il faut donc **rebuilder `@ng-org/web`** avec `NG_REDIR_SERVER`/`NG_DEV*` (paquet en TypeScript pur, sans wasm → build trivial).
## Le broker (ngd)
- Supporte déjà nativement l'inbox (`inbox_post`, `inbox_register`, `inbox_pop_for_user` dans `engine/net/src/server_broker.rs`). Un `ngd` standard router­ait l'inbox — aucun patch broker nécessaire.
- C'est un démon **WebSocket** (`async-tungstenite`), **stateful** : stockage RocksDB sous `--base-path`, identité de pair (PeerId) persistée. Le volume est critique (clés + données chiffrées des users).
- CLI (`bin/ngd/src/cli.rs`) : `--local PORT`, et surtout `--domain DOMAIN:PORT,LOCAL_PORT` = mode « derrière reverse-proxy TLS-terminé qui envoie X-Forwarded-For » (adapté à Traefik/Coolify).
- **Ne sert pas de fichiers statiques** : pas de `ServeDir`/HTTP statique dans le crate. Le **ng-app frontend est un déploiement statique séparé** (`pnpm webfilebuild`). En prod, un reverse-proxy sert le statique du ng-app et proxy le WebSocket vers ngd sur un même domaine.
- Premier démarrage **interactif** : ngd émet un lien d'invitation pour créer le wallet admin (cf. DEV.md « first run »). Wrinkle pour un déploiement conteneurisé headless.
- Les Dockerfiles officiels (`bin/ngd/docker/Dockerfile.{alpine,fedora,ubuntu}`) sont **incomplets/cassés** (chemins obsolètes, échec de link llvm/clang documenté en commentaire) — pas de build conteneur turnkey.
## See Also
- [Stores NextGraph et droits d'accès](./nextgraph-stores-permissions.md) — stores, permissions, inbox au protocole, chemin du repo local
- [Data Layer](./data-layer.md) — usage actuel côté Festipod (auto-init iframe conditionnel)
- [Brief : forker NextGraph pour l'inbox](../briefs/fork-nextgraph-inbox.md) — consommateur de cette fiche