|
1 | 1 | # Restart plan — progress (`new-deepnotes`) |
2 | 2 |
|
3 | | -Checklist for [docs/RESTART_PLAN.md](../docs/RESTART_PLAN.md). **Procedure-level map:** [docs/TRPC_REST_MAP.md](./docs/TRPC_REST_MAP.md) (legacy tRPC + app-server WebSocket rows are marked **implemented** or **removed**). |
| 3 | +**Refs:** [RESTART_PLAN.md](../docs/RESTART_PLAN.md) · [TRPC_REST_MAP.md](./docs/TRPC_REST_MAP.md) (REST + legacy WS parity map). |
4 | 4 |
|
5 | | -**Last reviewed:** 2026-04-29 |
6 | | - |
7 | | ---- |
8 | | - |
9 | | -## Phase snapshot |
| 5 | +**Goal:** **Full behavioral parity** with legacy `apps/client` in `new-deepnotes` before cutover. **Exceptions** (explicit in RESTART_PLAN): no tRPC wire, no user/group **rotate-keys**, no **RevenueCat**. MVP = milestone, **not** scope ceiling. |
10 | 6 |
|
11 | | -| Phase | Status | Notes | |
12 | | -|-------|--------|--------| |
13 | | -| **0** — OpenAPI + Drizzle inventory | **Done** | TRPC/WS map, Drizzle baseline from `postgres-init.sql`, auth/CORS/forks docs. | |
14 | | -| **1** — Legacy repo hygiene | **Optional** | Only if still editing the old monorepo. | |
15 | | -| **2** — Repo bootstrap | **Done** | Turbo, CI, template DB tests, deploy notes. | |
16 | | -| **3** — REST + Drizzle | **In progress** | All **HTTP** items in TRPC_REST_MAP through **slice 10** (`…/collab-updates`), **Stripe**, **2FA**, membership, crypto bootstrap routes. **Not started:** **live Yjs collab WebSocket** and **realtime** (legacy `realtime-server` / msgpackr — separate from collab). | |
17 | | -| **4** — Client MVP | **In progress** | Same as Phase 4 checklist; **added** MSW + Vitest session POST contracts and `useSession` unit matrix. **Done:** Playwright demo session E2E; **Next:** optional password-login Playwright or Phase 3 collab/realtime WS MVP. | |
18 | | -| **5** — Cutover | **Not started** | Canary, retire `/trpc` when safe. | |
| 7 | +**Last reviewed:** 2026-04-29 |
19 | 8 |
|
20 | 9 | --- |
21 | 10 |
|
22 | | -## Legacy coverage (summary) |
23 | | - |
24 | | -Cross-check [TRPC_REST_MAP.md](./docs/TRPC_REST_MAP.md): **sessions**, **users.account** (incl. Stripe), **users.pages**, **groups** (password/privacy/deletion), **pages** (create/bump/backlinks/snapshots/deletion/move), **collab bootstrap** (`GET`/`POST …/collab-updates`), and **WebSocket parity** for invites/requests/roles/remove/password/email-change/move/make-private are **implemented** on REST. **Removed by design:** user/group **rotate-keys**, **RevenueCat**. |
| 11 | +## Gap to parity (snapshot) |
25 | 12 |
|
26 | | -**Intentional / optional gaps (not bugs):** |
| 13 | +| Area | State | |
| 14 | +|------|--------| |
| 15 | +| **API / REST** | TRPC_REST_MAP HTTP rows largely done; **collab WS** + **realtime** (legacy msgpackr) **not**. | |
| 16 | +| **SPA** | Auth, lists, **`PageEditorView`** (Tiptap+Y+collab REST), groups/**members**/invite/join, notifications **metadata** only. Missing: theme UX, live collab, account/billing/pages ops/group prefs UIs, notification decrypt, native shells. Editor ≠ legacy infinite canvas/note tree until product-aligned. | |
27 | 17 |
|
28 | | -- **Anonymous public read** for `GET /api/groups/:groupId/pages` (legacy optional auth) — still auth-only; add if product needs it. |
29 | | -- **Stripe:** optional `checkout.session.completed` / richer webhook tests. |
30 | | -- **Marketing `vite-ssg`** site — `apps/marketing` (static landing + `Open app` via `VITE_WEB_APP_URL`); deploy doc updated in `docs/DEPLOY_CLOUDFLARE.md`. |
31 | | -- **Legacy `scheduler` / `manager` / standalone `collab-server` & `realtime-server` processes** — not ported; greenfield targets Workers + future WS/DO topology instead. |
| 18 | +**Deferred (confirm vs parity):** optional anon `GET …/groups/:id/pages`; richer Stripe webhook tests. **Infra naming:** Workers/DO replaces standalone collab/realtime/scheduler processes. |
32 | 19 |
|
33 | 20 | --- |
34 | 21 |
|
35 | | -## Phase 0 — exit criteria |
| 22 | +## Phases |
36 | 23 |
|
37 | | -- [x] tRPC + WS → proposed REST/WS names |
38 | | -- [x] OpenAPI from code |
39 | | -- [x] Drizzle + baseline migration vs `postgres-init.sql` |
40 | | -- [x] Auth/CORS + CLIENT_FORKS docs |
| 24 | +| # | Status | Blocking work toward parity | |
| 25 | +|---|--------|----------------------------| |
| 26 | +| **0** | Done | Map, OpenAPI, Drizzle baseline, CLIENT_FORKS | |
| 27 | +| **1** | Skip? | Legacy monorepo only | |
| 28 | +| **2** | Done | Turbo/CI/template DB/deploy docs | |
| 29 | +| **3** | WIP | **Collab WS** + **realtime**; integration tests; [RESTART_PLAN §4.3](../docs/RESTART_PLAN.md) | |
| 30 | +| **4** | WIP | See checklist below | |
| 31 | +| **5** | Todo | Cutover after **parity gate** + metrics + decrypt spot-checks | |
41 | 32 |
|
42 | 33 | --- |
43 | 34 |
|
44 | | -## Phase 3 — REST (compact) |
| 35 | +## Phase 4 — client checklist |
45 | 36 |
|
46 | | -| Area | Session / worker entrypoints (representative) | |
47 | | -|------|-----------------------------------------------| |
48 | | -| Account | `login`, `refresh`, `logout`, `demo`, `POST /api/users`, email verify, email change, password, delete, 2FA routes, billing | |
49 | | -| User prefs | `user-page-prefs.ts` — starting path, recents, favorites, defaults, notifications | |
50 | | -| Groups/pages | `group-permissions`, `group-pages`, `group-password`, `group-privacy`, `group-deletion`, `group-membership`, `group-main-and-members`, `group-invite-crypto-bootstrap`, `user-public-keyring`, `page-operations`, `page-move`, `page-collab-updates`, `stripe-billing` | |
| 37 | +**Required for parity** unless *Deferred* above. |
51 | 38 |
|
52 | | -**Still to build:** WebSocket **collab** (Yjs fan-out, JWT upgrade, room per `pageId`) and **realtime** channel (legacy msgpackr-style live protocol, [RESTART_PLAN §4.3](../docs/RESTART_PLAN.md)); optional Redis hot buffer; integration tests per chosen topology. |
| 39 | +**Done:** typed client, `useSession`, register/login/demo/logout+2FA, home+pages, `PageEditorView`, groups+members+invite/join+crypto, notifications shell, MSW+Vitest session matrix, ESLint restricted imports, Playwright **demo**, `apps/marketing`. |
53 | 40 |
|
54 | | ---- |
| 41 | +**Open:** |
55 | 42 |
|
56 | | -## Phase 4 — client (compact) |
| 43 | +- [ ] Password (registered) Playwright + stronger session/crypto asserts |
| 44 | +- [ ] Theme: persist + `prefers-color-scheme` + toggle (tokens exist in `globals.css`) |
| 45 | +- [ ] Live editing: **collab WS** client + Phase 3 server path |
| 46 | +- [ ] `[parity]` Account / billing / 2FA / email / delete — UIs wired to REST ([TRPC_REST_MAP](./docs/TRPC_REST_MAP.md)) |
| 47 | +- [ ] `[parity]` Page ops + group settings + prefs (recents/favorites/path…) — UIs |
| 48 | +- [ ] `[parity]` Editor UX vs legacy (rich + spatial/world if in scope) |
| 49 | +- [ ] `[parity]` Notifications: decrypt/display as legacy |
| 50 | +- [ ] Legacy **realtime** equivalent (after protocol choice) |
| 51 | +- [ ] Capacitor/Tauri **after web parity** |
57 | 52 |
|
58 | | -- [x] OpenAPI codegen + `openapi-fetch` + `credentials: "include"` |
59 | | -- [x] Router, `useSession`, register/login/demo/logout, 2FA branch |
60 | | -- [x] Home + page list + `PageEditorView` (Tiptap + Yjs + debounced `POST …/collab-updates`) |
61 | | -- [x] `@deepnotes/e2ee`, session keyrings + `passwordSalt` from login |
62 | | -- [x] `/groups`, `/groups/:id`, invite landing `/invite`, join `/join`, membership crypto |
63 | | -- [x] `/notifications` (ciphertext not decrypted in UI) |
64 | | -- [x] MSW: `GET /api/health`, `GET /api/users/me`; ESLint `no-restricted-imports` on `src/**/*.ts` |
65 | | -- [x] MSW + Vitest: session POST routes (`login`, `demo`, `refresh`, `logout`) + `useSession` flows (password login, 2FA flag, demo, logout, bootstrap) |
66 | | -- [x] Playwright: demo session against real `wrangler dev` + Vite (see **E2E / Playwright** below) |
67 | | -- [x] Marketing landing (`vite-ssg`): `apps/marketing` |
68 | | -- [ ] Password-login (or registered-user) Playwright path; optional/crypto assertions beyond cookies |
69 | | -- [ ] Capacitor / Tauri after web MVP |
70 | | - |
71 | | -### E2E / Playwright (detail) |
72 | | - |
73 | | -| Item | Detail | |
74 | | -|------|--------| |
75 | | -| **Spec** | [`apps/web/e2e/session.spec.ts`](./apps/web/e2e/session.spec.ts) — “Try demo”, assert `accessToken` / `refreshToken` **not** in `document.cookie`, `loggedIn` hint present, **reload** then still “Signed in” (refresh + `/me`). | |
76 | | -| **Config** | [`apps/web/playwright.config.ts`](./apps/web/playwright.config.ts) — `webServer`: `pnpm --filter @deepnotes/api-worker dev` (waits on `GET /api/health`) + `pnpm --filter @deepnotes/web dev` on `127.0.0.1:5174`. | |
77 | | -| **CI secrets file** | [`e2e/dev.vars.ci`](./e2e/dev.vars.ci) — copied to `apps/api-worker/.dev.vars` in GitHub Actions (non-production test-only values, same shape as `account-flows.integration.test.ts`). | |
78 | | -| **CI DB** | Job runs `pnpm db:migrate` on the service Postgres **before** lint/test so the worker’s Hyperdrive DB matches the session integration template schema. | |
79 | | -| **Local** | Docker Compose Postgres on **5433** (matches `wrangler.toml` `localConnectionString`), `pnpm db:migrate`, copy `e2e/dev.vars.ci` → `apps/api-worker/.dev.vars`, then `pnpm test:e2e` from repo root. | |
| 53 | +**E2E:** `apps/web/e2e/session.spec.ts` · `pnpm test:e2e` — needs migrated DB + `e2e/dev.vars.ci` → `apps/api-worker/.dev.vars` (see CI + [docs/DEPLOY_CLOUDFLARE.md](./docs/DEPLOY_CLOUDFLARE.md)). |
80 | 54 |
|
81 | 55 | --- |
82 | 56 |
|
83 | | -## Phase 2 & 5 |
| 57 | +## Tests (where to run) |
84 | 58 |
|
85 | | -**Phase 2:** [x] pnpm/Turbo, Compose Postgres+Redis, Wrangler/Hyperdrive doc, CI with template DB + `DATABASE_ADMIN_URL`, real Vitest in `@deepnotes/web`. |
| 59 | +| Package | Command / note | |
| 60 | +|---------|----------------| |
| 61 | +| `@deepnotes/session` | `pnpm --filter @deepnotes/session exec vitest run src/account-flows.integration.test.ts` (+ `.env` DB URLs) | |
| 62 | +| `@deepnotes/web` | `pnpm --filter @deepnotes/web test` (Vitest) | |
| 63 | +| `@deepnotes/api-worker` | 503 matrix env-smoke in `index.test.ts` | |
| 64 | +| Root E2E | `pnpm test:e2e` | |
86 | 65 |
|
87 | | -**Phase 5:** [ ] Staged cutover; decommission legacy when metrics + decrypt spot-checks are green. |
| 66 | +**Follow-ups:** Redis failed-login IT; refresh expiry; optional OpenAPI snapshot CI. |
88 | 67 |
|
89 | 68 | --- |
90 | 69 |
|
91 | | -## Tests & tooling (maintenance) |
| 70 | +## RESTART_PLAN §8 — still open here |
92 | 71 |
|
93 | | -| Package | What runs | Notes | |
94 | | -|---------|-----------|-------| |
95 | | -| `@deepnotes/session` | **`account-flows.integration.test.ts`** — **24** `it()` when `DATABASE_URL` + admin URL set; clones template DB | Account, 2FA, groups/pages, prefs, slices 4–10, membership, collab REST | |
96 | | -| `@deepnotes/db` | `template-db.test.ts` — **6** FK/clone cases | | |
97 | | -| `@deepnotes/api` | `openapi.test.ts`, `schemas/users.test.ts`, … | | |
98 | | -| `@deepnotes/api-worker` | **`index.test.ts`** — **71** route × 503 matrix + **1** extra `email-verification/confirm` 503 | Totals **72** env-missing smoke cases | |
99 | | -| `@deepnotes/web` | Vitest + happy-dom; MSW + `useSession` tests | **34** unit smoke cases (incl. session routes + `useSession`) | |
100 | | -| `@deepnotes/marketing` | `vite-ssg build` → `dist/` | Static landing; `VITE_WEB_APP_URL` for app link | |
101 | | -| **Playwright** | `pnpm test:e2e` (root) → `@deepnotes/web` **1** spec (demo cookies + reload) | Needs migrated DB + `.dev.vars`; CI installs Chromium only | |
| 72 | +**Already met:** OpenAPI + typed client; no tRPC/superjson/RevenueCat/key-rotation ([CLIENT_FORKS](./docs/CLIENT_FORKS.md)); Drizzle + template Postgres IT ([DRIZZLE_MIGRATIONS](./docs/DRIZZLE_MIGRATIONS.md)); web Vitest CI + import restrictions. |
102 | 73 |
|
103 | | -Run session integration (from repo root): |
104 | | -`pnpm --filter @deepnotes/session exec vitest run src/account-flows.integration.test.ts` |
105 | | -(requires `new-deepnotes/.env` with DB URLs as in package README.) |
| 74 | +**Open:** |
106 | 75 |
|
107 | | -**Follow-ups:** Redis failed-login integration; expired refresh JWT; optional OpenAPI snapshot CI drift check; second Playwright spec for email/password registration + login. |
| 76 | +- [ ] Collab **and** realtime: ≥1 integration test each (stack TBD) |
| 77 | +- [ ] Stripe / high-risk: deeper tests when secrets allow |
| 78 | +- [ ] Staging CF: Hyperdrive + Postgres + Redis + WS topology load-tested |
| 79 | +- [ ] E2E beyond demo (password path) |
| 80 | +- [ ] **UI parity** in `@deepnotes/web` (goal above) |
108 | 81 |
|
109 | 82 | --- |
110 | 83 |
|
111 | | -## Success criteria (from RESTART_PLAN §8, condensed) |
| 84 | +## Log (recent) |
112 | 85 |
|
113 | | -- [x] OpenAPI + generated client types; no tRPC/superjson/RevenueCat/key-rotation in this tree; [CLIENT_FORKS](./docs/CLIENT_FORKS.md). |
114 | | -- [x] SQL-heavy flows: template Postgres tests (`@deepnotes/db`, `@deepnotes/session`). |
115 | | -- [x] Drizzle “empty → current” production upgrade doc ([docs/DRIZZLE_MIGRATIONS.md](./docs/DRIZZLE_MIGRATIONS.md)). |
116 | | -- [ ] Collab **and** **realtime** each: ≥1 integration test with chosen deps. |
117 | | -- [ ] Stripe (and other high-risk paths): deeper automated coverage where secrets allow. |
118 | | -- [ ] Cloudflare staging: Hyperdrive + Postgres + Redis + chosen WS topology load-tested. |
119 | | -- [x] Web: Vitest in CI; restricted imports from `apps/web` TS. |
120 | | -- [ ] E2E smoke **complete for client MVP:** demo path [x]; password/session edge cases [ ]. |
| 86 | +| Date | Note | |
| 87 | +|------|------| |
| 88 | +| 2026-04-29 | Compacted doc; parity goal + checklist preserved; condensed tests/E2E. | |
| 89 | +| 2026-04-29 | Full parity as product gate; `[full parity]` rows + Phase 5 parity gate. | |
| 90 | +| 2026-04-27 | TRPC_REST_MAP verified; realtime vs collab WS called out; counts corrected. | |
121 | 91 |
|
122 | | ---- |
123 | | - |
124 | | -## Short log (newest first) |
125 | | - |
126 | | -| Date | Change | |
127 | | -|------|--------| |
128 | | -| 2026-04-29 | MSW handlers + contract tests for session POST routes; Vitest `useSession` matrix (`resetSessionSingletonForTests`); plan progress (+ session integration `it()` count). | |
129 | | -| 2026-04-29 | `apps/marketing` (`vite-ssg` single-page), `docs/DRIZZLE_MIGRATIONS.md`, deploy doc row for marketing + `VITE_WEB_APP_URL`; plan progress. | |
130 | | -| 2026-04-27 | Compacted PLAN_PROGRESS; verified legacy map vs `TRPC_REST_MAP` — HTTP + listed WS flows migrated; added **realtime** vs **collab WS** distinction, optional gaps (public page list, vite-ssg, scheduler). Corrected counts: session integration `it()` tally and **72** worker 503 smokes (71-route matrix + confirm). | |
131 | | -| 2026-04-27 | MSW contract tests + ESLint restricted imports on web `*.ts`. | |
132 | | -| 2026-04-27 | Tiptap + Yjs editor; invite/join E2EE + crypto bootstrap API; members detail UI; notifications thin SPA; groups overview; collab REST + `passwordSalt`; Stripe. | |
| 92 | +Add a row when phase boundaries shift (collab WS, realtime MVP, cutover). |
133 | 93 |
|
134 | | -Add a row for meaningful future milestones (e.g. first collab WS, realtime MVP, cutover). |
0 commit comments