_ _ _ ______ _ _
| | | | | | | ____(_) |
| |__| |_ _ __| |_ __ __ _| |__ _| |_
| __ | | | |/ _` | '__/ _` | __| | | __|
| | | | |_| | (_| | | | (_| | | | | |_
|_| |_|\__, |\__,_|_| \__,_|_| |_|\__|
__/ |
|___/
- About HydraFit
- Key Features
- Tech Stack
- Project Structure
- System Requirements
- Installation Guide
- Database Configuration
- Email Configuration (PHPMailer)
- ImgBB Configuration (Photo Upload)
- User Flow
- API Endpoints
- Admin Panel
- Security
- Contributors
HydraFit is a PHP & MySQL-based health management web application that helps users monitor and manage their fitness journey — from daily weight tracking and real-time BMI calculation to accessing an interactive workout library.
"We Help You Go From Fat To Fit"
This application is designed with a multi-role approach (User & Admin), features a 3-step onboarding system, and integrates various modern libraries such as Chart.js for weight data visualization, SweetAlert2 for interactive notifications, and PHPMailer for OTP password reset email services.
| Feature | Description |
|---|---|
| 🔐 Registration & Login | Register with a username/email, login with either. Passwords are hashed using BCrypt. |
| 📋 3-Step Onboarding | Step-by-step profile setup flow: (1) Register → (2) Name → (3) Physical Data. |
| 📊 Weight Tracker | Input daily weight, visualized with interactive line charts (1W / 1M / ALL). |
| 🧮 BMI Calculator | Automatic and real-time BMI calculation every time the weight is updated. |
| 📚 Course Library | Access the workout library with real-time search capabilities. |
| 💪 Workout Detail | View detailed exercise movements complete with animated GIFs and instructions. |
| ⚙️ Account Settings | Edit profile, change photo (upload to ImgBB), change password, delete account. |
| 🔑 Forgot Password | Reset password via a 6-digit OTP sent to email (valid for 5 minutes). |
| 🚪 Auto-Logout | The session is automatically cleared when navigating to the login page while already logged in. |
| Feature | Description |
|---|---|
| 📊 Admin Dashboard | Quick statistics: total users, total admins, total active courses. |
| 📝 Manage Courses | Full CRUD for course data (title, tagline, thumbnail, banner, target muscle). |
| 💪 Manage Exercises | CRUD for exercise movements per course (name, duration/reps, GIF URL, instructions). |
| 👥 Manage Users | View all users, change roles (User/Admin), delete user accounts. |
| 👑 Super Admin | Super Admin account protection — cannot be modified/deleted by regular admins. |
| 🔒 Role-Based Access | Automatic routing: Admin → admin/dashboard.php, User → welcome.php. |
- PHP 8.x — Server-side logic, session management, prepared statements
- MySQL / MariaDB — Relational database
- PHPMailer — Sending OTP emails via Gmail SMTP
- ImgBB API — Cloud image hosting for user profile photos
- HTML5 — Semantic page structure
- Vanilla CSS3 — Fully custom styling without a framework
- Vanilla JavaScript (ES6+) — Fetch API, async/await, DOM manipulation
- Google Fonts (Poppins) — Modern typography
- Chart.js — Interactive weight chart visualization
- SweetAlert2 — Elegant dialogs/notifications
- Canvas API — Interactive particle animation on the landing page
- LocalStorage API — Saving the sidebar collapse state
HydraFit_Project/
│
├── 📄 index.php # Landing page (Hero + Particle animation)
├── 📄 login.php # Login page
├── 📄 register.php # Registration page
├── 📄 logout.php # Logout handler (clears session)
│
├── 📄 create-profile.php # Onboarding Step 2 — Enter name
├── 📄 complete-profile.php # Onboarding Step 3 — Physical data (Height, Weight, etc.)
├── 📄 welcome.php # Welcome page after setup is complete
│
├── 📄 dashboard.php # Main user dashboard (chart, BMI, stats)
├── 📄 course.php # Workout course library
├── 📄 workout_detail.php # Movement details within a course
├── 📄 settings.php # User account settings
│
├── 📄 forgot_password.php # Email input form for password reset
├── 📄 verify_otp.php # Form to verify the 6-digit OTP code
├── 📄 reset_password.php # New password input form
├── 📄 send_otp.php # PHPMailer logic — send OTP email
│
├── 📄 api_weight.php # REST API — GET & POST weight data
├── 📄 api_settings.php # REST API — Update profile, change password, delete account
│
├── 📄 koneksi.php # MySQL database connection configuration
│
├── 📁 admin/ # Admin Panel (restricted access: role='admin')
│ ├── 📄 dashboard.php # Admin dashboard — global statistics
│ ├── 📄 manage_course.php # CRUD course data
│ ├── 📄 manage_exercises.php # CRUD exercise movements per course
│ ├── 📄 manage_users.php # User & role management
│ └── 📄 logout.php # Admin logout
│
├── 📁 assets/
│ ├── 📁 css/
│ │ ├── style.css # Global CSS & Landing Page
│ │ ├── onboarding.css # CSS for Auth & Onboarding forms
│ │ ├── dashboard.css # CSS for Dashboard, Sidebar, Cards
│ │ ├── course.css # CSS for Course Library & Workout Detail
│ │ ├── settings.css # CSS for Settings Page
│ │ ├── welcome.css # CSS for Welcome Page
│ │ ├── admin.css # Specific CSS for Admin Panel
│ │ ├── manage_users.css # CSS for Manage Users table
│ │ └── auth_style.css # CSS for Forgot/Reset Password pages
│ │
│ ├── 📁 js/
│ │ ├── script.js # Landing page JS (particles, modals, navigation)
│ │ ├── dashboard.js # Dashboard JS (Chart.js, Weight API, Search)
│ │ ├── settings.js # Settings JS (AJAX profile, password, delete)
│ │ ├── toggle_password.js # JS to toggle show/hide password
│ │ ├── onboarding.js # Onboarding form JS
│ │ ├── manage_users.js # Admin JS — confirm user deletion
│ │ ├── auth_validation.js # Auth form validation JS
│ │ └── welcome.js # Welcome page JS
│ │
│ └── 📁 image/
│ ├── Fit.jpg # Hero section image
│ └── google.png # Other image assets
│
└── 📁 PHPMailer-master/ # PHPMailer library for OTP emails
└── src/
├── PHPMailer.php
├── SMTP.php
└── Exception.php
Before installation, ensure your environment meets the following requirements:
| Component | Minimum Version | Description |
|---|---|---|
| PHP | 7.4+ (Recommended 8.x) | With mysqli, curl, openssl extensions enabled |
| MySQL | 5.7+ / MariaDB 10.3+ | Relational database |
| Web Server | Apache / Nginx | Recommended: Apache with XAMPP/Laragon |
| Browser | Chrome 90+ / Firefox 88+ | For Canvas & ES6 features |
| Internet Connection | Optional | Required for Google Fonts, Chart.js CDN, SweetAlert2, and ImgBB |
💡 Recommendation: Use XAMPP (Windows) or Laragon for the easiest local setup.
# Clone using Git
git clone https://github.com/YosuaSurianto/HydraFit.git
# Or download the ZIP, then extract it# For XAMPP (Windows)
C:\xampp\htdocs\HydraFit_Project\
# For Laragon (Windows)
C:\laragon\www\HydraFit_Project\
# For Linux (Apache)
/var/www/html/HydraFit_Project/
- Open phpMyAdmin (usually at
http://localhost/phpmyadmin) - Create a new database named
db_hydrafit - Import the following SQL schema:
-- ============================================================
-- DATABASE: db_hydrafit
-- ============================================================
CREATE DATABASE IF NOT EXISTS `db_hydrafit`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE `db_hydrafit`;
-- ============================================================
-- TABLE: users
-- ============================================================
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL,
`email` VARCHAR(100) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`role` ENUM('user','admin') NOT NULL DEFAULT 'user',
`first_name` VARCHAR(50) DEFAULT NULL,
`last_name` VARCHAR(50) DEFAULT NULL,
`birth_date` DATE DEFAULT NULL,
`gender` ENUM('Male','Female') DEFAULT NULL,
`blood_type` ENUM('A','B','AB','O') DEFAULT NULL,
`height` FLOAT DEFAULT NULL COMMENT 'in cm',
`current_weight` FLOAT DEFAULT NULL COMMENT 'in kg',
`target_weight` FLOAT DEFAULT NULL COMMENT 'in kg',
`avatar` TEXT DEFAULT NULL COMMENT 'Photo URL from ImgBB',
`otp_code` VARCHAR(10) DEFAULT NULL,
`otp_expiry` DATETIME DEFAULT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ============================================================
-- TABLE: weight_tracking
-- ============================================================
CREATE TABLE `weight_tracking` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`weight` FLOAT NOT NULL COMMENT 'in kg',
`recorded_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_weight_user`
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ============================================================
-- TABLE: courses
-- ============================================================
CREATE TABLE `courses` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(150) NOT NULL,
`tagline` VARCHAR(255) DEFAULT NULL COMMENT 'Short course slogan',
`description` TEXT DEFAULT NULL,
`thumbnail` TEXT DEFAULT NULL COMMENT 'Card image URL (16:9 ratio)',
`banner` TEXT DEFAULT NULL COMMENT 'Wide header image URL',
`target_muscle` VARCHAR(100) DEFAULT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ============================================================
-- TABLE: exercises
-- ============================================================
CREATE TABLE `exercises` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`course_id` INT(11) NOT NULL,
`name` VARCHAR(150) NOT NULL,
`duration` VARCHAR(100) DEFAULT NULL COMMENT 'Example: 30 Seconds / 15 Reps',
`instruction` TEXT DEFAULT NULL,
`gif_image` TEXT DEFAULT NULL COMMENT 'Movement animation GIF URL',
PRIMARY KEY (`id`),
CONSTRAINT `fk_exercise_course`
FOREIGN KEY (`course_id`) REFERENCES `courses`(`id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ============================================================
-- SEED: Default Admin Account
-- Password: admin123 (BCrypt hash)
-- ============================================================
INSERT INTO `users` (`username`, `email`, `password`, `role`, `first_name`)
VALUES (
'superadmin',
'admin@hydrafit.com',
'$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'admin',
'Admin'
);
⚠️ Note: The password hash above is forpassword(plain text). Replace it with a hash you generate yourself usingpassword_hash('yourpassword', PASSWORD_DEFAULT)in PHP.
Open the koneksi.php file and adjust the configuration:
<?php
$host = "localhost"; // Database host (usually localhost)
$user = "root"; // Database username
$pass = ""; // Database password (empty if XAMPP default)
$db = "db_hydrafit"; // Database name
$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) {
die("Connection Failed: " . mysqli_connect_error());
}
?>Open your browser and access:
http://localhost/HydraFit_Project/
HydraFit uses PHPMailer via Gmail SMTP for the password reset feature with OTP.
Open the send_otp.php file and change the following configuration:
$mail->Username = 'youremail@gmail.com'; // Replace with your Gmail address
$mail->Password = 'xxxx xxxx xxxx xxxx'; // Gmail App Password (not your regular password!)
$mail->setFrom('no-reply@hydrafit.com', 'HydraFit Support');- Go to Google Account Settings → Security
- Enable 2-Step Verification (required)
- Search for App passwords → Generate a new password
- Select App: Mail | Device: Other (Custom name) → Type "HydraFit"
- Copy the 16 characters that appear → paste into
$mail->Password
🔐 Important: Do not commit your App Password to a public repository. Use environment variables or a
.envfile for production.
User profile photos are uploaded to ImgBB (a free image hosting service).
Open the api_settings.php file and replace the API Key:
// Around line 43
$api_key = 'YOUR_API_KEY_HERE';- Register/login at https://imgbb.com
- Go to https://api.imgbb.com
- Click Get API Key → Copy the provided API key
- Paste it into the
$api_keyvariable inapi_settings.php
Landing Page (index.php)
│
├──[Click "Sign Up"]──► register.php
│ │
│ [Enter username, email, password]
│ │
│ ▼
│ create-profile.php ◄── Step 2 of 3
│ │
│ [Enter first name & last name]
│ │
│ ▼
│ complete-profile.php ◄── Step 3 of 3
│ │
│ [Enter birth date, gender,
│ blood type, height, weight]
│ │
│ ▼
│ welcome.php ──► dashboard.php
│
└──[Click "Login"]───► login.php
│
[Admin] ──► admin/dashboard.php
[User] ──► welcome.php ──► dashboard.php
login.php
│
[Click "Forgot Password?"]
│
▼
forgot_password.php
│
[Enter email → Server sends OTP via Gmail SMTP]
│
▼
verify_otp.php
│
[Enter 6-digit OTP (valid for 5 mins)]
│
▼
reset_password.php
│
[Enter new password → Password hashed with BCrypt → Saved]
│
▼
login.php ✅
dashboard.php
│
[User types a number → Clicks "Update Weight"]
│
▼ [Fetch POST]
api_weight.php
│
[INSERT to weight_tracking + UPDATE current_weight in users]
[CALCULATE new BMI]
│
▼ [JSON Response]
dashboard.js
│
[Update UI: Weight card, BMI card, Refresh Chart]
HydraFit has two internal API files that are consumed via AJAX by the frontend JavaScript.
| Method | Parameter | Description | Response |
|---|---|---|---|
GET |
?range=1W |
Fetch weight data for the last 1 week (20 entries) | {status, data[{label, value}]} |
GET |
?range=1M |
Fetch weight data for the last 1 month (60 entries) | {status, data[{label, value}]} |
GET |
?range=ALL |
Fetch all weight data (500 entries) | {status, data[{label, value}]} |
POST |
{weight: float} |
Save new body weight & calculate BMI | {status, message, new_bmi: {score, status, color}} |
Auth: All endpoints require an active login session (
$_SESSION['user_id']).
| Method | Action | Parameter | Description |
|---|---|---|---|
POST |
update_profile |
first_name, last_name, username, height, target_weight, avatar (optional file) |
Update profile data + upload photo to ImgBB |
POST |
change_password |
current_password, new_password |
Verify old password → hash & save new password |
POST |
delete_account |
(none) | Delete all user data + weight tracking, destroy session |
- Log in using an account with
role = 'admin' - The system automatically redirects to
admin/dashboard.php - Or access it directly:
http://localhost/HydraFit_Project/admin/dashboard.php
- Go to Admin Panel → Manage Courses
- Fill out the form: Course Title, Tagline, Target Muscle, Thumbnail URL, Banner URL (optional), Description
- Click "Save New Course"
💡 Tip: Use image URLs from Google Images, Unsplash, or other hosting. The ideal thumbnail uses a 16:9 ratio.
- In the Course Library table, click the "Exercises" button on the desired course
- Fill out the form: Exercise Name, Duration/Reps (e.g.,
30 Secondsor15 Reps), GIF/Image URL, Instructions - Click "Add Exercise"
💡 Tip: Use animated movement GIFs from Giphy or other sources for a better user experience.
- Go to Admin Panel → Manage Users
- Change the user's role using the User/Admin dropdown (auto-submits)
- Delete a user with the Delete button (with a SweetAlert confirmation)
🛡️ Super Admin Protection: Accounts listed in the
$super_adminsarray inmanage_users.phpcannot be modified or deleted by any admin.
// admin/manage_users.php — Lines 17-19
$super_admins = [
'superadminemail@gmail.com', // Add Super Admin email here
];HydraFit implements various layers of security:
| Mechanism | Implementation | Location |
|---|---|---|
| Password Hashing | BCrypt via password_hash() & password_verify() |
register.php, api_settings.php |
| SQL Injection Prevention | Prepared Statements (mysqli->prepare(), bind_param()) |
All PHP files that query the database |
| Session Security | session_regenerate_id(true) after successful login |
login.php |
| XSS Prevention | htmlspecialchars() on all data output to HTML |
All view files |
| Role-Based Access Control | Checking $_SESSION['role'] on every admin page |
admin/*.php |
| Auth Guard | Redirect to login if the session does not exist | All protected pages |
| OTP Expiry | Password reset OTP expires in 5 minutes | forgot_password.php, verify_otp.php |
| Super Admin Protection | Whitelisted Super Admin emails cannot be modified | admin/manage_users.php |
| Self-Action Prevention | Admins cannot delete/change the role of their own account | admin/manage_users.php |
| File Upload Validation | File type & size validation (max 2MB, JPG/PNG) | settings.js, api_settings.php |
⚠️ Note for Production: Some code sections still usemysqli_real_escape_string()(instead of Prepared Statements). It is recommended to fully migrate to Prepared Statements before deploying to a production environment.
┌─────────────────────────────────────────────────────────────────────────┐
│ USERS │
│ id │ username │ email │ password │ role │ first_name │ last_name │ ... │
│ PK │ │ UNIQUE│ BCrypt │ ENUM │ │ │ │
└──────────────────────────────────┬──────────────────────────────────────┘
│ id = user_id (FK)
┌──────────────┘
│
┌───────────▼─────────────┐
│ WEIGHT_TRACKING │
│ id │ user_id │ weight │
│ PK │ FK(users)│ FLOAT │
│ │ CASCADE │ │
└─────────────────────────┘
┌──────────────────────────────────────────────┐
│ COURSES │
│ id │ title │ tagline │ thumbnail │ banner │ │
│ PK │ │ │ URL │ URL │ │
└────────────────────────┬─────────────────────┘
│ id = course_id (FK)
┌──────────┘
│
┌──────────▼──────────────────────────────┐
│ EXERCISES │
│ id │ course_id │ name │ duration │ gif │
│ PK │ FK(courses)│ │ │ URL │
│ │ CASCADE │ │ │ │
└─────────────────────────────────────────┘
HydraFit uses a modern design with the following concepts:
- Primary Color: Blue (
#2563eb) — main actions and branding - Accent Color: Cyan (
#06b6d4) — welcomes, highlights - Success Color: Green (
#22c55e) — Normal BMI, confirmations - Warning Color: Orange (
#f97316) — Overweight BMI - Danger Color: Red (
#ef4444) — Obese BMI, delete account - Font: Poppins (Google Fonts) — Modern, clean, easy to read
- Animations: Interactive canvas particles on the landing page, fade-in transitions, smooth sidebar collapse
- Components: Glassmorphism-like cards, collapsible navigation sidebar, interactive charts
- This project was built as a learning project for pure PHP web development (native PHP, no framework).
- It does not use Composer — all libraries are included manually (PHPMailer is copied directly).
- It does not use a
.envfile — sensitive configurations are directly in the PHP files (adjust for production). - Routing is handled manually using PHP's
header("Location: ...").
|
Yosua Surianto FullStack Developer 📸 Instagram • 🐦 Twitter/X |
This project is released under the MIT license. You are free to use, modify, and distribute this project provided that you include attribution to the original creator.
Made with ❤️ by Yosua Surianto
"The only bad workout is the one that didn't happen."