An interview scheduling system built with Spring Boot 3.4, MySQL 8, and a React frontend. Interviewers define weekly availability, slots are auto-generated, and candidates can browse and book them — all from a single localhost:8080 deployment.
- Interviewer profiles with weekly capacity limits
- Recurring availability & automatic 2-week slot generation
- Candidate slot browsing with cursor-based pagination
- Atomic booking with race-condition protection (single SQL + optimistic locking)
- Slot capacity updates and cancellation
- Booking cancellation with automatic capacity adjustment
- React frontend bundled into the Spring Boot JAR (no separate dev server needed)
- Debounced filtering, color-coded status, loading states
| Layer | Technology |
|---|---|
| Backend | Java 21, Spring Boot 3.4, Maven |
| Database | MySQL 8 (H2 for tests) |
| ORM | Hibernate 6 / Spring Data JPA |
| Auth | Spring Security (HTTP Basic) |
| Frontend | React 18, Vite 5 |
- Java 21+
- Maven 3.6+
- MySQL 8.0+
- Node.js 18+ / npm (for frontend build, invoked automatically by Maven)
mysql -u root -p < scripts/init-db.sqlThis creates the interview_scheduler database, the scheduler_user account, and all tables.
mvn spring-boot:runMaven will automatically npm install + npm run build the frontend, copy it into the classpath, and start the app.
- UI: http://localhost:8080
- API: http://localhost:8080/api
- Credentials:
admin/password
interview-scheduler/
├── frontend/ # React app (Vite)
│ └── src/
│ ├── components/ # BookingModal, CandidatePanel, InterviewerPanel, etc.
│ ├── hooks/ # useDebounce
│ ├── styles/ # colors, shared styles
│ └── utils/ # dateUtils
├── scripts/
│ └── init-db.sql # Database schema & user setup
├── src/main/java/.../interviewscheduler/
│ ├── config/ # SecurityConfig
│ ├── controller/ # REST controllers
│ ├── dto/ # Request/response DTOs
│ ├── exception/ # GlobalExceptionHandler, ResourceNotFoundException
│ ├── model/ # JPA entities (Interviewer, Slot, Booking, etc.)
│ ├── repository/ # Spring Data repositories
│ └── service/ # Business logic
├── src/main/resources/
│ ├── application.yml # MySQL config (default profile)
│ └── application-dev.yml
├── src/test/ # Unit, integration, and concurrency tests
└── pom.xml
All write endpoints require HTTP Basic auth (admin / password).
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/interviewers |
Create interviewer |
| POST | /api/interviewers/{id}/availability |
Add weekly availability |
| POST | /api/interviewers/{id}/generate-slots?weeks=2 |
Generate slots |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/slots?limit=20&cursor={token} |
List slots (cursor pagination) |
| PATCH | /api/slots/{id} |
Update capacity / status |
| POST | /api/slots/{id}/cancel |
Cancel a slot |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/slots/{id}/book |
Book a slot |
| POST | /api/bookings/{id}/cancel |
Cancel a booking |
{
"timestamp": "2026-03-03T10:15:30.123Z",
"status": 409,
"error": "Conflict",
"message": "Slot is full or no longer available",
"path": "/api/slots/123/book",
"code": "CONFLICT"
}mvn test # all tests
mvn test -Dtest=SlotControllerTest # single test classTests run against an in-memory H2 database (configured via the test profile).
Database credentials are in src/main/resources/application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/interview_scheduler
username: scheduler_user
password: scheduler_passPort 8080 in use:
lsof -i :8080 # find the process
kill <PID> # kill itMySQL access denied:
Make sure you ran scripts/init-db.sql as root first, then connect as scheduler_user:
mysql -u scheduler_user -pscheduler_pass -e "SHOW TABLES" interview_schedulerEducational / evaluation project.