feat(backend): automatisches taegliches SQLite-Online-Backup

This commit is contained in:
Kenearos 2026-07-07 15:50:34 +02:00
parent 45503f03ee
commit 97e58903b8
3 changed files with 56 additions and 1 deletions

34
server/backup.js Normal file
View file

@ -0,0 +1,34 @@
const path = require('path');
const fs = require('fs');
const { db, DATA_DIR } = require('./db');
const BACKUP_DIR = path.join(DATA_DIR, 'backups');
const KEEP = 14;
async function runBackup(now) {
fs.mkdirSync(BACKUP_DIR, { recursive: true });
const stamp = now.replace(/[:.]/g, '-');
const dest = path.join(BACKUP_DIR, `dienstplan-${stamp}.db`);
await db.backup(dest); // Online-Backup-API von SQLite — konsistent, ohne cp-Risiko
prune();
return dest;
}
function prune() {
const files = fs.readdirSync(BACKUP_DIR)
.filter(f => f.startsWith('dienstplan-') && f.endsWith('.db'))
.sort(); // ISO-abgeleiteter Stamp → lexikografisch == chronologisch
const excess = files.length - KEEP;
for (let i = 0; i < excess; i++) {
fs.unlinkSync(path.join(BACKUP_DIR, files[i]));
}
}
function scheduleBackups() {
const tick = () => runBackup(new Date().toISOString())
.catch(e => console.error('Backup fehlgeschlagen:', e));
tick();
setInterval(tick, 24 * 60 * 60 * 1000);
}
module.exports = { runBackup, scheduleBackups, BACKUP_DIR };

17
server/backup.test.js Normal file
View file

@ -0,0 +1,17 @@
const { test } = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'dp-backup-'));
const { putDoc } = require('./db');
const { runBackup, BACKUP_DIR } = require('./backup');
test('runBackup erzeugt eine nicht-leere DB-Datei', async () => {
putDoc('employees', ['Max'], '2026-07-07T10:00:00.000Z');
const dest = await runBackup('2026-07-07T10:00:00.000Z');
assert.ok(fs.existsSync(dest), 'Backup-Datei existiert');
assert.ok(fs.statSync(dest).size > 0, 'Backup ist nicht leer');
assert.ok(dest.startsWith(BACKUP_DIR), 'Backup liegt im BACKUP_DIR');
});

View file

@ -1,6 +1,7 @@
const path = require('path');
const express = require('express');
const { getDoc, putDoc } = require('./db');
const { scheduleBackups } = require('./backup');
const app = express();
app.use(express.json({ limit: '5mb' }));
@ -36,7 +37,10 @@ app.use(express.static(path.join(__dirname, '..')));
if (require.main === module) {
const PORT = process.env.PORT || 3000;
app.listen(PORT, '0.0.0.0', () => console.log(`Dienstplan-Pro auf :${PORT}`));
app.listen(PORT, '0.0.0.0', () => {
console.log(`Dienstplan-Pro auf :${PORT}`);
scheduleBackups();
});
}
module.exports = app;