A comprehensive Gym Customer Relationship Management system built with microservices architecture using Spring Boot and Spring Cloud.
- Overview
- Architecture
- Services
- Technology Stack
- Prerequisites
- Getting Started
- API Documentation
- Testing
- Project Structure
- Configuration
- Security
- Monitoring
- Contributing
The Gym CRM System is a microservices-based application designed to manage gym operations including trainers, trainees, training sessions, and workload tracking. The system uses modern Spring technologies and follows clean architecture principles.
- π₯ User Management: Trainee and Trainer registration and profiles
- π Training Sessions: Create, update, and track training sessions
- π Workload Tracking: Real-time trainer workload calculation with monthly summaries
- π Security: JWT-based authentication and authorization
- π Service Discovery: Eureka-based microservice discovery
- π‘οΈ Resilience: Circuit breaker pattern for fault tolerance
- π Logging: Two-level logging with MDC correlation IDs
- π API Documentation: Swagger/OpenAPI 3.0 documentation
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Eureka Server (8761) β
β Service Discovery β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββ΄ββββββββββββββββ
β β
βββββββββββββΌβββββββββββ βββββββββββββΌβββββββββββ
β Gym-CRM-System β β Workload-Service β
β Port: 8080 ββββββββΊβ Port: 8082 β
β β Feign β β
β - Trainers β β - Workload Tracking β
β - Trainees β β - Monthly Summaries β
β - Trainings β β - In-Memory Storage β
β - PostgreSQL β β - JWT Auth β
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
- Service Discovery: Eureka Server
- Inter-Service Communication: OpenFeign (declarative REST client)
- Resilience: Resilience4j Circuit Breaker with fallback
- Load Balancing: Client-side load balancing via Eureka
- Application Name:
Gym-discovery-service - Port: 8761
- Purpose: Service registry and discovery
- URL:
http://localhost:8761 - Configuration:
- Does not register itself with Eureka (
register-with-eureka: false) - Does not fetch registry (
fetch-registry: false) - Acts as standalone service discovery server
- Does not register itself with Eureka (
- Application Name:
gym-crm-system - Port: 8081 (dev), 8080 (prod)
- Purpose: Main CRM application
- Database: PostgreSQL
- Key Features:
- User management (Trainers, Trainees)
- Training session management
- Authentication & Authorization (JWT)
- Metrics and monitoring with Prometheus
- Integration with workload-service via OpenFeign
- Circuit Breaker:
- Sliding window size: 10 calls
- Failure rate threshold: 50%
- Wait duration in open state: 5s
- Eureka Configuration:
- Registers with Eureka:
true - Fetches registry:
true - Lease renewal interval: 30s
- Registers with Eureka:
- Application Name:
workload-service - Port: 8082
- Purpose: Trainer workload tracking
- Storage: In-memory (ConcurrentHashMap)
- Key Features:
- Real-time workload calculation
- Monthly summary aggregation
- Thread-safe operations
- Stateless JWT authentication
- Logging:
- Root level: INFO
- Application level: DEBUG
- Log file:
logs/workload-service.log
- Eureka Configuration:
- Registers with Eureka:
true - Fetches registry:
true - Lease renewal interval: 30s
- Registers with Eureka:
- Java: 17
- Spring Boot: 3.4.5
- Spring Cloud: 2024.0.0
- Spring Security: JWT Authentication
- Spring Data JPA: Database access
- PostgreSQL: Main database
- Liquibase: Database migration
- Netflix Eureka: Service discovery
- OpenFeign: Declarative REST client
- Resilience4j: Circuit breaker
- Lombok: Code generation
- MapStruct: Object mapping
- Swagger/OpenAPI: API documentation
- JUnit 5: Testing framework
- Mockito: Mocking framework
- Actuator: Application monitoring
- Maven: Build automation
- Git: Version control (mono-repo approach)
- Java 17 or higher
- Maven 3.8+
- PostgreSQL 14+
- Git
- Docker (for containerized deployment)
- Postman (for API testing)
git clone https://github.com/DesBasito/Gym_system.git
cd Gym_systemCREATE DATABASE gym_crm;
CREATE USER gym_user WITH PASSWORD 'gym_password';
GRANT ALL PRIVILEGES ON DATABASE gym_crm TO gym_user;Update services/Gym-CRM-system/src/main/resources/application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/gym_crm
username: gym_user
password: gym_passwordcd services/discovery-service
mvn spring-boot:runWait for Eureka to start at http://localhost:8761
cd services/workload-service
mvn spring-boot:runService will register with Eureka at port 8082
cd services/Gym-CRM-system
mvn spring-boot:run -Dspring-boot.run.profiles=devService will register with Eureka at port 8081 (dev profile)
Note: For production, use
-Dspring-boot.run.profiles=prod(port 8080)
- Eureka Dashboard: http://localhost:8761
- Check that both
gym-crm-systemandworkload-serviceare registered
- Check that both
- Gym-CRM Swagger: http://localhost:8081/swagger-ui.html (dev)
- API documentation and testing interface
- Workload Swagger: http://localhost:8082/swagger-ui.html
- Workload service API documentation
- Actuator Endpoints:
- Gym-CRM: http://localhost:8081/actuator/health
- Workload: http://localhost:8082/actuator/health
Swagger UI: http://localhost:8080/swagger-ui.html
POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
PUT /api/auth/change-passwordPOST /api/trainees
GET /api/trainees/{username}
PUT /api/trainees/{username}
DELETE /api/trainees/{username}
PUT /api/trainees/{username}/trainersPOST /api/trainers
GET /api/trainers/{username}
PUT /api/trainers/{username}
GET /api/trainers/not-assigned/{traineeUsername}POST /api/trainings
GET /api/trainings/trainee
GET /api/trainings/trainer
GET /api/trainings/typesSwagger UI: http://localhost:8082/swagger-ui.html
POST /api/workload # Update trainer workload
GET /api/workload/{username} # Get trainer workload
GET /api/workload # Get all workloads# Gym-CRM-System
cd services/Gym-CRM-system
mvn clean test
# Workload-Service
cd services/workload-service
mvn clean testmvn clean test jacoco:report
# Report: target/site/jacoco/index.htmlmvn verify -P integration-testsGym_system/
βββ services/
β βββ discovery-service/ # Eureka Server (Service Discovery)
β β βββ src/
β β β βββ main/
β β β β βββ java/
β β β β β βββ epam/gym/
β β β β β βββ GymDiscoveryServiceApplication.java
β β β β βββ resources/
β β β β βββ application.yaml
β β β βββ test/
β β βββ pom.xml
β β
β βββ Gym-CRM-system/ # Main CRM application
β β βββ src/
β β β βββ main/
β β β β βββ java/
β β β β β βββ epam/gym/
β β β β β βββ config/
β β β β β β βββ SecurityConfig.java
β β β β β β βββ OpenApiConfig.java
β β β β β β βββ AsyncConfiguration.java
β β β β β βββ constants/
β β β β β βββ domain/
β β β β β β βββ dto/
β β β β β β βββ models/
β β β β β β βββ services/
β β β β β βββ infrastructure/
β β β β β βββ client/ # Feign clients
β β β β β β βββ WorkloadServiceClient.java
β β β β β β βββ WorkloadServiceClientFallbackFactory.java
β β β β β β βββ config/
β β β β β β βββ dto/
β β β β β βββ controllers/
β β β β β βββ entities/
β β β β β βββ repositories/
β β β β β βββ security/
β β β β β βββ monitoring/
β β β β βββ resources/
β β β β βββ application.yml
β β β β βββ application-dev.yml
β β β β βββ application-test.yml
β β β β βββ application-prod.yml
β β β βββ test/
β β βββ pom.xml
β β
β βββ workload-service/ # Workload tracking microservice
β βββ src/
β β βββ main/
β β β βββ java/
β β β β βββ abu/epam/com/workloadservice/
β β β β βββ config/
β β β β β βββ SecurityConfig.java
β β β β β βββ OpenApiConfig.java
β β β β βββ domain/
β β β β β βββ dto/
β β β β β β βββ WorkloadRequest.java
β β β β β βββ model/
β β β β β β βββ TrainerWorkload.java
β β β β β β βββ TrainerYearlySummary.java
β β β β β β βββ TrainerMonthlySummary.java
β β β β β βββ service/
β β β β β βββ WorkloadService.java
β β β β βββ infrastructure/
β β β β βββ controller/
β β β β β βββ WorkloadController.java
β β β β β βββ GlobalExceptionHandler.java
β β β β βββ filter/
β β β β β βββ TransactionLoggingFilter.java
β β β β βββ security/
β β β β βββ JwtAuthenticationFilter.java
β β β β βββ JwtUtil.java
β β β βββ resources/
β β β βββ application.yml
β β β βββ logback-spring.xml
β β βββ test/
β β βββ java/
β β βββ abu/epam/com/workloadservice/
β β βββ domain/service/
β β βββ WorkloadServiceTest.java
β βββ pom.xml
β
βββ .gitmodules # Git submodules configuration
βββ Task_Microservices.pdf # Requirements documentation
βββ README.md # This file
# Database (Gym-CRM-System)
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=gym_crm
export DB_USER=gym_user
export DB_PASSWORD=gym_password
# JWT (Shared across services)
export JWT_SECRET=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
export JWT_EXPIRATION=86400000 # 24 hours in milliseconds
# Eureka
export EUREKA_URL=http://localhost:8761/eureka/| Service | Dev Port | Prod Port |
|---|---|---|
| Discovery Service | 8761 | 8761 |
| Gym-CRM-System | 8081 | 8080 |
| Workload-Service | 8082 | 8082 |
- dev: Development profile (port 8081, detailed logging)
- test: Testing profile (H2 in-memory database)
- prod: Production profile (port 8080, optimized settings)
# Development
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# Production
mvn spring-boot:run -Dspring-boot.run.profiles=prodspring:
cloud:
openfeign:
circuitbreaker:
enabled: true
client:
config:
default:
connect-timeout: 5000 # 5 seconds
read-timeout: 5000 # 5 seconds
logger-level: basicBoth services use Resilience4j with default configuration:
- Sliding window size: 10 calls
- Minimum calls: 5 (before calculating failure rate)
- Failure rate threshold: 50%
- Wait duration in open state: 5 seconds
- Half-open state calls: 3 (permitted calls)
- Automatic transition: Enabled (from OPEN to HALF_OPEN)
All API endpoints (except /api/auth/*) require JWT authentication.
Both services use the same JWT secret for token validation:
jwt:
secret: 404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
expiration: 86400000 # 24 hours# Login via Gym-CRM-System
curl -X POST http://localhost:8081/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "john.doe",
"password": "password123"
}'Response:
{
"token": "eyJhbGciOiJIUzUxMiJ9...",
"type": "Bearer"
}# Access Gym-CRM-System endpoints
curl -X GET http://localhost:8081/api/trainees/john.doe \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..."
# Access Workload-Service endpoints
curl -X GET http://localhost:8082/api/workload/jane.smith \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..."Note: The same JWT token works for both services as they share the same secret key
- TRAINEE: Can manage own profile and trainings
- TRAINER: Can manage own profile and view trainees
- ADMIN: Full system access
[TRANSACTION_ID: abc-123] Request: GET /api/trainers/john.doe
[TRANSACTION_ID: abc-123] Response: 200 OK
[TRANSACTION_ID: abc-123] Finding trainer by username: john.doe
[TRANSACTION_ID: abc-123] Trainer found, mapping to DTO
Logs are configured in logback-spring.xml:
- Console: Colored output for development
- File:
logs/application.log(rolled daily) - MDC: Correlation IDs for request tracing
@FeignClient(
name = "workload-service",
fallbackFactory = WorkloadServiceClientFallbackFactory.class
)
public interface WorkloadServiceClient {
@PostMapping("/api/workload")
void updateWorkload(@RequestBody WorkloadRequest request);
}When workload-service is unavailable:
- Circuit breaker catches exception
- Fallback logs error
- Main operation continues successfully
- No data loss - workload can be recalculated
curl -X POST http://localhost:8081/api/trainees \
-H "Content-Type: application/json" \
-d '{
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1990-01-15",
"address": "123 Main St"
}'Response:
{
"username": "john.doe",
"password": "aBcD1234"
}curl -X POST http://localhost:8081/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "john.doe",
"password": "aBcD1234"
}'Response:
{
"token": "eyJhbGciOiJIUzUxMiJ9...",
"type": "Bearer"
}curl -X POST http://localhost:8081/api/trainings \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"traineeUsername": "john.doe",
"trainerUsername": "jane.smith",
"trainingName": "Morning Workout",
"trainingType": "FITNESS",
"trainingDate": "2026-02-15",
"trainingDuration": 60
}'Note: This request automatically triggers a workload update to workload-service via OpenFeign
curl -X GET http://localhost:8082/api/workload/jane.smith \
-H "Authorization: Bearer <token>"Response:
{
"username": "jane.smith",
"firstName": "Jane",
"lastName": "Smith",
"isActive": true,
"years": {
"2026": {
"months": {
"2": {
"totalDuration": 60
}
}
}
}
}Gym-CRM-System: http://localhost:8081/actuator (dev)
/actuator/health- Health check with full details/actuator/metrics- Application metrics (read-only)/actuator/info- Application info/actuator/prometheus- Prometheus metrics export (read-only)
Configuration:
management:
endpoints:
web:
exposure:
include: health,info,prometheus,metrics
endpoint:
health:
show-details: always
show-components: always
metrics:
tags:
application: gym-crm-systemWorkload-Service: http://localhost:8082/actuator
/actuator/health- Health check with full details/actuator/metrics- Application metrics (read-only)/actuator/info- Application info/actuator/prometheus- Prometheus metrics export (read-only)
Configuration:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
tags:
application: workload-serviceMonitor all registered services at http://localhost:8761
Features:
- View all registered service instances
- Check service health status
- Monitor lease renewal intervals
- View service metadata
- Check Eureka server is running
- Verify
eureka.client.service-url.defaultZoneinapplication.yml - Check network connectivity
- Ensure same JWT secret in both services
- Check token expiration time
- Verify
Authorization: Bearer <token>header format
- Verify PostgreSQL is running
- Check database credentials
- Ensure database exists
main- Production-ready codefeature/*- New featuresbugfix/*- Bug fixeshotfix/*- Production hotfixes
Follow conventional commits:
feat: Add trainer workload endpoint
fix: Resolve JWT token expiration issue
docs: Update API documentation
test: Add unit tests for TrainingService
This project is part of EPAM Systems specialization task.
- Developer: Abu
- Organization: EPAM Systems
Last Updated: February 2026