Backend-First State Audit
Audit of each tool's persistence model and plan to wire all tools to backend APIs
Backend-First State Audit - Session 136
Audit Results
Already Backend-First (Good)
| Tool | Service | Backend Endpoint | Notes |
|---|---|---|---|
| vibe-universe | PageContentGeneratorService |
POST /api/spaces/:spaceId/pages |
Saves generated pages to backend |
| modularity-lib | ModuleSyncService |
/api/spaces/:spaceId/modules |
Syncs modules to backend |
| modularity-lib | ModuleExportApiService |
/api/spaces/:spaceId/modules/export |
Exports to backend |
| page-builder | PageSaveService |
${API_BASE_URL}/pages/:pageId |
Saves pages to backend |
| page-builder | PageDeploymentService |
/api/deployment/:tenantId/deploy-bundle |
Deploys to backend |
Local-Only (Need Backend Wiring)
| Tool | Service | Current Storage | Target Backend Endpoint |
|---|---|---|---|
| modularity-lib | ModuleStorageService |
autoFlashState (IndexedDB) |
/api/spaces/:spaceId/modules |
| universe-canvas | PlatformStateService |
autoFlashState (IndexedDB) |
/api/spaces/:spaceId/universes/:universeId |
| universe-canvas | PlatformDeploymentService |
GgStorage |
/api/universes/:id/publish |
| universe-canvas | CanvasStateService |
GgStorage |
/api/spaces/:spaceId/universes/:universeId (structure) |
| universe-explorer | ArchitectStateService |
createFlashState |
/api/spaces/:spaceId/universes/:universeId (structure) |
| modular-universe | ModuleInstallationService |
GgStorage |
/api/spaces/:spaceId/modules |
| flow-engine-lib | BackendFlowClientService |
GgStorage + partial sync |
/api/spaces/:spaceId/universes/:universeId/data/* |
Pattern to Follow
Each local-only tool should implement the Session 129 pattern:
@Injectable({ providedIn: 'root' })
export class ExampleApiService {
private readonly http = inject(HttpClient);
private readonly apiBaseUrl = inject(API_BASE_URL);
// Backend data in a SEPARATE signal (not autoFlashState)
private readonly _backendData = signal<MyData | null>(null);
// Local state can still use autoFlashState for offline/optimistic UI
private readonly _localState = autoFlashState<MyData>('example-key', defaultValue);
// Merged view: backend takes priority
readonly data = computed(() => {
const backend = this._backendData();
const local = this._localState();
return backend ?? local;
});
loadFromBackend(): Observable<MyData> {
return this.http.get<MyData>(`${this.apiBaseUrl}/endpoint`).pipe(
tap(data => this._backendData.set(data))
);
}
saveToBackend(data: MyData): Observable<MyData> {
return this.http.put<MyData>(`${this.apiBaseUrl}/endpoint`, data).pipe(
tap(saved => {
this._backendData.set(saved);
this._localState.set(saved); // Keep local in sync
})
);
}
}
Priority Order for Wiring
- flow-engine-lib - Model citizen (Phase 2 already started this)
- universe-canvas - Most impactful (canvas state = platform structure)
- universe-explorer - Architect state maps to universe structure
- modularity-lib
ModuleStorageService- Module context should persist - modular-universe - Module installation data
Existing Backend Endpoints Available
All needed endpoints already exist in backend-api:
| Endpoint | Supports |
|---|---|
/api/spaces/:id/universes (CRUD) |
Universe structure |
/api/spaces/:id/universes/:id/galaxies (CRUD) |
Galaxy management |
/api/spaces/:id/modules (CRUD + batch) |
Module persistence |
/api/spaces/:id/space-pages (CRUD) |
Page persistence |
/api/spaces/:id/widgets (CRUD) |
Widget persistence |
/api/spaces/:id/universes/:id/data/* (dynamic CRUD) |
Flow engine data |
/api/spaces/:id/universes/:id/data/schemas (CRUD) |
Entity schemas |
/api/universes/:id/publish |
Deployment |
/api/modules/unified/all |
Module discovery |
No new backend endpoints are needed. The gap is purely on the frontend: services need to be updated to call these endpoints instead of (or in addition to) local storage.