const express = require('express'); const cors = require('cors'); const path = require('path'); const db = require('./db/database'); const app = express(); const PORT = process.env.PORT || 3001; app.use(cors()); app.use(express.json()); app.use(express.static(path.join(__dirname, 'client', 'dist'))); // ── Health ───────────────────────────────────────────────────────────────── app.get('/api/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); // ── Employees ────────────────────────────────────────────────────────────── app.get('/api/employees', (req, res) => { const rows = db.prepare( 'SELECT id, name, department, supervisor FROM employees ORDER BY name ASC' ).all(); res.json(rows); }); app.post('/api/employees', (req, res) => { const { name, department, supervisor } = req.body; if (!name) return res.status(400).json({ error: 'name is required' }); const existing = db.prepare( 'SELECT * FROM employees WHERE LOWER(name) = LOWER(?)' ).get(name); if (existing) { if (department || supervisor) { db.prepare( 'UPDATE employees SET department = COALESCE(?, department), supervisor = COALESCE(?, supervisor) WHERE id = ?' ).run(department || null, supervisor || null, existing.id); } return res.json({ ...existing, department, supervisor }); } const result = db.prepare( 'INSERT INTO employees (name, department, supervisor) VALUES (?, ?, ?)' ).run(name, department || null, supervisor || null); res.status(201).json({ id: result.lastInsertRowid, name, department, supervisor }); }); // ── Employee CPAS Score (rolling 90-day) ─────────────────────────────────── app.get('/api/employees/:employeeId/score', (req, res) => { const row = db.prepare( 'SELECT * FROM active_cpas_scores WHERE employee_id = ?' ).get(req.params.employeeId); res.json(row || { employee_id: req.params.employeeId, active_points: 0, violation_count: 0 }); }); // ── Violation type usage counts for an employee (90-day window) ──────────── // Returns { violation_type: count } so the frontend can badge the dropdown app.get('/api/employees/:employeeId/violation-counts', (req, res) => { const rows = db.prepare(` SELECT violation_type, COUNT(*) as count FROM violations WHERE employee_id = ? AND incident_date >= DATE('now', '-90 days') GROUP BY violation_type `).all(req.params.employeeId); const map = {}; rows.forEach(r => { map[r.violation_type] = r.count; }); res.json(map); }); // ── All-time violation type counts for recidivist point suggestion ───────── app.get('/api/employees/:employeeId/violation-counts/alltime', (req, res) => { const rows = db.prepare(` SELECT violation_type, COUNT(*) as count, MAX(points) as max_points_used FROM violations WHERE employee_id = ? GROUP BY violation_type `).all(req.params.employeeId); const map = {}; rows.forEach(r => { map[r.violation_type] = { count: r.count, max_points_used: r.max_points_used }; }); res.json(map); }); // ── Violation history for an employee ───────────────────────────────────── app.get('/api/violations/employee/:employeeId', (req, res) => { const limit = parseInt(req.query.limit) || 50; const rows = db.prepare(` SELECT * FROM violations WHERE employee_id = ? ORDER BY incident_date DESC, created_at DESC LIMIT ? `).all(req.params.employeeId, limit); res.json(rows); }); // ── POST new violation ───────────────────────────────────────────────────── app.post('/api/violations', (req, res) => { const { employee_id, violation_type, violation_name, category, points, incident_date, incident_time, location, details, submitted_by, witness_name } = req.body; if (!employee_id || !violation_type || !points || !incident_date) { return res.status(400).json({ error: 'Missing required fields: employee_id, violation_type, points, incident_date' }); } const result = db.prepare(` INSERT INTO violations ( employee_id, violation_type, violation_name, category, points, incident_date, incident_time, location, details, submitted_by, witness_name ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( employee_id, violation_type, violation_name || violation_type, category || 'General', points, incident_date, incident_time || null, location || null, details || null, submitted_by || null, witness_name || null ); res.status(201).json({ id: result.lastInsertRowid }); }); // ── SPA fallback ─────────────────────────────────────────────────────────── app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'client', 'dist', 'index.html')); }); app.listen(PORT, '0.0.0.0', () => { console.log(`[CPAS] Server running on port ${PORT}`); });