Summary
DailyForge's core differentiator is documented as:
"Automatically detects and prevents scheduling conflicts for the
same day"
The overlap detection logic lives in the React RoutineBuilder.jsx
component — it checks in-memory state before allowing a drop. However,
routineController.js (backend) does not validate for time slot
conflicts before saving to MongoDB.
Concrete Bypass Scenarios
Scenario 1 — Race condition:
Two browser tabs are open to the same routine. Both add tasks to the same
time slot at the same millisecond. Both pass the client-side check (both
see the slot as empty). Both POST to /api/routines/:id. Both succeed.
MongoDB now has two overlapping tasks.
Scenario 2 — Direct API call:
# Add "Study" 09:00–10:00 to Monday
curl -X POST http://localhost:5000/api/routines/abc123/tasks \
-H "Authorization: Bearer <token>" \
-d '{"day": "Monday", "startTime": "09:00", "endTime": "10:00", "taskId": "study"}'
# Add "Meeting" 09:30–10:30 to Monday — overlaps, but backend accepts it
curl -X POST http://localhost:5000/api/routines/abc123/tasks \
-H "Authorization: Bearer <token>" \
-d '{"day": "Monday", "startTime": "09:30", "endTime": "10:30", "taskId": "meeting"}'
# Result: Both saved. Conflict exists in MongoDB.
Proposed Fix
Add conflict detection in routineController.js:
// routineController.js — addTaskToRoutine handler
export const addTaskToRoutine = async (req, res) => {
const { day, startTime, endTime, taskId } = req.body;
const routine = await Routine.findById(req.params.id);
// ✅ Server-side overlap detection
const start = timeToMinutes(startTime);
const end = timeToMinutes(endTime);
const conflict = routine.tasks.find(t =>
t.day === day &&
timeToMinutes(t.startTime) < end &&
timeToMinutes(t.endTime) > start
);
if (conflict) {
return res.status(409).json({
success: false,
message: `Time conflict: "${conflict.title}" occupies ${conflict.startTime}–${conflict.endTime} on ${day}`,
});
}
// Proceed with save...
};
function timeToMinutes(timeStr) {
const [h, m] = timeStr.split(':').map(Number);
return h * 60 + m;
}
Acceptance Criteria
Labels: bug, backend, data-integrity, level: intermediate
Summary
DailyForge's core differentiator is documented as:
The overlap detection logic lives in the React
RoutineBuilder.jsxcomponent — it checks in-memory state before allowing a drop. However,
routineController.js(backend) does not validate for time slotconflicts before saving to MongoDB.
Concrete Bypass Scenarios
Scenario 1 — Race condition:
Two browser tabs are open to the same routine. Both add tasks to the same
time slot at the same millisecond. Both pass the client-side check (both
see the slot as empty). Both POST to
/api/routines/:id. Both succeed.MongoDB now has two overlapping tasks.
Scenario 2 — Direct API call:
Proposed Fix
Add conflict detection in
routineController.js:Acceptance Criteria
routineController.jsvalidates time overlap before saving any tasktimeToMinutes()utility function coversHH:MMformatLabels:
bug,backend,data-integrity,level: intermediate