11# DeepNotes — Restart (greenfield) plan — v4
22
33> ** Last updated:** 2026-05-30
4- > ** Status:** Phase 0 foundation complete. Phase 1 spatial checklist complete. ** Phase 2 backend parity verified.** ** Phase 3 collab wire parity complete.** Phase 4 routing decision complete.
4+ > ** Status:** Phase 0 foundation complete. Phase 1 spatial checklist complete. ** Phase 2 backend parity verified.** ** Phase 3 collab wire parity complete.** Phase 4 routing decision complete. ** Phase 5 spatial canvas MVP in progress (notes + arrows + camera + drag-to-move wired to PageEditorView.vue). **
55> ** This document replaces all prior restart plan versions.** If a prior statement conflicts with this one, this version wins.
66> ** Analyzed:** 2026-05-30 — additional gaps identified in §0.2–0.4, §3, §4, §6–8. Collab protocol gap and routing/product-model divergence newly documented.
77
2525| ** Page management UI** | ` apps/web/src/features/pages/* ` | Partial | Bump, favorite, recent, snapshots, soft-delete, restore, purge, move, path breadcrumb. |
2626| ** Rich-text editor** | ` apps/web/src/features/pages/PageEditorTiptapCard.vue ` | Partial | Tiptap + Yjs, tables, images, tasks, code, math, YouTube, collab carets. |
2727| ** Marketing site** | ` apps/marketing/ ` | Done | ` vite-ssg ` placeholder. |
28- | ** Spatial / world canvas** | ` apps/web/src/features/spatial/* ` | ** Stub only ** | ` SpatialWorldStubView ` shows page pins on a pan/zoom canvas. ** No interactive notes, arrows, or containers. ** |
28+ | ** Spatial / world canvas** | ` apps/web/src/features/spatial/* ` | ** In progress ** | Drag-to-move notes, double-click create, arrows rendered, page-level Yjs doc wired. Tiptap editors inside notes, resize, arrow creation UI, containers pending. |
2929| ** Collab pagination** | ` GET /api/pages/:pid/collab-updates ` | Done | ` ?sinceIndex= ` + ` ?limit= ` (default 100, max 500). Client loops. |
3030| ** Playwright E2E** | ` apps/web/playwright.config.ts ` | Skeleton | Config + smoke test created; needs ` pnpm install ` + ` playwright install ` . |
3131
@@ -562,55 +562,48 @@ The new `usePageCollabEditor` only syncs a ProseMirror `Y.XmlFragment`. We need
562562
563563** Deliverables:**
564564
565- 1 . ** Camera / viewport (` features/spatial/camera.ts ` )**
566- - ` SpatialWorldCanvas.vue ` becomes the actual page editor background.
565+ 1 . ** Camera / viewport (` features/spatial/camera.ts ` )** ✅
566+ - ` SpatialWorldCanvas.vue ` is the page editor background.
567567 - Pan: wheel, space+drag, middle-drag.
568568 - Zoom: ctrl/cmd+wheel toward cursor.
569- - Pinch: touch pinch-to-zoom.
570- - Fit-to-screen: button that centers on all notes.
571-
572- 2 . ** Note model (` features/spatial/note-model.ts ` )**
573- - Class or composable representing a note on the page.
574- - Properties: ` id ` , ` pos: Vec2 ` , ` width ` , ` head: { enabled, height, value: Y.XmlFragment } ` , ` body: { enabled, height, value: Y.XmlFragment } ` , ` container: { enabled, spatial, horizontal, children } ` , ` color ` , ` zIndex ` , ` collapsing ` , ` movable ` , ` resizable ` .
575- - Must read from / write to the page Yjs doc.
576-
577- 3 . ** Note rendering (` features/spatial/DisplayNote.vue ` )**
578- - Render note frame at ` (note.pos.x, note.pos.y) ` .
579- - Head section: Tiptap editor (using existing Tiptap extensions) bound to ` note.head.value ` .
580- - Body section: Tiptap editor bound to ` note.body.value ` .
581- - Container section: renders child notes inside (if ` container.enabled ` ).
582- - Resize handles (8 corners/sides).
583- - Drag handle on note frame.
584-
585- 4 . ** Arrow model (` features/spatial/arrow-model.ts ` )**
586- - Properties: ` id ` , ` source ` , ` target ` , ` sourceAnchor ` , ` targetAnchor ` , ` bodyType ` , ` bodyStyle ` , ` sourceHead ` , ` targetHead ` , ` label: Y.XmlFragment ` , ` color ` .
587-
588- 5 . ** Arrow rendering (` features/spatial/DisplayArrow.vue ` )**
589- - SVG overlay on top of notes.
590- - Curve or line body between source and target note edges.
591- - Arrow heads at source/target.
592- - Label near midpoint.
593-
594- 6 . ** Basic interaction**
595- - Click to select a note.
596- - Drag to move a note.
597- - Drag resize handles to resize.
598- - Create note: double-click on empty canvas (or button).
599- - Create arrow: drag from note edge handle to another note.
600- - Delete: ` Delete ` key when note selected.
601-
602- 7 . ** Collab for spatial state**
603- - When a note is moved, the position update syncs via collab WS within 200 ms.
604- - When an arrow is created, it appears on remote clients within 1 second.
605- - Remote cursor awareness shows which user is editing which note.
606-
607- 8 . ** DOM / world coordinate system**
608- - Replicate legacy ` space/pos.ts ` , ` space/rects.ts ` , ` space/sizes.ts ` behavior:
609- - ` clientToWorld ` , ` worldToClient ` , ` screenToWorld ` , ` worldToScreen ` transforms.
610- - ` getContainerWorldRect ` , ` getOriginWorldPos ` for nested regions (containers).
611- - Required for accurate drag, resize, arrow anchor placement, and fit-to-screen.
612-
613- 9 . ** Default note / arrow templates**
569+ - Pinch: touch pinch-to-zoom. (structure ready, needs mobile testing)
570+ - Fit-to-screen: pending.
571+
572+ 2 . ** Note model (` features/spatial/note-model.ts ` )** ✅
573+ - Composable ` useNoteModel ` with all legacy properties: ` pos ` , ` width ` , ` head ` , ` body ` , ` container ` , ` color ` , ` zIndex ` , ` collapsing ` , ` movable ` , ` resizable ` , ` anchor ` , timestamps.
574+ - Reads/writes to the page Yjs doc via hybrid reactive proxy.
575+ - Tested in ` note-model.test.ts ` .
576+
577+ 3 . ** Note rendering (` features/spatial/DisplayNote.vue ` )** ✅ (partial)
578+ - Render note frame at ` (note.pos.x, note.pos.y) ` — done.
579+ - Drag to move — done (zoom-aware pointer capture).
580+ - Head/body Tiptap editor — pending (requires inline editor component).
581+ - Container section with child notes — pending.
582+ - Resize handles — pending.
583+
584+ 4 . ** Arrow model (` features/spatial/arrow-model.ts ` )** ✅
585+ - Composable ` useArrowModel ` with all legacy properties.
586+ - Tested in ` arrow-model.test.ts ` .
587+
588+ 5 . ** Arrow rendering (` features/spatial/DisplayArrow.vue ` )** ✅ (partial)
589+ - SVG line between source and target note centers — done.
590+ - Curve/line body styles, arrow heads, label — pending.
591+
592+ 6 . ** Basic interaction** ✅ (partial)
593+ - Drag to move a note — done.
594+ - Create note via double-click on empty canvas — done.
595+ - Click to select, resize handles, create arrow via drag, Delete key — pending.
596+
597+ 7 . ** Collab for spatial state** ✅ (partial)
598+ - ` ydoc.on('updateV2') ` listener in ` usePageEditor.ts ` schedules push for non-Tiptap mutations — done in Phase 0.
599+ - Position updates trigger collab push via Yjs diff — done.
600+ - Full two-client integration test — pending.
601+
602+ 8 . ** DOM / world coordinate system** ✅ (partial)
603+ - ` screenToWorld ` , ` worldToScreen ` , ` wheelZoomCameraTowardScreenPoint ` , ` panCameraByScreenDelta ` — done in ` spatial-viewport-math.ts ` .
604+ - ` getContainerWorldRect ` , ` getOriginWorldPos ` for containers — pending.
605+
606+ 9 . ** Default note / arrow templates** ⬜
614607 - On creation, new notes must use the user's ` encrypted_default_note ` column (decrypted via session keyrings).
615608 - New arrows must use ` encrypted_default_arrow ` .
616609 - These set default colors, widths, head/body enabled states, and arrow styles.
@@ -623,10 +616,15 @@ The new `usePageCollabEditor` only syncs a ProseMirror `Y.XmlFragment`. We need
623616- Integration test: two tabs, create note in A, assert note appears in B within 2 seconds.
624617
625618** Exit criteria:**
626- - [ ] User can create, move, resize, and delete notes on an infinite canvas.
627- - [ ] User can create arrows between notes.
628- - [ ] Canvas pan/zoom works with mouse and touch.
629- - [ ] Changes sync across tabs via collab WS.
619+ - [x] User can create notes on an infinite canvas.
620+ - [x] User can drag to move notes.
621+ - [ ] User can resize notes.
622+ - [ ] User can delete notes.
623+ - [x] Arrows render between notes (source/target positions tracked).
624+ - [ ] User can create arrows between notes via UI drag interaction.
625+ - [x] Canvas pan/zoom works with mouse.
626+ - [ ] Canvas pan/zoom works with touch (pinch).
627+ - [x] Changes sync across tabs via collab WS (page-level Yjs doc + ` updateV2 ` listener).
630628- [ ] Phase 1 checklist rows for "Notes (basic)" and "Arrows (basic)" are marked done.
631629
632630---
0 commit comments