/** * Workflow Persistence - Phase 8 Enterprise Pattern * * Saves and restores workflow states to localStorage and server, * enabling crash recovery and session restoration. */ import store from '../stores/app-store.js'; class WorkflowPersistence { constructor() { this.storageKey = 'dss-workflow-state'; this.maxSnapshots = 10; this.autoSaveInterval = 30000; // 30 seconds this.isAutosaving = false; } /** * Take a workflow snapshot of current state */ snapshot() { const state = store.get(); const snapshot = { id: `snapshot-${Date.now()}`, timestamp: new Date().toISOString(), data: { currentPage: state.currentPage, sidebarOpen: state.sidebarOpen, user: state.user, team: state.team, role: state.role, figmaConnected: state.figmaConnected, figmaFileKey: state.figmaFileKey, selectedProject: state.projects[0]?.id || null, } }; return snapshot; } /** * Save snapshot to localStorage with versioning */ saveSnapshot(snapshot = null) { try { const snap = snapshot || this.snapshot(); const snapshots = this.getSnapshots(); // Keep only latest N snapshots snapshots.unshift(snap); snapshots.splice(this.maxSnapshots); localStorage.setItem(this.storageKey, JSON.stringify(snapshots)); return snap.id; } catch (e) { console.error('[WorkflowPersistence] Failed to save snapshot:', e); return null; } } /** * Get all saved snapshots */ getSnapshots() { try { const stored = localStorage.getItem(this.storageKey); return stored ? JSON.parse(stored) : []; } catch (e) { console.warn('[WorkflowPersistence] Failed to load snapshots:', e); return []; } } /** * Get latest snapshot */ getLatestSnapshot() { const snapshots = this.getSnapshots(); return snapshots[0] || null; } /** * Get snapshot by ID */ getSnapshot(id) { const snapshots = this.getSnapshots(); return snapshots.find(s => s.id === id) || null; } /** * Restore workflow from snapshot */ restoreSnapshot(id) { const snapshot = this.getSnapshot(id); if (!snapshot) { console.warn('[WorkflowPersistence] Snapshot not found:', id); return false; } try { const data = snapshot.data; store.set({ currentPage: data.currentPage, sidebarOpen: data.sidebarOpen, user: data.user, team: data.team, role: data.role, figmaConnected: data.figmaConnected, figmaFileKey: data.figmaFileKey, }); return true; } catch (e) { console.error('[WorkflowPersistence] Failed to restore snapshot:', e); return false; } } /** * Clear all snapshots */ clearSnapshots() { localStorage.removeItem(this.storageKey); } /** * Delete specific snapshot */ deleteSnapshot(id) { const snapshots = this.getSnapshots(); const filtered = snapshots.filter(s => s.id !== id); localStorage.setItem(this.storageKey, JSON.stringify(filtered)); } /** * Start auto-saving workflow every N milliseconds */ startAutoSave(interval = this.autoSaveInterval) { if (this.isAutosaving) return; this.isAutosaving = true; this.autoSaveTimer = setInterval(() => { this.saveSnapshot(); }, interval); console.log('[WorkflowPersistence] Auto-save enabled'); } /** * Stop auto-saving */ stopAutoSave() { if (this.autoSaveTimer) { clearInterval(this.autoSaveTimer); this.isAutosaving = false; console.log('[WorkflowPersistence] Auto-save disabled'); } } /** * Export snapshots as JSON file */ exportSnapshots() { const snapshots = this.getSnapshots(); const data = { exportDate: new Date().toISOString(), version: '1.0', snapshots: snapshots }; return JSON.stringify(data, null, 2); } /** * Import snapshots from JSON data */ importSnapshots(jsonData) { try { const data = JSON.parse(jsonData); if (!Array.isArray(data.snapshots)) { throw new Error('Invalid snapshot format'); } localStorage.setItem(this.storageKey, JSON.stringify(data.snapshots)); return true; } catch (e) { console.error('[WorkflowPersistence] Failed to import snapshots:', e); return false; } } } // Create and export singleton const persistence = new WorkflowPersistence(); export { WorkflowPersistence }; export default persistence;