Issue Found
In backend/models/schema.js, there are no unique indexes defined on the RoomBooking collection for (room_id, date, startTime).
Why This matters
The bookRoom controller in backend/controllers/roomBookingController.js (line 407) does app-level clash detection inside a MongoDB transaction, which is good. However, the cancelBooking method (line 654) does NOT use a transaction — it's an unprotected findById + save operation.
Race condition in cancelBooking
exports.cancelBooking = async (req, res) => {
const booking = await RoomBooking.findById(id); // No session, no transaction
// ...
booking.status = "Cancelled";
await booking.save(); // No unique index protects against concurrent modification
};
Two concurrent cancel requests could both read the booking before either updates it.
Missing unique constraint on users
The User model does not have unique indexes on user_id (ID number) or email. This means:
- Duplicate users can be created with the same ID number
- Duplicate users can be created with the same email
- Onboarding could corrupt data if called twice
How to fix
1. Cancel booking should use a transaction:
exports.cancelBooking = async (req, res) => {
const session = await mongoose.startSession();
try {
await session.withTransaction(async () => {
const booking = await RoomBooking.findById(id).session(session);
if (!booking) throw new Error("Booking not found");
// ... validate ...
booking.status = "Cancelled";
await booking.save({ session });
});
} finally {
session.endSession();
}
};
2. Add unique indexes to schema:
userSchema.index({ user_id: 1 }, { unique: true, sparse: true });
userSchema.index({ email: 1 }, { unique: true });
roomBookingSchema.index({ room: 1, date: 1, startTime: 1 }, { unique: true });
Issue Found
In
backend/models/schema.js, there are no unique indexes defined on theRoomBookingcollection for(room_id, date, startTime).Why This matters
The
bookRoomcontroller inbackend/controllers/roomBookingController.js(line 407) does app-level clash detection inside a MongoDB transaction, which is good. However, thecancelBookingmethod (line 654) does NOT use a transaction — it's an unprotectedfindById+saveoperation.Race condition in
cancelBookingTwo concurrent cancel requests could both read the booking before either updates it.
Missing unique constraint on users
The
Usermodel does not have unique indexes onuser_id(ID number) oremail. This means:How to fix
1. Cancel booking should use a transaction:
2. Add unique indexes to schema: