This updates gallery handling to support video playback with generated poster thumbnails, adds authenticated admin upload/delete flows, and improves dev/runtime behavior including reliable thumbnail generation and media-safe response handling. Co-authored-by: Cursor <cursoragent@cursor.com>
Technical Kiwi Limited — Website
A small business site built with Go, templ (server-side HTML templates), and HTMX for gallery interactions.
Requirements
- Docker and Docker Compose
Quick start
cp .env.example .env # optional SMTP settings
make dev # live reload → http://localhost:7331
Make targets
| Target | Description |
|---|---|
make dev |
Dev with Air + templ browser live reload (default) |
make build |
Build production website image |
make up |
Run production website service |
make down |
Stop compose services |
make generate |
Run templ generate in dev container |
make tidy |
Run go mod tidy in dev container |
make logs |
Follow dev container logs |
Features
- Single-page layout: hero, services, gallery, contact
- Gallery loads via HTMX (
hx-get="/gallery") - Lightbox modal with previous/next navigation
- Contact form with SMTP relay (HTMX submit, no page reload)
- Serves photos from
app/images/(not in git — mount or copy locally) - Password-protected gallery admin at
/admin/
Gallery admin
Set both ADMIN_USER and ADMIN_PASSWORD in .env, then open http://localhost:8080/admin/ (or via your public URL).
- Sign in with username/password
- Upload JPEGs into an album (or create a new album folder)
- Delete images (removes originals and generated thumbs/hero)
- Changes appear on the public site immediately
Contact form (SMTP)
Set relay details in .env:
| Variable | Description |
|---|---|
SMTP_HOST |
Relay hostname (required) |
SMTP_PORT |
Port (default 587) |
SMTP_USER / SMTP_PASSWORD |
Auth if your relay requires it |
SMTP_FROM |
Envelope/header From address (required) |
SMTP_TO |
Where contact messages are delivered (required) |
SMTP_TLS |
auto, tls (465), or plain (25/local relay) |
If SMTP is not configured, the page shows a mailto fallback instead of the form.
Dev container
make dev mounts ./app and your host Go caches (~/go/pkg/mod, ~/.cache/go-build by default). Override with GOMODCACHE / GOCACHE in .env.
Use http://localhost:7331 in the browser — the templ proxy injects live reload on .templ, .go, and .css changes. Port 8080 hits the app directly without auto-reload.
Only run dev or website at a time if you map both to the same host ports.
Production website mounts ./app/images into the container (photos stay on the host). It joins the external caddy Docker network for reverse proxy labels.
Project layout
app/
cmd/server/ HTTP server entrypoint
internal/gallery/ Scan and sort images from disk
internal/contact/ Form validation
internal/mail/ SMTP relay
internal/handlers/ Routes and HTMX partials
templates/ templ components (.templ → generated Go)
static/ CSS
images/ Gallery photos (served at /images/)
Dockerfile Production image
Dockerfile.dev Dev image (Go + templ + Air)
docker-compose.yaml
.env.example
Gallery images
On startup the server generates missing derivatives under app/images/thumbs/ (and hero/ for JPEGs only). Photos get resized JPEG thumbs; videos (.mp4, .webm, .mov) get a poster frame JPEG via ffmpeg when installed. The lightbox plays full videos or shows full-resolution photos. Derivatives are gitignored and rebuilt when source files are newer.
Deploy notes
First request after deploy may take a moment while thumbnails are generated under the mounted app/images/ directory.