Repository navigation
Add GOBLOG_DATA_DIR: one directory for everything goblog writes - #661
Conversation
goblog writes .env, the SQLite file, uploads and installed plugins and themes into its working directory, next to the files it ships with. In a container that means the documented quick start loses the whole site when the container is replaced, and keeping it takes a bind mount per path. With GOBLOG_DATA_DIR set, all of those live under that directory, so one volume keeps the site. A relative SQLite path is resolved inside it; absolute paths and THEMES_INSTALLED_DIR are left alone. Unset, every path is what it was, so existing installs are unaffected. The install smoke test now runs with a data volume and replaces the container half way through, checking the site, its settings and an uploaded file are still there. A fourth job covers the old layout. Closes #653. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The include entry only added a key to the existing sqlite job, so the matrix ran sqlite without a data directory and never with one. Making legacy a matrix key gives the include its own job. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The CI matrix include merges legacy into the existing sqlite combination instead of adding a fourth job, so the SQLite-on-a-volume scenario central to #653 is never smoke-tested.
Review effort: Balanced
Findings: 1
What changed in this PR
This PR introduces a GOBLOG_DATA_DIR environment variable and a small datadir package so that everything goblog writes at runtime (.env, the SQLite database, uploads, installed plugins, and installed themes) can live under a single directory. The goal (issue #653) is that a Docker user can keep one volume and not lose their site when the container is replaced on an image upgrade. When unset, every path stays exactly as before, so existing deployments are unaffected.
Changes:
- New
datadirpackage (Dir()/Path()) that prefixesGOBLOG_DATA_DIRfor relative paths, leaving absolute paths untouched; wired into.env, SQLite, uploads, plugin, and theme paths. - Uploads are written under
<data>/uploadsand served at/uploads(falling through towww); the data directory is created at startup. - README quick-start updated to use the volume, and the install smoke test / CI matrix extended to cover container replacement on a volume plus a legacy (no data dir) layout.
| File | Description |
|---|---|
datadir/datadir.go |
New package resolving writable paths under GOBLOG_DATA_DIR. |
datadir/datadir_test.go |
Unit test for Path() (relative, absolute, unset). |
goblog.go |
Routes .env, plugin dirs, and uploads serving through datadir; creates the data dir at startup. |
db.go |
Opens the SQLite file via datadir.Path. |
admin/admin.go |
Writes uploads to <data>/uploads when a data dir is set. |
theme/theme.go |
InstalledRoot now resolves under the data dir (unless THEMES_INSTALLED_DIR set). |
wizard/wizard.go, auth/auth.go, blog/blog.go |
.env loads/writes go through datadir.Path (keeping local.env fallback). |
scripts/install-smoke-test.sh |
Runs on a volume, replaces the container, uploads a file, and verifies persistence; legacy mode restarts instead. |
.github/workflows/install-smoke.yml |
Adds a legacy matrix entry and passes GOBLOG_SMOKE_LEGACY. |
README.md |
Documents GOBLOG_DATA_DIR in the Docker quick start and plugins section. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Closes #653.
Problem
goblog writes its state into its working directory, mixed in with the files it ships:
.env, the SQLite file,www/uploads,plugins/wasm,plugins/dynamicandthemes/installed. The documented quick start (docker run -p 7000:7000 compscidr/goblog:latest) therefore loses the whole site when the container is replaced, and keeping it takes one bind mount per path.Change
New
datadirpackage andGOBLOG_DATA_DIRenvironment variable. When set, everything goblog writes lives under it:GOBLOG_DATA_DIR=/data.env./.env/data/.env./goblog.db/data/goblog.db./www/uploads//data/uploads/, served at/uploads./plugins/{wasm,dynamic}//data/plugins/{wasm,dynamic}/./themes/installed//data/themes/installed/THEMES_INSTALLED_DIRstill wins for themes.The README quick start becomes:
Smoke test
The install smoke test now runs the container that way, uploads a file during the wizard, then removes the container and starts a new one on the same volume, and checks the site, its title and the upload are still there. A fourth CI job (
sqlite, no data directory) keeps covering the old layout with a restart.Testing
go test ./...passes, including a newdatadirtest.Not covered
datadir.Path, but the smoke test does not install one, so those two paths are untested end to end./wp-content/uploads, the WordPress-compatibility route, still reads only fromwww.local.env, the development fallback, is still read from the working directory.goblog-site-theme) still shows the old one-linedocker run.🤖 Generated with Claude Code