- Two views of the same photos — a day-grouped **timeline** and a flat **grid** — either one as the site root (`-default-view`); the other lives under `/timeline/` or `/grid/`. 3-column square grid (2 on mobile) with infinite-scroll pagination.
- **Single-day pages** (`/day/<date>/`) linked from each timeline date heading.
- **Albums**: tag photos with free-text, lowercase tags; each tag is an album at `/album/<tag>/`, indexed at `/albums/`, plus a machine-readable `/tags.json`.
- **Single photo pages** with newer/older navigation (arrow keys + touch swipe) and a link to the original.
- **Open Graph / Twitter-card link previews** so shared photo links unfurl.
- **Atom feed** at `/feed.xml`. Gruvbox-dark theme; configurable fonts and identity.
**Content & management (no database)**
-`.toml` sidecars are the source of truth; the binary watches the content dir and rebuilds on any change. Four renditions per photo (original, 600² thumbnail, 1600px medium, 1200px OG), each skipped when already up to date.
- **Web upload** (`/upload`): pick one or many photos, each with its own EXIF-prefilled date, caption and tag-autocompleting tags field; posted with per-photo status and retry.
- **Manage UI** (`/manage`): edit caption/date/tags, bulk tag add/remove, and delete — delete is reversible (moves to `content/.trash/`, with restore / empty).
- Tag autocomplete across the upload and manage forms, fed by `/tags.json`.
**Auth & security**
- App-side **HTTP Basic auth** (bcrypt htpasswd, `-htpasswd`) on every write endpoint; nginx just terminates TLS and proxies. Failed attempts are rate-limited; state-changing requests get a same-origin (CSRF) check.
- A **signed-in indicator** + management toolbar (Upload / Manage / Edit this) appear on every page when authenticated, via a silent `/api/session` probe (no login dialog for anonymous visitors).
- **Android** uploader/manager (Kotlin/Compose, `android/`): pick or share photos, multi-photo bulk upload with captions/dates/tags, plus a Manage screen to edit or delete published posts.
1. Drop `photo.jpg` + `photo.toml` into the content directory (or upload via the web UI at `/upload`, the manage UI, or an app).
2. The binary watches the directory and rebuilds the static site on any change (and on every upload/edit/delete).
3. nginx terminates TLS, serves `public/`, and proxies the dynamic endpoints (`/upload`, `/manage`, `/api/`) to the local API. **Auth is the app's job** now (bcrypt htpasswd via `-htpasswd`), not nginx's.