Skip to content

A microservices-based gym management system built with Spring Boot, featuring trainer workload tracking, member management, and service discovery with Eureka. Implements JWT authentication, circuit breakers, and RESTful APIs for comprehensive gym operations.

Notifications You must be signed in to change notification settings

DesBasito/Gym_system

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Gym CRM System

A comprehensive Gym Customer Relationship Management system built with microservices architecture using Spring Boot and Spring Cloud.

πŸ“‹ Table of Contents


🎯 Overview

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.

Key Features

  • πŸ‘₯ 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

πŸ— Architecture

Microservices Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     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           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Communication Pattern

  • 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

πŸ”§ Services

1. Discovery Service (Eureka Server)

  • 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

2. Gym-CRM-System

  • 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

3. Workload-Service

  • 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

πŸ›  Technology Stack

Backend

  • 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

Tools & Libraries

  • Lombok: Code generation
  • MapStruct: Object mapping
  • Swagger/OpenAPI: API documentation
  • JUnit 5: Testing framework
  • Mockito: Mocking framework
  • Actuator: Application monitoring

Build & DevOps

  • Maven: Build automation
  • Git: Version control (mono-repo approach)

πŸ“¦ Prerequisites

Required

  • Java 17 or higher
  • Maven 3.8+
  • PostgreSQL 14+
  • Git

Optional

  • Docker (for containerized deployment)
  • Postman (for API testing)

πŸš€ Getting Started

1. Clone the Repository

git clone https://github.com/DesBasito/Gym_system.git
cd Gym_system

2. Setup PostgreSQL Database

CREATE DATABASE gym_crm;
CREATE USER gym_user WITH PASSWORD 'gym_password';
GRANT ALL PRIVILEGES ON DATABASE gym_crm TO gym_user;

3. Configure Application Properties

Update services/Gym-CRM-system/src/main/resources/application.yml:

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/gym_crm
    username: gym_user
    password: gym_password

4. Start Services (in order)

Step 1: Start Discovery Service (Eureka Server)

cd services/discovery-service
mvn spring-boot:run

Wait for Eureka to start at http://localhost:8761

Step 2: Start Workload Service

cd services/workload-service
mvn spring-boot:run

Service will register with Eureka at port 8082

Step 3: Start Gym-CRM-System

cd services/Gym-CRM-system
mvn spring-boot:run -Dspring-boot.run.profiles=dev

Service will register with Eureka at port 8081 (dev profile)

Note: For production, use -Dspring-boot.run.profiles=prod (port 8080)

5. Verify Services


πŸ“– API Documentation

Gym-CRM-System API

Swagger UI: http://localhost:8080/swagger-ui.html

Authentication

POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
PUT  /api/auth/change-password

Trainee Management

POST   /api/trainees
GET    /api/trainees/{username}
PUT    /api/trainees/{username}
DELETE /api/trainees/{username}
PUT    /api/trainees/{username}/trainers

Trainer Management

POST   /api/trainers
GET    /api/trainers/{username}
PUT    /api/trainers/{username}
GET    /api/trainers/not-assigned/{traineeUsername}

Training Management

POST   /api/trainings
GET    /api/trainings/trainee
GET    /api/trainings/trainer
GET    /api/trainings/types

Workload-Service API

Swagger 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

πŸ§ͺ Testing

Run All Tests

# Gym-CRM-System
cd services/Gym-CRM-system
mvn clean test

# Workload-Service
cd services/workload-service
mvn clean test

Test Coverage

mvn clean test jacoco:report
# Report: target/site/jacoco/index.html

Integration Tests

mvn verify -P integration-tests

πŸ“‚ Project Structure

Gym_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

βš™οΈ Configuration

Environment Variables

# 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 Ports

Service Dev Port Prod Port
Discovery Service 8761 8761
Gym-CRM-System 8081 8080
Workload-Service 8082 8082

Application Profiles

  • 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=prod

OpenFeign Configuration (Gym-CRM-System)

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true
      client:
        config:
          default:
            connect-timeout: 5000    # 5 seconds
            read-timeout: 5000       # 5 seconds
            logger-level: basic

Circuit Breaker Configuration

Both 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)

πŸ” Security

JWT Authentication

All API endpoints (except /api/auth/*) require JWT authentication.

JWT Configuration

Both services use the same JWT secret for token validation:

jwt:
  secret: 404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
  expiration: 86400000  # 24 hours

Get JWT Token

# 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"
}

Use Token

# 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

Authorization

  • TRAINEE: Can manage own profile and trainings
  • TRAINER: Can manage own profile and view trainees
  • ADMIN: Full system access

πŸ“ Logging

Two-Level Logging with MDC

Transaction Level

[TRANSACTION_ID: abc-123] Request: GET /api/trainers/john.doe
[TRANSACTION_ID: abc-123] Response: 200 OK

Operation Level

[TRANSACTION_ID: abc-123] Finding trainer by username: john.doe
[TRANSACTION_ID: abc-123] Trainer found, mapping to DTO

Log Configuration

Logs are configured in logback-spring.xml:

  • Console: Colored output for development
  • File: logs/application.log (rolled daily)
  • MDC: Correlation IDs for request tracing

πŸ”„ Microservices Communication

Circuit Breaker Pattern

@FeignClient(
    name = "workload-service",
    fallbackFactory = WorkloadServiceClientFallbackFactory.class
)
public interface WorkloadServiceClient {
    @PostMapping("/api/workload")
    void updateWorkload(@RequestBody WorkloadRequest request);
}

Fallback Behavior

When workload-service is unavailable:

  1. Circuit breaker catches exception
  2. Fallback logs error
  3. Main operation continues successfully
  4. No data loss - workload can be recalculated

🎯 Usage Examples

Register a Trainee

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"
}

Login to Get JWT Token

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"
}

Create a Training Session

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

Check Trainer Workload

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
        }
      }
    }
  }
}

πŸ“Š Monitoring

Actuator Endpoints

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-system

Workload-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-service

Eureka Dashboard

Monitor all registered services at http://localhost:8761

Features:

  • View all registered service instances
  • Check service health status
  • Monitor lease renewal intervals
  • View service metadata

πŸ› Troubleshooting

Service Not Registering with Eureka

  1. Check Eureka server is running
  2. Verify eureka.client.service-url.defaultZone in application.yml
  3. Check network connectivity

JWT Token Issues

  1. Ensure same JWT secret in both services
  2. Check token expiration time
  3. Verify Authorization: Bearer <token> header format

Database Connection Failed

  1. Verify PostgreSQL is running
  2. Check database credentials
  3. Ensure database exists

🀝 Contributing

Branch Strategy

  • main - Production-ready code
  • feature/* - New features
  • bugfix/* - Bug fixes
  • hotfix/* - Production hotfixes

Commit Messages

Follow conventional commits:

feat: Add trainer workload endpoint
fix: Resolve JWT token expiration issue
docs: Update API documentation
test: Add unit tests for TrainingService

πŸ“„ License

This project is part of EPAM Systems specialization task.


πŸ‘₯ Authors

  • Developer: Abu
  • Organization: EPAM Systems

πŸ”— Related Links


Last Updated: February 2026

About

A microservices-based gym management system built with Spring Boot, featuring trainer workload tracking, member management, and service discovery with Eureka. Implements JWT authentication, circuit breakers, and RESTful APIs for comprehensive gym operations.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published