From f44d018d5ccdc2666287290ac7e57199e219a330 Mon Sep 17 00:00:00 2001 From: Rafael Foster Date: Wed, 29 Apr 2026 14:35:59 -0300 Subject: [PATCH] fix(docs): restore backups without helper script --- docs/installation.md | 12 ++++++++---- public/locales/ar.json | 2 +- public/locales/de.json | 2 +- public/locales/el.json | 2 +- public/locales/en.json | 2 +- public/locales/es.json | 2 +- public/locales/fr.json | 2 +- public/locales/hi.json | 2 +- public/locales/it.json | 2 +- public/locales/ja.json | 2 +- public/locales/pt.json | 2 +- public/locales/ru.json | 2 +- public/locales/sv.json | 2 +- public/locales/tr.json | 2 +- public/locales/uk.json | 2 +- public/locales/zh.json | 2 +- public/pages/settings.js | 8 +++++--- public/sw.js | 8 ++++---- 18 files changed, 32 insertions(+), 26 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index d6f9aa7..3b759d4 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -468,14 +468,18 @@ Admins can also download a backup from **Settings → Backup Management**. ### Restore -Admins can restore a backup from **Settings → Backup Management**. For operational restores via Docker Compose, stop the running app, mount the backup into a temporary container that uses the same Docker volume, and run the restore helper: +Admins can restore a backup from **Settings → Backup Management**. For operational restores via Docker Compose, stop the running app, mount the backup into a temporary container that uses the same Docker volume, and replace the database file: ```bash -docker compose stop oikos -docker compose run --rm -v "$PWD/oikos-backup-20260401.db:/tmp/oikos-restore.db:ro" oikos node scripts/restore-backup.js /tmp/oikos-restore.db -docker compose up -d +SERVICE=oikos +BACKUP="$PWD/oikos-backup-20260401.db" +docker compose stop "$SERVICE" +docker compose run --rm -v "$BACKUP:/tmp/oikos-restore.db:ro" --entrypoint sh "$SERVICE" -c 'set -eu; target="${DB_PATH:-/data/oikos.db}"; stamp=$(date -u +%Y%m%dT%H%M%SZ); if [ -f "$target" ]; then cp "$target" "$target.pre-restore-$stamp"; fi; rm -f "$target-wal" "$target-shm"; cp /tmp/oikos-restore.db "$target"; chown node:node "$target" 2>/dev/null || true' +docker compose up -d "$SERVICE" ``` +If your Compose service is renamed, set `SERVICE` to that name, for example `SERVICE=familyplanner`. + For a local CLI restore outside Docker, set the same environment variables used by the app and run: ```bash diff --git a/public/locales/ar.json b/public/locales/ar.json index 419f4bd..9c26769 100644 --- a/public/locales/ar.json +++ b/public/locales/ar.json @@ -767,7 +767,7 @@ "backupRestoring": "جارٍ الاستعادة...", "backupRestoredToast": "تمت استعادة قاعدة البيانات. جارٍ إعادة التحميل...", "backupCliTitle": "استعادة CLI / Docker Compose", - "backupCliHint": "للاستعادة التشغيلية، اربط النسخة داخل الحاوية وشغّل مساعد الاستعادة.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "يمكنك أيضًا إنشاء نسخة مباشرة عبر Docker Compose:" }, "login": { diff --git a/public/locales/de.json b/public/locales/de.json index 8200f3c..78d1f46 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -792,7 +792,7 @@ "backupRestoring": "Wird wiederhergestellt...", "backupRestoredToast": "Datenbank wiederhergestellt. Seite wird neu geladen...", "backupCliTitle": "CLI / Docker-Compose-Wiederherstellung", - "backupCliHint": "Kopiere für operative Wiederherstellungen das Backup in den Container und starte den Restore-Helfer.", + "backupCliHint": "Für operative Wiederherstellungen die App stoppen, das Backup in einen temporären Container einbinden und die Datenbankdatei ersetzen.", "backupCliBackupHint": "Du kannst auch direkt über Docker Compose ein Backup erstellen:" }, "login": { diff --git a/public/locales/el.json b/public/locales/el.json index f56659a..f767eb4 100644 --- a/public/locales/el.json +++ b/public/locales/el.json @@ -767,7 +767,7 @@ "backupRestoring": "Γίνεται επαναφορά...", "backupRestoredToast": "Η βάση επαναφέρθηκε. Επαναφόρτωση...", "backupCliTitle": "Επαναφορά CLI / Docker Compose", - "backupCliHint": "Για λειτουργική επαναφορά, προσαρτήστε το αντίγραφο στο container και εκτελέστε τον βοηθό.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Μπορείτε επίσης να δημιουργήσετε αντίγραφο απευθείας με Docker Compose:" }, "login": { diff --git a/public/locales/en.json b/public/locales/en.json index 8eeb9d9..9e75a9f 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -767,7 +767,7 @@ "backupRestoring": "Restoring...", "backupRestoredToast": "Database restored. Reloading...", "backupCliTitle": "CLI / Docker Compose restore", - "backupCliHint": "For operational restores, copy the backup into the container and run the restore helper.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "You can also create a backup directly from Docker Compose:" }, "login": { diff --git a/public/locales/es.json b/public/locales/es.json index 465d8a5..d3b3c8b 100644 --- a/public/locales/es.json +++ b/public/locales/es.json @@ -767,7 +767,7 @@ "backupRestoring": "Restaurando...", "backupRestoredToast": "Base de datos restaurada. Recargando...", "backupCliTitle": "Restauración por CLI / Docker Compose", - "backupCliHint": "Para restauraciones operativas, monta la copia en el contenedor y ejecuta el asistente de restauración.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "También puedes crear una copia directamente con Docker Compose:" }, "login": { diff --git a/public/locales/fr.json b/public/locales/fr.json index dc2b111..d774ef0 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -767,7 +767,7 @@ "backupRestoring": "Restauration...", "backupRestoredToast": "Base restaurée. Rechargement...", "backupCliTitle": "Restauration CLI / Docker Compose", - "backupCliHint": "Pour une restauration opérationnelle, monte la sauvegarde dans le conteneur et lance l’assistant.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Tu peux aussi créer une sauvegarde directement avec Docker Compose :" }, "login": { diff --git a/public/locales/hi.json b/public/locales/hi.json index 382af74..ce71352 100644 --- a/public/locales/hi.json +++ b/public/locales/hi.json @@ -767,7 +767,7 @@ "backupRestoring": "पुनर्स्थापित हो रहा है...", "backupRestoredToast": "डेटाबेस पुनर्स्थापित हुआ। फिर से लोड हो रहा है...", "backupCliTitle": "CLI / Docker Compose पुनर्स्थापना", - "backupCliHint": "ऑपरेशनल पुनर्स्थापना के लिए, बैकअप को कंटेनर में माउंट करें और restore helper चलाएँ।", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "आप Docker Compose से सीधे बैकअप भी बना सकते हैं:" }, "login": { diff --git a/public/locales/it.json b/public/locales/it.json index c7e2287..78ef983 100644 --- a/public/locales/it.json +++ b/public/locales/it.json @@ -767,7 +767,7 @@ "backupRestoring": "Ripristino...", "backupRestoredToast": "Database ripristinato. Ricaricamento...", "backupCliTitle": "Ripristino CLI / Docker Compose", - "backupCliHint": "Per ripristini operativi, monta il backup nel container ed esegui l’helper.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Puoi anche creare un backup direttamente con Docker Compose:" }, "login": { diff --git a/public/locales/ja.json b/public/locales/ja.json index 9fc43a0..21a9df7 100644 --- a/public/locales/ja.json +++ b/public/locales/ja.json @@ -767,7 +767,7 @@ "backupRestoring": "復元中...", "backupRestoredToast": "データベースを復元しました。再読み込み中...", "backupCliTitle": "CLI / Docker Compose 復元", - "backupCliHint": "運用復元では、バックアップをコンテナにマウントして復元ヘルパーを実行します。", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Docker Compose から直接バックアップを作成することもできます:" }, "login": { diff --git a/public/locales/pt.json b/public/locales/pt.json index 1fbd7d8..b00678d 100644 --- a/public/locales/pt.json +++ b/public/locales/pt.json @@ -767,7 +767,7 @@ "backupRestoring": "Restaurando...", "backupRestoredToast": "Banco de dados restaurado. Recarregando...", "backupCliTitle": "Restauração via CLI / Docker Compose", - "backupCliHint": "Para restaurações operacionais, copie o backup para o container e execute o helper de restauração.", + "backupCliHint": "Para restaurações operacionais, pare a aplicação, monte o backup em um container temporário e substitua o arquivo do banco de dados.", "backupCliBackupHint": "Você também pode criar um backup diretamente pelo Docker Compose:" }, "login": { diff --git a/public/locales/ru.json b/public/locales/ru.json index c370d92..07f4eb8 100644 --- a/public/locales/ru.json +++ b/public/locales/ru.json @@ -767,7 +767,7 @@ "backupRestoring": "Восстановление...", "backupRestoredToast": "База данных восстановлена. Перезагрузка...", "backupCliTitle": "Восстановление CLI / Docker Compose", - "backupCliHint": "Для операционного восстановления подключите копию к контейнеру и запустите помощник восстановления.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Также можно создать копию напрямую через Docker Compose:" }, "login": { diff --git a/public/locales/sv.json b/public/locales/sv.json index 340ac4f..f740898 100644 --- a/public/locales/sv.json +++ b/public/locales/sv.json @@ -767,7 +767,7 @@ "backupRestoring": "Återställer...", "backupRestoredToast": "Databasen återställd. Laddar om...", "backupCliTitle": "CLI / Docker Compose-återställning", - "backupCliHint": "För driftåterställning, montera backupen i containern och kör återställningshjälpen.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Du kan också skapa en backup direkt med Docker Compose:" }, "login": { diff --git a/public/locales/tr.json b/public/locales/tr.json index 0a26d13..0d5656f 100644 --- a/public/locales/tr.json +++ b/public/locales/tr.json @@ -767,7 +767,7 @@ "backupRestoring": "Geri yükleniyor...", "backupRestoredToast": "Veritabanı geri yüklendi. Yeniden yükleniyor...", "backupCliTitle": "CLI / Docker Compose geri yükleme", - "backupCliHint": "Operasyonel geri yüklemeler için yedeği konteynere bağlayın ve geri yükleme yardımcısını çalıştırın.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Docker Compose ile doğrudan yedek de oluşturabilirsiniz:" }, "login": { diff --git a/public/locales/uk.json b/public/locales/uk.json index 79f11d5..913ac4e 100644 --- a/public/locales/uk.json +++ b/public/locales/uk.json @@ -767,7 +767,7 @@ "backupRestoring": "Відновлення...", "backupRestoredToast": "Базу даних відновлено. Перезавантаження...", "backupCliTitle": "Відновлення CLI / Docker Compose", - "backupCliHint": "Для операційного відновлення підключіть копію до контейнера та запустіть помічник.", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "Також можна створити копію безпосередньо через Docker Compose:" }, "login": { diff --git a/public/locales/zh.json b/public/locales/zh.json index a5a417a..dabc3ef 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -767,7 +767,7 @@ "backupRestoring": "正在恢复...", "backupRestoredToast": "数据库已恢复。正在重新加载...", "backupCliTitle": "CLI / Docker Compose 恢复", - "backupCliHint": "对于运维恢复,请将备份挂载到容器并运行恢复助手。", + "backupCliHint": "For operational restores, stop the app, mount the backup in a temporary container and replace the database file.", "backupCliBackupHint": "也可以直接通过 Docker Compose 创建备份:" }, "login": { diff --git a/public/pages/settings.js b/public/pages/settings.js index 5315f47..6ca6a29 100644 --- a/public/pages/settings.js +++ b/public/pages/settings.js @@ -760,9 +760,11 @@ export async function render(container, { user }) {

