Student-Faculty Services v2 Case Study

A full rewrite of my senior capstone: students book 5 to 45 minute office-hour slots, and faculty set their hours, closures, booking rules, and approvals. Undo, reminders, ratings, and a waitlist are built in.

A 48-second walkthrough: guest login, browsing faculty availability, selecting 5 to 45 minute session lengths, picking an office-hour slot to book, viewing notifications, and switching to faculty schedule management.

The problem

A student needs five minutes to check a grade. Another needs forty-five for a project review. Both are chasing the same weekly office hour, often with no idea which slots are still open. One walks across campus for a time that was taken an hour earlier; a faculty member sits in an empty room because a cancellation was never offered to anyone else.

Faculty end up running the queue by hand: cap how many students they see, close for a meeting, turn away a request that came too late, approve or decline another, and remember to send a reminder. A shared spreadsheet, a whiteboard, or an email thread leaves everyone guessing how long a meeting should be, whether the room is free, and who is next.

How it fits together

v2 turns that manual queue into the product. Faculty publish their weekly hours, set session lengths and rules, close a day when something comes up, and approve requests. Students see the real open slots, book one, cancel and undo for a few seconds, and join a waitlist when the time they need is full. Reminders and ratings close the loop.

React 19, TypeScript, Vite, React Router, and TanStack Query run the front end. The API is plain PHP 8.4 with no framework: a router, controllers, services, and repositories over PDO. MariaDB 11.4 holds 13 tables, and the API exposes 46 REST endpoints, 28 of them writes.

That is more structure than the first version had, but it is what makes the rules testable. The service layer owns the transaction and the checks; the controllers only validate input and shape the response.

Four decisions

Ten rules, one transaction

A booking locks the student row, then the faculty row, always in that order, and checks notice, overlaps, limits, closures, and the rest before it writes. The order is deliberate: it cannot deadlock, and it gives one winner under contention.

Trade-off: a little more work per booking, in exchange for a rule set that cannot half-apply. An eight-student race for one slot produces exactly one booking.

Undo re-checks every rule

A cancelled time is held for 15 seconds on the server; the interface offers 10. Undo does not restore a saved booking blindly. It runs the same checks under the same locks, so a slot that was taken in the meantime stays taken.

Trade-off: a short hold on the slot, in exchange for undo that cannot create an overlap. An undo racing seven bookings still wins.

Reminders that never double-send

Each reminder is claimed with a conditional update, so it is created once. Optional email goes through an outbox, is scheduled ahead, and is skipped if the reason for it has gone.

Trade-off: a little scheduling machinery, in exchange for a reminder path that survives retries without sending twice.

Tested before every deploy

339 PHPUnit tests, 143 Vitest tests, and 20 Playwright tests run in CI, with accessibility checks in light and dark. The booking race test was proven by removing the lock: without it, it produced double bookings.

Trade-off: a slower pipeline, in exchange for deploy gates that catch the failures that matter.

Details

The full feature set and the engineering behind it, including booking correctness, reminders, security, and testing.

Features

Students
  • Faculty directory: search by name or college, with each person's next free time.
  • Faculty profiles: details, weekly office hours with their rooms or online meetings, and rating averages once there are three ratings.
  • Booking grid for the next 7 days: pick a session length (5, 15, 30 or 45 minutes) with free-slot counts per length; times inside a faculty member's minimum notice show as "Too soon".
  • Limits: at most 5 upcoming appointments, one per faculty member per day, and no overlaps.
  • Cancel with a 10-second undo.
  • Waitlist when nothing is free (up to 5 at once): one alert when a time opens, in the app and by email if enabled.
  • Ratings after an attended appointment: three 1-5 criteria within 14 days, anonymous to faculty.
  • Reminders the day before each appointment and before the rating window closes, plus optional email with a verified address.
  • Profile with name, major and photo; sign-up with a university-format student ID and a "Suggest an ID" helper.
Faculty
  • Dashboard with today's appointments and Close now for emergencies.
  • Weekly office-hours blocks (1.5 hours, up to two a day), each in a campus room or online; editing or removing one previews which bookings it would cancel.
  • Closures: close a range of time with a preview of who is affected; a 10-second undo restores their bookings, and students are told once it is final.
  • Booking rules: minimum notice, session lengths offered, and a gap around each appointment; they apply to new bookings only.
  • Approvals: mark finished appointments attended or not, with an optional report, which opens rating for the student.
Everyone
  • Notification bell (checked every minute while the tab is visible): bookings, cancellations, closures, reminders, approvals, rating requests and "a time is free"; shows the newest 30 with Show older and Clear read.
  • Light and dark themes, phone layouts, and short tips on every page.
  • Guest access: one-click student and faculty accounts, or sign in as any of the 155 faculty and 200 sample students; the sample data resets weekly.

Technical details

Architecture
  • React 19, TypeScript, Vite, React Router and TanStack Query on the front end.
  • A layered, framework-free PHP 8.4 API: router, controllers, services and repositories over PDO, with 46 REST endpoints (28 of them write endpoints).
  • MariaDB 11.4 with 13 tables (11 foreign keys, 11 CHECK constraints and 4 unique keys).
  • All times use Asia/Dubai through one clock that tests can freeze.
Booking correctness
  • One transaction locks the student row, then the faculty row (always in that order, so bookings cannot deadlock) and checks ten rules.
  • Tested three ways: a test holding a shared lock from a second connection, eight students racing for one slot over real HTTP (exactly one wins), and every rule checked in SQL at four times of the week; the race test fails without the lock.
  • Undo: a cancelled time is held for 15 seconds (the interface offers 10), the other side's notification is dated at the end of the window, and undo re-checks every rule under the same locks; an undo racing seven bookings always wins.
Reminders, email and upkeep
  • Reminders are claimed with a conditional update, so each is created once; optional emails go through an outbox, are scheduled ahead, and one whose reason is gone is never sent.
  • Email addresses are verified with a click that needs a real button press, so mail scanners cannot confirm them.
  • New database migrations, the weekly sample-data reset and reminders run automatically on the first request that needs them, under database locks; a test proves the original schema plus every migration equals the current schema.
Security
  • Prepared statements (real server-side prepares) for every query that takes user input; ownership is checked in the SQL itself.
  • A CSRF token is required on all 28 write endpoints; login throttling by email and IP; strict sessions with a new ID on login and logout.
  • Uploaded photos are re-encoded to WebP, which drops metadata and hidden payloads; security headers are set on responses.
Testing and delivery
  • 339 PHPUnit tests (unit tests and feature tests through the real router), plus real-HTTP tests through Apache, 143 Vitest tests, and 20 Playwright tests that run on desktop and phone with axe accessibility checks in light and dark mode.
  • The booking race test was proven by removing the lock: without it, it produced double bookings; Lighthouse scores 100 for accessibility and best practices on the login page.
  • GitHub Actions runs the web and API checks, integration tests and a production-layout check, and deploys only when everything passes; local development and CI use the same MariaDB version as production.
  • A README with architecture and data-model diagrams, a handoff guide for new developers, and a deploy guide with the migration procedure.

What it doesn't cover yet

  • It is a public build: the guest accounts are shared with every visitor and the sample data resets weekly.
  • The 155 faculty and 200 students are sample data, not a live university deployment.
  • The project is a rewrite of a capstone, not a production service with real institutional data.

Got something to build?

Let's talk it through and build it together.