Adds the decision half of the app updater. Detection (P2) and the snapshot-first apply/revert (P3) were already real, but nothing ever pressed the button — every update waited for a click. CFG_<APP>_UPDATE_TYPE=auto|manual per app, default auto (33 templates) CFG_UPDATER_AUTO=true|false master switch, default true updaterAppPolicy resolves the two the way backupResolveStrategy already resolves backup strategy: the global switch can only make things more manual. updaterApplyAuto runs at the end of `updater check` and enqueues the ordinary updater_apply task for each auto app that has an update — never applies inline, so an automatic update is the same code path, task log, History entry and Roll back button as a manual one. Safety: each attempt stamps its target digest under generated/auto/, so a build that fails is rolled back and then left alone rather than retried on every scan; in-flight updater tasks are skipped so scans can't stack. Tracked end to end: updates.json carries each app's resolved update_type, History entries carry trigger=manual|auto. The WebUI says whether updates install themselves, chips only the apps that opted out, labels automatic history, and — since an auto app's pending update needs no decision — keeps it off the Overview board's "Needs action" view. Also fixes artifactApplyAuto enqueueing without --detach: it runs inside the single-threaded task processor's own poll, so following the new task in the foreground waits for a task that cannot start until it returns. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MoneyApp
Self-hosted money management for one or more users in a household. Recurring rules, projected ledger, budgets, savings goals + compound-interest calculator, and a 12-month forecast with what-if sliders.
Stack: Next.js 15 + SQLite (Drizzle ORM) + Auth.js. Runs as a single Docker container.
Requirements
- Docker 20.10+ with Compose v2 (
docker compose versionshould print v2.x or v5.x) - Port 3000 free on the host
Install
# 1. From inside the MoneyApp folder, create the environment file
cp .env.example .env
# 2. Edit .env and set AUTH_SECRET to a random 32-byte string.
# Generate one with:
echo "AUTH_SECRET=$(openssl rand -base64 32)" >> .env
# 3. Build and start
docker compose up -d --build
The first build takes 3-5 minutes (it compiles better-sqlite3 natively and runs next build inside the container). Subsequent starts are instant.
Open http://localhost:3000 and sign up. The first account becomes the household owner.
Daily commands
| What | Command |
|---|---|
| Start | docker compose up -d |
| Stop | docker compose down (data preserved) |
| Logs | docker compose logs -f |
| Restart after pulling new code | docker compose up -d --build |
| Shell inside container | docker compose exec moneyapp sh |
Updating
Replace the source folder with the new version (keep your .env and the moneyapp-data Docker volume), then:
docker compose up -d --build
Migrations run automatically on container start.
Backup
The entire database is one SQLite file at /data/moneyapp.db inside the container, mounted from the named volume moneyapp-data.
# Snapshot
docker compose exec moneyapp sh -c 'cat /data/moneyapp.db' > backup-$(date +%F).db
# Restore (with the app stopped)
docker compose down
docker run --rm -v moneyapp_moneyapp-data:/data -v "$PWD":/host alpine \
sh -c 'cp /host/backup-2026-05-07.db /data/moneyapp.db'
docker compose up -d
Accessing from other devices on the LAN
By default the container listens on 0.0.0.0:3000, so from the same network just use the host's IP: http://<host-ip>:3000. For HTTPS or remote access, put a reverse proxy (Caddy, Traefik, nginx) in front.
If you do put it behind a domain, update AUTH_URL in .env to the public URL — Auth.js uses it to construct callback URLs.
Troubleshooting
set AUTH_SECRET in .envonup— you skipped step 2 above. Create.envand setAUTH_SECRET.- Port 3000 already in use — stop whatever else is on 3000, or change the host-side port in
docker-compose.yml(e.g."3001:3000"). - Database looks empty after a rebuild — that means the volume was removed.
docker compose downkeeps it;docker compose down -vdeletes it. Restore from a backup if needed.
Project layout
MoneyApp/
├── Dockerfile multi-stage build (deps → build → runtime)
├── docker-compose.yml service + volume definition
├── .dockerignore
├── .env.example template; copy to .env and fill in
├── README.md
└── app/ the Next.js project
├── src/ application code
├── drizzle/ generated SQL migrations
├── public/ static assets
├── package.json + lock
└── *.ts/.mjs build configs (tsconfig, tailwind, postcss, etc.)
The deployment files stay at the root so it's clear what the installer interacts with. Everything inside app/ is the application itself — the Dockerfile copies it in during the build.