production hardening: future-date guard, per-day hour cap, totalHours in history, header cleanup

This commit is contained in:
BizzleBot
2026-02-19 04:48:43 +00:00
parent 47c35c1e3a
commit a0234cdd31
11 changed files with 222 additions and 51 deletions
+15 -2
View File
@@ -7,6 +7,7 @@ const {
copyWeekSchema,
validateBody,
validateQuery,
validateIdParam,
} = require('../utils/validation');
const router = express.Router();
@@ -119,6 +120,18 @@ router.post('/', validateBody(createEntrySchema), async (req, res) => {
return res.status(400).json({ error: 'Invalid or inactive homeowner' });
}
// Check per-day hour cap (max 24h total across all entries)
const existingHours = await req.prisma.timeEntry.aggregate({
where: { userId: req.user.id, date: new Date(date + 'T00:00:00Z') },
_sum: { hoursWorked: true },
});
const totalForDay = parseFloat(existingHours._sum.hoursWorked || 0) + hoursWorked;
if (totalForDay > 24) {
return res.status(400).json({
error: `Total hours for this day would be ${totalForDay.toFixed(1)}. Maximum is 24.`,
});
}
const entry = await req.prisma.timeEntry.create({
data: {
userId: req.user.id,
@@ -151,7 +164,7 @@ router.post('/', validateBody(createEntrySchema), async (req, res) => {
});
// ─────────────── PUT /api/entries/:id ───────────────
router.put('/:id', validateBody(updateEntrySchema), async (req, res) => {
router.put('/:id', validateIdParam, validateBody(updateEntrySchema), async (req, res) => {
try {
const { id } = req.params;
@@ -230,7 +243,7 @@ router.put('/:id', validateBody(updateEntrySchema), async (req, res) => {
});
// ─────────────── DELETE /api/entries/:id ───────────────
router.delete('/:id', async (req, res) => {
router.delete('/:id', validateIdParam, async (req, res) => {
try {
const { id } = req.params;