Skip to content

ToDo

This document tracks actionable items that are not yet captured in an issue. Completed items are removed — history lives in git.

1.0.0

Documentation

  • [x] Replace drawio diagrams (docs/assets/architecture_*.drawio.svg) with Mermaid diagrams embedded directly in docs/ARCHITECTURE.md so they can be maintained without a separate diagramming tool
  • [x] Architecture diagram
  • [x] User documentation (API consumers)
  • [x] Developer documentation (contributors)
  • [x] Administrator documentation (installation and operations; cover creating a dedicated snackbox system user/group and running the binary under it)
  • [x] Add package-level comments plus exported type/method docs to key server packages (config, database, middleware, handlers, router) so go doc surfaces meaningful context in IDE hovers
  • [x] Document how to preview the API via godoc (e.g. godoc -http=:6060) inside docs/DEVELOPER.md so contributors can discover it without digging through issues

Deployment

  • [x] Provide example systemd service file (incl. recommended FHS paths as env vars and User=snackbox/Group=snackbox)
  • [x] Dockerfile (run as non-root snackbox user via USER instruction)
  • [x] docker-compose.yml

Release

  • [x] CI/CD pipeline (boilerplate already there)

Testing

  • [ ] Replace the placeholder cmd/server/main_test.go with a real smoke test that starts the server on an ephemeral port, hits /healthz, exercises the metrics mux, and shuts everything down via context cancel
  • [x] Consolidate withUserContext (users_test.go) into withUserID (posts_test.go) — both helpers in package handlers_test do the same thing; delete withUserContext, replace its call-sites with withUserID, and move withUserID + withUserRole to handlers_test.go so they are obviously available to all files in the package
  • [ ] Fix shared-state ordering dependency in TestUserHandler_FindAll — the "empty list" and "returns all users" subtests share the same outer repo; give each subtest its own isolated DB/repo like the "limit capped at 100" subtest already does
  • [x] Trim TestLoggingMiddleware — the three status-code subtests (200, 404, 500) exercise the same code path; one is sufficient; keep the TestLoggingMiddleware_RemoteAddr test as-is
  • [ ] Fix weak assertion in TestRouter_AdminAuthorRoutes_AllowedRoles — routes are hit without a body so they return 400 (bad request), which satisfies the != 401/403 check but proves nothing; either supply minimal valid bodies per route or remove the test (the auth matrix is already covered by the no-auth and wrong-role router tests)
  • [ ] Add admin-override subtest to TestPageHandler_Update_Ownership to match the equivalent three-subtest structure in TestPostHandler_Update_Ownership
  • [x] Add .golangci.yml and enable paralleltest and thelper linters — all tests already use isolated in-memory DBs and t.TempDir() so adding t.Parallel() to the ~80 top-level test functions is safe and will cut CI test time significantly on multi-core runners; thelper prevents helper functions from regressing on missing t.Helper() calls
  • [ ] Add focused unit tests for internal/metrics (path normalization/status helpers), internal/config (env fallback/validation), and the error branches in internal/database.RunMigrations to close the remaining coverage gaps
  • [x] Add a race-enabled test target (e.g. make test-race wrapping go test -race ./...) so developers can catch data races locally before CI

