2026-06-20 20:48:09 +02:00
|
|
|
# Changelog
|
|
|
|
|
|
|
|
|
|
All notable changes to **nuntius** are documented in this file.
|
|
|
|
|
|
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
|
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
|
|
2026-07-26 21:13:02 +02:00
|
|
|
## [development]
|
|
|
|
|
|
|
|
|
|
## [1.1.0] — 2026-07-26
|
|
|
|
|
|
|
|
|
|
### Added
|
|
|
|
|
|
|
|
|
|
- **RISC-V and LoongArch builds** — CI now produces binaries for `linux/riscv64`,
|
|
|
|
|
`linux/loong64`, and `freebsd/riscv64` in addition to the existing four
|
|
|
|
|
targets.
|
|
|
|
|
- **80 % coverage gate** — `just test` and CI enforce ≥ 80 % test coverage on
|
|
|
|
|
`internal/` and `pkg/` packages.
|
|
|
|
|
- **Handler and email test suites** — 22 handler tests covering CORS, rate
|
|
|
|
|
limiting, validation, honeypot, and send/store paths via mock interfaces.
|
|
|
|
|
12 email composition tests covering all four form types.
|
|
|
|
|
|
|
|
|
|
### Changed
|
|
|
|
|
|
|
|
|
|
- **Module migrated to sourcedock.dev** — all imports and documentation now
|
|
|
|
|
reference `sourcedock.dev/petrbalvin/nuntius`.
|
|
|
|
|
- **CI migrated from Forgejo to Gitea** — workflows now live in
|
|
|
|
|
`.gitea/workflows/`, run on the `fedora` runner, and use the standard
|
|
|
|
|
`actions/*` short form.
|
|
|
|
|
- **Dependency bump** — `interpres` updated to v1.1.1.
|
|
|
|
|
- **IPv6-first** — the server now binds `[::]:port` for explicit dual-stack.
|
|
|
|
|
- **Installer rewritten in Python** — `install.py` replaces `install.sh`.
|
|
|
|
|
- **nginx → Caddy** — all documentation and the installer now use Caddy as the
|
|
|
|
|
recommended reverse proxy.
|
|
|
|
|
|
|
|
|
|
### Fixed
|
|
|
|
|
|
|
|
|
|
- **Rate limiter memory leak** — a periodic cleanup goroutine removes expired
|
|
|
|
|
IP entries from the token-bucket map.
|
|
|
|
|
- **Silent template errors** — `compose()` now produces a fallback HTML message
|
|
|
|
|
instead of silently discarding template execution errors.
|
|
|
|
|
- **Silent JSON encoding errors** — all `json.NewEncoder(w).Encode()` calls now
|
|
|
|
|
log errors instead of discarding them.
|
|
|
|
|
- **CI formatting gate** — `gofmt -l` in the test workflow now actually fails
|
|
|
|
|
when it finds unformatted files.
|
|
|
|
|
- **Missing `just fmt` recipe** — added `gofmt -w` target.
|
|
|
|
|
- **Copyright headers** — added to all Go and Python source files.
|
|
|
|
|
|
|
|
|
|
[development]: https://sourcedock.dev/petrbalvin/nuntius/compare/v1.1.0...development
|
|
|
|
|
[1.1.0]: https://sourcedock.dev/petrbalvin/nuntius/releases/tag/v1.1.0
|
|
|
|
|
|
2026-06-20 20:48:09 +02:00
|
|
|
## [1.0.0] — 2026-06-20
|
|
|
|
|
|
|
|
|
|
First stable release of nuntius: a small, opinionated, modular contact form
|
|
|
|
|
backend written in Go. A single static binary, four form kinds out of the box,
|
|
|
|
|
SMTP delivery, a JSONL newsletter log, strict TOML configuration, and env-var
|
|
|
|
|
secrets. Its only dependency outside the standard library is the first-party
|
2026-07-26 20:29:01 +02:00
|
|
|
[interpres](https://sourcedock.dev/petrbalvin/interpres)
|
2026-06-20 20:48:09 +02:00
|
|
|
|
|
|
|
|
### Added
|
|
|
|
|
|
|
|
|
|
- **Server** — `cmd/server`, the HTTP entry point. `http.Server` with explicit
|
|
|
|
|
`ReadHeaderTimeout` (10 s), `ReadTimeout` (15 s), `WriteTimeout` (30 s), and
|
|
|
|
|
`IdleTimeout` (60 s). Graceful shutdown on `SIGINT` / `SIGTERM` with a 15 s
|
|
|
|
|
budget. Structured logging via `log/slog` (JSON handler, INFO level, stdout)
|
|
|
|
|
with one log line per request. `GET /health` endpoint. `--version` flag.
|
|
|
|
|
- **Four form kinds** — `contact`, `feedback`, `newsletter`, and `generic`, each
|
|
|
|
|
with its own endpoint, per-IP rate limit, CORS allowlist, and honeypot field.
|
|
|
|
|
One `POST` + one `OPTIONS` handler per form on a fresh `http.ServeMux`.
|
|
|
|
|
- **SMTP delivery** — stdlib `net/smtp` with `PLAIN` auth, `multipart/alternative`
|
|
|
|
|
HTML + plain text bodies, one dedicated template per form type.
|
|
|
|
|
- **Newsletter JSONL log** — append-only `data_dir/newsletter-<name>.jsonl` with
|
|
|
|
|
crash-safe `O_APPEND` writes; `Count` and `List` skip malformed lines.
|
|
|
|
|
- **`pkg/contactform`** — public Go package with `Request` / `Response` /
|
|
|
|
|
`FieldError` / `ErrorResponse` types and a `Validate` function for all four
|
|
|
|
|
form types.
|
|
|
|
|
- **Per-IP rate limiting** — in-memory token bucket per form, configurable per
|
|
|
|
|
hour.
|
|
|
|
|
- **Per-form honeypot** — silent 200 on bot fill, no mail, no subscriber line.
|
|
|
|
|
- **Per-form CORS** — allowlist enforced on preflight and actual requests, with
|
|
|
|
|
echoed `Access-Control-Allow-Origin` + `Vary: Origin`.
|
|
|
|
|
- **TOML configuration** — parsed by the first-party `interpres` library, with
|
|
|
|
|
strict unknown-field rejection and per-type validation that fails loud on
|
|
|
|
|
typos at startup.
|
|
|
|
|
- **Env-var secrets** — `${VAR_NAME}` / `$VAR_NAME` expansion before the config
|
|
|
|
|
is parsed, so SMTP passwords never live in the file.
|
|
|
|
|
- **Auto-generated config** — a three-form TOML template is written to
|
|
|
|
|
`/etc/nuntius/config.toml` on first start.
|
|
|
|
|
- **systemd unit** — installed inline from `docs/deployment.md` with
|
|
|
|
|
`Restart=on-failure` and `EnvironmentFile=`.
|
2026-07-26 20:44:10 +02:00
|
|
|
- **Install script** — `install.py`, idempotent, handles user creation, config
|
2026-06-20 20:48:09 +02:00
|
|
|
generation, and secrets file mode `0600`.
|
|
|
|
|
- **docs/** — `architecture.md`, `configuration.md`, `api-reference.md`,
|
|
|
|
|
`deployment.md`, `security.md`, `library-usage.md`.
|
|
|
|
|
|
2026-07-26 21:13:02 +02:00
|
|
|
[1.1.0]: https://sourcedock.dev/petrbalvin/nuntius/releases/tag/v1.1.0
|
|
|
|
|
|
2026-07-26 20:29:01 +02:00
|
|
|
[1.0.0]: https://sourcedock.dev/petrbalvin/nuntius/releases/tag/v1.0.0
|