Stack
The app is one Node process. The browser is a SvelteKit client. Notes are files in a git clone on the server. There is no separate database.
UI
| Piece | Role |
|---|---|
| Svelte 5 | Components, using runes ($state, $derived, $props) |
| SvelteKit | Routes, form actions, server load, and the API under src/routes/api |
| TypeScript | Types for repos, sync status, diffs, and resolve options |
| Vite | Dev server and production build |
| CodeMirror 6 | The editor, with @codemirror/lang-markdown |
| marked | Markdown to HTML |
| vite-plugin-pwa | Web app manifest and a service worker that updates itself |
The file page renders markdown on the client while you edit, so the preview tracks the buffer. The public notebook you are reading is rendered on the server at build time: the preview route is prerendered and has client-side routing turned off, which lets nginx serve those pages as files.
Git and files
isomorphic-git implements clone, fetch, fast-forward, commit, push, and the status matrix inside Node. The HTTP client is isomorphic-git/http/node. The server passes Node's fs into the library. Clones live in data/repos/<id>/.
Two JSON files next to the clones hold app state:
data/repos.jsonis the list of remotes, ids, and content roots.data/settings.jsonholds the author name and email, the git token, the DeepSeek key, the default repo, and favourites.
Both are gitignored. A deploy updates the application code and leaves data/ in place.
AI
DeepSeek is called only from the server, so the API key is not sent to the browser. src/lib/server/ai.ts posts to the chat-completions endpoint and can require a JSON object. Callers are the convert route and the resolve routes.
How a request is split
SvelteKit's Node adapter serves the signed-in app. In production, nginx sits in front.
/previewand the built client assets are files. A guest never needs Node to read this notebook./login,/auth/, and/logoutare proxied to Node, with a tighter rate limit.- Any other path reaches Node only when the session cookie is present. Guests are redirected to
/preview./api/without a cookie returns 401.
The session is an HMAC of the email and an expiry, signed with AUTH_SECRET, in an HTTP-only cookie. Google is used to learn the email. The email must appear in ALLOWED_EMAILS or the callback sends the visitor back here.
What is intentionally absent
- No test runner is configured.
npm run checkissvelte-check. - No SQL database. If it is not a file in the clone or a field in those two JSON files, the app does not store it.
- No git binary. Anything git must do is a function in
src/lib/server/git.ts, which is why a few ordinary git operations are missing on purpose. That is the subject of Challenges.