Files
ng-eventually/docs/decisions/shared-wallet-login-flow.md
Sylvain Duchesne 63ecfeeff8 docs+refactor(client): fidelity pass — id identity, drop connections, no faux-login, accurate NextGraph framing
Align the polyfill's surface and docs with the verified NextGraph reality and
remove application-level concepts:

- Identity is an ID, not a username: AccountRecord.id, shim predicate shim:id,
  normalizeId; accounts core becomes IdentityStore (set/clear/get) — the faux
  login/logout framing is gone (identity is set at wallet-import time).
- Relationship/connection is an application concept, not a platform primitive
  (NextGraph has no bilateral-connection primitive: grantee is unpersisted
  scaffolding, cap-send is unimplemented). Remove connections.ts; caps exposes
  only a directed grantRead(doc, granteeId) + a read-only protectedDocsOf(owner).
  Delete the now-dead isolation.ts social-visibility axis.
- Inbox docs: NextGraph has no separate curator — the recipient's own verifier
  unseals and applies each queued sealed message inline (process_inbox);
  inbox_post_link is a proposed/future API. Stop attributing the emulated
  curator to the platform.
- Read isolation reframed around the outcome: no cap -> empty union read;
  targeted read of an unheld repo -> RepoNotFound; cap introspection
  (canRead/governsRead) is emulation-only with no NextGraph API behind it.
- read-model.md corrected: the listing path is per-doc ANCHORED default-graph
  queries, never the anchorless GRAPH ?g union (that is O(wallet)); the probe
  section no longer claims the opposite.
- README recap table restructured (target | current NextGraph status | current
  emulation); INDEX_ACCOUNT documented as reservedAccount("index") in the
  sentinel namespace; de-domained generic-layer comments; softened tone.

Consumer application (Festipod) rewired separately to own the relationship
concept and feed the lib an id. Lib gates: bun test 83 pass / 0 fail, tsc clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 14:02:16 +02:00

3.9 KiB

ADR — Shared-wallet identity flow (perceived login)

Date: 2026-06-15 · Status: Accepted (frozen). The rationale behind how the consumer application presents identity selection as a perceived login, and why the lib's identity store (accounts.ts) must never touch NextGraph. The lib itself no longer frames this as a login: it receives an identity id, set at wallet-import time; the perceived-login UX lives entirely in the consumer application.

Starting constraint

NextGraph login is not programmable: it is a web redirect to the broker page (nextgraph.net). The shared wallet cannot be opened silently — at least one broker-redirect pass is required per device. The question is therefore not "how to avoid the redirect" but "how to order and present it" so the UX stays coherent.

Decision — technical gate first, application "Connexion" second

Two distinct layers, presented in this order:

  1. Real layer (technical, not perceived as login). The broker redirect appears immediately, before any app render. Because it precedes the app, the user reads it as a technical access barrier to the test environment (a beta wall), not an application login. Same shared credentials for everyone (given in the invitation, "access code" style). Once per device, then persistent. It is not labelled "login."
  2. Application layer (perceived as the login). A "Connexion" screen where the user picks an identity id (relayed to the lib's identity store, persisted in localStorage, the current principal). This is the login in the user's perception, presented by the consumer application. No password — declarative selection (anyone takes any id — coherent with zero-security / friends). In practice the id is often a human-friendly handle. "Déconnexion" clears only the stored id and returns to "Connexion"; it calls no NG function.

The real logout (ng.session_stop / user_disconnect / wallet_close) stays hidden (settings/debug), because it forces a new redirect.

Why (vs the rejected option)

Rejected — a perceived login first, then a warning page "enter this id/password", then a Continue button triggering the redirect. Rejected: strange workflow, dissonant double-login, a warning page that looks like a scam, and the redirect resurfacing mid-use on every session expiry.

Chosen because: the mental model stays coherent (the technical barrier not being perceived as login, the app-level Connexion/Déconnexion pair is complete and self-consistent); graceful degradation (a re-gate after a browser restart reads as "reconnecting to the environment", not a bug); and similarity to the target infra — the "broker redirect → app" shape is exactly the real multi-wallet flow. At migration you remove the id "Connexion" screen and the technical barrier becomes the real per-user login — the flow shape does not change.

Verified technical facts (nextgraph-rs, 2026-06-15)

  • Session persistence: yes. Wallet remembered iframe-side (localStorage long-term + sessionStorage for the active session); on reload init() recovers the session without re-triggering the redirect while the broker session exists (sdk/js/web/src/index.ts, sdk/js/api-web/main.ts). A full browser restart (losing sessionStorage) can re-trigger the gate.
  • Real logout exposed: yes. ng.session_stop(), ng.user_disconnect(), ng.wallet_close() (sdk/js/lib-wasm/src/lib.rs); they stop the session / clear the wallet and force a new redirect afterwards — hence the app-level "Déconnexion" does not call them, and the real logout stays hidden.

How this lib realizes it

accounts.ts is an IdentityStore: set(id) / clear() / get() only read/write the identity id in an injected AccountStorage; they never call NG. The id is set at wallet-import time and relayed via the lib's current-identity call; the perceived login is the consumer application's. See the identity store in ../simulation.md.