← back to Dw Boardroom Governance
src/api/routes/initiatives.ts
110 lines
import { Router, Request, Response } from 'express';
import { query, queryOne, execute } from '../../db/db';
import { Initiative } from '../../types';
import { v4 as uuidv4 } from 'uuid';
const router = Router();
// GET /api/initiatives
router.get('/', async (_req: Request, res: Response) => {
try {
const initiatives = await query<Initiative>(
'SELECT * FROM gov_initiative_registry ORDER BY created_at DESC LIMIT 50'
);
res.json(initiatives);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
// POST /api/initiatives
router.post('/', async (req: Request, res: Response) => {
try {
const id = uuidv4();
await query(
`INSERT INTO gov_initiative_registry
(id, title, description, driver_agent, kpi, risk_level, capital_allocated, status)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8)`,
[
id,
req.body.title,
req.body.description || null,
req.body.driverAgent || 'unassigned',
req.body.kpi || null,
req.body.riskLevel || 'low',
req.body.capitalAllocated || 0,
req.body.status || 'proposed',
]
);
const initiative = await queryOne<Initiative>(
'SELECT * FROM gov_initiative_registry WHERE id = $1', [id]
);
res.json(initiative);
} catch (err: any) {
res.status(400).json({ error: err.message });
}
});
// GET /api/initiatives/:id
router.get('/:id', async (req: Request, res: Response) => {
try {
const initiative = await queryOne<Initiative>(
'SELECT * FROM gov_initiative_registry WHERE id = $1', [req.params.id]
);
if (!initiative) return res.status(404).json({ error: 'Initiative not found' });
res.json(initiative);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
// PATCH /api/initiatives/:id
router.patch('/:id', async (req: Request, res: Response) => {
try {
const fields: string[] = [];
const values: any[] = [];
let idx = 1;
const allowedFields = ['title', 'description', 'driver_agent', 'kpi', 'risk_level', 'capital_allocated', 'status', 'progress'];
for (const field of allowedFields) {
const camelKey = field.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
if (req.body[camelKey] !== undefined || req.body[field] !== undefined) {
fields.push(`${field} = $${idx++}`);
values.push(req.body[camelKey] ?? req.body[field]);
}
}
if (fields.length === 0) return res.status(400).json({ error: 'No fields to update' });
fields.push(`updated_at = NOW()`);
values.push(req.params.id);
await execute(
`UPDATE gov_initiative_registry SET ${fields.join(', ')} WHERE id = $${idx}`,
values
);
const initiative = await queryOne<Initiative>(
'SELECT * FROM gov_initiative_registry WHERE id = $1', [req.params.id]
);
res.json(initiative);
} catch (err: any) {
res.status(400).json({ error: err.message });
}
});
// DELETE /api/initiatives/:id
router.delete('/:id', async (req: Request, res: Response) => {
try {
await execute(
"UPDATE gov_initiative_registry SET status = 'cancelled', updated_at = NOW() WHERE id = $1",
[req.params.id]
);
res.json({ status: 'cancelled' });
} catch (err: any) {
res.status(400).json({ error: err.message });
}
});
export default router;