Plan to Sync Update All Tools
Comprehensive plan to sync and modernize all 15 platform builder tools with proven patterns
Comprehensive Plan to Sync & Update All Platform Builder Tools
Session: 27.1 - Universe Architect Interactive Evolution Status: Planning Phase Complete, Ready for Implementation Confidence: 98% (Based on proven Singularity + Canvas Builder patterns)
🎯 Executive Summary
Current State
15 Platform Builder Tools Identified:
- ✅ Production Ready (5 tools): Universe Canvas (100%), Modularity Lib (100%), Modular Universe (100%), Vibe Universe (100% - Orchestration Hub), Editor-Web Lib (95%)
- 🔄 Functional but Needs Modernization (3 tools): Universe Architect (95%), Singularity Lib (95%), Space-Map Lib (95%)
- 📋 Partially Complete (7 tools): Page Builder (50%), Universe Map, Module Browser, Platform Shell, Deployment System, Launch Station, Structure Management
Critical Gaps Identified
- Universe Architect: No drag-drop, no connections, artificial "Universe Core" not in database
- Space-Map: Using deprecated NGXS patterns, dual storage services, not using Flash Persistence
- Integration Issues: Double persistence, missing context (universeId/pageId), real-time sync race conditions
- Architecture Mismatch: Incomplete flat architecture migration, global window registry pattern
Proven Patterns Available
From Singularity (85% complete, production-ready):
- Custom drag-drop with global mouse handlers
- Node connection system with type-safe ports
- Bezier curve SVG paths
- Real-time connection updates during drag
- Throttled persistence (300ms)
From Canvas Builder (100% complete):
- Recursive component pattern with
forwardRef() - Flat structure (no artificial root)
- Event pass-through without modification
- Template-based layouts
From Vibe Coding (100% complete):
- ToolOrchestrationService for seamless handoffs
- Natural language generation
- ModuleHandoff interface
- Intent recognition and entity extraction
Success Criteria
- ✅ All tools use Flash Persistence (eliminate NGXS)
- ✅ Unified drag-drop system across all visual tools
- ✅ ToolOrchestrationService integration for seamless handoffs
- ✅ Complete vibe coding integration
- ✅ 100% test coverage with E2E tests
- ✅ Sub-100ms performance for all interactions
📊 Platform Builder Tool Catalog
Active Production Tools (5)
| Tool | Status | Completion | Key Features |
|---|---|---|---|
| Universe Canvas | ✅ Active | 100% | Visual builder, module placement, real-time preview, deployment |
| Modularity Lib | ✅ Active | 100% | 6-step module builder, AI generation, action flows |
| Modular Universe | ✅ Active | 100% | Flexbox/Grid layouts, drag-drop, responsive config |
| Vibe Universe | ✅ Active | 100% | AI generation, ToolOrchestrationService, handoff coordination |
| Editor-Web Lib | ✅ Active | 95% | Page editor, widget palette, Singularity integration |
Tools Needing Modernization (3)
| Tool | Status | Completion | Issues |
|---|---|---|---|
| Universe Architect | 🔄 Active | 95% | Missing drag-drop, connections, vibe integration |
| Singularity Lib | 🔄 Active | 95% | Proven patterns but needs route fixes |
| Space-Map Lib | 🔄 Active | 95% | NGXS deprecation, dual storage, performance |
Tools Needing Completion (7)
| Tool | Status | Completion | Priority |
|---|---|---|---|
| Page Builder | 📋 Partial | 50% | High - Core workflow tool |
| Universe Map | 📋 Active | 50-70% | Medium - Visualization |
| Module Browser | 📋 Active | Active | Medium - Discovery |
| Platform Shell | 📋 Active | Active | Medium - Container |
| Deployment System | 📋 Active | Active | Medium - Deployment |
| Launch Station | 📋 Active | Active | Medium - Launch UI |
| Structure Management | 📋 Active | Active | Low - Validation |
🏗️ PHASE 1: Universe Architect Enhancement
Goal: Transform from static visualization to fully interactive tool Priority: HIGHEST (Foundation for all other tools) Effort: 40-50 hours Dependencies: None (can start immediately)
1.1 Remove Artificial Universe Core (6 hours)
Problem: Universe Core node doesn't exist in database, creating data sync issues
Tasks:
Remove artificial root node creation (2h)
- File:
libs/libs-space/universe-architect/src/lib/components/architect-canvas/architect-canvas.component.ts - Action: Lines 876-911 - Remove
onAddUniverseCore()andonAddFirstModule()methods - Update: Empty state to show "Import Universe" button instead of "Add Universe Core"
- File:
Update module converter for flat structure (2h)
- File:
libs/libs-space/universe-architect/src/lib/services/architect-module-converter.service.ts - Action: Remove root node injection in
modulesToNodes()method - Pattern: Use actual database modules as root nodes (no wrapping)
- Reference: Canvas Builder doesn't create artificial "Canvas Core" - same pattern
- File:
Fix data loading from backend (2h)
- File: Lines 270-400 in
architect-canvas.component.ts - Action: Remove
structureNodeToModule()temporary client-side hydration - Implement: Proper backend API call to
/api/universes/:id/hydrate - Backend Task: Create hydration endpoint (coordinate with backend team)
- File: Lines 270-400 in
Success Criteria:
- ✅ No artificial "Universe Core" node appears in UI
- ✅ All nodes come from real MongoDB
universe.structure[]data - ✅ Empty state shows proper import/create flow
- ✅ 1:1 mapping between database and visual representation
1.2 Implement Singularity Drag-Drop Pattern (16 hours)
Problem: Nodes are completely static, cannot be moved or organized
Proven Solution: Copy exact pattern from Singularity's flow-composer
Tasks:
Create global mouse handler service (4h)
- New File:
libs/libs-space/universe-architect/src/lib/services/architect-drag-handler.service.ts - Copy Pattern From:
libs/libs-structural/singularity-lib/src/lib/components/flow-composer/flow-composer.component.ts(lines 245-280) - Implement:
@Injectable({ providedIn: 'root' }) export class ArchitectDragHandlerService { isDraggingNode = signal(false); draggedNodeId = signal<string | null>(null); dragOffset = signal({ x: 0, y: 0 }); onNodeDragStart(node: CosmicNode, event: MouseEvent): void { const rect = event.currentTarget.getBoundingClientRect(); this.dragOffset.set({ x: event.clientX - node.position.x, y: event.clientY - node.position.y }); this.isDraggingNode.set(true); this.draggedNodeId.set(node.id); } onNodeDrag(event: MouseEvent): void { if (!this.isDraggingNode()) return; const newPosition = { x: event.clientX - this.dragOffset().x, y: event.clientY - this.dragOffset().y }; // Update position immediately for smooth UX this.architectState.updateNodePosition(this.draggedNodeId()!, newPosition); // Update connections in real-time requestAnimationFrame(() => this.updateConnectionPaths()); } onNodeDragEnd(): void { // Throttled persistence (300ms like Singularity) this.throttledPersist(); this.isDraggingNode.set(false); this.draggedNodeId.set(null); } }
- New File:
Add drag handles to cosmic nodes (4h)
- File:
libs/libs-space/universe-architect/src/lib/components/cosmic-nodes/base-cosmic-node.component.ts - Add: Drag handle element with
(mousedown)listener - Template:
<div class="drag-handle" (mousedown)="onDragStart($event)" [class.dragging]="isDragging()"> <i class="fas fa-grip-vertical"></i> </div> - Emit: Drag events to parent canvas
- Visual Feedback: During drag - opacity 0.7, box-shadow increase, cursor 'grabbing'
- File:
Implement throttled persistence (4h)
- File:
libs/libs-space/universe-architect/src/lib/services/architect-state.service.ts - Add: Debounced save (300ms throttle like Singularity)
- Use: RxJS
throttleTimeoperator on position updates - Batch: Multiple node moves into single backend save
- Pattern:
private throttledPersist = throttle((nodeId: string, position: Position) => { this.backendApi.updateNodePosition(nodeId, position).subscribe(); }, 300);
- File:
Add snap-to-grid (4h)
- File:
architect-canvas.component.ts - Add: Grid configuration to ArchitectState (gridSize: 20px default)
- Implement: Grid snapping during drag (round position to nearest grid point)
- UI: Add toggle for snap-to-grid in canvas controls toolbar
- Persist: Save grid preference to user settings
- File:
Files to Modify:
libs/libs-space/universe-architect/src/lib/components/architect-canvas/architect-canvas.component.tslibs/libs-space/universe-architect/src/lib/services/architect-state.service.tslibs/libs-space/universe-architect/src/lib/components/cosmic-nodes/base-cosmic-node.component.ts
Success Criteria:
- ✅ Nodes draggable with smooth, sub-100ms response
- ✅ Position persists to backend automatically
- ✅ Grid snapping works when enabled
- ✅ Multi-node drag works (select multiple, drag together)
- ✅ Undo/redo for position changes
1.3 Add Node Connection System (12 hours)
Problem: No way to visually connect related nodes
Proven Solution: Singularity's Bezier curve connection system
Tasks:
Create connection ports on nodes (3h)
- File:
base-cosmic-node.component.tstemplate - Add: Output port (right side) and input port (left side) to each node
- Port Types:
- Universe Core: Output only (connects to Galaxies)
- Galaxy: Input + Output (receives from Core, connects to Worlds)
- World: Input + Output (receives from Galaxy, connects to Pages)
- Page: Input only (leaf node)
- Hover Detection: Glow effect on hover, connection-ready indicator
- Template:
<div class="node-ports"> @if (node.type !== 'page') { <div class="port output" (click)="onPortClick($event, 'output')" [class.can-connect]="connectionState.isConnecting"> </div> } @if (node.type !== 'universe-core') { <div class="port input" (click)="onPortClick($event, 'input')" [class.can-connect]="canConnectToThisPort()"> </div> } </div>
- File:
Implement connection drawing (4h)
- File:
architect-canvas.component.ts - Add: SVG overlay layer for connections (lines 806-826 already started)
- Bezier Curve Calculation (copy from Singularity):
calculateConnectionPath(source: Position, target: Position): string { const dx = target.x - source.x; const distance = Math.sqrt(dx * dx + (target.y - source.y) ** 2); const controlOffset = Math.min(distance * 0.4, 150); return `M${source.x},${source.y} C${source.x + controlOffset},${source.y} ${target.x - controlOffset},${target.y} ${target.x},${target.y}`; } - Real-time Preview: Animated dashed line following mouse during connection drag
- SVG Template:
<svg class="connections-layer"> @for (connection of connections(); track connection.id) { <path [attr.d]="connection.path" stroke="#7c4dff" stroke-width="3" fill="none" [class.animated]="connection.animated"> </path> } @if (connectionPreview.isVisible) { <path [attr.d]="connectionPreviewPath" stroke="#fbbf24" stroke-width="3" stroke-dasharray="8,4" fill="none"> <animate attributeName="stroke-dashoffset" values="0;12;0" dur="1.5s" repeatCount="indefinite"/> </path> } </svg>
- File:
Connection validation (3h)
- New File:
libs/libs-space/universe-architect/src/lib/services/connection-validator.service.ts - Validation Rules:
- Universe Core → Galaxy only
- Galaxy → World or Page
- World → Page only
- Page → Nothing (leaf nodes)
- Prevent cycles (no circular connections)
- Prevent duplicate connections
- Type-Safe Validation:
@Injectable({ providedIn: 'root' }) export class ConnectionValidatorService { canConnect(sourceType: CosmicNodeType, targetType: CosmicNodeType): boolean { const validConnections: Record<CosmicNodeType, CosmicNodeType[]> = { 'universe-core': ['galaxy'], 'galaxy': ['world', 'page'], 'world': ['page'], 'page': [] }; return validConnections[sourceType]?.includes(targetType) ?? false; } detectCycle(sourceId: string, targetId: string, connections: Connection[]): boolean { // Graph traversal to detect cycles } }
- New File:
Connection persistence (2h)
- File:
architect-state.service.ts - Add Methods:
addConnection(),removeConnection(),updateConnection() - Backend Sync: Save connections to MongoDB
- Load on Init: Fetch connections when loading universe
- Delete UI: Click connection to select, Delete key to remove
- File:
Files to Create:
libs/libs-space/universe-architect/src/lib/services/connection-validator.service.ts
Files to Modify:
libs/libs-space/universe-architect/src/lib/components/architect-canvas/architect-canvas.component.tslibs/libs-space/universe-architect/src/lib/components/cosmic-nodes/base-cosmic-node.component.tslibs/libs-space/universe-architect/src/lib/services/architect-state.service.ts
Success Criteria:
- ✅ Connections drawn as smooth Bezier curves
- ✅ Connection validation prevents invalid links
- ✅ Connections persist to backend automatically
- ✅ Click connection to select, Delete key to remove
- ✅ Connections update in real-time when nodes drag
- ✅ Animated preview during connection creation
1.4 Integrate Vibe Coding Toolbar (6 hours)
Problem: No AI-powered module generation directly in Universe Architect
Proven Solution: Vibe Universe's ToolOrchestrationService handoff pattern
Tasks:
Add vibe coding button to toolbar (2h)
- File:
libs/libs-space/universe-architect/src/lib/components/canvas-controls/canvas-controls.component.ts - Add: "✨ Generate with AI" button to toolbar
- Click Handler: Navigate to Vibe Universe with current universe context
- Template:
<button class="vibe-coding-btn" (click)="openVibeGenerator()" matTooltip="Generate modules with AI"> <i class="fas fa-magic"></i> Generate with AI </button>
- File:
Implement module handoff receiver (2h)
- File:
architect-canvas.component.ts - Inject:
ToolOrchestrationServicefrom@libs-structural/vibe-universe - Listen: For pending handoffs on component init
- Copy Pattern From:
libs/libs-structural/vibe-universe/src/lib/services/tool-orchestration.service.ts(lines 295-317) - Implementation:
ngOnInit(): void { // Check for pending module handoffs const handoff = this.toolOrchestration.getPendingHandoff(); if (handoff && handoff.targetTool === 'universe-architect') { this.receiveModuleHandoff(handoff); } } private receiveModuleHandoff(handoff: ModuleHandoff): void { const cosmicNodes = handoff.modules.map(module => this.convertModuleToNode(module) ); this.architectState.addNodes(cosmicNodes); this.toolOrchestration.completeHandoff(handoff.id); // Show success toast this.toastService.success(`Added ${cosmicNodes.length} AI-generated modules`); }
- File:
Create nodes from AI modules (2h)
- Convert:
ModuleReference→CosmicNode - Auto-Layout: Position new nodes intelligently (avoid overlaps)
- Save: Persist to backend immediately
- Navigate: Return to Universe Architect with new nodes visible
- Visual Feedback: Highlight newly added nodes with glow animation
- Convert:
Files to Modify:
libs/libs-space/universe-architect/src/lib/components/architect-canvas/architect-canvas.component.tslibs/libs-space/universe-architect/src/lib/components/canvas-controls/canvas-controls.component.ts
Success Criteria:
- ✅ "Generate with AI" button opens Vibe Universe
- ✅ AI-generated modules appear as cosmic nodes
- ✅ Handoff completes successfully with toast notification
- ✅ Data persists to backend
- ✅ New nodes auto-positioned to avoid overlaps
🔄 PHASE 2: Space-Map Modernization
Goal: Migrate Space-Map from deprecated NGXS to modern Signals + Flash Persistence Priority: HIGH (Foundational infrastructure tool) Effort: 35-45 hours Dependencies: Can run in parallel with Phase 1
2.1 Migrate from NGXS to Signals (16 hours)
Problem: Space-Map uses deprecated NGXS state management pattern
Current State:
- File:
libs/libs-structural/space-map-lib/src/lib/state/space-map.state.ts - Issue: Uses
autoFlashState()(line 132) but still has NGXS-style action dispatching - Goal: Pure signal-based state like modern tools
Tasks:
Remove NGXS actions (4h)
- Delete File:
libs/libs-structural/space-map-lib/src/lib/state/space-map.actions.ts - Find & Replace: All
dispatch(new SpaceMapAction())calls - Replace With: Direct signal updates
state.update(s => ({ ...s, ...changes })) - Files Affected: All components in
libs/libs-structural/space-map-lib/src/lib/components/
- Delete File:
Convert to pure Signal state (6h)
- File:
space-map.state.ts - Remove: All NGXS decorators (
@State,@Action,@Selector) - Convert: Class to pure signal-based service
- Keep:
autoFlashState()for persistence (already correct pattern) - Pattern:
@Injectable({ providedIn: 'root' }) export class SpaceMapState { // Replace NGXS state with signals private readonly state = autoFlashState<SpaceMapStateModel>('space-map-state', { universes: [], selectedUniverse: null, viewMode: 'tree', // ... }); // Computed signals for derived state readonly universes = computed(() => this.state().universes); readonly selectedUniverse = computed(() => this.state().selectedUniverse); // Methods replace NGXS actions addUniverse(universe: Universe): void { this.state.update(s => ({ ...s, universes: [...s.universes, universe] })); } }
- File:
Update component imports (4h)
- Find: All components using
@Select()decorator - Replace: With
computed()signals - Before:
@Select(SpaceMapState.universes) universes$: Observable<Universe[]>; - After:
readonly universes = this.spaceMapState.universes; - Update Templates: Remove
| asyncpipe (signals are synchronous)
- Find: All components using
Remove NGXS dependencies (2h)
- File:
package.json - Remove:
@ngxs/store,@ngxs/logger-plugin,@ngxs/devtools-plugin - File:
tsconfig.base.json - Remove: NGXS path mappings
- Run:
npm installto update lock file
- File:
Success Criteria:
- ✅ Zero NGXS dependencies
- ✅ All state is signal-based
- ✅ Flash Persistence continues working
- ✅ No performance regression (signals are faster than NGXS)
- ✅ All tests pass
2.2 Replace Dual Storage with Flash Persistence (8 hours)
Problem: Space-Map has dual storage causing race conditions
Current Issues:
SpaceMapStorageServicehandles backend syncautoFlashState()handles local persistence- Two save paths = race conditions and data drift
Tasks:
Audit storage service (2h)
- File:
libs/libs-structural/space-map-lib/src/lib/services/space-map-storage.service.ts - Document: What it does beyond Flash Persistence
- Identify: Unique responsibilities that must be kept
- Result: Create migration checklist
- File:
Consolidate to Flash Persistence (4h)
- Keep: Backend sync logic only in storage service
- Move: All local state management to Flash Persistence
- Implement: Sync policy (immediate for critical, debounced for non-critical)
- Pattern: Use Flash Persistence's built-in HTTP sync adapter
- Configuration:
const state = autoFlashState('space-map', defaultState, { sync: { enabled: true, endpoint: '/api/space-map/sync', strategy: 'debounce', debounceMs: 300 } });
Remove redundant code (2h)
- Delete: Duplicate persistence logic in SpaceMapStorageService
- Update: All save calls to use Flash Persistence only
- Clean: Unused imports and methods
- Test: Verify no functionality lost
Success Criteria:
- ✅ Single source of truth (Flash Persistence)
- ✅ Backend sync works reliably
- ✅ No duplicate saves
- ✅ Performance improved (70-85% like theme system migration)
- ✅ Zero data loss during migration
2.3 Implement Recursive Visualization (6 hours)
Problem: Space-Map doesn't show nested structure recursively like Canvas Builder
Tasks:
Create recursive tree component (4h)
- New File:
libs/libs-structural/space-map-lib/src/lib/components/recursive-tree-view/recursive-tree-view.component.ts - Pattern: Use
forwardRef()like Canvas Builder's CanvasSectionComponent - Template:
@Component({ selector: 'lib-recursive-tree-view', imports: [ CommonModule, forwardRef(() => RecursiveTreeViewComponent) // Self-reference! ] }) export class RecursiveTreeViewComponent { @Input() node!: UniverseNode; @Input() depth = 0; expanded = signal(true); } - Template:
<div class="tree-node" [style.padding-left.px]="depth * 20"> <div class="node-header" (click)="expanded.set(!expanded())"> <i [class]="expanded() ? 'fa-chevron-down' : 'fa-chevron-right'"></i> {{ node.name }} </div> @if (expanded() && node.children) { @for (child of node.children; track child.id) { <lib-recursive-tree-view [node]="child" [depth]="depth + 1" /> } } </div>
- New File:
Add to main visualization (2h)
- File:
space-map.component.ts - Add: Toggle between flat list and tree view
- Persist: View preference to user settings
- UI: View switcher in toolbar
- File:
Success Criteria:
- ✅ Tree view shows full Universe → Galaxy → World → Page hierarchy
- ✅ Nodes expand/collapse smoothly
- ✅ Performance acceptable for 1000+ nodes (virtual scrolling if needed)
- ✅ View preference persists
2.4 Add Drag-Drop to Space-Map (8 hours)
Problem: Cannot drag nodes to reorganize hierarchy
Tasks:
Implement node dragging to change parent (4h)
- Use: Same ArchitectDragHandlerService pattern
- Drag: Node to different parent to change parentId
- Visual: Drop zone highlights when hovering
- Validation: Prevent invalid parent-child relationships
Implement sibling reordering (4h)
- Drag: Within same parent to change order
- Update:
orderfield in database - Auto-save: On drop with throttled persistence
- Visual: Insertion line showing drop position
Success Criteria:
- ✅ Nodes draggable to reorganize hierarchy
- ✅ Visual feedback during drag
- ✅ Changes persist to backend
- ✅ Undo/redo support
2.5 Sync with Universe Architect (7 hours)
Problem: Space-Map and Universe Architect show same data but don't sync
Tasks:
Create shared data service (3h)
- New File:
libs/libs-space/shared/src/lib/services/universe-data.service.ts - Purpose: Unified API for both Space-Map and Universe Architect
- Pattern: Single source of truth with reactive signals
- Implementation:
@Injectable({ providedIn: 'root' }) export class UniverseDataService { private readonly state = autoFlashState<UniverseData>('universe-data', { universes: [], nodes: [], connections: [] }); readonly universes = computed(() => this.state().universes); readonly nodes = computed(() => this.state().nodes); readonly connections = computed(() => this.state().connections); updateNode(nodeId: string, updates: Partial<CosmicNode>): void { this.state.update(s => ({ ...s, nodes: s.nodes.map(n => n.id === nodeId ? { ...n, ...updates } : n) })); } }
- New File:
Update Universe Architect to use shared service (2h)
- File:
architect-canvas.component.ts - Replace: Direct API calls with shared data service
- Subscribe: To reactive updates from shared service
- File:
Update Space-Map to use shared service (2h)
- File:
space-map.component.ts - Replace: SpaceMapStorageService with shared service
- Subscribe: To reactive updates
- File:
Success Criteria:
- ✅ Both tools show identical data
- ✅ Changes in one tool reflect immediately in other
- ✅ No data duplication
- ✅ Real-time sync via BroadcastChannel (cross-tab)
🔗 PHASE 3: Cross-Tool Integration
Goal: Fix integration gaps between all 15 platform builder tools Priority: MEDIUM (Enables seamless workflows) Effort: 30-40 hours Dependencies: Phases 1 & 2 must be complete
3.1 Fix Double Persistence (8 hours)
Problem: Some data saved to multiple collections causing race conditions
Current Issues:
- Universe data saved to both
spacesandmodulescollections - Module data duplicated across services
- Race conditions on concurrent saves
Tasks:
Audit all persistence points (3h)
- Grep: All
.save(),.update(),.patch()calls across codebase - Document: Which service saves what data
- Identify: Overlapping saves
- Create: Data ownership matrix
- Grep: All
Define clear boundaries (2h)
- Rule: Space-level data → SpaceService ONLY
- Rule: Module-level data → ModuleService ONLY
- Rule: Universe structure → UniverseService ONLY
- Document: In architecture.md
Refactor overlapping saves (3h)
- Remove: Duplicate save calls
- Centralize: Through shared service
- Add: Validation to prevent future double-saves
- Test: No data loss, no race conditions
Success Criteria:
- ✅ Each data type saved exactly once
- ✅ No race conditions
- ✅ Clear ownership documented
- ✅ Validation prevents future issues
3.2 Add Missing Context (universeId/pageId) (10 hours)
Problem: Some tools missing universeId or pageId in state/operations
Tasks:
Add context to Page Builder (3h)
- File:
libs/libs-structural/page-builder/src/lib/page-builder.component.ts - Already Has: UniverseContextService injection (line 62)
- Add: pageId to all widget operations
- Add: universeId to all save operations
- Pattern:
saveWidget(widget: Widget): void { const context = this.universeContext.getCurrentContext(); this.widgetService.save({ ...widget, universeId: context.universeId, pageId: context.pageId }); }
- File:
Add context to Module Workbench (3h)
- File: Module workbench component
- Add: Inject UniverseContextService
- Ensure: moduleId and universeId tracked in all operations
Add context to Widget Builder (2h)
- Track: widgetId, moduleId, pageId, universeId
- Include: In all saves and queries
Update Flash Persistence keys (2h)
- Pattern: Include context in storage keys
- Format:
${universeId}:${moduleId}:${pageId}:widget-state - Benefit: Prevents key collisions between different universes
- Update: All
autoFlashState()calls to include context
Success Criteria:
- ✅ All tools have full context (universeId, pageId, moduleId)
- ✅ Storage keys include context
- ✅ No key collisions between universes
- ✅ Data properly scoped
3.3 Implement Idempotent Real-Time Updates (8 hours)
Problem: Real-time WebSocket updates can cause duplicate processing
Tasks:
Add update deduplication (4h)
- Service: RealtimeSyncService
- Track: Set of processed update IDs (WeakMap for memory efficiency)
- Pattern:
private processedIds = new Set<string>(); handleUpdate(update: Update): void { if (this.processedIds.has(update.id)) { console.debug('Ignoring duplicate update', update.id); return; } this.processedIds.add(update.id); this.processUpdate(update); // Clean up old IDs after 5 minutes setTimeout(() => this.processedIds.delete(update.id), 300000); }
Add optimistic updates (4h)
- Pattern: Update UI immediately before backend confirms
- Rollback: On server error
- Merge: Server response with local state
- Implementation:
updateNode(nodeId: string, updates: Partial<Node>): void { // Optimistic update this.state.update(s => ({ ...s, nodes: s.nodes.map(n => n.id === nodeId ? { ...n, ...updates } : n) })); // Backend save this.api.updateNode(nodeId, updates).subscribe({ next: (serverNode) => { // Merge server response (server wins on conflicts) this.state.update(s => ({ ...s, nodes: s.nodes.map(n => n.id === nodeId ? serverNode : n) })); }, error: () => { // Rollback on error this.state.update(s => ({ ...s, nodes: s.nodes.map(n => n.id === nodeId ? originalNode : n) })); } }); }
Success Criteria:
- ✅ No duplicate update processing
- ✅ Optimistic updates work smoothly
- ✅ Rollback on error works
- ✅ Server state wins on conflicts
3.4 Replace Global Registry with DI (6 hours)
Problem: Some tools use fragile window['globalRegistry'] pattern
Tasks:
Find global registrations (2h)
- Search:
window['globalRegistry'],globalThis.__widgetRegistry__ - Document: Current usage and dependencies
- Search:
Create proper DI services (3h)
- Replace: With Angular services using
providedIn: 'root' - Maintain: Same API for backward compatibility during transition
- Example:
// OLD (fragile): window['globalThis'].__widgetRegistry__ = this.registry; // NEW (type-safe): @Injectable({ providedIn: 'root' }) export class WidgetRegistryService { private registry = new Map<string, Widget>(); register(widget: Widget): void { this.registry.set(widget.id, widget); } }
- Replace: With Angular services using
Update all consumers (1h)
- Replace:
windowaccess with DI injection - Update: Imports to use new services
- Replace:
Success Criteria:
- ✅ Zero window globals
- ✅ All DI-based services
- ✅ Type-safe throughout
- ✅ Better testability
3.5 Complete Flat Architecture Migration (8 hours)
Problem: Some code still assumes hierarchical tree structure (legacy pattern)
Current State:
- Space-Map has "FLAT STRUCTURE" comments (line 242 in space-map.state.ts)
- Universe Architect expects flat structure
- Some legacy code uses inefficient tree traversal
Tasks:
Remove tree traversal functions (3h)
- File:
space-map.state.tslines 1040-1088 - Delete:
addPageToTree(),updatePageInTree(),removePageFromTree() - Replace: With flat array operations using
parentId - Keep:
childrenfield ONLY for UI display (not persistence)
- File:
Update all queries to flat pattern (3h)
- Replace: Recursive searches with
filter() - Use:
parentIdfor hierarchy relationships - Pattern:
// OLD (slow recursive): findNodeInTree(nodeId: string, tree: Node[]): Node | null { for (const node of tree) { if (node.id === nodeId) return node; const found = this.findNodeInTree(nodeId, node.children); if (found) return found; } return null; } // NEW (fast flat): findNode(nodeId: string): Node | null { return this.nodes().find(n => n.id === nodeId) ?? null; } getChildren(nodeId: string): Node[] { return this.nodes().filter(n => n.parentId === nodeId); }
- Replace: Recursive searches with
Update documentation (2h)
- Create:
docs/architecture/flat-architecture.md - Document: Flat structure pattern
- Add: Migration guide for other tools
- Update: README files
- Create:
Success Criteria:
- ✅ All code uses flat structure
- ✅ Zero tree traversal functions
- ✅ Performance improved (O(n) instead of O(n*depth))
- ✅ Documentation complete
🚀 PHASE 4: Missing Features
Goal: Complete partially implemented tools Priority: MEDIUM (User-facing features) Effort: 45-60 hours Dependencies: Phase 3
4.1 Complete Page Builder (50% → 100%) (20 hours)
Current State: Basic canvas and widgets work, but missing key features
Missing Features:
Responsive breakpoints (6h)
- File:
libs/libs-structural/page-builder/src/lib/types/page-builder.types.ts(lines 11-55) - Status: Types defined but not implemented
- Add: Breakpoint switcher to toolbar (Desktop, Tablet, Mobile)
- Save: Separate positions per breakpoint
- Preview: Real-time breakpoint preview
- File:
Widget resize handles (4h)
- Add: Resize handles (8 corners + edges) to canvas-widget
- Update: Width/height on drag
- Constrain: Min/max sizes from widget definition
- Aspect Ratio: Lock option
Layer panel (4h)
- Show: Widget hierarchy in left sidebar
- Drag: To reorder z-index
- Lock/Unlock: Prevent accidental edits
- Visibility: Toggle layer visibility
AI widget generation (4h)
- Integrate: Vibe Coding service
- Generate: Widgets from natural language prompts
- Auto-place: On canvas with smart positioning
- Handoff: Via ToolOrchestrationService
Export/Import (2h)
- Export: Page as JSON
- Import: From JSON file
- Template Library: Save/load page templates
Files to Update:
libs/libs-structural/page-builder/src/lib/page-builder.component.tslibs/libs-structural/page-builder/src/lib/canvas/page-canvas.component.ts
Success Criteria:
- ✅ All features working
- ✅ Responsive design preview works
- ✅ AI generation integrated
- ✅ Export/import reliable
4.2 Enhance Module Browser (8 hours)
Current State: Basic list view only
Tasks:
Add filtering (3h)
- Filter by: Type, tags, status, creator, date
- Multi-filter: Combine multiple filters
- Search: Full-text search by name, description
Add sorting (2h)
- Sort by: Date, name, status, usage count
- Direction: Ascending/descending
- Persist: Sort preference
Add bulk actions (3h)
- Multi-select: Checkbox selection
- Bulk activate/deactivate: Change status
- Bulk delete: With confirmation
- Bulk tag: Add/remove tags
Success Criteria:
- ✅ Filtering works with multiple criteria
- ✅ Sorting persists
- ✅ Bulk actions complete successfully
4.3 Finish Launch Station Features (8 hours)
Current State: Basic deployment works
Tasks:
Add deployment preview (4h)
- Preview: Before deploy shows what will be deployed
- Validate: Configuration completeness
- Checklist: Required steps (tests pass, no errors, etc.)
Add rollback (4h)
- Track: Deployment history with versions
- One-click rollback: To previous version
- Confirmation: With preview of changes
- Status: Track rollback progress
Success Criteria:
- ✅ Preview shows accurate deployment info
- ✅ Rollback works reliably
- ✅ History tracked
4.4 Add Collaborative Editing (9 hours)
Current State: Single-user only
Tasks:
Add presence indicators (3h)
- Show: Who's editing what (avatar badges)
- Cursors: Other users' cursor positions
- Selections: Highlight selected elements
Add operational transforms (4h)
- Handle: Concurrent edits without conflicts
- Merge: Changes from multiple users
- Conflict Resolution: Last-write-wins with timestamps
Add chat (2h)
- In-editor chat: Sidebar panel
- @mentions: Notify specific users
- Notifications: Desktop notifications for mentions
Success Criteria:
- ✅ Presence indicators work
- ✅ Concurrent editing doesn't conflict
- ✅ Chat functional
✅ PHASE 5: Testing & Polish
Goal: Production-ready quality Priority: HIGH (Quality assurance) Effort: 35-45 hours Dependencies: Phase 4
5.1 Comprehensive E2E Tests (20 hours)
Tasks:
Universe Architect tests (5h)
- Test drag-drop nodes
- Test create connections
- Test AI handoff from Vibe Universe
- Test persistence
- Test undo/redo
Space-Map tests (4h)
- Test CRUD operations
- Test drag-drop reorganize
- Test tree/flat view switching
- Test sync with Architect
Integration tests (6h)
- Test tool handoffs (Vibe → Canvas → Workbench)
- Test data sync across tools
- Test real-time updates
- Test collaborative editing
Cross-browser tests (5h)
- Chrome, Firefox, Safari, Edge
- Mobile browsers (iOS Safari, Chrome Android)
- Automated Playwright tests for CI/CD
Files to Create:
apps/gograb-space-e2e/src/universe-architect/*.spec.tsapps/gograb-space-e2e/src/space-map/*.spec.tsapps/gograb-space-e2e/src/integration/*.spec.ts
Success Criteria:
- ✅ 90%+ test coverage
- ✅ All tests pass
- ✅ CI/CD integrated
- ✅ Tests run on every PR
5.2 Performance Optimization (8 hours)
Tasks:
Virtual scrolling for large lists (3h)
- Implement: CDK Virtual Scroll for 1000+ items
- Apply: Module Browser, Space-Map tree
- Measure: Improvement (target: 60fps)
Canvas rendering optimization (3h)
- Use:
requestAnimationFramefor all animations - Throttle: Render updates to 60fps max
- Canvas culling: Only render visible nodes (viewport check)
- Use:
Bundle size optimization (2h)
- Lazy load: Heavy components (e.g., AI services)
- Tree-shake: Unused code
- Analyze: Webpack Bundle Analyzer
- Target: <500kb main bundle
Success Criteria:
- ✅ 60fps rendering achieved
- ✅ <3s initial load time
- ✅ <500kb main bundle
- ✅ No jank during interactions
5.3 UI Polish (7 hours)
Tasks:
Animation polish (3h)
- Smooth transitions: All state changes
- Loading states: Skeleton loaders
- Success/error feedback: Toast notifications
- Micro-interactions: Hover effects, button presses
Keyboard shortcuts (2h)
- Document: All shortcuts in help modal
- Add: Shortcut hint UI (tooltips with "Ctrl+S")
- Customize: User-defined shortcuts
Accessibility (2h)
- ARIA labels: All interactive elements
- Keyboard navigation: Tab order, focus management
- Screen reader: Tested with NVDA/JAWS
- Target: WCAG 2.1 AA compliance
Success Criteria:
- ✅ All animations smooth (no jank)
- ✅ Shortcuts documented
- ✅ WCAG 2.1 AA compliant
- ✅ Screen reader tested
5.4 Documentation (10 hours)
Tasks:
User guides (4h)
- Getting started: Quick start tutorial
- Feature guides: Each tool documented
- Video tutorials: Screen recordings
Developer docs (4h)
- Architecture overview: System design
- API reference: Service documentation
- Contributing guide: How to add features
API docs (2h)
- JSDoc comments: All public methods
- Generated docs: Compodoc or TypeDoc
- Examples: Code snippets
Success Criteria:
- ✅ Complete user documentation
- ✅ Complete developer documentation
- ✅ API docs auto-generated
- ✅ Video tutorials published
📋 IMPLEMENTATION ROADMAP
Week 1-2: Phase 1 (Universe Architect)
- Remove Universe Core
- Implement drag-drop
- Add connections
- Vibe coding integration
Week 3-4: Phase 2 (Space-Map)
- NGXS to Signals migration
- Flash Persistence consolidation
- Recursive visualization
- Sync with Architect
Week 5-6: Phase 3 (Integration)
- Fix double persistence
- Add missing context
- Idempotent updates
- Replace global registry
- Flat architecture completion
Week 7-9: Phase 4 (Features)
- Complete Page Builder
- Enhance Module Browser
- Finish Launch Station
- Add collaborative editing
Week 10-11: Phase 5 (Testing & Polish)
- E2E tests
- Performance optimization
- UI polish
- Documentation
Total Timeline: 11 weeks (185-245 hours)
🎯 SUCCESS METRICS
Technical
- ✅ 100% test coverage for critical paths
- ✅ Sub-100ms response time for all interactions
- ✅ <3s initial load time
- ✅ <500kb main bundle
- ✅ 60fps rendering
Quality
- ✅ Zero NGXS dependencies
- ✅ Single source of truth (Flash Persistence)
- ✅ No double persistence
- ✅ Type-safe throughout
- ✅ WCAG 2.1 AA compliant
Integration
- ✅ All 15 tools use ToolOrchestrationService
- ✅ Seamless handoffs between tools
- ✅ Real-time sync across tools
- ✅ Collaborative editing works
User Experience
- ✅ Intuitive drag-drop
- ✅ AI generation integrated
- ✅ Smooth animations
- ✅ Comprehensive documentation
🚨 RISK MITIGATION
High-Risk Items
Backend API Changes
- Risk: Backend doesn't support needed endpoints (hydration, sync)
- Mitigation: Create backend tickets in parallel with Phase 1
- Owner: Backend team coordination required
Data Migration
- Risk: Breaking changes to data structure during NGXS → Signals
- Mitigation: Write migration scripts, version all data, test on staging
- Rollback Plan: Keep NGXS code for 1 sprint as fallback
Performance Regression
- Risk: New features slow down tools
- Mitigation: Performance budgets, continuous monitoring, before/after benchmarks
- Target: Maintain <100ms response times
Merge Conflicts
- Risk: 5 phases = many concurrent changes
- Mitigation: Small PRs, feature flags, daily syncs, dedicated integration branch
Scope Creep
- Risk: 185-245 hours is ambitious
- Mitigation: Strict phase gates, MVP first, polish later, defer non-critical features
📁 CRITICAL FILES REFERENCE
Phase 1 Files
libs/libs-space/universe-architect/src/lib/
├── components/architect-canvas/architect-canvas.component.ts
├── services/architect-state.service.ts
├── services/architect-module-converter.service.ts
└── services/connection-validator.service.ts (NEW)
libs/libs-structural/singularity-lib/src/lib/
└── components/flow-composer/flow-composer.component.ts (REFERENCE)
Phase 2 Files
libs/libs-structural/space-map-lib/src/lib/
├── state/space-map.state.ts
├── services/space-map-storage.service.ts
└── components/recursive-tree-view/ (NEW)
Phase 3 Files
libs/libs-foundational/core-angular/src/lib/services/
├── universe-context.service.ts
└── realtime-sync.service.ts
libs/libs-structural/vibe-universe/src/lib/
└── services/tool-orchestration.service.ts (REFERENCE)
Phase 4 Files
libs/libs-structural/page-builder/src/lib/
├── page-builder.component.ts
├── canvas/page-canvas.component.ts
└── types/page-builder.types.ts
Phase 5 Files
apps/gograb-space-e2e/src/
├── universe-architect/*.spec.ts (NEW)
├── space-map/*.spec.ts (NEW)
└── integration/*.spec.ts (NEW)
🎓 LESSONS FROM PROVEN PATTERNS
Singularity Drag-Drop (Copy Exactly)
- Global mouse handlers registered in
ngAfterViewInit - Offset calculation:
offsetX = mouseX - nodeX - Real-time updates with
requestAnimationFrame() - Throttled persistence at 300ms
- Result: Sub-100ms drag response
Canvas Builder Recursion (Copy Exactly)
- Self-referencing component with
forwardRef() - Same component at all nesting levels
- Events bubble without modification
- No artificial root node
- Result: Infinitely nestable, intuitive
Vibe Coding Handoff (Copy Exactly)
- ToolOrchestrationService coordinates all handoffs
- ModuleHandoff interface carries full context
- Backend persistence at transition points
- Toast notifications for user feedback
- Result: Seamless tool-to-tool transitions
✅ NEXT STEPS
- Review & Approve: User reviews this comprehensive plan
- Backend Coordination: Create backend tickets for API endpoints
- Start Phase 1: Begin Universe Architect enhancement
- Weekly Syncs: Track progress, adjust as needed
- Celebrate Wins: Each phase completion
Estimated Completion: 11 weeks from approval
Plan created: January 6, 2026 Confidence: 98% Session: 27.1 Status: Ready for Implementation