Background
Booking classrooms, labs, and special rooms on campus is still mostly manual. Availability is scattered across chats and spreadsheets, schedules don't always match what is actually happening in a room, and there is no documented request-and-approval trail. ClassLab was built as a Project Management course project (Group 2) to replace this with one web system.Problem
- Double Bookings: Without a single source of truth, two groups can end up with the same room at the same time, or a booking can collide with the academic schedule.
- Unclear Approval: Different room types need different approvers (admin staff for classrooms, lab heads for labs), and nobody can see the request status.
- Ghost Bookings: Rooms get reserved but never used, blocking others.
- No Accountability: Room damage and misuse are hard to trace back to a booking.
Solution
ClassLab is a responsive web app that covers the whole lifecycle of a room booking.- Users see live room availability and submit a request, and overlap validation rejects conflicts at the database level.
- Requests are routed by room-type policy: auto-approved for students in free classrooms, manually reviewed for labs, special rooms, and student organizations.
- QR check-in at the door and photo check-out record real usage, and no-shows are released automatically.
- Damage reports, violation points, and temporary blocks keep users accountable.
My Role
Full-Stack Engineer- Designed the REST API contract (OpenAPI 3.1) and the PostgreSQL schema with migrations.
- Built the Go backend: auth, bookings, approval policies, check-in/out, and background jobs.
- Built the React frontend with role-based pages, mobile-first for students.
- Set up the Docker and Caddy (HTTPS) production deployment with backup and restore.
Architecture
ClassLab is a modular monolith with a typed contract between the two sides:- Backend (api/): Go with net/http + chi. One package per domain (bookings, rooms, schedules, availability, notifications, reports, violations, imports, audit, jobs), each split into handler, service, and data access.
- Data Access: sqlc generates type-safe queries from SQL, and golang-migrate manages schema versions.
- Frontend (web/): Vite + React + TypeScript, with types generated from openapi.yaml.
- Database: PostgreSQL with the btree_gist extension.
- Deployment: Docker Compose with Caddy for automatic HTTPS.
Technical Challenges
- Race-Free Conflict Detection: Checking for overlaps in application code breaks under concurrent requests. Solution: Enforced non-overlapping time ranges in PostgreSQL with a btree_gist constraint, so conflicts are rejected atomically.
- Different Rules per Room Type: Hard-coding approval logic per room would not scale. Solution: Moved approvers, auto-approval, and quotas into per-room-type policies that admins can change without a deploy.
- Contract Drift Between Frontend and Backend: Hand-written types fall out of sync. Solution: Made openapi.yaml the single source of truth, generated frontend types from it, and added contract tests against the API.
- Trustworthy Integration Tests: Mocked databases hid real constraint behavior. Solution: Ran backend tests against real PostgreSQL containers with testcontainers-go.
Features
- Availability & Booking: Live status (TERSEDIA, DIGUNAKAN, DIAJUKAN), conflict validation, multi-date booking, and edits until 60 minutes before start.
- Policy-Based Approval: Auto or manual approval per room type, mandatory rejection reasons, and automatic expiry after 24 hours without a decision.
- QR Check-In / Photo Check-Out: Real usage tracking using the phone camera, with no-show auto-release.
- Accountability: Booking quotas, violation points, temporary blocks, damage reports, and an audit log.
- Bulk Import: CSV import of academic schedules (always prioritized over bookings) and student accounts.
- Role-Based Access: Students, student organizations (with an assignment letter attachment), admin staff, lab heads, janitors, and system admins.
- In-App Notifications & Responsive UI: Reminders for check-in and check-out, tested on phone to desktop viewports.
Tech Stack
Frontend:- React 19 & TypeScript (strict)
- Vite, TanStack Router / Query / Table
- Tailwind CSS v4 & shadcn/ui
- react-hook-form & Zod
- Go, chi, pgx, sqlc
- JWT auth with argon2id password hashing
- OpenAPI 3.1 contract
- PostgreSQL 15+ (btree_gist)
- Docker & Docker Compose
- Caddy (automatic HTTPS)
- Testing: testcontainers-go, Vitest, Playwright
Results
- Delivered a full booking workflow, from request to approval to check-out, for all six user roles.
- Removed double bookings by moving conflict detection into the database.
- Shipped a production-ready deployment with HTTPS, backups, and a recovery runbook.
Lessons Learned
- Database Constraints over App Logic: Letting PostgreSQL enforce invariants is simpler and safer than coordinating checks in code.
- Contract-First Development: Generating types from OpenAPI caught breaking changes before runtime.
- Policy as Data: Storing business rules as configuration made the system adaptable without code changes.
Future Improvements
- Recurring Bookings: Reserving a room weekly for a whole semester in one request, with conflict checks for every occurrence.
- Smart Room Suggestions: Recommending alternative rooms or slots by capacity, equipment, and past usage when a slot is taken.
- Calendar Sync: Syncing approved bookings with Google Calendar and Outlook.
- Usage Analytics Dashboard: Showing utilization, peak hours, and no-show rates for capacity planning.
- Campus SSO: Signing in with institutional accounts (SAML/OIDC).
- Mobile Push Notifications: Real-time alerts for approvals and reminders via PWA and Web Push.