You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -75,6 +76,41 @@ The legacy collab syncs the **entire page state** (note positions, arrow endpoin
75
76
76
77
---
77
78
79
+
## 0.4 Additional critical gaps discovered
80
+
81
+
These were found during the v3 analysis and must be addressed in the phases below.
82
+
83
+
1.**`usePageCollabEditor.ts` is already a god object (708 lines)**
84
+
- The plan itself recommends capping composables at 300 lines (§7). The main collab composable already violates this.
85
+
-**Fix:** Split into `useCollabWebSocket.ts`, `useCollabCrypto.ts`, `useCollabPush.ts`, `usePageEditor.ts` before any spatial work.
86
+
87
+
2.**`PageCollabRoom` DO is a stateless relay, not an in-memory Yjs host**
88
+
- Legacy `collab-server` held Yjs `Doc` instances in memory and synced via `y-protocols`. The new DO only decrypts/relays opaque blobs via `WORKER_SELF`.
89
+
-**Impact:** The server cannot enforce page size limits, merge updates intelligently, or validate structure.
90
+
-**Fix:** Document the architectural trade-off in `docs/COLLAB_DO_ARCHITECTURE.md`. If page-level Yjs is added (Phase 3), consider whether the DO should load the Yjs doc into memory.
91
+
92
+
3.**`page_updates` backward compatibility**
93
+
- Existing production rows contain encrypted ProseMirror-only Yjs updates. Phase 3 will introduce page-level Yjs docs (notes + arrows).
94
+
-**Decision required:** Add `page_spatial_updates` table, or version the update format within `page_updates` so old rows remain readable.
95
+
96
+
4.**SSR and i18n regressions vs legacy**
97
+
- Legacy `apps/client` had SSR (`src-ssr`) and `vue-i18n`. New `apps/web` is pure SPA with no i18n infrastructure.
98
+
-**Fix:** Product decision — document as accepted regressions or schedule recovery.
99
+
100
+
5.**Group password unlock is unscheduled**
101
+
-`unlockPageCollabSymmetricKeyring` throws when a group requires a password. The comment says "Unlock is not implemented in the web MVP."
102
+
-**Fix:** Add to Phase 8 (group/account polish) or document as v2 scope.
103
+
104
+
6.**`page_links` / backlink UI is missing**
105
+
- The backend has `pageLinks` table and routes (`POST /api/pages/:pageId/backlinks`). No SPA UI exposes backlinks.
106
+
-**Fix:** Add backlink display to Phase 5 or Phase 8.
107
+
108
+
7.**No scheduler / manager CLI replacement**
109
+
- Legacy had `apps/scheduler` (cleanup) and `apps/manager` (ops CLI). New repo defers scheduler to "Cron Triggers or Queues" but has no implementation.
110
+
-**Fix:** Add deferred scheduler task to Phase 8 or Phase 9.
111
+
112
+
---
113
+
78
114
## 1. What "restart" should mean (revised)
79
115
80
116
| Goal | Meaning in practice |
@@ -217,18 +253,29 @@ Each phase has:
217
253
- Add `services: postgres` to the GitHub Actions `test` job (or use `docker-compose up -d` in a step).
218
254
- Export `DATABASE_URL`, `DATABASE_ADMIN_URL`, `TEST_DB_TEMPLATE_NAME` so `template-db.test.ts` and `account-flows.integration.test.ts` run instead of skipping.
219
255
256
+
6.**Refactor `usePageCollabEditor.ts` into focused composables**
257
+
- Split the 708-line composable into `useCollabWebSocket.ts`, `useCollabPush.ts`, `useCollabCrypto.ts`, `usePageEditor.ts`. Each must be < 300 lines.
258
+
- Update `PageEditorView.vue` imports.
259
+
260
+
7.**Add root `vitest.workspace.ts` in `new-deepnotes`**
261
+
- The outer repo root (`DeepNotes/`) has its own `vitest.config.ts` for legacy. `new-deepnotes` needs its own workspace file so `pnpm test` from `new-deepnotes/` resolves `apps/web/vite.config.ts` correctly.
262
+
- Verify `pnpm test` from `new-deepnotes/` root passes with 0 failures.
263
+
220
264
**Verification:**
221
265
```bash
266
+
# From new-deepnotes/
222
267
pnpm test
223
268
# Expected: 0 failures, 0 skips for core tests.
224
269
# Integration tests may still be long-running but must not be skipped for env reasons.
225
270
```
226
271
227
272
**Exit criteria (all must be yes):**
228
-
-[ ]`pnpm test` from repo root passes with 0 failures.
273
+
-[ ]`pnpm test` from `new-deepnotes/` root passes with 0 failures.
229
274
-[ ]`apps/web` unit tests run in `happy-dom` and can mount `.vue` files.
230
275
-[ ]`useSession.test.ts` passes in isolation and in batch (`--run` 3 times).
231
276
-[ ] CI test job runs integration tests against a real Postgres service.
277
+
-[ ]`usePageCollabEditor.ts` is split into composables ≤ 300 lines each.
278
+
-[ ]`router.ts` exports a factory and has zero module-load `window` access.
- Verify that the server can persist and serve **page-level updates** (not just ProseMirror).
331
-
- If the current `page_updates` table stores only ProseMirror diffs, extend the schema or add a separate `page_state_updates` table. **Decision required.**
382
+
-**Decision required (see §0.4 gap 3):**If the current `page_updates` table stores only ProseMirror diffs, extend the schema or add a separate `page_spatial_updates` table. Document the compatibility strategy in `docs/COLLAB_DATA_MIGRATION.md`.
332
383
333
384
3.**SPA page document loader**
334
385
- Replace `createPageCollabDoc()` (which creates a bare `Y.Doc`) with a function that loads the page structure from the server bootstrap and initializes `Y.Map`s for notes and arrows.
@@ -338,6 +389,16 @@ The new `usePageCollabEditor` only syncs a ProseMirror `Y.XmlFragment`. We need
338
389
- Add `PAGE_DOC` message type for page-level Yjs updates (note positions, arrow creation, etc.).
339
390
- Update `PageCollabRoom` DO to accept and relay `PAGE_DOC` updates.
340
391
392
+
5.**`page_updates` backward compatibility**
393
+
- Existing rows contain ProseMirror-only encrypted Yjs updates. Page-level updates must not corrupt old rows.
394
+
-**Option A:** Add `page_spatial_updates` table for page-level Yjs diffs; keep `page_updates` for ProseMirror-only legacy rows.
395
+
-**Option B:** Embed a version byte in the encrypted payload or add a `formatVersion` column.
396
+
-**Decision required before coding.** Document in `docs/COLLAB_DATA_MIGRATION.md`.
397
+
398
+
6.**DO architecture decision document**
399
+
- Document why `PageCollabRoom` is a stateless relay (no in-memory Yjs doc) vs legacy's stateful `collab-server`.
400
+
- If the DO should load the Yjs doc into memory for validation/size limits, include a spike in Phase 3.
401
+
341
402
**Verification:**
342
403
- Unit test: create a `YPageDoc`, add a note, encode state, decode state, assert note position matches.
343
404
- Integration test: two clients connect to `PageCollabRoom` via WS; client A creates a note; client B receives the update and the note appears in its Yjs doc within 2 seconds.
@@ -346,6 +407,8 @@ The new `usePageCollabEditor` only syncs a ProseMirror `Y.XmlFragment`. We need
346
407
-[ ]`packages/collab-wire` can encode/decode a page-level Yjs update.
347
408
-[ ]`PageCollabRoom` persists and relays page-level updates (not just ProseMirror).
348
409
-[ ] Two browser tabs can sync note creation/deletion via WS (integration test or manual QA with sign-off).
410
+
-[ ]`docs/COLLAB_DATA_MIGRATION.md` documents the `page_updates` compatibility strategy.
-`unlockPageCollabSymmetricKeyring` currently throws for password-protected groups.
666
+
- Implement group password UI and key derivation so users can unlock password-protected groups.
667
+
- Add integration test for password-protected group join + page decrypt.
668
+
669
+
6.**Scheduler / background cleanup**
670
+
- Legacy `apps/scheduler` ran scheduled cleanup (purge soft-deleted data).
671
+
- Implement a Cloudflare Cron Trigger or Queue worker that calls `performScheduledCleanup` from `@deepnotes/session`.
672
+
- Document in `docs/SCHEDULER.md`.
673
+
586
674
**Verification:**
587
675
- E2E smoke test: register → create group → create page → invite member → member joins → both edit page → logout.
588
676
- This smoke test must pass against a preview deployment or local compose stack.
@@ -641,25 +729,34 @@ The new `usePageCollabEditor` only syncs a ProseMirror `Y.XmlFragment`. We need
641
729
|**Stripe-only after dropping RevenueCat**| Low | User churn | Communicate to IAP users before cutover. Offer migration grace period. |
642
730
|**Worker CPU limits under collab load**| Medium | Dropped connections | Load test early (Phase 9 staging). If DO CPU is the bottleneck, shard `PageCollabRoom` by page ID prefix. |
643
731
|**God-object state returns**| Medium | Unmaintainable code | Cap composable size at 300 lines. If `useSpatialViewport.ts` grows beyond that, split into `useCamera`, `usePanning`, `useZooming`. |
732
+
|**`page_updates` format migration**| Medium | Data corruption or unreadable legacy pages | Decide Option A/B in Phase 3 before any spatial collab code. Test decrypt of 100 random legacy pages after migration. |
733
+
|**DO hibernation drops WS state**| Medium | Users see collab reconnects |`PageCollabRoom` is stateless relay, so hibernation is safe. Document in `docs/COLLAB_DO_ARCHITECTURE.md`. If stateful DO chosen later, implement reconnect protocol. |
734
+
|**i18n / SSR regressions**| Low | Accessibility, SEO, share-ability loss | Document as accepted v2 regressions or schedule recovery. |
735
+
|**Group password not implemented**| Low | Users cannot access password-protected groups in new app | Add to Phase 8. If deferred, document v2 scope. |
736
+
|**No scheduler = soft-deleted data accumulates**| Medium | DB bloat | Add Cron Trigger or Queue cleanup to Phase 8/9. |
0 commit comments