Project · Salt
Notez
Crystalline structure for the things you keep.
Essence
For the people who use it
Notez is a desktop note-taking application — Windows, macOS, Linux — that treats your notes the way a filesystem treats your files. Every note lives in a hierarchical project tree of unlimited depth. Drag to rearrange, fold to focus, search across everything. It's a place to put the things you want to find again.
The editor is rich without being heavy: tables, code blocks, formatting, attachments, inline images. Open any PDF or Word document straight in a tab with proper zoom and page navigation — no external app, no download. Tabs work the way a browser's do: pinned, preview, drag to reorder, split a pane to compare two notes side by side.
A finished project can be shared with anyone as a public read-only link — no account needed to read, every change reflected immediately, revoke at any time. Teams can also collaborate with proper per-project, per-user permissions. Everything is soft-deleted until you choose to purge, so nothing is ever truly gone by accident.
- Unlimited-depth project trees — drag to reorder, fold to focus.
- Rich text editor built on TipTap — formatting, tables, code blocks, inline images.
- Browser-style tabs — pinned, preview, drag-to-reorder, split-pane side-by-side editing.
- Native file previews — PDF with zoom and page navigation, Word .docx, images, plain text.
- Public read-only sharing — recipients open the project in their browser, no account required.
- Full-text search across nodes, text content, attachments and tags.
- Multi-user collaboration with granular per-project CRUD permissions.
- Soft delete throughout — nothing is destroyed until you deliberately purge it.
- Cross-platform — Windows, macOS, Linux desktop, plus a lightweight browser viewer.
Construction
For the engineers
Stack
- Desktop
- Electron 40 · React 18 · TypeScript · Tailwind · Vite
- State
- Zustand · TanStack Query 5
- Editor
- TipTap 3.17 (ProseMirror), with table support
- Drag & drop
@dnd-kit/core·@dnd-kit/sortable- Tree virtualisation
@tanstack/react-virtual- Previews
pdfjs-dist·mammothfor .docx- Web client
- React 18 + Tailwind + Vite SPA (read-only share viewer)
- Server
- Express 4.18 · TypeScript · Node
- Database
- SQL Server via the
mssqlpackage — raw, parameterised SQL - Security
- JWT HS256 · bcrypt (12 rounds) · Zod validation everywhere
- Testing
- Vitest · Testing Library · Playwright end-to-end
Architecture
npm workspaces monorepo with four packages: @notez/client (Electron desktop),
@notez/server (Express API), @notez/client-web (web sharing SPA), and
@notez/shared (the source of truth for API routes and DTO types). Both clients import the
same shared constants so a renamed endpoint or DTO cannot drift between renderer and server.
Layered server, no ORM. Requests flow routes → controllers → services →
repositories → raw SQL. Zod validates every body, query and route param at the controller boundary.
Repositories use parameterised queries through the mssql driver and map rows into typed
objects. Soft deletes are first-class: every major table carries a deleted_at column and
every query filters it.
Permissions in the JWT. Each user's per-project CRUD rights are encoded in their
token, so the requirePermission() middleware authorises without a database round-trip.
Tokens reissue on permission changes; share-link revocation hits the database on every request to
guarantee instant revocation.
Electron security model. Context isolation is on, node integration is off, and the preload bridge exposes only the API surface the renderer actually needs. File uploads are validated by magic byte, not just by extension. DOMPurify runs on both client and server so any malicious paste-in cannot survive the round-trip.
Notable details
- Tree assembled server-side in a single request, cached client-side in a Zustand
Map. - Tab state — pinned, preview, split panes, unsaved edits — owned by a dedicated Zustand store.
- Per-project file storage layout simplifies backup, deletion and future multi-tenancy.
- Rate limits per endpoint class:
100/minglobal,10/minauth,60/minshare. - Share-link ZIP cap: 500 files, 500 MB.
- Wayland
app_idworkaround for proper GNOME taskbar icons on Linux. - Pre-commit hooks via Husky and lint-staged enforce ESLint + Prettier.
- End-to-end tests via Playwright; single worker for serial execution against a real database.