PAGE PERSISTENCE FLOW
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
📄 Page Persistence Flow - Complete Guide
Date: November 5, 2025
Status: ✅ Documented & Fixed
Purpose: Explain where and how pages are persisted when created in the Editor
🎯 The Complete Flow
When You Navigate to /editor (Blank Canvas):
1. User navigates to: /space/{space}/editor
↓
2. EditorWorkspaceComponent loads
↓
3. No pageId in route → context = 'blank-canvas'
↓
4. User adds widgets to canvas
↓
5. EditorService.setWidgets() called
↓
6. ❓ No page exists → Creates temporary page
↓
7. Page is stored in TWO places:
✅ EditorService.editorState.page (Flash Persistence)
✅ PagesStateService.pages[] (Flash Persistence)
↓
8. Widgets stored in:
✅ EditorService.editorState.widgetsByPage[pageId] (Flash Persistence)
📦 Where Pages Are Persisted
1. EditorService Flash State (autoFlashState('editor-state'))
Storage Key: editor-state
Location: GgStorage (IndexedDB → Online Sync)
What's Stored:
{
page: Page | null, // Current active page metadata
widgetsByPage: { // Widgets organized by page ID
[pageId: string]: Widget[]
},
// ... other editor state
}
Persistence: ✅ Automatic via Flash Persistence
Reload: ✅ Yes, persists across sessions
2. PagesStateService Flash State (autoFlashState('pages-state'))
Storage Key: pages-state
Location: GgStorage (IndexedDB → Online Sync)
What's Stored:
{
pages: Page[], // All pages (metadata only)
activePage: Page | null, // Currently active page
draftPages: Page[], // Draft pages
publishedPages: Page[], // Published pages
archivedPages: Page[] // Archived pages
}
Persistence: ✅ Automatic via Flash Persistence
Reload: ✅ Yes, persists across sessions
Purpose: Page discovery, page selector, page management
🔄 The Complete Persistence Chain
When Creating a New Page:
// 1. User adds widget → EditorService.setWidgets()
if (!currentPageId && widgets.length > 0) {
// 2. Create temporary page
const tempPage: Page = {
id: `page-${Date.now()}-${random}`,
title: 'New Page',
widgets: [],
// ... full page structure
};
// 3. Set in EditorService (stores page metadata)
this.setPage(tempPage);
// 4. Register in PagesStateService (makes it discoverable)
this.pagesStateService.addPageIfNotExists(tempPage);
// 5. Store widgets (page-scoped)
widgetsByPage[tempPage.id] = widgets;
}
When Updating Widget Properties:
// 1. User changes widget name → onPropertyChange()
editorService.updateWidget(updatedWidget);
// 2. updateWidget() updates BOTH:
this.editorState.update(state => ({
widgets: [...], // Legacy array
widgetsByPage: { // Page-scoped storage
[pageId]: [updatedWidget, ...] // ✅ Updated here!
}
}));
// 3. Flash Persistence automatically saves to GgStorage
// 4. Changes persist across reloads
🗄️ Storage Architecture
Dual Storage System:
| Component | Storage Key | Purpose | Contains |
|---|---|---|---|
| EditorService | editor-state |
Editor UI state | Active page, widgets by page, selection, undo/redo |
| PagesStateService | pages-state |
Page registry | All pages metadata, active page, page lists |
Why Two Storages?
- EditorService = Editor-specific state (selection, clipboard, zoom, etc.)
- PagesStateService = Page registry (discoverable pages, page management)
Both use Flash Persistence → Automatic save/load, offline sync, online sync
🔍 How to Verify Persistence
Check EditorService State:
// In browser console:
const editorState = await storage.get('editor-state');
console.log('Current page:', editorState.page);
console.log('Widgets by page:', editorState.widgetsByPage);
Check PagesStateService State:
// In browser console:
const pagesState = await storage.get('pages-state');
console.log('All pages:', pagesState.pages);
console.log('Active page:', pagesState.activePage);
Check GgStorage:
// In browser console:
const storage = window.ggStorage; // If exposed
const keys = await storage.list();
console.log('All storage keys:', keys);
✅ What Was Fixed
Before (Broken):
- ✅ Page created in
EditorService.editorState.page - ✅ Widgets stored in
widgetsByPage[pageId] - ❌ Page NOT registered in
PagesStateService - ❌ Page not discoverable
- ❌ Page selector won't show it
After (Fixed):
- ✅ Page created in
EditorService.editorState.page - ✅ Widgets stored in
widgetsByPage[pageId] - ✅ Page registered in
PagesStateService.pages[] - ✅ Page discoverable
- ✅ Page selector shows it
- ✅ Widget updates persist correctly
📍 Route: /space/{space}/editor
When you're at this route:
No pageId → Blank canvas mode
First widget added → Temporary page created
Page saved to:
editor-state(EditorService) → Page metadata + widgetspages-state(PagesStateService) → Page registry
On reload:
- PagesStateService loads all pages from
pages-state - EditorService loads editor state from
editor-state - If page exists, widgets load automatically
- PagesStateService loads all pages from
🎯 Summary
Where is it persisting?
- ✅ EditorService Flash State (
editor-state) → Page metadata + widgets by page - ✅ PagesStateService Flash State (
pages-state) → Page registry
How does it work?
- Flash Persistence automatically saves to GgStorage
- GgStorage persists to IndexedDB (offline)
- GgStorage syncs to online storage (when available)
Why two storages?
- EditorService = Editor UI state (temporary, editor-specific)
- PagesStateService = Page registry (permanent, discoverable)
Everything works now! ✅