Ayushi Codes

Fit-Meter

· Ayushi Gupta

About the Application

This fitness application is designed to be your personal digital fitness coach.
It doesn’t just track your activities — it helps you understand them.
With every activity you perform, the app:

  • Measures your performance → tracks details like calories burned, duration, distance, and speed.
  • Analyzes your progress → identifies strengths and areas that need more focus.
  • Provides smart recommendations → suggests what activity you should try next.
  • Keeps you safe → gives guidance on precautions and safety measures to avoid injury or overtraining.

The goal is simple: to turn raw fitness data into actionable insights that help you stay consistent, improve steadily, and build a healthier lifestyle.
Check out the full source code on GitHub

Project Setup Guide

This guide helps you set up and run the full backend project locally, including all microservices, Eureka server, API Gateway, RabbitMQ, and Keycloak using Docker.


1. Prerequisites

Make sure you have the following installed:

  • Java 17+
  • Maven
  • Docker & Docker Compose
  • Postman (optional, for testing APIs)
  • Ports: Ensure the following ports are free:
    • Keycloak: 8080
    • RabbitMQ: 5672
    • Eureka Server: 8761
    • Config Server: 8888
    • Gateway: 8081
    • Microservices: 8082, 8083, 8084 (users, activity, AI)

2. Project Structure

Project contains the following modules:

backend/
├── config-server
├── eureka-server
├── api-gateway
├── user-service
├── activity-service
├── ai-service
├── docker images running in backgroud
│   ├── rabbitmq
│   └── keycloak
  • config-server: Centralized configuration for all microservices.
  • eureka-server: Service registry for microservices.
  • api-gateway: Gateway for routing API requests to services.
  • user-service: Handles user registration and authentication.
  • activity-service: Tracks fitness activities.
  • ai-service: Provides AI-powered analysis and recommendations.
  • docker: Contains Docker setup for RabbitMQ and Keycloak.

3. Setup Docker Services

  1. RabbitMQ

Run RabbitMQ container:

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
  • Management UI: http://localhost:15672
  • Default credentials: guest / guest
  1. KeyCloak

Run KeyCloak container:

docker run -d --name keycloak -p 8181:8080 \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
quay.io/keycloak/keycloak:20.0.3 start-dev
  • Admin console → http://localhost:8080
  • Default credentials → admin/admin

Configure realms, clients, and users via Keycloak UI.

4. Configure the Project

  1. Clone the Repository
git clone https://github.com/g14ayushi/FitMeter
cd FitMeter
  1. Configure AI Service

Inside configserver/src/main/resources/config/ai-service.yml, you will see the following environment variables:

gemini:
  api:
    url: ${GEMINI_API_URL}
    key: ${GEMINI_API_KEY}

Set the environment variables before running the service:
For MacOs:

  export GEMINI_API_URL=https://api.gemini.com/v1
  export GEMINI_API_KEY=your-secret-key

These will be used by the AI Service for external API integration.

5. Start Config Server and Eureka Server

  1. Run Config Server:
cd configserver
mvn spring-boot:run

Default Port: 8888

  1. Run Eureka Server:
cd eurekaserver
mvn spring-boot:run

Once it starts, you can access the them Dashboard at:

http://localhost:8761

6. Start API Gateway

cd gateway
mvn spring-boot:run
  • Gateway port: 8081
  • All requests are routed via the gateway.

7. Start Microservices

Start the microservices in this order:

  1. User Service
cd user-service
mvn spring-boot:run
  1. Activity Service
cd activity-service
mvn spring-boot:run
  1. AI Service
cd ai-service
mvn spring-boot:run
  • Ensure each service application.yml has the correct configuration

8. Access RabbitMQ

Microservices communicate asynchronously through RabbitMQ queues.

9. Access Keycloak

Steps:

  1. Create a Realm (e.g., fitmeter).
  2. Add Clients (microservices and gateway).
  3. Configure Roles (e.g., USER, ADMIN).
  4. Create Test Users and assign roles.

