0b37d17c2f
Les deux contrats et la doctrine portent des centaines de citations `file:line` vers `src/`. Le rangement par destin les périmait en bloc — 208 reprises (45 chemins `src/x.ts`, 163 mentions nues). Sans ça la réorganisation pourrissait l'instrument même qui tient la discipline qu'elle sert. Et un défaut relevé par le contrat interne, vérifié : `ng-proxy` fabriquait un membre `login`. `@ng-org/web` n'expose aucune méthode de ce nom — zéro occurrence dans les déclarations installées comme dans `sdk/js/lib-wasm/src/lib.rs` — mais le proxy répondait une fonction au lieu d'`undefined`, laquelle plantait à l'appel. C'était le seul endroit où ce wrapper ajoutait à la surface du SDK, contre son propre en-tête. 157 tests unitaires, typecheck src/test/e2e vert.
71 lines
4.0 KiB
Markdown
71 lines
4.0 KiB
Markdown
# 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 (`shared-wallet/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
|
|
|
|
`shared-wallet/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`](../simulation.md).
|