feat: add packaging, deployment, error pages, and project docs
Phase 7 — Polish: - Error page template with styled 404/403/500 pages - Error rendering helper on Renderer Phase 8 — Packaging & Deployment: - Containerfile: multi-stage build, non-root user, health check, OCI labels with build date and git revision - Makefile: build, test, cross-compile, deb, rpm, container, tarballs, checksums targets - nfpm.yaml: .deb and .rpm package config - systemd service: hardened with NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, RestrictSUIDSGID - Default environment file with commented examples - postinstall/preremove scripts (shellcheck validated) - compose.yaml: example Podman/Docker Compose - Caddyfile.example: subdomain, subpath, and remote proxy configs - CHANGELOG.md for release notes - CLAUDE.md with architecture, conventions, and quick reference Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
845b152f15
commit
1fc42bf1b2
16 changed files with 435 additions and 2 deletions
64
CLAUDE.md
Normal file
64
CLAUDE.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Favoritter — Project Guide
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
go build ./cmd/favoritter # Build
|
||||
go test ./... # Test
|
||||
FAVORITTER_DEV_MODE=true \
|
||||
FAVORITTER_ADMIN_USERNAME=admin \
|
||||
FAVORITTER_ADMIN_PASSWORD=dev \
|
||||
go run ./cmd/favoritter # Run (dev mode)
|
||||
make build # Build with version info
|
||||
make test # Run tests
|
||||
make container # Build container image
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Single Go binary serving HTML (server-rendered templates + HTMX) and a JSON API. SQLite for storage, filesystem for uploaded images. All templates and static assets are embedded via `go:embed`.
|
||||
|
||||
### Directory Layout
|
||||
|
||||
- `cmd/favoritter/` — Entry point, wiring, graceful shutdown
|
||||
- `internal/config/` — Environment variable configuration
|
||||
- `internal/database/` — SQLite connection, PRAGMAs, migration runner
|
||||
- `internal/model/` — Domain types (no logic, no DB)
|
||||
- `internal/store/` — Data access layer (one file per entity, plain SQL)
|
||||
- `internal/handler/` — HTTP handlers for web UI
|
||||
- `internal/handler/api/` — JSON REST API handlers
|
||||
- `internal/middleware/` — HTTP middleware (auth, CSRF, rate limit, etc.)
|
||||
- `internal/render/` — Template rendering with layout support
|
||||
- `internal/image/` — Image upload processing (validate, resize, strip EXIF)
|
||||
- `web/templates/` — HTML templates (layouts, pages, partials)
|
||||
- `web/static/` — CSS, JS, vendored Pico CSS + HTMX
|
||||
- `dist/` — Packaging artifacts (systemd, env file, install scripts)
|
||||
|
||||
### Key Design Decisions
|
||||
|
||||
- **Go 1.22+ stdlib router** — no framework, `http.ServeMux` with method routing
|
||||
- **3 external dependencies** — modernc.org/sqlite (pure Go), golang.org/x/crypto (Argon2id), gorilla/feeds
|
||||
- **`SetMaxOpenConns(1)`** — SQLite works best with a single writer; PRAGMAs are set once on the single connection
|
||||
- **Templates embedded in binary** — `//go:embed` for single-binary deployment; dev mode reads from disk for live reload
|
||||
- **Middleware chain order matters** — Recovery → SecurityHeaders → BasePath → RealIP → Logger → SessionLoader → CSRF → MustResetGuard
|
||||
|
||||
### Database
|
||||
|
||||
SQLite with WAL mode. Migrations are embedded SQL files in `internal/database/migrations/`, applied sequentially on startup. Forward-only — no down migrations.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Norwegian Bokmål** for all user-facing text (templates, flash messages, error text)
|
||||
- **SPDX license headers** on all source files
|
||||
- **Argon2id** for password hashing (never bcrypt)
|
||||
- **UUID filenames** for all uploads — never use user-provided filenames
|
||||
- **Errors**: log with `slog.Error` at the handler level, return generic messages to users — never leak internal errors
|
||||
- **Tests**: use real in-memory SQLite (`:memory:`), set fast Argon2 params (`Memory=1024, Time=1`) in tests
|
||||
- **Session cookie name**: use `middleware.SessionCookieName` constant, never hardcode `"session"`
|
||||
- **CSRF**: auto-included in HTMX requests via `htmx:configRequest` JS hook
|
||||
|
||||
## Hosting
|
||||
|
||||
- Hosted on Forgejo at `kode.naiv.no` — use `fj` CLI, not `gh`
|
||||
- Supports deployment as: standalone binary, .deb package, .rpm package, or container
|
||||
- Reverse proxy (Caddy) may be on a different machine — always use `EXTERNAL_URL` and `TRUSTED_PROXIES`
|
||||
Loading…
Add table
Add a link
Reference in a new issue