Each microservice validates JWT tokens issued by Keycloak for OAuth2 authentication.

10. Test APIs

Use Postman or cURL to test endpoints via the API Gateway (http://localhost:8081).

  1. Register a User
POST http://localhost:8081/users/register
  1. Add an Activity
POST http://localhost:8081/activities/register
  1. Get AI Recommendations for an Activity
GET http://localhost:8081/recommendations/activity/<activityId>
  • All requests must include the Authorization header with a valid Keycloak token:
    Authorization: Bearer <access_token>

How Users Can Use the Application

Getting started with our fitness app is simple and straightforward.

1. Register Yourself

Create an account in the application with your basic details. This allows the app to personalize recommendations based on your profile.

2. Log Your Activities

After completing an activity (like walking, running, cycling, or a workout), you can record it in the app. Along with the activity type, you can also add important details such as calories burned, duration, distance covered, average speed, and any other relevant information.

3. Get Personalized Recommendations & Analysis

Once your data is logged, the app analyzes it to provide personalized recommendations (what activity you should do next), focus areas (where you need to improve), and safety tips (how to avoid injuries and overtraining). The idea is to make fitness tracking more than just numbers. With clear insights and tailored guidance, you can focus on **improving your health step by step**.

User Flow in Fitness App

System Architecture

Our application follows a microservice architecture instead of a traditional monolithic design.
It is composed of three independent services:

  • User Service – manages user registration, authentication, and profiles.
  • Activity Service – handles logging and storage of fitness activities with metadata.
  • AI Service – analyzes user data and generates personalized recommendations.

Each service has its own database, ensuring data isolation and independence.
The services communicate with each other using Eureka Server for service discovery and Spring WebClient for inter-service calls.
To simplify external access, there is a single endpoint exposed through the API Gateway. Every incoming request is routed to the correct microservice.
For authentication, the application uses Keycloak with OAuth2 + PKCE flow to secure requests and manage user authorization.

Architecture Diagram

System Architecture Diagram

Core Components Explained

Microservice vs Monolithic Architecture

  • Monolithic → One large application where all features are tightly coupled and deployed together. Easier to start, but harder to scale and maintain.
  • Microservices → Application is divided into smaller, independent services that communicate with each other. Each service can be developed, deployed, and scaled independently.

Eureka Server

A service discovery tool that keeps track of available microservices. Instead of hardcoding service locations, each microservice registers itself with Eureka, making dynamic communication possible.

WebClient

A non-blocking, reactive HTTP client in Spring used for inter-service communication. It helps microservices talk to each other efficiently.

API Gateway

A single entry point for all clients. It routes incoming requests to the correct microservice, applies security checks, and hides internal service details from the outside world.

Keycloak

An open-source Identity and Access Management (IAM) tool. It manages user authentication and authorization using OAuth2 with PKCE. This ensures secure login and protects APIs from unauthorized access.

RabbitMQ

A message broker that enables asynchronous communication between microservices. It allows services to exchange data through queues, ensuring reliable delivery, decoupling service dependencies, and improving system scalability.

Backend APIs

User Service APIs

  • Register a new user
POST /api/users/register

Authorization Header: Bearer <access_token>

Request Body: { “firstName” : “user1”, “lastName” : “LastName1”, “email” : user1@gmail.com, “password”: “Password1” }

Response: { “firstName”: “user1”, “lastName”: “LastName1”, “email”: user1@gmail.com, “password”: “dummyPassword123”, “id”: “86e4fffb-6570-4b2b-a85f-cde77d8103d6”, “createdAt”: “2025-09-15T18:14:20.732206”, “updatedAt”: “2025-09-15T18:14:20.732403”, “keyCloakId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52” }

  • Fetch User Details
GET /api/users/<id>

Authorization Header: Bearer <access_token>

Response: { “firstName”: “user1”, “lastName”: “LastName1”, “email”: user1@gmail.com, “password”: “dummyPassword123”, “id”: “86e4fffb-6570-4b2b-a85f-cde77d8103d6”, “createdAt”: “2025-09-15T18:14:20.732206”, “updatedAt”: “2025-09-15T18:14:20.732403”, “keyCloakId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52” }

  • Validate User
GET /api/users/validate/<keyCloakId>

Authorization Header: Bearer <access_token>

Response: true

Activity Service APIs

  • Register an activity
POST /api/activities/register

Authorization Header: Bearer <access_token>

Request Body: { “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “duration”: 45, “caloriesBurned”: 500, “startedAt”: “2025-06-07T10:00:00”, “type”: “SWIMMING”, “additionalmetrics”: { “distance”: 0.6, “averageSpeed”: 0, “maxHeartRate”: 98 } }

Response: { “id”: “68e3ac9ec323b1b15867eb01”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “type”: “SWIMMING”, “duration”: 45, “caloriesBurned”: 500, “startedAt”: “2025-06-07T10:00:00”, “additionalmetrics”: { “distance”: 0.6, “averageSpeed”: 0, “maxHeartRate”: 98 }, “createdAt”: “2025-10-06T17:18:46.103251”, “updatedAt”: “2025-10-06T17:18:46.103251” }

  • Fetch user activities
GET /api/activities

Authorization Header: Bearer <access_token> Header: X-User-Id: <keyCloakId>

Response: [ { “id”: “68e3ac9ec323b1b15867eb01”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “type”: “SWIMMING”, “duration”: 45, “caloriesBurned”: 500, “startedAt”: “2025-06-07T10:00:00”, “additionalmetrics”: { “distance”: 0.6, “averageSpeed”: 0, “maxHeartRate”: 98 }, “createdAt”: “2025-10-06T17:18:46.103”, “updatedAt”: “2025-10-06T17:18:46.103” }, { “id”: “68e3b40cc323b1b15867eb02”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “type”: “WALKING”, “duration”: 65, “caloriesBurned”: 50, “startedAt”: “2025-09-07T10:00:00”, “additionalmetrics”: { “distance”: 1.2, “averageSpeed”: 4, “maxHeartRate”: 97 }, “createdAt”: “2025-10-06T17:50:28.804”, “updatedAt”: “2025-10-06T17:50:28.804” } ]

  • Fetch Activity By ID
GET /api/activities/<id>

Authorization Header: Bearer <access_token>

Response: { “id”: “68e3ac9ec323b1b15867eb01”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “type”: “SWIMMING”, “duration”: 45, “caloriesBurned”: 500, “startedAt”: “2025-06-07T10:00:00”, “additionalmetrics”: { “distance”: 0.6, “averageSpeed”: 0, “maxHeartRate”: 98 }, “createdAt”: “2025-10-06T17:18:46.103”, “updatedAt”: “2025-10-06T17:18:46.103” }

AI Recommendation APIs

  • Fetch Activity Recommendation
GET /api/recommendations/activity/<id>

Authorization: Bearer <access_token>

Response: { “id”: “68e3aca654aafc5e6a2e899a”, “activityId”: “68e3ac9ec323b1b15867eb01”, “createdAt”: “2025-10-06T17:18:54.641”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “activityType”: “SWIMMING”, “analysis”: “Overall: "The swimming activity shows a moderate effort with a calorie burn of 500 in 45 minutes…"\n\nPace: "Given the duration…"\n\nHeart Rate: "A max heart rate of 98 is very low…"\n\nCalories: "Burning 500 calories in 45 minutes…"\n\n” “improvements”: [ “Area: "Pace and Distance"\nRecommendation: "Focus on increasing the swimming pace…"\n\n”, “Area: "Heart Rate Intensity"\nRecommendation: "Increase the intensity of the workouts…"\n\n”, “Area: "Technique"\nRecommendation: "Refine swimming technique to improve efficiency…"\n\n” ], “suggestions”: [ “WorkOut: "Interval Training Swim"\nDescription: "Warm-up for 5 minutes…"\n\n”, “WorkOut: "Distance Swim with Focus on Technique"\nDescription: "Warm-up for 5 minutes…"\n\n”, “WorkOut: "Drill-Based Swim"\nDescription: "Warm-up for 5 minutes…"\n\n” ], “safety”: [ “Stay hydrated by drinking water before, during, and after your swim.", “Always warm-up before swimming to prepare your muscles and prevent injuries.", “Be aware of your surroundings and swim in designated areas.", “If you are new to swimming or have any underlying health conditions, consult with a doctor…", “Never swim alone.", “Know your limits and avoid overexertion." ] }

  • Fetch User Recommendations
GET /api/recommendations/user/<keyCloakId>

Authorization: Bearer <access_token>

Response: [ { “id”: “68e3aca654aafc5e6a2e899a”, “activityId”: “68e3ac9ec323b1b15867eb01”, “createdAt”: “2025-10-06T17:18:54.641”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “activityType”: “SWIMMING”, “analysis”: “Overall: "The swimming activity shows a moderate effort with a calorie burn of 500 in 45 minutes…"\n\nPace: "Given the duration…"\n\nHeart Rate: "A max heart rate of 98 is very low…"\n\nCalories: "Burning 500 calories in 45 minutes…"", “improvements”: [ “Area: "Pace and Distance"\nRecommendation: "Focus on increasing the swimming pace…"", “Area: "Heart Rate Intensity"\nRecommendation: "Increase the intensity of the workouts…"", “Area: "Technique"\nRecommendation: "Refine swimming technique to improve efficiency…"" ], “suggestions”: [ “WorkOut: "Interval Training Swim"\nDescription: "Warm-up for 5 minutes…"", “WorkOut: "Distance Swim with Focus on Technique"\nDescription: "Warm-up for 5 minutes…"", “WorkOut: "Drill-Based Swim"\nDescription: "Warm-up for 5 minutes…"" ], “safety”: [ “Always warm-up before swimming to prepare your muscles and prevent injuries.", “Stay hydrated by drinking water before, during, and after your swim.", “Be aware of your surroundings and swim in designated areas.", “If you are new to swimming or have any underlying health conditions, consult with a doctor or qualified swimming instructor before starting a new workout routine.", “Never swim alone.", “Know your limits and avoid overexertion." ] }, { “id”: “68e3b41a54aafc5e6a2e899b”, “activityId”: “68e3b40cc323b1b15867eb02”, “createdAt”: “2025-10-06T17:50:42.186”, “userId”: “49d45cbb-a7b0-46c6-a198-6728ce1dca52”, “activityType”: “WALKING”, “analysis”: “Overall: "The activity indicates a light-intensity walk. The duration is adequate, but the calorie burn is very low…"", “improvements”: [ “Area: "Intensity"\nRecommendation: "Increase walking pace to elevate heart rate…"", “Area: "Incline"\nRecommendation: "Incorporate hills or use a treadmill with an incline…"", “Area: "Duration"\nRecommendation: "Gradually increase the duration of the walks…"", “Area: "Weight"\nRecommendation: "Consider using a weighted vest or carrying light dumbbells…"" ], “suggestions”: [ “WorkOut: "Brisk Walking Intervals"\nDescription: "Warm-up with 5 minutes of easy walking…"", “WorkOut: "Hill Walking"\nDescription: "Find a route with several hills…"", “WorkOut: "Power Walking"\nDescription: "Engage your core, pump your arms, and take longer strides…"" ], “safety”: [ “Wear comfortable and supportive shoes.", “Stay hydrated by drinking water before, during, and after the walk.", “Warm-up before starting and cool down afterwards.", “Be aware of your surroundings and watch out for traffic or other hazards.", “Listen to your body and stop if you feel any pain or discomfort.", “If walking in low light, wear reflective clothing and carry a light.", “Check the weather forecast and dress appropriately." ] } ]