Tooling

  • [x] Expand .PHONY coverage for every developer-facing target and reorganize the Makefile into clearly labeled sections (build, test, run, tooling)
  • [x] Add a discoverable make help target that prints concise descriptions for all public targets and highlights daily vs pre-PR workflows
  • [ ] Centralize development environment variables (JWT secret, admin creds, DB path, port) via a shared include or variable block used by run and smoke targets to eliminate duplication
  • [ ] Provide a make setup (or install-tools) target that verifies required CLIs (golangci-lint, hurl, etc.) and gives clear install guidance
  • [ ] Enhance test targets so make test produces coverage artifacts under build/coverage and supports a FAST=1 flag to skip expensive smoke tests when needed
  • [ ] Replace arbitrary test data identifiers (e.g. smoke-tag, smoke-post, smoke-author@example.com) in test/*.hurl with well-known patterns such as RFC 2606 names (Alice, Bob) and reserved domains (alice@example.com) to improve readability and intent
  • [x] Rename the Hurl-based smoke workflow (e.g. make smoke target and docs) to an "API"/"integration" label so Go-based smoke tests own the name; be sure to update documentation and CI references alongside the rename
  • [ ] Harden dev-server lifecycle management (controllable port, graceful teardown/trap, no manual lsof cleanup) for run/smoke
  • [ ] Add Docker convenience targets (e.g. docker-run, docker-compose-up, docker-compose-down, docker-logs) to streamline parity environments
  • [ ] Update README and docs/DEVELOPER.md quickstart sections to showcase the improved Makefile workflow (make setup && make run, etc.)
  • [x] Configure golangci-lint (e.g. enable revive's doc-comments rule) so CI fails when exported identifiers lack documentation
  • [x] Add a make fmt (or make format) target that runs go fmt ./... (and optionally goimports) so contributors can auto-format before committing
  • [ ] Extend README quickstart with a native Go workflow (using make run / make unit) so contributors who skip Docker know the supported steps

Optional / To Evaluate

  • [ ] Investigate pinning developer tooling versions (e.g. golangci-lint, hurl) via a tools/tools.go pattern or alternatives like Mage/Just; document the recommended approach before enforcing it in CI

Optional

  • [ ] Startup and shutdown banner — the server currently emits plain log.Println lines on start and stop. Replace with a short, single-line banner that surfaces key runtime facts (listen address, database path, version). Avoid ANSI color codes or multi-line ASCII art — they break line-oriented log collectors (Loki, Fluentd, CloudWatch). If a version string is included, embed it at build time via -ldflags "-X main.version=…" so the binary is self-describing without requiring a separate file
  • [ ] Lightweight feature flags

2.0.0

Features

  • [ ] Add an editor role — can manage any post/page regardless of author. Requires: new role in DB CHECK constraint + ValidRole, updated router guards, migration, and test coverage
  • [ ] Multiple authors per post/page — replace single author_id with a post_authors / page_authors join table. Requires: migration, updated models, syncAuthors helper, handler + OpenAPI changes, and tests
  • [ ] MariaDB as an alternative database backend (recommended for Kubernetes). Introduce DATABASE_DRIVER env var (sqlite3 default, mariadb opt-in); abstract driver-specific setup in database.New(); use dialect-specific migration directories or golang-migrate
  • [ ] Images for tags — add optional image_url TEXT column to tags (migration), expose in Tag / TagInput models, update OpenAPI + validation + tests
  • [ ] CLI flags for configuration — add flag or cobra layer so operators can pass --config, --listen-addr, --database-path; flags take precedence over env vars
  • [ ] S3-compatible media storage backend — add MEDIA_BACKEND env var (local default, s3 opt-in) with S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY; replace local disk writes in handlers/media.go with an S3 client. Recommended backend for Kubernetes deployments (e.g. Garage)
  • [ ] Kubernetes manifest or Helm chart — recommended stack: MariaDB + S3 media (e.g. Garage). Resources: Deployment, Service, ConfigMap, Secret, Ingress. Depends on MariaDB backend + S3 media items above and rootless + FHS path items from 1.0.0 Deployment
  • [ ] Scheduled publishing — allow posts/pages to define a future publish timestamp so content goes live automatically; implement via publish_at plus an explicit snackbox publish-due admin command suitable for cron or Kubernetes CronJobs before considering a dedicated worker model
  • [ ] Social-post automation — when content is published, auto-generate and send shareable snippets to X/Twitter, LinkedIn, Facebook, Instagram, and especially Mastodon (highest priority). Build this on top of publish events/webhooks and provider adapters rather than coupling network calls directly into the core request path; requires provider credentials, per-network formatting, opt-in settings, and retry-safe delivery
  • [ ] Explicit admin subcommands — add dedicated CLI entry points such as snackbox migrate, snackbox create-admin, snackbox seed-fixtures, snackbox publish-due, and snackbox backup so one-off operational tasks are not coupled to web-server startup
  • [ ] Backup command — add snackbox backup to create operator-friendly backups of the database and media directory, with a format that works for both local storage and future MariaDB/S3-backed deployments
  • [ ] Outbound webhooks/event hooks — emit structured publish/update/delete events to operator-configured endpoints so external automation can react without polling; define this as the primary integration boundary for downstream automations; include signing/verification and retry-safe delivery
  • [ ] Redis-backed shared state — add Redis as an attachable backing service for cross-instance rate limiting, caching, lightweight analytics buffering, or future coordination so replicas do not depend on in-memory process-local state
  • [ ] Lightweight content analytics — let users see which posts/pages are most popular and basic trends without turning Snackbox into a full analytics platform. Prefer aggregated counters/top-lists and optional batched writes or Redis-assisted buffering over raw per-request event storage in the primary database