Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
18 KiB
Plan: "Notara" — A Private, Superfast, Beautifully-Crafted Notion for Windows 11
Context
You want a personal, single-user Notion replacement for Windows 11 that is fast, not Electron, built on Rust, and — most importantly — a real, polished, installable app with a guided first-run wizard and a genuinely great experience for you. START.md catalogs the entire Notion product, but ~60% of it (SSO, SCIM, teamspaces, sharing, comments, audit logs, the public API, billing, mobile) is multi-user/enterprise and irrelevant here. We keep the hard, valuable core and pour the saved effort into craft: onboarding, microinteractions, keyboard-first flow, templates, and stability.
Confirmed decisions:
- Tauri v2 — Rust backend + web UI in WebView2 (tiny binary, low RAM, not bundled Chromium).
- All 4 pillars in v1: block editor + page tree, databases + views, global search, deep polish.
- Local-first, sync-ready: SQLite on your PC now; pages stored as Yjs CRDTs so self-hosted sync later is plug-in, not rewrite.
- This is a product, not a prototype: a first-run setup wizard, a proper
.msi/.exeinstaller, starter templates, auto-backups, a settings screen, and Notion-grade microinteractions.
Why these tech choices (grounded in current docs):
- BlockNote (
@blocknote/react) is a Notion-style block editor on ProseMirror/TipTap — it hands us the single hardest part of any Notion clone, and is Yjs-native. - Yjs (CRDT) is the page document format from day one → sync later = "attach a provider," no storage rewrite.
- Tauri v2 SQL plugin (SQLite + migrations) for storage; SQLite FTS5 for instant search; Tauri updater + bundler for a real installer and future auto-updates.
"GPU / superfast" reality: no hand-written shaders. Speed = Rust I/O + local SQLite + WebView2's own GPU compositing + a disciplined, virtualized frontend. This beats Notion/Electron on cold-start and RAM. A pure GPU-native editor (egui/GPUI) was rejected — it means building rich text from scratch (months–years), the wrong trade for a solo build.
Architecture Overview
┌───────────────────────────────────────────────────────────┐
│ WebView2 (Windows built-in) — Frontend (TypeScript) │
│ │
│ React + Vite + Tailwind + Framer Motion │
│ ├─ First-run WIZARD (welcome → workspace → theme → │
│ │ templates → done) │
│ ├─ Sidebar (page tree, favorites, trash, search entry) │
│ ├─ Editor = BlockNote ⇄ Yjs (Y.Doc per page) │
│ ├─ Databases = TanStack Table/Virtual (Table/Board/...) │
│ ├─ Side-peek / center-peek for DB rows │
│ ├─ Command palette + quick-switcher (Ctrl+P / Ctrl+K) │
│ └─ Settings (theme, backups, shortcuts, about) │
│ │ @tauri-apps/api invoke() │ │
└──────────────┼────────────────────────────┼───────────────┘
▼ ▼
┌───────────────────────────────────────────────────────────┐
│ Rust core (Tauri v2) │
│ ├─ tauri-plugin-sql → SQLite (pages, blocks, dbs, FTS) │
│ ├─ tauri-plugin-fs → asset files (images, uploads) │
│ ├─ tauri-plugin-updater → future auto-updates │
│ ├─ commands → export, import, backup, heavy search │
│ └─ (LATER) yrs-based self-hosted sync server │
└───────────────────────────────────────────────────────────┘
│
▼
%APPDATA%\Notara\ → workspace.db + \assets\ + \backups\
First-Run Setup Wizard (a headline feature)
On first launch (no workspace.db yet), a polished full-window wizard runs — this is the "wizard and everything" you asked for. It sets workspace_meta.onboarded = 1 when finished so it never re-appears (re-openable from Settings → "Run setup again").
- Welcome — app name, one-line pitch, animated logo; "Get started".
- Workspace — name your workspace; choose data folder (default
%APPDATA%\Notara, changeable); we create the DB + folders here. - Appearance — pick Dark / Light / System; pick accent color; font (Default/Serif/Mono). Live preview pane updates instantly.
- Import (optional) — "Bring your notes": import Markdown/
.mdfolder, or a Notion Markdown+CSV export ZIP, or start empty. Progress bar with counts. - Templates — check the starter pages/databases to seed (see gallery below), or "Empty workspace".
- Done — quick 4-tip cheat sheet (slash
/,Ctrl+P, drag to reorder, right-click menus) → drops you into your new home page.
Starter templates gallery (also reachable later via "New → From template"): Daily Journal, Tasks board (To-do/Doing/Done), Reading list (database), Meeting notes, Project tracker, Quick note. Each is just seed pages/DB rows created in SQLite.
Experience & Polish Principles ("best experience")
These are first-class requirements, verified per milestone — not "nice later":
- Keyboard-first: command palette (
Ctrl+K) for every action; quick-switcher (Ctrl+P); full editing/nav shortcut map; markdown input rules (#→H1,-→bullet,[]→todo). - Microinteractions (Framer Motion, subtle & fast, ~120–180ms): sidebar expand/collapse, page open cross-fade, drag-and-drop blue placement guides, hover-revealed block handles (
+/⋮⋮), toast confirmations, skeleton loaders. - Right-click context menus everywhere (pages, blocks, rows): rename, duplicate, delete, move, copy link, favorite.
- Side-peek / center-peek: open a database row in a side panel (Notion's signature flow) without leaving the list;
Esccloses. - Empty states, not blank screens: every empty page/DB/search shows a friendly prompt + one-click action (Notion's discoverability model).
- Native-feeling chrome: custom title bar, window controls, remembers size/position, opens where you left off, launch-on-startup option, tray icon.
- Instant everywhere: virtualized lists (TanStack Virtual) so a 5,000-row database and a 1,000-page sidebar stay smooth.
- Zero data loss: debounced autosave + crash-safe Yjs persistence + rolling local backups.
Visual Fidelity — an exact, modern Notion-like interface
A hard goal: someone glancing at the screen should read it as Notion. We replicate Notion's actual layout, spacing, type, and color system (a clean-room rebuild of the look & feel — our own code/assets, no copied proprietary files):
- Overall layout: left sidebar (~240px, resizable, collapsible with
<<) + main content area; centered page column (~708px content width, "Full width" toggle expands it); generous whitespace, calm density. - Sidebar look: subtle gray background, small uppercase section labels (Favorites / Private / Shared), page rows with emoji/icon + title, hover-revealed
+and⋮(•••) controls, disclosure triangles for nesting, drag handles. Workspace switcher at top, Search + Settings + Trash near it. - Typography: Notion uses a system UI stack (Inter-like sans) — ship Inter as the default, plus Serif (Lyon-like → Georgia/serif) and Mono page styles; heading sizes and line-heights matched to Notion (H1 ~1.875rem, body ~16px, ~1.5 line-height); "Small text" and "Full width" page toggles.
- Color system (CSS variables, light + dark): near-white
#ffffff/ dark#191919backgrounds,#37352ftext on light /#e9e9e7on dark, Notion's exact block highlight palette (gray/brown/orange/yellow/green/blue/purple/pink/red for text + backgrounds),#2383e2-style blue accents and selection. - Editor chrome: hover block handle (
⋮⋮drag ++insert) in the left gutter,/slash menu styled like Notion's (grouped, icons, search), the bubble/selection toolbar (B/I/U/S, code, link, color), placeholder text ("Type '/' for commands"), the "Press Enter to continue" empty-line feel. - Page header: hover-revealed Add icon / Add cover / Add comment row, large title, breadcrumb bar up top,
Share-less (private) but with•••menu (style, small text, full width, export, move to trash) and updates/history. - Database chrome: view tabs row with
+ New view, right-aligned Filter/Sort/Search/•••/blue New button; table with resizable/reorderable columns, property-type icons, row hover⋮⋮, the blue+ Newrow; Board columns with count badges. - Icons: Lucide chosen to match Notion's line-icon weight; emoji picker for page icons like Notion.
We'll tune this against Notion side-by-side (screenshots from START.md's UI/UX spec) each milestone until it reads as a match. Fidelity is a verification item, not an afterthought.
Tech Stack (pinned)
| Layer | Choice | Why |
|---|---|---|
| Shell | Tauri v2 (+ updater + bundler) | Rust, WebView2, ~10MB, real installer |
| Backend | Rust | Speed; yrs for future sync |
| Frontend | React 18 + TypeScript + Vite | BlockNote is React; best ecosystem for a novice |
| Editor | BlockNote (@blocknote/react, /core) |
Notion-style, Yjs-native |
| Doc format | Yjs | CRDT → sync-ready day one |
| Styling | Tailwind CSS + CSS vars | Theming (dark/light/accent) |
| Motion | Framer Motion | Polished, restrained animations |
| DB grids | TanStack Table + Virtual | Fast virtualized database views |
| App state | Zustand | Tiny client state |
| Storage | SQLite via tauri-plugin-sql (+FTS5) |
Local, instant, migrations |
| Assets/backup | tauri-plugin-fs |
Images/uploads + backup files |
| Icons | Lucide | Clean, Notion-like |
Data Model (SQLite)
Structured metadata in relational tables; page bodies as Yjs binary blobs (editor's source of truth) — keeps tree/search/DB queries fast while keeping rich text conflict-free and sync-ready.
CREATE TABLE workspace_meta ( -- single row: name, data_dir, theme, accent, onboarded, last_page
id INTEGER PRIMARY KEY CHECK (id=1), name TEXT, theme TEXT, accent TEXT,
onboarded INTEGER DEFAULT 0, last_page_id TEXT, settings JSON
);
CREATE TABLE pages (
id TEXT PRIMARY KEY, parent_id TEXT REFERENCES pages(id),
title TEXT DEFAULT '', icon TEXT, cover TEXT,
sort_order REAL, is_favorite INTEGER DEFAULT 0, in_trash INTEGER DEFAULT 0,
created_at INTEGER, updated_at INTEGER
);
CREATE TABLE page_docs ( page_id TEXT PRIMARY KEY REFERENCES pages(id), ydoc BLOB );
CREATE TABLE databases ( id TEXT PRIMARY KEY, page_id TEXT, name TEXT );
CREATE TABLE db_properties ( id TEXT PRIMARY KEY, database_id TEXT, name TEXT, type TEXT, config JSON, sort_order REAL );
CREATE TABLE db_rows ( id TEXT PRIMARY KEY, database_id TEXT, page_id TEXT REFERENCES pages(id), sort_order REAL );
CREATE TABLE db_values ( row_id TEXT, property_id TEXT, value JSON, PRIMARY KEY(row_id, property_id) );
CREATE TABLE db_views ( id TEXT PRIMARY KEY, database_id TEXT, name TEXT, type TEXT,
filters JSON, sorts JSON, groups JSON, visible_props JSON, sort_order REAL );
CREATE VIRTUAL TABLE pages_fts USING fts5(page_id UNINDEXED, title, body);
- Fractional
sort_order→ drag-reorder is a one-row update. - DB rows are pages (Notion's model) → reuse the editor +
page_docsfor row bodies. - FTS mirror updated on save from the Y.Doc's plain text → instant search.
Phased Roadmap
Ships a usable app early, then layers craft. Each milestone runs and is verified independently.
Milestone 0 — Environment, scaffold, installer skeleton (1 day)
- Install prerequisites (below). Scaffold
create-tauri-app(React+TS+Vite). Wire Tailwind, Zustand, Framer Motion, Lucide. - Add
tauri-plugin-sql+tauri-plugin-fs; first migration creates all tables. Custom title bar + window state persistence. - Confirm
npm run tauri buildproduces a working.msi/.exeyou can install. Create projectPLAN.md(this file).
Milestone 1 — First-run wizard + pages + block editor (the core) (2 weeks)
- The wizard (all 6 steps above), gated on
workspace_meta.onboarded. - Sidebar tree: create/rename/delete, drag-reorder & nest with blue guides, favorites, trash + restore, right-click menus.
- Editor: BlockNote bound to a per-page Y.Doc; debounced persist to
page_docs+ FTS mirror; page header (title, emoji icon, cover). - Starter templates seeding.
- Outcome: a real, private note app with onboarding you'd use daily.
Milestone 2 — Search + command palette (3–4 days)
Ctrl+Pquick-switcher;Ctrl+Kcommand palette (all actions); FTS full-text search, instant + keyboard-navigable; empty/no-result states.
Milestone 3 — Databases & views (3–4 weeks; second pillar)
- Inline & full-page databases; property types: text, number, select, multi-select, status, date, checkbox, URL, created/edited time.
- Views: Table (TanStack Table+Virtual), Board (group-by), List, Gallery, Calendar; per-view filters/sorts/groups/column-visibility.
- Side-peek row → full page editor (reuses M1). Row context menus.
Milestone 4 — Deep polish, settings, backups, export/import (2 weeks)
- Settings screen: appearance (theme/accent/font), backups, shortcuts reference, data folder, launch-on-startup, "run setup again", about/version.
- Dark/light/system + accent theming; finalize all shortcuts & markdown rules; motion pass.
- Auto-backups: rolling timestamped copies of
workspace.dbto\backups\(on close + interval); restore-from-backup UI. - Export: page/workspace → Markdown & HTML (Rust command); PDF via WebView print. Import: Markdown folder + Notion export ZIP (also used in wizard).
- Tray icon, launch-on-startup, remembers last page.
Milestone 5 (LATER, optional) — Self-hosted sync + auto-update
- Pages are already Yjs → add a client provider + small
yrs(Rust) self-hosted server, single shared secret. Wiretauri-plugin-updaterfor one-click app updates. No data-model change.
Proposed Directory Structure
D:\Projects\Notion\
├─ PLAN.md
├─ package.json vite.config.ts index.html
├─ src\ # FRONTEND
│ ├─ main.tsx App.tsx
│ ├─ wizard\ # first-run onboarding steps + templates
│ ├─ store\ # Zustand: workspace, ui, theme
│ ├─ db\ # TS data layer over sql plugin / invoke()
│ ├─ editor\ # BlockNote + Yjs binding + persistence hook
│ ├─ sidebar\ # page tree, drag-reorder, context menus
│ ├─ database\ # views: table/board/calendar/gallery/list + peek
│ ├─ search\ # quick-switcher + command palette + FTS
│ ├─ settings\ # settings screen, backups UI
│ └─ components\ # title bar, menus, modals, toasts, empty states
└─ src-tauri\ # BACKEND (Rust)
├─ Cargo.toml tauri.conf.json
├─ migrations\0001_init.sql
└─ src\ lib.rs main.rs commands\ (export, import, backup, search)
First files (M0–M1): src-tauri/src/lib.rs (plugin init + migrations), migrations/0001_init.sql, src/db/index.ts (typed helpers), src/editor/useYjsPage.ts (load blob→hydrate Y.Doc→bind BlockNote→debounced persist+FTS), src/wizard/Wizard.tsx, src/App.tsx, custom TitleBar.tsx.
Prerequisites (Milestone 0 — you run these; prefix with ! in the session or use a terminal)
- Rust via
rustup(https://rustup.rs). 2. Node.js LTS v20+. 3. Microsoft C++ Build Tools (MSVC). 4. WebView2 Runtime (preinstalled on Win11 — verify). The Tauri bundler produces the.msi; WebView2 is auto-bootstrapped in the installer.
Verification (per milestone — prove it actually works)
- M0:
tauri devopens; SQLite insert/read round-trips;tauri buildyields an.msithat installs and launches; custom title bar drags/resizes. - M1: Fresh profile → wizard runs end-to-end, seeds templates, never reappears. Create nested pages, drag-reorder, rich blocks; close & reopen → content persists; kill mid-edit → no loss.
- M2: ~50 pages:
Ctrl+Pand search return correct results <50ms;Ctrl+Kruns actions. - M3: DB with 3–4 property types; switch Table↔Board↔Calendar; filter/sort/group; side-peek a row and edit its body.
- M4: Toggle theme/accent live; export a tree to Markdown and diff; trigger a backup and restore it; import a Markdown folder.
- Perf throughout: cold-start & idle RAM measured vs. Notion (expect large wins); 1k-page sidebar + 5k-row DB stay smooth.
- Fidelity throughout: side-by-side against real Notion screenshots each milestone — sidebar, page column width, type scale, color/highlight palette, block handles, slash menu, and database chrome must read as a visual match.
Risks & Mitigations
- Scope: dropped all multi-user/enterprise; strict phasing; M1 alone is usable.
- Databases (biggest sub-project): isolated to M3; can ship M1–M2 and live in it first.
- Yjs persistence: start with full-state blob per page (simple/correct); move to incremental updates only if a page grows large.
- Rust curve: most logic is TypeScript; Rust ≈ plugin config + a few export/import/backup commands.
- Polish creep: motion/interaction budget fixed (fast, subtle) so it never balloons.
What comes first when building starts
- Scaffold Tauri v2 + React + TS; custom title bar; confirm it launches and builds an installer.
- Wire SQLite migrations + the M1 wizard/editor/sidebar skeleton.
- (Interactive installs of Rust/Node/Build Tools are run by you with
!.)