${t('settings.backupCliTitle')}

${t('settings.backupCliHint')}

-
docker compose stop oikos
-docker compose run --rm -v "$PWD/oikos-backup.db:/tmp/oikos-restore.db:ro" oikos node scripts/restore-backup.js /tmp/oikos-restore.db
-docker compose up -d
+
SERVICE=oikos
+BACKUP="$PWD/oikos-backup.db"
+docker compose stop "$SERVICE"
+docker compose run --rm -v "$BACKUP:/tmp/oikos-restore.db:ro" --entrypoint sh "$SERVICE" -c 'set -eu; target="\${DB_PATH:-/data/oikos.db}"; stamp=$(date -u +%Y%m%dT%H%M%SZ); if [ -f "$target" ]; then cp "$target" "$target.pre-restore-$stamp"; fi; rm -f "$target-wal" "$target-shm"; cp /tmp/oikos-restore.db "$target"; chown node:node "$target" 2>/dev/null || true'
+docker compose up -d "$SERVICE"

${t('settings.backupCliBackupHint')}

docker compose exec oikos node -e "import('./server/db.js').then(async db => { await db.backupToFile('/data/oikos-backup.db'); process.exit(0); })"
 docker cp oikos:/data/oikos-backup.db ./oikos-backup.db
diff --git a/public/sw.js b/public/sw.js index 7dc648b..332f5fa 100644 --- a/public/sw.js +++ b/public/sw.js @@ -13,10 +13,10 @@ * → bypassCacheUntil (in-memory + Cache API für SW-Restart-Robustheit) */ -const SHELL_CACHE = 'oikos-shell-v71'; -const PAGES_CACHE = 'oikos-pages-v66'; -const LOCALES_CACHE = 'oikos-locales-v15'; -const ASSETS_CACHE = 'oikos-assets-v66'; +const SHELL_CACHE = 'oikos-shell-v72'; +const PAGES_CACHE = 'oikos-pages-v67'; +const LOCALES_CACHE = 'oikos-locales-v16'; +const ASSETS_CACHE = 'oikos-assets-v67'; const BYPASS_CACHE = 'oikos-bypass-flag'; const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, LOCALES_CACHE, ASSETS_CACHE];