hampter.
documentation · written for a reader who does not code

How this site works.

I run everything you see here: six sections, one program, one server. This page explains what that program does, the decisions behind it, and how I know it still works after a change.

program1 sections6 migrations27 tests · as of 2026-10-051123

What it is

The site is one program written in Rust. A visitor asks for a page, the program reads what it needs from a small database, fills in an HTML template and sends back a finished page. There is no app to install, no front-end framework to keep up with, and no front-end build step: the browser gets the page as the server wrote it.

That choice keeps a page light on a phone on mobile data, and keeps the whole thing small enough for one person to run. Everything below follows from it.

For a technical reader

Rust and Axum, SQLite through sqlx, Askama templates, and HTMX with hx-boost for navigation. Images live in S3-compatible object storage. Sign-in is a WebAuthn passkey or a name and PIN. Five of the six sections share one header and one stylesheet; the drinks games carry their own. 27 database migrations run automatically at startup: 24 for the site's database and 3 for the drinks games' own.

What happens when you open a page

Four steps on one server; the drawings themselves come from object storage.

  1. step 1 The front door nginx handles the encrypted connection, limits how fast anyone can try to sign in, and tells browsers to keep the site's static files for a year.
  2. step 2 The program One Rust binary matches the address to a section and checks whether you are allowed to see it.
  3. step 3 The data Text and numbers come from SQLite on the same machine; drawings come from object storage.
  4. step 4 The page A template is filled in and sent as finished HTML. The one exception is the sorting board, which the browser draws from the day's plan.

The six sections

Five of them share the site's header and stylesheet. Drinks is a separate part of the same program, with its own templates, database and sign-in.

SectionWhat it doesWho can use it
Drawing Portfolio/artportfolio A feed of my drawings, grouped by month and filterable by tag or collection. Anyone. Admins upload.
Drawing Tasks/tasks Practice prompts attached to reference images, filterable by subject, difficulty and type. Anyone can read it. Admins manage it.
Drinks/drinks Four party games in one room — pick a name and PIN, then join with a room code. Live standings, and a big-screen view for the room. Anyone, after picking a name and PIN.
Fitness Tracker/fitness A food log with calorie and macro targets, a week view, and barcode scanning in the phone camera. Signed in, and private per person.
Sorting/sorting Crate sort and van load — a pick checklist, a live loading diagram, and the counts checked against each other. Signed in; built for a tablet.
CV/cv My CV, in Norwegian, with a print-ready PDF. Anyone.

A worked example: uploading a drawing

Uploading used to take 39 seconds. Nothing was removed — the slow work was moved out of the wait.

  1. in the browser On the admin form, the picture is converted to WebP before it leaves the device, so the server never converts what the browser already can.
  2. during the upload The file is stored, the row is written, and the finished card comes back. At this point I can close the tab.
  3. nobody waits A second format, AVIF, is slower to produce, so it is made in the background and used from the next page load. If it fails, the page still works.

The rule I took from it: if a step does not change what the person sees next, it does not belong in the wait. The same rule shapes the rest of the site — images reserve their space before they load, so the page does not jump as they arrive, and the first image on a feed is given priority while the rest load as you scroll.

Who can see what

Sections like the food log hold personal data, so who may see what is decided in one place, and every page behind a sign-in names the rule it uses.

visitor

Sees the public drawings, the practice board, the CV and this page, and can join the drinks games with a name and PIN. A page behind the site's sign-in sends them to sign in.

member

Signs in with a name and PIN on an account the owner created, and gets their own food log and their own sorting plans. A member cannot see anyone else's.

admin

Manages drawings and the practice board: admins upload, caption, tag and set visibility. Being signed in is not enough on its own.

owner

One account. Creates accounts, resets PINs, grants admin. An admin cannot do any of those, so nothing granted can be turned back on the owner.

For a technical reader

Four session extractors, one per rule — OptionalAdmin never refuses, AuthSession wants any account, RequireAdmin an admin, RequireOwner the owner — so picking the wrong one is visible in the handler's signature. A visitor without a session is sent to sign in. A signed-in account that lacks the rule gets a 404 rather than a 403, since a 403 would confirm the page exists. Every function that reads a post takes a required viewer argument, so forgetting it is a compile error rather than a leak. A site account's PIN attempts are counted in the database: 5 wrong ones lock that account for 15 minutes, and a restart does not clear the count.

How I build it

How I use AI. I design the solution first — the data model, the boundaries, the failure cases, what has to be tested — then hand Claude Code a precise brief to implement it. Because I know the technology and where it usually goes wrong, the brief names the right constraints up front, so the first pass lands close and there are few rounds of correction. That keeps both cycle time and token cost low. Review is scaled to risk: I weigh how critical a change is and how likely it is to go wrong. Routine, low-stakes work gets a quick check; anything that reaches live users, touches security or data, or is complex enough to hide errors gets a thorough review — often of the plan, before any code is written.

More about me: CV (in Norwegian).

How I know it still works

A hobby project is where habits are cheap to build. These are the same ones I would bring to a team.

1123 + 458 Automated checks Tests covering sign-in, the database layer, the calorie maths and every game, plus 458 checks on the loading rules of the van board. Counted on 2026-10-05.
2 gates Fast check, full check A check of a few seconds after every small piece of work, and one full run — formatting, linting, the whole test suite — before anything is called done.
tried in a browser Before it counts as finished A passing test proves the code runs, not that the screen is right. Anything a person touches gets opened and used first.

Decisions I would defend

Each one costs something. Knowing what it costs is the point.

Server-rendered HTML instead of a front-end framework Less fashionable, and some interactions take more care to build. In return there is no front-end build step, less dependency churn, and a page arrives complete on a slow connection.
An unlisted drawing is not a secret one Post addresses are sequential, so someone determined could guess an unlisted one. Unlisted means "not in the feed"; anything that must not be seen is hidden instead, and that returns a plain 404.
The day boundary is UTC, not local time Food logged in the first hour or two after midnight lands on the previous day. Accepted knowingly, written down, and cheap to change if it ever matters to someone else.
Static files are cached in the browser for a year A returning visitor does not download an unchanged stylesheet again, but a deploy has to change the address of every file it replaces. For the stylesheet and scripts that happens automatically, and a test fails if a page forgets.
One theme, no light/dark toggle A toggle doubles every visual decision, so one theme gets the care instead. The few screens still on the old light look are listed below.

What I would change

Split the largest modules A few files have grown past what one person reads comfortably in a sitting. They want splitting along the seams the code already has.
Bring the last light screens over /tasks and the sign-in page still wear the site's original light look.
Finish the admin redesign /admin and its accounts page are still the old light pages, and their redesign is planned.

The site by keyboard

From any of the site's own pages, every section is one shortcut away: press the two keys, type a few letters, and press Enter.