← back to Dw Boardroom Governance

src/api/routes/governance.ts

81 lines

import { Router, Request, Response } from 'express';
import { query, execute } from '../../db/db';
import { isRunning, getActiveMeetingId } from '../../engine/meetingEngine';
import { getConnectionCount } from '../../ws/broadcast';

const router = Router();

// GET /api/governance/config — get all governance settings
router.get('/config', async (_req: Request, res: Response) => {
  try {
    const rows = await query('SELECT key, value FROM gov_config ORDER BY key');
    const config: Record<string, any> = {};
    rows.forEach((r: any) => { config[r.key] = r.value; });
    res.json(config);
  } catch (err: any) {
    res.status(500).json({ error: err.message });
  }
});

// POST /api/governance/config — update config
router.post('/config', async (req: Request, res: Response) => {
  try {
    const updates = req.body;
    for (const [key, value] of Object.entries(updates)) {
      await execute(
        `INSERT INTO gov_config (key, value, updated_at) VALUES ($1, $2, NOW())
         ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,
        [key, JSON.stringify(value)]
      );
    }
    const rows = await query('SELECT key, value FROM gov_config ORDER BY key');
    const config: Record<string, any> = {};
    rows.forEach((r: any) => { config[r.key] = r.value; });
    res.json(config);
  } catch (err: any) {
    res.status(400).json({ error: err.message });
  }
});

// GET /api/governance/status — full system status
router.get('/status', async (_req: Request, res: Response) => {
  try {
    const [decisions, delegations, initiatives, meetings, config] = await Promise.all([
      query("SELECT status, COUNT(*)::int as count FROM gov_decision_log GROUP BY status"),
      query("SELECT status, COUNT(*)::int as count FROM gov_delegation_contract GROUP BY status"),
      query("SELECT status, COUNT(*)::int as count FROM gov_initiative_registry GROUP BY status"),
      query("SELECT status, COUNT(*)::int as count FROM gov_meetings GROUP BY status"),
      query("SELECT key, value FROM gov_config"),
    ]);

    const toMap = (rows: any[]) => {
      const m: Record<string, number> = {};
      rows.forEach(r => { m[r.status] = r.count; });
      return m;
    };

    const configMap: Record<string, any> = {};
    config.forEach((r: any) => { configMap[r.key] = r.value; });

    res.json({
      meeting: {
        active: isRunning(),
        activeMeetingId: getActiveMeetingId(),
      },
      decisions: toMap(decisions),
      delegations: toMap(delegations),
      initiatives: toMap(initiatives),
      meetings: toMap(meetings),
      config: configMap,
      websocket: {
        connections: getConnectionCount(),
      },
      uptime: process.uptime(),
    });
  } catch (err: any) {
    res.status(500).json({ error: err.message });
  }
});

export default router;