fix: preserve all tags on upload and return empty array on no match
Tags beyond the first were silently dropped because `r.FormValue("tags")`
returns only the first value when the frontend sends each tag as a
separate FormData field. Changed to `r.Form["tags"]`.
Nil slices in API responses (`var images []Image`) marshalled to JSON
`null`, causing a TypeError in the Svelte template (`null.length`),
making "Loading..." persist forever. Initialized all API-facing slices
with `make()` so they marshal as `[]`.
💘 Generated with Crush
Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 15:16:05 +0200
feat: implement core backend API and SvelteKit SPA Full MVP implementation of the weimar media repository: - CLI commands for user CRUD, image deletion, password reset - HTTP API with auth (cookie sessions), upload, browse, download, thumbnail serving, and tag autocomplete - SQLite-backed storage with migrations - Hash-partitioned disk storage with EXIF stripping and thumbnails - SvelteKit SPA with login, upload, browse grid, and image detail pages - Makefile build flow: SvelteKit build -> Go embed -> single binary
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 14:03:41 +0200
feat: initial project scaffolding Single-binary media repository for home servers — Go backend with embedded SvelteKit SPA. - Cobra CLI with viper config (TOML, env vars WEIMAR_*, flags) - Commands: serve, users, image, version - HTTP server with Go 1.22+ ServeMux, API route stubs, SPA fallback - SvelteKit frontend with adapter-static (SPA mode, 5 routes) - Build pipeline: Makefile, GoReleaser, UPX compression - ldflags-based version and build date injection 💘 Generated with Crush Assisted-by: Crush:deepseek-reasoner
Maxwell Jensen maxwelljensen@posteo.net
Wed, 13 May 2026 11:05:44 +0200