Issue 1: cancelBooking lacks transaction protection
The bookRoom controller (line 396) correctly uses MongoDB transactions, but cancelBooking (line 654) does NOT:
exports.cancelBooking = async (req, res) => {
const booking = await RoomBooking.findById(id); // No session, no transaction
booking.status = "Cancelled";
await booking.save(); // No transaction
};
Two concurrent cancel requests could both read the booking, causing data inconsistency or double-processing.
Issue 2: No unique indexes on critical collections
The User model has no unique indexes on:
- user_id (ID number) - duplicate students can be created
- email - duplicate accounts with same email are possible
The RoomBooking model has no unique compound index on (room, date, startTime). While the app-level transaction in bookRoom prevents this under normal operation, direct database access or a bug could create duplicate bookings.
Fix
Add unique indexes to the schema:
userSchema.index({ user_id: 1 }, { unique: true, sparse: true });
userSchema.index({ email: 1 }, { unique: true });
roomBookingSchema.index({ room: 1, date: 1, startTime: 1, status: 1 }, { partialFilterExpression: { status: { $in: ["Pending", "Approved"] } } });
Wrap cancelBooking in a transaction similar to bookRoom.
Issue 1: cancelBooking lacks transaction protection
The bookRoom controller (line 396) correctly uses MongoDB transactions, but cancelBooking (line 654) does NOT:
Two concurrent cancel requests could both read the booking, causing data inconsistency or double-processing.
Issue 2: No unique indexes on critical collections
The User model has no unique indexes on:
The RoomBooking model has no unique compound index on (room, date, startTime). While the app-level transaction in bookRoom prevents this under normal operation, direct database access or a bug could create duplicate bookings.
Fix
Add unique indexes to the schema:
Wrap cancelBooking in a transaction similar to bookRoom.