M10: durable Yjs autosave persistence + re-grounded roadmap#16
Merged
Conversation
Boards previously lived only in each client's IndexedDB and the ephemeral Realtime broadcast, so a fresh client or a late-joiner arriving after every peer had left loaded an empty board. The snapshots table already supports a single self-compacting `autosave` row per board (unique partial index + RLS insert/update on public boards), so this wires the missing client loop with no migration and no compaction function: - packages/sync/src/autosave.ts: loadAutosave (Y.applyUpdate merge — not the destructive restoreSnapshot) and startAutosave (debounced writer with a pagehide/visibilitychange flush, update-or-insert), plus shared bytea hex helpers. - shapeStore.initBoard: load then start autosave after IndexedDB + realtime attach, only when a Supabase client is configured (local-only unchanged). - snapshotsApi: reuse the hex helpers from @notux/sync (drop the duplicates). Adds docs/ROADMAP.md with the re-grounded M10–M16 + Living Cosmos design track. Verified: pnpm typecheck + pnpm build pass; encode -> hex bytea -> applyUpdate round-trip reproduces pages/shapes/pageList and is idempotent on re-merge. https://claude.ai/code/session_01QFK6Z1fYzo7XSogUETXnwe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A strategy doc recommended a 7-stage enhancement plan, but it assumed the repo sat at M4. The repo is actually at M9 —
perfect-freehand, Yjs + a custom Supabase-broadcast provider,y-indexeddb, PDF/image import, audio + YouTube/gdrive embeds, named snapshots, and selection/transform are all already shipped. This PR re-grounds the plan around the genuine gaps and ships the highest-priority fix.The critical gap (lead milestone, M10)
Board state previously lived only in (a) each client's IndexedDB and (b) the ephemeral Supabase Realtime broadcast.
shapeStore.initBoardloaded IndexedDB then attached the broadcast provider — it never loaded a server-side snapshot, andlastSavedwas a purely local debounced timestamp. Consequence: a fresh client with no IndexedDB, or a late-joiner arriving after all peers had left, got an empty board.The
snapshotstable already supports this: a single self-compactingautosaverow per board (unique partial index + RLS insert/update on public boards). So — diverging from the originaldocument_updatesappend-log + compaction-Edge-Function proposal — no migration and no Edge Function are needed. The fix is purely client wiring.What changed
packages/sync/src/autosave.ts(new):loadAutosave(fetch the autosave row andY.applyUpdatemerge — deliberately not the destructiverestoreSnapshotused for named-snapshot time travel) andstartAutosave(debounced ~2s / max-wait ~10s writer that update-or-inserts the row, with a best-effortpagehide/visibilitychangeflush). Also home for the sharedbyteahex helpers.packages/canvas/src/store/shapeStore.ts(initBoard): after IndexedDB hydrate + realtime attach,loadAutosavethenstartAutosave— only when a Supabase client is configured. Local-only mode is unchanged. Stops the previous board's loop on switch.apps/web/src/features/board/snapshotsApi.ts: reuses the hex helpers from@notux/sync(drops the duplicate copies).docs/ROADMAP.md(new): the re-grounded M10–M16 milestones + a Living Cosmos design re-skin track.Verification
pnpm typecheck✅ andpnpm build✅ across all packages.byteahex →Y.applyUpdatemerge reproduces pages/shapes/pageList and is idempotent on re-merge (the late-joiner case).VITE_SUPABASE_URL+VITE_SUPABASE_ANON_KEY): draw on a board, wait ~2s for theautosaverow to populate, open the same board URL in a fresh incognito window (no IndexedDB) → strokes load; close all tabs and reopen → board persists.Roadmap (subsequent milestones)
M11 native ink feel · M12 scale (rbush culling + Konva perf flags) · M13 editing polish · M14 URL bookmarks (unfurl Edge Function) · M15 embeds registry · M16 PWA + Capacitor packaging · Living Cosmos re-skin. See
docs/ROADMAP.md.https://claude.ai/code/session_01QFK6Z1fYzo7XSogUETXnwe
Generated by Claude Code