/** * Audit Routes * Based on: docs/foundation/Agent_Governance_Protocol_v1.md */ import { Router, Request, Response } from 'express'; import { auditService } from '../services/governance/audit.service'; import { GovernanceEventType, GovernanceScope } from '../domain/governance/types'; import { logger } from '../infra/logger/logger'; const router = Router(); /** * GET /api/v1/audit/events * Get audit events with filters */ router.get('/events', async (req: Request, res: Response) => { try { const { eventType, actorId, targetId, scope, createdAtFrom, createdAtTo, limit, offset, } = req.query; const result = await auditService.getEvents({ eventType: eventType as GovernanceEventType | undefined, actorId: actorId as string | undefined, targetId: targetId as string | undefined, scope: scope as GovernanceScope | undefined, createdAtFrom: createdAtFrom ? new Date(createdAtFrom as string) : undefined, createdAtTo: createdAtTo ? new Date(createdAtTo as string) : undefined, limit: limit ? parseInt(limit as string, 10) : 50, offset: offset ? parseInt(offset as string, 10) : 0, }); res.json(result); } catch (error) { logger.error('Error getting audit events', error); res.status(500).json({ error: 'Failed to get audit events' }); } }); /** * GET /api/v1/audit/events/:id * Get single audit event */ router.get('/events/:id', async (req: Request, res: Response) => { try { const { id } = req.params; const event = await auditService.getEvent(id); if (!event) { return res.status(404).json({ error: 'Event not found' }); } res.json(event); } catch (error) { logger.error('Error getting audit event', error); res.status(500).json({ error: 'Failed to get audit event' }); } }); /** * GET /api/v1/audit/actor/:actorId * Get events by actor */ router.get('/actor/:actorId', async (req: Request, res: Response) => { try { const { actorId } = req.params; const { limit } = req.query; const events = await auditService.getEventsByActor( actorId, limit ? parseInt(limit as string, 10) : 50 ); res.json(events); } catch (error) { logger.error('Error getting events by actor', error); res.status(500).json({ error: 'Failed to get events by actor' }); } }); /** * GET /api/v1/audit/target/:targetId * Get events by target */ router.get('/target/:targetId', async (req: Request, res: Response) => { try { const { targetId } = req.params; const { limit } = req.query; const events = await auditService.getEventsByTarget( targetId, limit ? parseInt(limit as string, 10) : 50 ); res.json(events); } catch (error) { logger.error('Error getting events by target', error); res.status(500).json({ error: 'Failed to get events by target' }); } }); /** * GET /api/v1/audit/scope/:scope * Get events by scope */ router.get('/scope/:scope', async (req: Request, res: Response) => { try { const { scope } = req.params; const { limit } = req.query; const events = await auditService.getEventsByScope( scope as GovernanceScope, limit ? parseInt(limit as string, 10) : 50 ); res.json(events); } catch (error) { logger.error('Error getting events by scope', error); res.status(500).json({ error: 'Failed to get events by scope' }); } }); /** * GET /api/v1/audit/stats * Get event statistics */ router.get('/stats', async (req: Request, res: Response) => { try { const { fromDate, toDate } = req.query; const stats = await auditService.getEventStats( fromDate ? new Date(fromDate as string) : undefined, toDate ? new Date(toDate as string) : undefined ); res.json(stats); } catch (error) { logger.error('Error getting audit stats', error); res.status(500).json({ error: 'Failed to get audit stats' }); } }); /** * GET /api/v1/audit/entity/:entityType/:entityId * Get governance history for specific entity */ router.get('/entity/:entityType/:entityId', async (req: Request, res: Response) => { try { const { entityType, entityId } = req.params; const { limit } = req.query; if (!['agent', 'microdao', 'district', 'node', 'room'].includes(entityType)) { return res.status(400).json({ error: 'Invalid entity type' }); } const events = await auditService.getEntityHistory( entityType as 'agent' | 'microdao' | 'district' | 'node' | 'room', entityId, limit ? parseInt(limit as string, 10) : 50 ); res.json(events); } catch (error) { logger.error('Error getting entity history', error); res.status(500).json({ error: 'Failed to get entity history' }); } }); export default router;