← back to AbramsOS
routes/audit.js
73 lines
// /audit — read-only viewer for audit_log + auth_event.
// Provides transparency over every state-changing operation.
const express = require('express');
const db = require('../lib/db');
const router = express.Router();
const DEV_USER_ID = 'user_steve';
// Combined timeline query: union of both audit tables, newest first.
async function getEvents({ limit = 200, eventType = null, since = null } = {}) {
const params = [limit];
let whereAudit = '';
let whereAuth = '';
if (eventType) {
params.push(eventType);
whereAudit += ` AND event_type = $${params.length}`;
whereAuth += ` AND event_type = $${params.length}`;
}
if (since) {
params.push(since);
whereAudit += ` AND occurred_at >= $${params.length}`;
whereAuth += ` AND occurred_at >= $${params.length}`;
}
const sql = `
SELECT 'audit_log'::text AS source, occurred_at, actor_type, actor_id,
object_type, object_id, event_type, metadata_jsonb
FROM audit_log
WHERE 1=1 ${whereAudit}
UNION ALL
SELECT 'auth_event'::text AS source, occurred_at, 'user'::text AS actor_type, user_id::text AS actor_id,
'auth_session'::text AS object_type, session_id AS object_id, event_type, metadata_jsonb
FROM auth_event
WHERE 1=1 ${whereAuth}
ORDER BY occurred_at DESC
LIMIT $1
`;
const r = await db.query(sql, params);
return r.rows;
}
router.get('/audit', async (req, res) => {
const eventType = req.query.event_type || null;
const sinceDays = parseInt(req.query.since_days || '30', 10);
const since = new Date(Date.now() - sinceDays * 86400e3);
const events = await getEvents({ limit: 200, eventType, since });
// Aggregate counts by event_type for the filter chips
const counts = await db.query(`
SELECT event_type, count(*)::int AS n FROM (
SELECT event_type FROM audit_log
UNION ALL SELECT event_type FROM auth_event
) e GROUP BY event_type ORDER BY n DESC LIMIT 20
`);
res.render('audit', {
events,
counts: counts.rows,
activeFilter: eventType,
sinceDays,
});
});
router.get('/api/audit/events', async (req, res) => {
const limit = Math.min(500, parseInt(req.query.limit || '200', 10));
const eventType = req.query.event_type || null;
const sinceDays = parseInt(req.query.since_days || '30', 10);
const since = new Date(Date.now() - sinceDays * 86400e3);
res.json(await getEvents({ limit, eventType, since }));
});
module.exports = router;