// System health & monitoring routes — 2026-03-29 module.exports = async function systemRoutes(app, opts) { const os = require('os'); // GET /api/v1/system/health — comprehensive system status app.get('/system/health', async (request, reply) => { // System info const system = { hostname: os.hostname(), uptime: Math.floor(os.uptime()), loadavg: os.loadavg(), cpus: os.cpus().length, memory: { total: Math.round(os.totalmem() / 1024 / 1024), free: Math.round(os.freemem() / 1024 / 1024), used_pct: Math.round((1 - os.freemem() / os.totalmem()) * 100) } }; // DB check let db_status = { status: 'error' }; try { const { rows } = await app.db.query('SELECT NOW() as time, pg_database_size(current_database()) as size'); db_status = { status: 'ok', time: rows[0].time, size_mb: Math.round(rows[0].size / 1024 / 1024) }; } catch (e) { db_status = { status: 'error', message: e.message }; } // Redis check let redis_status = { status: 'error' }; try { const pong = await app.redis.ping(); const info = await app.redis.info('memory'); const usedMem = info.match(/used_memory_human:(.+)/)?.[1]?.trim(); redis_status = { status: pong === 'PONG' ? 'ok' : 'error', memory: usedMem }; } catch (e) { redis_status = { status: 'error', message: e.message }; } // Task stats let task_stats = {}; try { const { rows } = await app.db.query(` SELECT status, count(*)::int as count FROM tasks GROUP BY status UNION ALL SELECT 'total', count(*)::int FROM tasks UNION ALL SELECT 'users', count(*)::int FROM users UNION ALL SELECT 'goals', count(*)::int FROM goals `); task_stats = Object.fromEntries(rows.map(r => [r.status, r.count])); } catch (e) { task_stats = { error: e.message }; } // Determine overall status const overall = (db_status.status === 'ok' && redis_status.status === 'ok') ? 'ok' : 'degraded'; return { status: overall, timestamp: new Date().toISOString(), system, database: db_status, redis: redis_status, tasks: task_stats, version: require('../../package.json').version || '1.0.0' }; }); // GET /api/v1/system/ping — lightweight liveness check app.get('/system/ping', async () => ({ pong: true, ts: Date.now() })); };