How it's built¶
Small on purpose. No servers to patch, no containers to babysit: a SvelteKit app on Cloudflare's edge and a hosted Postgres database. Fewer moving parts means fewer things that break when there's no energy to spare for fixing them.
The shape of it¶
Phone or laptop
- Your browser
Cloudflare Pages
- The app's pages and assets
- SvelteKit server code: session check, page data, form actions, CSV export
Supabase
- Postgres with row-level security on every table
- Auth (email and password)
- Pages render on the server. Each page loads its data on the server using the signed-in user's session, so the browser receives finished pages.
- The database is the gatekeeper. Row-level security in Postgres decides which rows a user can see or change. The app never uses an all-powerful database key.
- Deploys are automatic. Cloudflare Pages builds every push: the main branch goes live, and every other branch gets its own preview address to try changes before they ship.
The stack¶
| Layer | Choice | Why |
|---|---|---|
| App | SvelteKit 2 with Svelte 5 and TypeScript (strict) | Fast pages, little code, server and client in one place |
| Styling | Tailwind 4 on top of hand-made design tokens | Every color in one file, so light and dark stay consistent |
| UI components | Hand-built primitives (button, field, modal, tile, toast) | Accessible by construction instead of patched later |
| Database and sign-in | Supabase: Postgres + Auth | Real SQL, row-level security, no backend server to write |
| Hosting | Cloudflare Pages | Runs at the edge, deploys on push, preview builds per branch |
| Charts | Plain SVG, no chart library | Light, printable, styled by the same tokens |
| Report | HTML plus a print stylesheet | The browser's own "Save as PDF", no PDF library |
| Tests | Vitest (unit) and Playwright (end to end + accessibility) | Critical flows are exercised like a real user would |
Data model¶
Nine tables, built around one idea: an event (something that happened) with things attached to it.
- Events
- Who, what type, when it started and ended, severity from 1 to 10, plus extra fields for types that need them.
- Notes, locations, interventions
- Attached to an event. Notes form the timeline; locations say where; interventions say what was tried and when.
- Event types, body locations, interventions
- The lists you pick from. Built-in defaults and personal additions live side by side.
- Scope tags
- Which interventions belong to which event types. An intervention with no tags appears everywhere.
- Report groups
- Named sets of event types for focused reports (in progress).
Design and accessibility¶
- Design tokens. Every color, radius, shadow and motion timing is a CSS custom property in one file. Components use only those tokens; a lint rule rejects hard-coded colors. Dark mode is the same tokens with different values.
- Color is never the only signal. Severity shows a number as well as a color, and categories have names as well as colors.
- Contrast is tested. Tokens are tuned so text clears WCAG AA contrast in both themes.
- Keyboard and screen readers. Dialogs use the browser's native dialog element, so focus stays inside and Escape closes them; buttons and fields carry proper labels.
- Automated checks. Playwright runs axe accessibility scans on the main screens as part of the test suite.
- Small files. Components stay under 200 lines and services under 300, so each piece does one job.
How changes ship¶
- An issue describes the change.
- Work happens on a branch; Cloudflare builds a preview of it.
- Type checks, linting and tests must pass before a merge request is merged.
- Merging to main deploys to production. Every previous deployment is kept and can be rolled back in one click.
Logbook's predecessor¶
Logbook is the second version of an earlier tracker. The first proved the idea: fast logging, interventions, history and export. It also collected hard-coded colors, oversized components and accessibility warnings. Logbook kept the data model and the good patterns, and rebuilt everything else with stricter rules: tokens only, small files, accessible primitives, tests on the flows that matter.