A high-performance meeting scheduling platform built with Spring Boot, designed to handle hundreds of users managing thousands of time slots efficiently.
- User Management: Create and manage user profiles
- Calendar Management: Personal calendars for each user with timezone support
- Time Slot Management:
- Create, update, and delete available time slots
- Mark slots as FREE, BUSY, or BOOKED
- Validate slots to prevent overlaps
- Configurable duration (15 minutes to 8 hours)
- Meeting Scheduling:
- Convert available slots into meetings
- Add multiple participants
- Meeting details (title, description)
- Manage participants dynamically
- Availability Queries: Query free and busy slots within time ranges
- Concurrent Booking Protection: Optimistic locking to handle race conditions
- REST API: Comprehensive RESTful endpoints
- API Documentation: Swagger/OpenAPI documentation
- Metrics: Prometheus metrics for monitoring
- Production Ready: Docker containerization with PostgreSQL
- Java 17
- Spring Boot 3.2.1
- Spring Data JPA with Hibernate
- PostgreSQL (Production)
- H2 (Testing)
- Docker & Docker Compose
- Swagger/OpenAPI for API documentation
- Prometheus for metrics
- Lombok for reducing boilerplate
- Gradle for build management
- User: Platform users with unique email addresses
- Calendar: One-to-one relationship with User, manages time zones
- TimeSlot: Time slots with status (FREE, BUSY, BOOKED) and overlap prevention
- Meeting: Scheduled meetings linked to time slots with multiple participants
- Database Indexing: Strategic indexes on frequently queried fields
- User email
- Calendar userId
- TimeSlot calendar+time range
- Meeting participants
- Pessimistic Locking: Prevents concurrent booking conflicts
- Optimistic Locking: Version control on TimeSlot for updates
- Lazy Loading: Optimized entity relationships to reduce database queries
- Query Optimization: Custom JPQL queries with proper JOIN strategies
- Connection pooling with HikariCP (20 max connections)
- Stateless REST API design
- Dockerized deployment for horizontal scaling
- Database indexes for query performance
- Metrics endpoint for monitoring bottlenecks
- Docker 20.10+
- Docker Compose 2.0+
- (Optional) Java 17+ and Gradle 8+ for local development
- Clone the repository:
git clone <repository-url>
cd MiniDoodle- Start all services:
docker-compose up --buildThis will start:
- PostgreSQL database on port 5432
- Mini Doodle application on port 8080
- Prometheus on port 9090
- Access the application:
- API Base URL: http://localhost:8080
- Swagger UI: http://localhost:8080/swagger-ui.html
- API Docs: http://localhost:8080/api-docs
- Health Check: http://localhost:8080/actuator/health
- Metrics: http://localhost:8080/actuator/metrics
- Prometheus: http://localhost:9090
- Start PostgreSQL (or use H2 by setting
spring.profiles.active=test):
docker run -d \
--name postgres \
-e POSTGRES_DB=minidoodle \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres:15-alpine- Run the application:
./gradlew bootRunhttp://localhost:8080/api/v1
POST /users- Create a new userGET /users- Get all usersGET /users/{id}- Get user by IDGET /users/email/{email}- Get user by emailPUT /users/{id}- Update userDELETE /users/{id}- Delete user
POST /timeslots/users/{userId}- Create time slot for userGET /timeslots/{id}- Get time slot by IDPUT /timeslots/{id}- Update time slotDELETE /timeslots/{id}- Delete time slotPATCH /timeslots/{id}/status?status={FREE|BUSY|BOOKED}- Update slot statusPATCH /timeslots/{id}/mark-busy- Mark slot as busyPATCH /timeslots/{id}/mark-free- Mark slot as freeGET /timeslots/users/{userId}?startTime={ISO8601}&endTime={ISO8601}- Get slots in time rangeGET /timeslots/users/{userId}/availability?startTime={ISO8601}&endTime={ISO8601}- Get availability
POST /meetings- Create meeting from time slotGET /meetings/{id}- Get meeting by IDPUT /meetings/{id}- Update meetingDELETE /meetings/{id}- Cancel meetingGET /meetings/users/{userId}?startTime={ISO8601}&endTime={ISO8601}- Get user's meetingsGET /meetings/users/{userId}/owned?startTime={ISO8601}&endTime={ISO8601}- Get meetings owned by userPOST /meetings/{meetingId}/participants/{userId}- Add participantDELETE /meetings/{meetingId}/participants/{userId}- Remove participant
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john.doe@example.com"
}'Response:
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"createdAt": "2025-01-15T10:00:00",
"updatedAt": "2025-01-15T10:00:00"
}curl -X POST http://localhost:8080/api/v1/timeslots/users/1 \
-H "Content-Type: application/json" \
-d '{
"startTime": "2025-01-20T10:00:00",
"endTime": "2025-01-20T11:00:00"
}'Or with duration:
curl -X POST http://localhost:8080/api/v1/timeslots/users/1 \
-H "Content-Type: application/json" \
-d '{
"startTime": "2025-01-20T10:00:00",
"durationMinutes": 60
}'curl "http://localhost:8080/api/v1/timeslots/users/1/availability?startTime=2025-01-20T00:00:00&endTime=2025-01-21T00:00:00"Response:
{
"freeSlots": [
{
"id": 1,
"calendarId": 1,
"startTime": "2025-01-20T10:00:00",
"endTime": "2025-01-20T11:00:00",
"status": "FREE",
"durationMinutes": 60,
"createdAt": "2025-01-15T10:00:00",
"updatedAt": "2025-01-15T10:00:00"
}
],
"busySlots": [],
"totalFreeSlots": 1,
"totalBusySlots": 0
}curl -X POST http://localhost:8080/api/v1/meetings \
-H "Content-Type: application/json" \
-d '{
"timeSlotId": 1,
"title": "Project Kickoff",
"description": "Initial project planning meeting",
"participantIds": [2, 3]
}'curl "http://localhost:8080/api/v1/meetings/users/1?startTime=2025-01-20T00:00:00&endTime=2025-01-21T00:00:00"./gradlew test./gradlew test jacocoTestReportcurl http://localhost:8080/actuator/health# All metrics
curl http://localhost:8080/actuator/metrics
# Specific metric
curl http://localhost:8080/actuator/metrics/jvm.memory.used
# Prometheus format
curl http://localhost:8080/actuator/prometheusAccess Prometheus at http://localhost:9090 to view:
- Request rates
- Response times
- JVM metrics
- Database connection pool stats
-- Users table
users (id, name, email, created_at, updated_at)
-- Calendars table
calendars (id, user_id, timezone, created_at, updated_at)
-- Time slots table
time_slots (id, calendar_id, start_time, end_time, status, version, created_at, updated_at)
-- Meetings table
meetings (id, time_slot_id, title, description, created_at, updated_at)
-- Meeting participants (many-to-many)
meeting_participants (meeting_id, user_id)DB_HOST: Database host (default: localhost)DB_PORT: Database port (default: 5432)DB_NAME: Database name (default: minidoodle)DB_USER: Database user (default: postgres)DB_PASSWORD: Database password (default: postgres)SPRING_PROFILES_ACTIVE: Active profile (default, test)
See src/main/resources/application.yml for configuration options.
- Authentication & Authorization: Add Spring Security with JWT
- Recurring Meetings: Support for recurring time slots
- Email Notifications: Send meeting invites and reminders
- Time Zone Handling: Better timezone conversion for participants
- Conflict Resolution: Advanced scheduling algorithms
- GraphQL API: Alternative to REST for complex queries
- Caching: Redis integration for frequently accessed data
- Event Sourcing: Track all state changes for audit trail
- WebSocket: Real-time updates for calendar changes
- Rate Limiting: API rate limiting for fair usage
Apache License 2.0
For issues and questions, please open an issue in the repository.