Skip to content

Howto Migrate to multi user

root edited this page Apr 19, 2026 · 1 revision

How to migrate to multi-user mode

Bindery v1.0 runs migration 019_multiuser.sql on first startup. This adds owner_user_id to every user-owned table and assigns all existing rows to user 1 (your original account). The migration runs in a transaction — if it fails, the database is untouched and Bindery exits with a repair hint in the logs.

This migration is a one-way door on SQLite. There is no automated rollback. Take a verified backup before you start.


Before you start

Single-user installs are unaffected in practice. After migration all data is still yours, still visible, and the UI works identically. You only gain the ability to create additional users.

Step 1 — Take a verified backup

Docker / binary

# Trigger a backup via API (writes a timestamped copy to BINDERY_DATA_DIR)
curl -X POST -H "X-Api-Key: <key>" http://bindery:8787/api/v1/backup

# Confirm the file was written
ls -lh /config/bindery_backup_*.db

Or via the UI: Settings → General → Backup → Create backup.

Kubernetes

Copy the file out of the PVC while Bindery is still running:

kubectl get pods -l app=bindery
kubectl cp bindery-0:/config/bindery.db ./bindery-pre-v1.db
sqlite3 ./bindery-pre-v1.db "SELECT count(*) FROM books;"  # confirm non-zero

Store bindery-pre-v1.db somewhere safe outside the cluster.

Step 2 — Dry-run the migration on a copy

Run the new binary against a copy of your database before touching the real one.

Docker dry-run

cp /config/bindery.db /tmp/bindery-dryrun.db

docker run --rm \
  -e BINDERY_DB_PATH=/tmp/bindery-dryrun.db \
  -v /tmp:/tmp \
  ghcr.io/vavallee/bindery:v1.0.0 \
  bindery migrate --dry-run

Look for migration 019 complete; all rows backfilled to user_id=1 in the output.

Verify integrity after dry-run

DB=/tmp/bindery-dryrun.db
sqlite3 $DB "SELECT count(*) FROM authors WHERE owner_user_id IS NULL;"   # expect 0
sqlite3 $DB "SELECT count(*) FROM books   WHERE owner_user_id IS NULL;"   # expect 0
sqlite3 $DB "SELECT count(*) FROM downloads WHERE owner_user_id IS NULL;" # expect 0

Step 3 — Upgrade

Docker / binary

docker stop bindery
docker pull ghcr.io/vavallee/bindery:v1.0.0
docker start bindery
docker logs -f bindery | grep -E "migration|error"
# Expect: migration 019 complete; all rows backfilled to user_id=1

Kubernetes (Helm)

helm upgrade bindery charts/bindery \
  --set image.tag=v1.0.0 \
  --reuse-values

kubectl rollout status deployment/bindery
kubectl logs deployment/bindery | grep -E "migration|error"

Step 4 — Verify

# Check row counts match pre-upgrade
curl -s -H "X-Api-Key: <key>" http://bindery:8787/api/v1/author | jq 'length'
curl -s -H "X-Api-Key: <key>" http://bindery:8787/api/v1/book   | jq 'length'

Open Settings → Users — your original account should appear with role admin.

Rollback

Restore from the backup taken in Step 1 and run the previous image:

# Docker
docker stop bindery
cp /config/bindery_backup_<timestamp>.db /config/bindery.db
docker run ... ghcr.io/vavallee/bindery:v0.24.0

# Kubernetes
kubectl cp ./bindery-pre-v1.db bindery-0:/config/bindery.db
helm rollback bindery

Any data written between the upgrade and the rollback is lost — it was scoped to the new schema.


Troubleshooting

Symptom Cause Fix
Startup fails: orphaned rows detected in downloads Rows reference non-existent book or user IDs from earlier bugs Run the repair query printed in the log. Typically: DELETE FROM downloads WHERE book_id NOT IN (SELECT id FROM books); Re-run Bindery after fixing.
Startup fails: migration 019: constraint violation A table row conflicts with the new NOT NULL owner_user_id constraint Run the dry-run, examine the exact error, apply the suggested fix. Restore from backup before retrying on the live DB.
All data appears under the wrong user post-migration Migration ran against a different DB file Confirm BINDERY_DB_PATH points to the correct file.
Admin account missing after migration Role column was not set on the user row sqlite3 /config/bindery.db "UPDATE users SET role='admin' WHERE id=1;" — safe to run on a live instance.

See also: Troubleshooting | docs/upgrade-v2.md

Clone this wiki locally