diff --git a/backend/src/routes/admin.js b/backend/src/routes/admin.js index b8bdc81..7b69a66 100644 --- a/backend/src/routes/admin.js +++ b/backend/src/routes/admin.js @@ -384,4 +384,87 @@ router.post('/cleanup-orphans', authenticate, requireAdmin, (req, res) => { } }); +// ── Disk-Analyse ────────────────────────────────────────────────────────── +router.get('/disk-analysis', authenticate, requireAdmin, (req, res) => { + const fs = require('fs'); + const path = require('path'); + + function dirSize(dirPath) { + let total = 0; + try { + for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { + const full = path.join(dirPath, entry.name); + if (entry.isDirectory()) total += dirSize(full); + else try { total += fs.statSync(full).size; } catch {} + } + } catch {} + return total; + } + + function fmt(b) { + if (b < 1024) return b + ' B'; + if (b < 1024**2) return (b/1024).toFixed(1) + ' KB'; + if (b < 1024**3) return (b/1024**2).toFixed(1) + ' MB'; + return (b/1024**3).toFixed(2) + ' GB'; + } + + // Alle relevanten Verzeichnisse scannen + const locations = [ + '/data', + '/data/uploads', + '/tmp', + '/app', + '/root', + '/var/log', + '/var/lib/docker', + ]; + + const result = {}; + for (const loc of locations) { + if (fs.existsSync(loc)) { + result[loc] = { raw: dirSize(loc), fmt: fmt(dirSize(loc)) }; + } + } + + // DB-Größe + const dbPath = process.env.DB_PATH || '/data/db.sqlite'; + if (fs.existsSync(dbPath)) { + result['database'] = { raw: fs.statSync(dbPath).size, fmt: fmt(fs.statSync(dbPath).size) }; + } + + // /tmp Details + const tmpFiles = []; + try { + for (const f of fs.readdirSync('/tmp')) { + try { + const stat = fs.statSync('/tmp/' + f); + if (stat.size > 1024*1024) tmpFiles.push({ name: f, size: fmt(stat.size) }); + } catch {} + } + } catch {} + + // Node modules Größe + const nodeModules = '/app/node_modules'; + const nodeSize = fs.existsSync(nodeModules) ? dirSize(nodeModules) : 0; + + // Top 10 größte Dateien in /data + const bigFiles = []; + function scanBig(dir) { + try { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) scanBig(full); + else try { + const s = fs.statSync(full).size; + if (s > 5*1024*1024) bigFiles.push({ path: full, size: fmt(s), raw: s }); + } catch {} + } + } catch {} + } + scanBig('/data'); + bigFiles.sort((a,b) => b.raw - a.raw); + + res.json({ locations: result, tmpFiles, nodeModulesMb: fmt(nodeSize), bigFiles: bigFiles.slice(0,20) }); +}); + module.exports = router;