Link to Android Play store: https://play.google.com/store/apps/details?id=com.applaud.fitbite
- Overview
- Why Use This App?
- Features
- Dependencies
- Build/deployment Instructions
- Configuration
- Usage Scenarios
- Test-Driven Development (TDD)
- Design Principles
- Code Coverage Summary
- Contribution Guidelines
The Fitbite is designed to help students maintain a healthier lifestyle by tracking their nutrition, physical activity. Stay on top of your wellness journey with real-time notifications, activity tracking.
🌱 Encourages mindful eating habits
🏃 Promotes an active lifestyle
📊 Provides real-time progress tracking
🔔 Sends useful meal notifications
✅ Meal Notifications – User gets notified when they forget to log a meal.
✅ Step & Calorie Tracking – Monitor your daily steps, calories burnt, and physical activity progress.
✅ Food Intake Monitoring – Log and track your meals and calories to maintain balanced nutrition.
✅ Health Report – Generate summaries of your daily step activity.
This project uses the following dependencies:
- Spring Boot Web, JPA, JDBC, Mail, Security
- JWT for Authentication
- Lombok for boilerplate reduction
- Jakarta Validation API
- Spring Boot Maven Plugin
- Maven Compiler Plugin (with Lombok)
- PMD Plugin (for code quality)
- Spring Boot Starter Test
- Spring Security Test
- Hibernate Validator
- Clone the project repository:
git clone https://git.cs.dal.ca/courses/2025-winter/csci-5308/group07.git
cd group07Build using Maven:
mvn clean installThe application can be run with the below command:
mvn spring-boot:runBefore running the application, ensure that the required properties are set in src/main/resources/application.properties.
spring.application.name=fitbite
server.port=8073
spring.profiles.active=productionConfigure the JWT secret key and expiration time in your application.properties file:
# Secret key for signing JWT tokens
security.jwt.secret-key=your_jwt_secret_key
# Token expiration time in milliseconds (e.g., 3500000 = ~58 minutes)
security.jwt.expiration-time=3500000Configure the email sender details in your application.properties file:
# SMTP settings for sending emails
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=your_email@gmail.com
spring.mail.password=your_app_password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
# Display name for outgoing emails
app.email.sender-name=FitBiteThymeleaf is used for rendering HTML templates, such as email content or web views. Configure it in your application.properties file:
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=falseThis repository contains both the Flutter frontend and Spring Boot backend, along with deployment configurations.
- 📂 Project Root
- ├── 📂 backend/ — Spring Boot application resources
- ├── 📂 frontend/ — Flutter application resources
- └── 📂 deployment/ — Deployment configurations
- ├── spring-deploy.yml (Spring Boot deployment)
- └── flutter-deploy.yml (Flutter deployment)
- Navigate to the
backend/directory. - Build and run the Spring Boot application.
- Ensure the backend is accessible via the configured API endpoints.
- Navigate to the
frontend/directory. - Install dependencies using
flutter pub get. - Run the application using
flutter run.
- The
deployment/directory contains the necessary YAML files for automating deployments. - Use the provided
spring-deploy.ymlandflutter-deploy.ymlfor deploying backend and frontend, respectively.
The project follows a Test-Driven Development approach to ensure code correctness, early bug detection, and maintainable design.
- JUnit 5 – Unit testing framework
- Mockito – Mocking dependencies for isolated testing
- Spring Boot Test – Integration and context testing
- Write unit or integration test cases first.
- Run the tests and watch them fail (Red).
- Implement the minimum code to pass the test (Green).
- Refactor while keeping tests green (Refactor).
We first developed the step tracking and calorie burn summary feature using a test-first approach.
- Initial Test: 0787f3c8 – Added test cases for
StepSessionSummaryCalculator - Implementation: 3e426b94 – Implemented aggregation logic for total steps over a duration and total calorie burnt.
It provides a comprehensive REST API for managing a user's step tracking and activity summaries.
- Initial Test: b1ada1fd – Added test cases for
StepSessionController - Implementation: 6e801dc1- Implemented HTTP Endpoints for managing a user's step tracking.
It provides the information of Ingredients of a meal.
- Initial Test: cdb1776a – Added test cases for
NutritionalInformationControllerandNutritionalInfoService. - Implementation: 5b3774c9 – Implemented Rest API to show Meal Ingredients.
mvn testBelow are some common usage scenarios that demonstrate how different users interact with the FitBite application:
- A new user signs up for the platform and logs in using their Dalhousie email Id and password.
- JWT token is generated upon successful login and used to access protected endpoints.
- Users can browse meals filtered by:
- Dining location (e.g., Sheriff Hall, Howe Hall, and Killam Library)
- Period (Breakfast, Lunch, Dinner)
- Meals are fetched dynamically.
- Users can view the nutritional information for each meal, including:
- Calories
- Macronutrients (Protein, Carbs, Fats)
- Allergens
- When a user selects a meal, its calorie value is added to their daily intake log.
- Users can monitor whether they're under or over their set daily calorie goals.
- Users can track their daily step count.
- The system calculates estimated calories burnt based on steps walked.
- Users can set personal goals such as:
- Daily calorie intake limits
- Steps per day
- A progress tracker shows how close they are to achieving these goals.
- User can generate summaries of their total steps completed.
Each class in the application has a well-defined single responsibility:
EmailService: Responsible solely for composing and sending email messages (both HTML and plain text) using the configured sender details and the SpringJavaMailSender.StepSessionSummaryCalculator: Handles only the aggregation logic for step session data by calculating total steps, duration, distance, and calories.MealCaloriesService: Focused solely on retrieving meal calorie information from the database through theMenuItemRepository.
The application is designed in a way that allows new behaviors to be added without modifying existing class logic:
StepSessionSummaryCalculator: Encapsulates step aggregation logic in a dedicated class. If new summary metrics (e.g., pace, heart rate zones) need to be introduced, they can be added by extending or decorating this class without modifying its existing method.MealCaloriesService: Designed to retrieve calorie information. New calorie-based filters (e.g., low-calorie meals, meal type-wise breakdown) can be added by introducing new methods or components, without altering existing logic.
Example from StepSessionSummaryCalculator.java:
@Component
public class StepSessionSummaryCalculator {
public StepSessionSummaryDto calculateSummary(List<StepSession> sessions) {
int totalSteps = 0;
int totalDurationMinutes = 0;
double totalDistanceMeters = 0.0;
double totalCaloriesBurned = 0.0;
for (StepSession session : sessions) {
totalSteps += session.getTotalSteps();
totalDurationMinutes += session.getDurationMinutes();
totalDistanceMeters += session.getDistanceMeters() != null ? session.getDistanceMeters() : 0.0;
totalCaloriesBurned += session.getCaloriesBurned() != null ? session.getCaloriesBurned() : 0.0;
}
StepSessionSummaryDto summary = new StepSessionSummaryDto();
summary.setTotalSteps(totalSteps);
summary.setTotalDurationMinutes(totalDurationMinutes);
summary.setTotalDistanceMeters(totalDistanceMeters);
summary.setTotalCaloriesBurned(totalCaloriesBurned);
return summary;
}
}The project uses inheritance to allow subclasses to replace base classes without compromising correctness:
DuplicateResourceException: ExtendsRuntimeExceptionand can be thrown and caught as a standard exception.
Example from DuplicateResourceException.java:
public class DuplicateResourceException extends RuntimeException {
public DuplicateResourceException(String message) {
super(message);
}
}The application is designed with interface boundaries that avoid forcing classes to depend on methods they don't use:
MenuItemRepository: Inherits from Spring Data JPA’s modular repository interfaces. It only depends on relevant operations forMenuItem.
Example from MenuItemRepository.java:
@Repository
public interface MenuItemRepository extends JpaRepository<MenuItem, String> {
Optional<MenuItem> getByItemId(String id);
Optional<List<MenuItem>> getAllByDiningLocation_LocationId(Integer id);
List<MealCaloriesResponse> getMealCalories();
List<MenuItem> findDistinctByItemNames(@Param("itemNames") List<String> itemNames);
}The system is designed so that high-level components do not depend on low-level implementations. Instead, both depend on abstractions (interfaces), which improves flexibility:
PasswordController: Depends on theAuthServiceinterface rather than a specific implementation.MealPeriodController: Relies on theMealPeriodsServiceabstraction for all meal period operations.
LCOM (Lack of Cohesion of Methods) values:
- AllergenTypeController : 0.0 (High cohesion)
- DiningLocationService : 0.0 (High cohesion)
- MenuItemsService : 0.0 (High cohesion)
Example of loose coupling:
-
PasswordController- FANIN: 0, FANOUT: 2
- Manages password-related operations like reset or update. It operates independently of other modules and only communicates with necessary services.
PasswordControllerdepends on abstract service interfacesAuthService, not concrete implementations:
@Controller @RequestMapping("/") public class PasswordController { private final AuthService authService; public PasswordController(AuthService authService) { this.authService = authService; } @PostMapping("/forgot-password") public ResponseEntity<?> forgotPassword(@RequestBody PasswordResetDto passwordResetDto) { authService.initiatePasswordReset(passwordResetDto.getEmail()); return ResponseEntity.ok("Password reset link sent."); } }
-
MealPeriodController- FANIN: 1, FANOUT: 2
- Handles API endpoints related to meal periods. It interacts with only two other components, keeping its integration points limited and controlled.
MealPeriodControllerdepends on abstract service interfacesMealPeriodsService, not concrete implementations:
@RestController @RequestMapping("/api/period") public class MealPeriodController { @Autowired private MealPeriodsService mealPeriodsService; @GetMapping public List<MealPeriod> getAllMealPeriods() { return mealPeriodsService.getAllMealPeriods(); } }
| Package/Module | Class % | Method % | Line % | Branch % |
|---|---|---|---|---|
| com.applaud.fitbite | 91% | 81% | 78% | 65% |
| builder | 85% | 77% | 78% | 66% |
| controller | 100% | 92% | 87% | 87% |
| dto | 88% | 81% | 76% | 100% |
| model | 90% | 73% | 75% | 50% |
| responses | 100% | 65% | 71% | 100% |
| services | 100% | 97% | 95% | 87% |
| utils | 100% | 100% | 75% | 42% |
-
Fork the repository and create your feature branch:
git checkout -b feature/new-feature
-
Commit your changes:
git commit -m "Add new feature" -
Push the branch:
git push origin feature/new-feature
-
Create a Pull Request for review.