Fix NextGraph write persistence: use private_store_id as useShape scope

Writes (doc_create, orm_frontend_update) failed with RepoNotFound because
useShape with did:ng:i scope doesn't open individual repos in the verifier's
cache. Switched to did🆖${session.private_store_id} as both scope and
@graph, matching the expense-tracker-rdf pattern. This opens the private
store repo via orm_start_graph, making it available for subsequent writes.

Also adds wallet login step to ensureAuth so the verifier bootstraps repos
from the remote broker into localStorage on first run.

Key changes:
- useShapeWithDefaults accepts storeNuri param (private store NURI)
- FestipodDataContext.useNgData() passes private store scope
- ensureGraphNuri() simplified: reuse existing @graph or private_store_id
- ngBootstrap uses ensureGraphNuri + flushAndWait between ORM adds
- harness-ng.tsx uses private store scope for test bridge shapes
- hooks.ts: wallet creation logs in to bootstrap verifier repos
- E2e steps for data loading and persistence verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-03-17 11:50:45 +01:00
parent 708cbeead8
commit ea8fbcf8b7
15 changed files with 590 additions and 95 deletions
+9 -6
View File
@@ -21,6 +21,7 @@ import {
import type { FpEvent, FpUserProfile, FpParticipation } from '../shapes/orm/festipodShapes.typings';
import { seedEvents, seedUsers, seedParticipations } from '../data/seedData';
import { bootstrapWallet } from '../utils/ngBootstrap';
import { ensureGraphNuri } from '../utils/ngGraph';
// ============================================================================
// App — uses real providers (same tree as the real app)
@@ -59,10 +60,11 @@ function ConnectedHarness() {
const ngCtx = useNextGraph();
const appData = useFestipodData();
// Raw DeepSignalSets for direct manipulation in tests
const events = useShape(FpEventShapeType, 'did:ng:i') as DeepSignalSet<FpEvent>;
const users = useShape(FpUserProfileShapeType, 'did:ng:i') as DeepSignalSet<FpUserProfile>;
const participations = useShape(FpParticipationShapeType, 'did:ng:i') as DeepSignalSet<FpParticipation>;
// Use private store NURI as scope (opens the repo for reads AND writes)
const privateNuri = ngCtx.session && `did:ng:${ngCtx.session.private_store_id}`;
const events = useShape(FpEventShapeType, privateNuri) as DeepSignalSet<FpEvent>;
const users = useShape(FpUserProfileShapeType, privateNuri) as DeepSignalSet<FpUserProfile>;
const participations = useShape(FpParticipationShapeType, privateNuri) as DeepSignalSet<FpParticipation>;
const [bridgeReady, setBridgeReady] = useState(false);
@@ -108,11 +110,12 @@ function ConnectedHarness() {
},
// --- Mutations (direct ngSet access) ---
joinEvent(eventId: string, userId: string) {
async joinEvent(eventId: string, userId: string) {
const already = [...participations].some(p => p.event === eventId && p.user === userId);
if (already) return;
const graph = await ensureGraphNuri(events as any, users as any, participations as any);
participations.add({
'@graph': `did:ng:${session.private_store_id}`,
'@graph': graph,
'@type': 'http://festipod.org/Participation',
'@id': '',
event: eventId,