# photogallery Personal static photo gallery with Atom feed and upload API. Single-user. No database, no framework — just a Go binary that watches a directory and regenerates a static site. ## Architecture ``` content/ # images + .toml sidecars (source of truth) public/ # generated output (served by nginx / --serve flag) templates/ # embedded HTML templates static/ # embedded CSS ``` The binary does three things at once: - Watches `content/` via fsnotify and rebuilds on any change - Serves a multipart upload API at `POST /upload` - In dev mode (`--serve`), also serves `public/` as static files In production nginx sits in front: serves `public/` directly, proxies `/upload` to localhost, htpasswd on the upload endpoint. ## Stack - **Go** — stdlib + `BurntSushi/toml`, `fsnotify/fsnotify`, `golang.org/x/image` - **Templates** — `html/template`, embedded via `embed.FS` - **Images** — centre-crop to square, Catmull-Rom resize to 600×600 JPEG thumbnails - **Feed** — Atom (`encoding/xml`) - **NixOS** — `flake.nix` + `module.nix`, exports `nixosModules.default` ## Sidecar format ```toml caption = "Tempelhof at sunrise" date = "2026-06-14" ``` Missing sidecar → filename as caption, today as date. ## Design - Gruvbox dark hard colour scheme - Vollkorn (serif) for headings and captions - Manjari for Malayalam text (bio line) - 3-column square grid → 2-column on mobile - Single photo page with sidebar ## Running locally ```bash nix develop go mod tidy go run . --serve # gallery: http://localhost:8080 # upload: http://localhost:8080/upload ``` ## NixOS module usage ```nix inputs.photogallery.url = "github:youruser/photogallery"; # in modules: inputs.photogallery.nixosModules.default # in configuration.nix: services.photogallery = { enable = true; baseURL = "https://photos.yourdomain.tld"; nginx = { enable = true; domain = "photos.yourdomain.tld"; htpasswdFile = "/etc/nginx/.htpasswd-gallery"; }; }; ``` ## Bootstrap (first nix build) ```bash go mod tidy # generates go.sum — commit it nix build # fails, prints correct vendorHash # paste hash into flake.nix nix build # succeeds ``` ## Key files | File | Purpose | |---|---| | `main.go` | Flags, wires generator + watcher + server | | `generator.go` | Scans content dir, renders HTML + Atom feed, generates thumbs | | `server.go` | Upload API + optional static file serving | | `watcher.go` | fsnotify watcher with 500ms debounce | | `assets.go` | `//go:embed` for templates and static | | `module.nix` | NixOS module (systemd service, tmpfiles, nginx vhost) | | `flake.nix` | `buildGoModule` package + devShell + nixosModules | ## What's not done yet - ActivityPub federation (planned later — start with RSS/Atom) - Multi-image upload - Delete/edit via UI - Any auth beyond nginx htpasswd