A full-stack hostel guest room booking portal for IIT Kanpur
Streamlining guest room bookings across IIT Kanpur hostels — from request to check-out.
Features · Roles · Tech Stack · Getting Started · Project Structure · Firestore Schema · Deployment
GRMS is a role-based web application that manages the complete lifecycle of guest room bookings at IIT Kanpur hostels. Students apply for guest rooms, wardens review and approve requests, caretakers handle physical check-in/check-out, and administrators oversee the entire system — all through a single unified portal.
The system enforces institutional access control at every level: only @iitk.ac.in email addresses are accepted, staff accounts require invite codes, and sensitive admin actions require passkey verification.
- Self-registration with
@iitk.ac.inemail enforcement - Room availability map with real-time status (Available / Booked / Pending / Maintenance)
- Multi-step booking form with guest details, dates, and purpose
- Mandatory document upload — Aadhar, College ID, Guest ID (via Cloudinary)
- Email notification assistant — pre-filled email body, subject, CC ready to copy and send to warden
- Live warden decision ticker on dashboard (colour-coded: green / amber / red)
- Full booking history with status tracking
- Scoped dashboard — only bookings for their assigned hostel
- One-click Approve / Conditional Approve / Reject actions
- Condition notes attached to approvals (visible to caretaker and student)
- Document viewer — opens each uploaded ID in a new tab for review
- Check-in / check-out guest management with timestamps
- Passkey displayed on dashboard (used by admin to unlock hostel for editing)
- Active guest list and booking history per hostel
- Full hostel and room management (add hostels, configure rooms, toggle AC, set capacity)
- Session-based passkey unlock per hostel — caretaker's invite code is the hostel key
- Maintenance mode per room — set duration, auto-clears on expiry, cancels overlapping bookings
- System-wide booking oversight with filters by hostel and status
- Admin override cancel on any active booking (passkey + reason required)
- Super Admin gate — invite code management is locked behind a hardcoded passkey, invisible to regular admins
| Role | Access Method | Responsibility |
|---|---|---|
| Student | Self-register (@iitk.ac.in) |
Submit bookings, upload documents, track status |
| Warden | Invite code | Review and approve/reject bookings for their hostel |
| Caretaker | Invite code | Check guests in and out; owns the hostel passkey |
| Admin | Invite code | Manage rooms, monitor all bookings, generate invite codes |
| Super Admin | Hardcoded passkey | Generate/revoke invite codes and staff passkeys |
Super Admin is not a separate account — it's an elevated mode within any admin session, activated by entering
IITK-GRMS-SA-2025in the Invite Codes tab. Change this before deploying to production.
Student Submits
│
▼
[ PENDING ] ──── Warden Reviews ────┬──► [ APPROVED ]
├──► [ CONDITIONAL ]
└──► [ REJECTED ]
│
┌────────────────────┘
▼
Caretaker Acts
│
┌─────┴──────┐
▼ ▼
[ CHECKED IN ] (bypass)
│
▼
[ CHECKED OUT ]
Admin / Maintenance can set ──► [ CANCELLED ] at any active stage
| Layer | Technology |
|---|---|
| Frontend | React 18 + React Router v6 |
| UI Components | Ant Design 5 |
| Authentication | Firebase Authentication |
| Database | Cloud Firestore |
| File Storage | Cloudinary (unsigned upload preset) |
| Styling | Custom CSS-in-JS via injected style tags |
| Fonts | Cormorant Garamond (serif headings), system sans |
| Hosting | Firebase Hosting (recommended) |
- Node.js 18+
- A Firebase project with Authentication and Firestore enabled
- A Cloudinary account with an unsigned upload preset
git clone https://github.com/your-org/iitk-grms.git
cd iitk-grms
npm installCreate src/firebaseConfig.js:
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_PROJECT.firebaseapp.com",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_PROJECT.appspot.com",
messagingSenderId: "YOUR_SENDER_ID",
appId: "YOUR_APP_ID",
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);In src/pages/StudentDashboard.jsx, update the upload constants:
const CLOUD_NAME = "your_cloud_name";
const UPLOAD_PRESET = "your_unsigned_preset";In src/pages/AdminHostels.jsx, line 17:
const SUPER_ADMIN_KEY = "YOUR-CUSTOM-PASSKEY-HERE";
⚠️ This value lives only in source code — it is never written to the database.
In src/pages/StudentDashboard.jsx:
const PORTAL_URL = "https://your-deployed-domain.com";npm run devrules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Students can read/write their own profile
match /users_student/{uid} {
allow read, write: if request.auth.uid == uid;
}
// Staff profiles readable by authenticated users
match /users_warden/{uid} { allow read: if request.auth != null; allow write: if request.auth.uid == uid; }
match /users_caretaker/{uid} { allow read: if request.auth != null; allow write: if request.auth.uid == uid; }
match /users_admin/{uid} { allow read: if request.auth != null; allow write: if request.auth.uid == uid; }
// Bookings — students own theirs, staff read all
match /bookings/{bookingId} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update: if request.auth != null;
}
// Hostels and rooms — read by all authenticated, write by admin
match /hostels/{hostelId} {
allow read: if request.auth != null;
allow write: if request.auth != null;
match /rooms/{roomId} {
allow read, write: if request.auth != null;
}
}
// Invite codes — read by authenticated users (passkey verified client-side)
match /invite_codes/{codeId} {
allow read, write: if request.auth != null;
}
}
}
src/
├── firebaseConfig.js # Firebase initialisation
├── index.js # App entry point + routes
│
├── components/
│ ├── NavigationBar.jsx
│ └── SizedBox.jsx
│
└── pages/
├── PortalTheme.js # Global CSS variables + shared styles
├── AuthContext.jsx # Auth state, role detection, logout
├── ProtectedRoute.jsx # Role-gated route wrapper
│
├── LandingPage.jsx # Public landing page
├── Login.jsx # Sign-in page
├── Signup.jsx # Multi-step registration (student + staff)
│
├── StudentDashboard.jsx # Booking form, status tracker, ticker
├── WardenDashboard.jsx # Booking review and approval
├── CaretakerDashboard.jsx # Check-in / check-out management
├── AdminHostels.jsx # Hostel/room admin + super admin gate
└── roomAvailability.jsx # Public room status component
hostels/{hostelId}
├── name, createdAt
└── rooms/{roomId}
├── capacity, ac, maintenance
├── maintenanceNote, maintenanceFrom, maintenanceTo, maintenanceDays
bookings/{bookingId}
├── hostelId, hostelName, roomId, roomCapacity, roomAc
├── studentId, studentName, phone
├── guestName, guestRelation, purpose
├── checkIn, checkOut, bookedAt
├── status: "pending" | "approved" | "conditional" | "rejected"
│ | "checked_in" | "checked_out" | "cancelled"
├── wardenNote, reviewedAt, checkedInAt, checkedOutAt, cancelledAt
└── documents: { aadhar, collegeId, guestId } ← Cloudinary URLs
users_student/{uid}
└── name, email, phone, rollNo, hostel, department, role, createdAt
users_warden/{uid}
└── name, email, phone, role, hostelId, hostelName, createdAt
users_caretaker/{uid}
└── name, email, phone, role, hostelId, hostelName, createdAt
users_admin/{uid}
└── name, email, role, createdAt
invite_codes/{codeId} ← Document ID = the passkey (e.g. CARETAKER-A3F9K2)
└── role, hostelId, hostelName, used, createdAt, usedBy, usedAt
The system has three independent layers of access control:
1. Email domain enforcement
All registrations require @iitk.ac.in — enforced client-side (live validation) and server-side (Firebase rejects other domains via a pre-check in signup logic).
2. Invite code system Warden, caretaker, and admin accounts can only be created by redeeming a one-time invite code generated by a super admin. Codes are single-use and stored in Firestore.
3. Passkey system (three tiers)
| Passkey | What It Unlocks | Where It Lives |
|---|---|---|
| Caretaker invite code ID | Hostel room editing (admin), booking cancellation (admin), hostel deletion (admin) | Firestore invite_codes collection |
| Caretaker dashboard display | Shown to caretaker on their dashboard for sharing with admin | Firestore (same doc ID) |
| Super Admin key | Invite Codes tab — generate / revoke all staff codes | Hardcoded in source only — never in database |
npm run build
firebase deploy --only hosting- Update
PORTAL_URLinStudentDashboard.jsxto your live domain - Change
SUPER_ADMIN_KEYinAdminHostels.jsxfrom the default value - Set Firestore security rules (see above)
- Enable Firebase Authentication → Email/Password provider
- Create Cloudinary upload preset (
iitk_docs) set to Unsigned - Delete all test Firebase Auth users and test Firestore documents
- Re-register all real staff accounts under the live system
| Path | Component | Access |
|---|---|---|
/ |
LandingPage |
Public |
/login |
Login |
Public |
/signup |
Signup |
Public |
/student/dashboard |
StudentDashboard |
Role: student |
/warden/dashboard |
WardenDashboard |
Role: warden |
/caretaker/dashboard |
CaretakerDashboard |
Role: caretaker |
/admin/hostels |
AdminHostels |
Role: admin |
* |
Redirect | → / |
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'Add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
This project is licensed under the MIT License — see the LICENSE file for details.
Built for IIT Kanpur · Hostel Administration
For issues or feature requests, open a GitHub issue.