A private, end-to-end encrypted journal. Keep a notebook for each thing you write (a diary, poems, quotes, letters) in a calm editor, readable only by you. Everything is encrypted in your browser; the server and database only ever hold ciphertext.
Try it: you-topia.vercel.app. Signup is open and free.
- Zero-knowledge encryption. Your password never leaves the device. It is stretched with Argon2id in the browser and used to unwrap the keys that encrypt every notebook, page and setting.
- Notebooks of pages. One notebook per thing you write, each with its own icon and colour. No streaks, moods or tags: writing here isn't a score.
- A calm editor. WYSIWYG with Markdown shortcuts, stored as Markdown. Serif or sans, adjustable text size and page width, plain, ruled, dotted or grid paper.
- Vaults. Lock any notebook behind an extra passphrase.
- Recovery key. Reset a forgotten password without anyone, including the server operator, being able to read your journal.
- Works offline. Installable PWA with an encrypted on-device cache and an outbox that syncs when you're back online.
- Your data, portable. Encrypted
.youtopiabackups and plain JSON export, importable into any account or deployment. - Devices and activity. See and revoke sessions; a security log of sign-ins and key changes.
Browser (trusted) Server (untrusted for content)
password ── Argon2id ──► key-encryption key stores: usernames, salts,
│ peppered verifiers,
▼ encrypted envelopes
master key ──► notebook keys ──► AES-GCM envelopes ──────────►
The server can see usernames, record counts, sizes and timestamps; it cannot see titles, text, notebook names or settings. A strict CSP with no third-party origins limits what served JavaScript can do. The full design and its limits are in Crypto design and the Threat model.
Requires Bun 1.3+ and Node 22+.
git clone https://github.com/avi1o1/YouTopia.git && cd YouTopia/code
bun install
cp .env.example .env # set AUTH_PEPPER; STORE=memory runs without a database
bun dev # http://localhost:5173Generate a pepper with
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))". For a local
MongoDB instead of the in-memory store, run bun run db:up and set STORE=mongo.
| Command | |
|---|---|
bun run check |
lint, typecheck and all tests |
bun run test |
Vitest (use this, not bun test) |
bun run format |
Biome formatter and safe fixes |
bun run build |
web bundle and self-host server bundle |
- Vercel + MongoDB Atlas (the free tiers are enough)
- Docker or bare Node
- Configuration and secrets
Any database can back the API by implementing the storage port; see Porting.
code/
apps/
web/ React SPA (Vite, TipTap, Tailwind)
api/ Hono API, storage port with MongoDB and in-memory adapters
packages/
crypto/ KDF, key hierarchy, envelopes (pure, no I/O)
protocol/ HTTP contract as zod schemas, shared by client and server
domain/ encrypted payload schemas and migrations
backup/ encrypted and plain export/import
docs/ architecture, security, data model, ADRs, operations, roadmap
Start with docs/README.md and Architecture. Every significant decision has a short record in docs/adr.
Bug reports, ideas and pull requests are welcome. Read CONTRIBUTING.md first; it covers setup, conventions and what is deliberately out of scope.
Please report security vulnerabilities privately through GitHub's Security → Report a vulnerability form rather than a public issue.
GNU Affero General Public License v3.0. If you run a modified version as a network service, you must offer its users the corresponding source code.