Commit Graph
2 Commits
Author SHA1 Message Date
Lauri Ojansivu 8e4d57c21d Show a recovery maintenance page on all FerretDB v1 platforms
During a #6492 data recovery, users should never see a bare connection error.
Two layers now cover the whole window on every FerretDB v1 launch path (snap,
bundled release, Docker):

- In-app spinner (already present): the server clears the RECOVERY_IN_PROGRESS
  marker only after a real health probe, so the full-screen overlay behaves
  identically everywhere.
- Static bridge page (new, cross-platform): for the brief window while a
  just-restored FerretDB comes back up and before Meteor can serve the client,
  the launch scripts serve a tiny standalone "recovering your data" page (HTTP
  503) on the web port. The snap reuses wekan-maintenance-page.mjs with a
  recovery wording; release/Docker serve the portable recovery-bridge.mjs. The
  bridge is time-bounded (WEKAN_RECOVERY_BRIDGE_SECONDS, default 20s) so it can
  never block WeKan from starting, hands straight over to the in-app spinner, and
  is skipped if its page file or the marker is absent.

The launch scripts do NOT delete the marker; only the server does, after
verifying the database serves reads. Tests enforce the bridge is bounded, is
guarded by the page file, and that no script deletes the marker.

Thanks to bluetopaz1204, mueschel and xet7 !

Fixes #6492,
2026-07-21 10:06:41 +03:00
Lauri Ojansivu 63c77a27f4 Automatic recovery/remediation for the SQLite text data + Admin Panel Recovery report
Completes the #6492 data-safety system on the WeKan side (FerretDB detection/repair/cap
landed in the fork):

- Decision brain: models/lib/recoveryPlan.js decideRecovery() picks the least-invasive
  recovery when the database is KNOWN corrupt (latest good backup -> previous backup ->
  re-migrate from MongoDB -> manual). It never acts on a healthy/unknown database and
  never restores a known-bad backup.
- Startup restore/re-migrate: every FerretDB launch path (snap, bundled release, Docker)
  can restore the text data BEFORE FerretDB opens the files, on request
  (WEKAN_FORCE_RESTORE env or a RESTORE_REQUESTED marker). It copies a known-good backup
  INTO the live database (dropping stale WAL side-files); backups are never deleted and
  the main wekan.sqlite is only overwritten, never removed. remigrate is delegated to
  migration-control. Attachments/avatars on the filesystem are untouched.
- Recovery events: the scripts append JSON lines to recovery-events.jsonl; the server
  (server/recovery.js) imports them into the recoveryEvents collection on startup, plus
  an admin-only recordRecoveryEvent method.
- Admin Panel / Problems / Recovery: a new admin-only report
  (server/publications/recoveryReport.js, wired in adminReports.js/.jade + i18n) lists
  the remediation history newest-first, readies up front and fetches directly (no hang).
- Docs: docs/Features/Admin-Panel/Problems/Recovery.md.

Tests (wired into npm run test:unit:node), verified by mirror since there is no Node
runtime here to execute them:
  - recoveryPlan.test.cjs (decision logic, positive + negatives)
  - recoveryEventsJsonl.test.cjs (parser: skips junk, normalizes severity, never throws)
  - recoveryReportQuery.test.cjs (search selector escapes regex metacharacters)
  - recoveryReportWiring.test.cjs (report wired; publication/count/method admin-gated)
  - ferretdbTextDataBackup.test.cjs extended: restore copies from a backup, is
    request-gated, and NEVER deletes the live text data or a backup copy

Thanks to bluetopaz1204, mueschel and xet7 !

Fixes #6492,
2026-07-21 10:06:40 +03:00