A full-stack MERN application for managing restaurant table reservations, supporting both customer bookings and administrative oversight.
- Frontend: React (Vite), React Router, Axios
- Backend: Node.js, Express
- Database: MongoDB (Mongoose)
- Authentication: JWT (JSON Web Tokens), bcrypt for password hashing
- Register / Login
- Reserve a table (date, time slot, number of guests)
- View own reservations
- Cancel own reservations
- Login
- View all reservations
- Filter reservations by date
- Update or cancel any reservation
- Manage restaurant tables (add / delete)
Restaurant-Reservation-System/
├── backend/
│ ├── config/ # MongoDB connection
│ ├── controllers/ # Business logic for each route
│ ├── middleware/ # Auth, role checks, error handling
│ ├── models/ # Mongoose schemas (User, Table, Reservation)
│ ├── routes/ # API route definitions
│ ├── utils/ # JWT helper, seed script
│ └── server.js
└── frontend/
├── src/
│ ├── components/ # Reusable UI pieces
│ ├── pages/ # Route-level pages
│ ├── context/ # AuthContext (global login state)
│ └── services/ # Axios API calls
- Node.js (v18+)
- MongoDB running locally on
mongodb://127.0.0.1:27017
cd backend
npm install
Create a .env file in backend/:
PORT=5000
MONGO_URI=mongodb://127.0.0.1:27017/restaurant_reservation
JWT_SECRET=your_secret_key_here
NODE_ENV=development
Seed sample tables:
npm run seed
Start the server:
npm run dev
Backend runs on http://localhost:5000.
cd frontend
npm install
Create a .env file in frontend/:
VITE_API_URL=http://localhost:5000/api
Start the dev server:
npm run dev
Frontend runs on http://localhost:5173.
Note: both the backend and frontend servers must be running at the same time, in separate terminals.
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /api/auth/register |
Public | Register a new user (customer or admin) |
| POST | /api/auth/login |
Public | Log in and receive a JWT |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /api/reservations |
Customer | Create a reservation |
| GET | /api/reservations/my |
Customer | View own reservations |
| DELETE | /api/reservations/:id |
Customer (owner only) | Cancel own reservation |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/reservations/admin |
Admin | View all reservations |
| GET | /api/reservations/admin?date=YYYY-MM-DD |
Admin | Filter reservations by date |
| PUT | /api/reservations/admin/:id |
Admin | Update any reservation |
| DELETE | /api/reservations/admin/:id |
Admin | Cancel any reservation |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/tables |
Any logged-in user | List all tables |
| POST | /api/tables |
Admin | Create a table |
| PUT | /api/tables/:id |
Admin | Update a table |
| DELETE | /api/tables/:id |
Admin | Delete a table |
When a customer requests a table for a given date, time slot, and guest count:
- The system finds all tables with
capacity >= guests, sorted smallest-first (to avoid seating 2 guests at a 6-person table when a 2-person table is free). - It checks which of those candidate tables already have a
confirmedreservation for the samedateandtimeSlot. - It assigns the customer to the smallest available table that fits their party.
- If every suitably-sized table is already booked at that date/time, the request is rejected with a
409 Conflictand a clear error message.
Cancelled reservations are soft-deleted (status changed to cancelled rather than removed from the database), so they no longer block a table's availability but remain in the history for admin visibility.
The same conflict check runs again when an admin updates a reservation's date, time, or table, to prevent an update from accidentally creating a double-booking.
- JWT tokens are issued on login/register and include the user's
role(customeroradmin). - Backend middleware (
protect) verifies the token on every protected route. - A second middleware (
authorize('admin')) restricts specific routes (table management, admin reservation views) to admins only. - On the frontend, a
ProtectedRoutecomponent restricts page access by role and redirects unauthorized users to/login. This is a UX convenience only — actual security enforcement happens on the backend. - Customers can only view/cancel their own reservations, enforced by comparing the reservation's
customerfield against the logged-in user's ID.
- Single restaurant, fixed set of tables (seeded via script, or created by an admin through the UI).
- Time slots are chosen from a fixed list (e.g.,
12:00,13:00,18:00,19:00,20:00,21:00) rather than freely typed, to keep availability logic predictable. dateis stored as aYYYY-MM-DDstring rather than a JSDateobject, to keep comparisons simple and avoid timezone issues.- Any registering user can technically request
role: "admin"in the request body — this is a deliberate simplification for ease of testing/grading. In a production system, admin accounts would be created via a separate secured process, not open self-registration.
- No email/notification system (out of scope per assignment).
- Past-date booking is prevented only on the frontend (date picker
min), not re-validated on the backend. - Admin's "Edit Reservation" UI currently only exposes editing the guest count; the backend API supports updating date/time/table/status as well, but the frontend form for that isn't built yet.
- No pagination on reservation lists — fine at small scale, would need it for a busy restaurant with a long history.
- No automated tests (unit/integration) were included given the 48-hour timeframe.
- Full reservation editing UI for admins (date, time slot, table reassignment).
- Backend-side validation rejecting past-date bookings.
- Pagination and search on the admin reservations list.
- Email confirmation on booking/cancellation.
- Automated tests for the reservation conflict logic (the most critical business logic in the app).
- Improved UI/UX styling — current UI is intentionally minimal per assignment scope ("polished UI not required"). =======