# TrainRec

**TrainRec** is a personal fitness web application that helps users work out safely and effectively at home or at the gym. It uses pose detection (MediaPipe) to assess exercise form in real time, tracks workout history and calorie data, and locates nearby gyms — all in a judgment-free environment.

Built with a **React + Vite frontend** (deployed on Vercel) and a **Flask backend API** (deployed on Render) backed by **PostgreSQL**.

---

## Table of Contents

1. [Directory Structure](#directory-structure)
2. [Database](#database)
3. [Prerequisites](#prerequisites)
4. [Installation Guide — Local Development](#installation-guide--local-development)
5. [Environment Variables](#environment-variables)
6. [Available Scripts](#available-scripts)
7. [Deployment](#deployment)
   - [Frontend — Vercel](#frontend--vercel)
   - [Backend — Render](#backend--render)
8. [User Manual](#user-manual)

---

## Directory Structure

```
TrainRec1/
├── README.md                  ← Top-level project overview
└── TrainRec/                  ← Application root
    ├── README.md              ← This file — full installation & user guide
    ├── package.json           ← Frontend Node.js dependencies & scripts
    ├── requirements.txt       ← Backend Python dependencies
    ├── trainrec_exercises.py  ← Flask backend server (API + database logic)
    ├── vite.config.js         ← Vite build configuration
    ├── eslint.config.js       ← ESLint configuration
    ├── index.html             ← HTML entry point for Vite
    ├── Procfile               ← Render/Heroku startup command (gunicorn)
    ├── render.yaml            ← Render infrastructure-as-code (service + DB)
    ├── vercel.json            ← Vercel deployment config (SPA rewrites)
    ├── data/
    │   └── pose_sessions/     ← Local pose session recordings (UUID-named folders)
    │       └── <uuid>/
    │           ├── landmarks.json   ← Full landmark data for the session
    │           ├── landmarks.jsonl  ← Streaming landmark data (line-delimited JSON)
    │           └── metadata.json   ← Session metadata (exercise, reps, timestamp)
    ├── public/
    │   └── exercise-videos/   ← Static exercise demo video assets
    ├── static/
    │   └── uploads/           ← Local file upload staging directory
    └── src/
        ├── main.jsx           ← React entry point
        ├── App.jsx            ← Root component — routing and auth guard
        ├── App.css            ← Global CSS overrides
        ├── index.css          ← Base CSS reset
        ├── config.js          ← API base URL (reads VITE_API_URL env var)
        ├── themes.js          ← MUI light/dark theme definitions
        ├── assets/            ← Static image assets (logo, etc.)
        ├── Components/
        │   ├── Login.jsx           ← Login, registration, and password reset
        │   ├── Dashboard.jsx       ← Daily checklist, calorie log, habit cards
        │   ├── Workouts.jsx        ← Exercise library + PoseTrainer launcher
        │   ├── PoseTrainer.jsx     ← pose detection and rep counting (MediaPipe)
        │   ├── Progress.jsx        ← Workout history, goals, calorie charts
        │   ├── Profile.jsx         ← User profile editor and avatar upload
        │   ├── GymLocator.jsx      ← Nearby gym search (Google Maps Places API)
        │   ├── Weather.jsx         ← Explore page host (gym locator)
        │   └── ResponsiveAppBar.jsx← Navigation bar with theme toggle
        └── util/
            └── poseMath.js    ← Landmark normalization, joint angle math, rep detection
```

---

## Database

TrainRec uses **PostgreSQL**. The schema is created automatically when the Flask server starts and a `DATABASE_URL` environment variable is provided — no manual SQL scripts are required.

### Tables created automatically by `trainrec_exercises.py`

| Table | Columns | Description |
|---|---|---|
| `users` | id, email, name, nickname, password_hash, sex, birthdate, height_in, weight_lb, fitness_activity, profile_pic, created_at, confidence_level | User accounts and profile data |
| `goals` | id, user_id, goal_text, created_at | User-defined fitness goals |
| `completed_workouts` | id, user_id, exercise_name, calories_burned, completed_at | Finished exercise sessions per user |

### Running locally without PostgreSQL

If `DATABASE_URL` is not set the Flask server still starts, but all endpoints that require authentication (login, register, workout logging, goals) will fail. For full local functionality you need a PostgreSQL database. Two free options:

- **Local:** Install PostgreSQL and run `createdb trainrec`, then use `DATABASE_URL=postgresql://localhost/trainrec`
- **Cloud (recommended):** Create a free database on [Neon](https://neon.tech) or [Supabase](https://supabase.com) and paste the connection string into your `.env` file

---

## Prerequisites

| Tool | Minimum Version | Link |
|---|---|---|
| Node.js + npm | 18 | https://nodejs.org |
| Python | 3.10 | https://www.python.org/downloads |
| pip | Latest (bundled with Python) | — |
| PostgreSQL *(optional for full local auth)* | 14 | https://www.postgresql.org/download |

### Frontend packages (installed automatically via `npm install`)

| Package | Version | Purpose |
|---|---|---|
| `react` | ^19.2.0 | UI library |
| `react-dom` | ^19.2.0 | React DOM renderer |
| `react-router-dom` | ^7.13.1 | Client-side routing |
| `@mui/material` | ^7.3.9 | Material UI component library |
| `@mui/icons-material` | ^7.3.9 | Material UI icons |
| `@mui/styled-engine-sc` | ^7.3.9 | MUI styled engine adapter |
| `@emotion/react` | ^11.14.0 | CSS-in-JS runtime (required by MUI) |
| `@emotion/styled` | ^11.14.1 | Styled-component support for Emotion |
| `styled-components` | ^6.3.12 | CSS-in-JS styling |
| `@mediapipe/tasks-vision` | ^0.10.34 | In-browser AI pose landmark detection |

### Backend packages (installed automatically via `pip install -r requirements.txt`)

| Package | Version | Purpose |
|---|---|---|
| `flask` | 3.0.3 | Python web framework / API server |
| `flask-cors` | 4.0.1 | Cross-origin resource sharing headers |
| `pyjwt` | 2.8.0 | JSON Web Token auth |
| `werkzeug` | 3.0.3 | Password hashing utilities |
| `psycopg2-binary` | 2.9.10 | PostgreSQL database driver |
| `cloudinary` | 1.40.0 | Cloud image upload (profile pictures) |
| `gunicorn` | 22.0.0 | Production WSGI server |

### Dev dependencies (frontend only)

| Package | Purpose |
|---|---|
| `vite` | Build tool and dev server |
| `@vitejs/plugin-react` | React Fast Refresh |
| `eslint` | Linting |
| `eslint-plugin-react-hooks` | React Hooks lint rules |
| `eslint-plugin-react-refresh` | React Refresh lint rules |

---

## Installation Guide — Local Development

> You need **two terminals** open simultaneously — one for the backend, one for the frontend.

### Step 1 — Get the code

```bash
git clone <repository-url>
cd TrainRec1/TrainRec
```

### Step 2 — Install frontend dependencies

```bash
npm install
```

### Step 3 — Create a Python virtual environment and install backend dependencies

```bash
python -m venv .venv

# macOS / Linux
source .venv/bin/activate

# Windows (Command Prompt)
.venv\Scripts\activate.bat

# Windows (PowerShell)
.venv\Scripts\Activate.ps1

pip install -r requirements.txt
```

### Step 4 — Configure environment variables

Create a file named **`.env`** inside `TrainRec1/TrainRec/` with the contents below. Replace placeholder values with your actual credentials.

```dotenv
# ── Backend variables (read by Python / os.environ) ────────────────
DATABASE_URL=postgresql://localhost/trainrec
JWT_SECRET=replace-with-a-long-random-string

# Cloudinary — required for profile picture uploads
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

# Google Maps — required for Gym Locator feature
GOOGLE_MAPS_API_KEY=your_google_maps_key

# ── Frontend variables (must start with VITE_) ─────────────────────
VITE_API_URL=http://localhost:5000
VITE_GOOGLE_MAPS_KEY=your_google_maps_key
```

**Where to get each credential:**

| Variable | How to obtain |
|---|---|
| `DATABASE_URL` | Local PostgreSQL: `postgresql://localhost/trainrec`. Cloud: free tier at [neon.tech](https://neon.tech) or [supabase.com](https://supabase.com) |
| `JWT_SECRET` | Run `python -c "import secrets; print(secrets.token_hex(32))"` and paste the output |
| `CLOUDINARY_*` | Sign up at [cloudinary.com](https://cloudinary.com) → Dashboard → copy Cloud Name, API Key, API Secret |
| `GOOGLE_MAPS_API_KEY` | [Google Cloud Console](https://console.cloud.google.com) → APIs & Services → enable *Maps JavaScript API* and *Places API* → Credentials |

> **Minimal setup (no external services):** The app runs with only `DATABASE_URL`, `JWT_SECRET`, and `VITE_API_URL`. Profile picture uploads and gym search will be unavailable, but auth, workouts, pose detection, progress tracking, and goals all work.

### Step 5 — Start the Flask backend

In **Terminal 1** (virtual environment must be active):

```bash
python trainrec_exercises.py
```

The API runs at **http://localhost:5000**. On first startup it automatically creates all database tables.

### Step 6 — Start the Vite frontend

In **Terminal 2**:

```bash
npm run dev
```

The frontend runs at **http://localhost:5173**.

Open **http://localhost:5173** in your browser. Both terminals must stay running.

---

## Environment Variables

### Backend (`os.environ` — set in `.env` or the hosting platform)

| Variable | Required | Description |
|---|---|---|
| `DATABASE_URL` | Yes (for auth/data) | PostgreSQL connection string |
| `JWT_SECRET` | Yes | Secret key for signing JSON Web Tokens |
| `CLOUDINARY_CLOUD_NAME` | Optional | Cloudinary account identifier |
| `CLOUDINARY_API_KEY` | Optional | Cloudinary API key |
| `CLOUDINARY_API_SECRET` | Optional | Cloudinary API secret |
| `GOOGLE_MAPS_API_KEY` | Optional | Google Maps key for the backend gym-search proxy |
| `FRONTEND_URL` | Production only | Full URL of deployed frontend — added to CORS allowlist |
| `FLASK_DEBUG` | Dev only | Set `"true"` to enable Flask debug mode |

### Frontend (`import.meta.env` — must start with `VITE_`)

| Variable | Required | Description |
|---|---|---|
| `VITE_API_URL` | Yes | Base URL of the Flask backend |
| `VITE_GOOGLE_MAPS_KEY` | Optional | Google Maps key for the client-side gym map |

---

## Available Scripts

### Frontend (`TrainRec1/TrainRec/`)

| Command | Description |
|---|---|
| `npm run dev` | Start Vite development server with hot module replacement |
| `npm run build` | Compile and bundle for production into `dist/` |
| `npm run preview` | Serve the production build locally |
| `npm run lint` | Run ESLint across all source files |

### Backend

| Command | Description |
|---|---|
| `python trainrec_exercises.py` | Start the Flask development server on port 5000 |
| `gunicorn trainrec_exercises:app` | Start with Gunicorn (production mode) |

---

## Deployment

### Frontend — Vercel

The `vercel.json` file at the project root configures all routes to rewrite to `index.html` so that React Router handles client-side navigation.

1. Push the repository to GitHub.
2. Go to [vercel.com](https://vercel.com) → **Add New Project** → import the repository.
3. Set **Root Directory** to `TrainRec1/TrainRec`.
4. Vercel auto-detects Vite. The build command (`npm run build`) and output directory (`dist`) are already set in `vercel.json`.
5. Add **Environment Variables** in the Vercel project settings:

   | Key | Value |
   |---|---|
   | `VITE_API_URL` | Public URL of your Render backend (e.g. `https://trainrec-backend.onrender.com`) |
   | `VITE_GOOGLE_MAPS_KEY` | Your Google Maps API key *(optional)* |

6. Click **Deploy**. Redeploy whenever you push to the connected branch.

### Backend — Render

The `render.yaml` file at the project root defines the web service and a PostgreSQL database as a Render Blueprint.

1. Go to [render.com](https://render.com) → **New** → **Blueprint** → connect the repository.
2. Render reads `render.yaml` and automatically creates the web service and the `trainrec-db` PostgreSQL database.
3. In the Render service dashboard, add the **Environment Variables** marked `sync: false` (they must be entered manually):

   | Key | Value |
   |---|---|
   | `CLOUDINARY_CLOUD_NAME` | Your Cloudinary cloud name |
   | `CLOUDINARY_API_KEY` | Your Cloudinary API key |
   | `CLOUDINARY_API_SECRET` | Your Cloudinary API secret |
   | `FRONTEND_URL` | Public URL of your Vercel frontend (e.g. `https://trainrec.vercel.app`) |
   | `GOOGLE_MAPS_API_KEY` | Your Google Maps API key *(optional)* |

4. `JWT_SECRET` is auto-generated by Render. `DATABASE_URL` is injected automatically from the linked database.
5. After both services are live, update the Vercel `VITE_API_URL` variable to the Render backend URL and trigger a Vercel redeploy.

---

## User Manual

### Getting started

1. Navigate to the app (local: `http://localhost:5173` or the Vercel deployment URL).
2. On the **Login** screen, click **Register** to create an account. Enter your name, email, password, and basic fitness info (sex, birthdate, height, weight, activity level).
3. After registering you are automatically logged in and taken to the Dashboard.

---

### Dashboard

Your daily home base.

- **Habit cards** — six daily habits (Hydration, Nutrition, Sleep, Workout, Mindfulness, Energy). Click a card to log it for today and grow your streak.
- **Calorie intake log** — enter meal names and calorie counts throughout the day. The log resets automatically at midnight.
- **Daily checklist** — add and check off custom tasks for the day (e.g., "stretch for 10 minutes"). Items persist and are also visible on the Workouts page.

---

### Workouts

The full exercise library and AI form coach.

1. **Browse** — use the search bar or category toggle buttons (Upper Body, Lower Body, Core, Full Body, Cardio) to filter exercise cards.
2. **Add to checklist** — click the bookmark icon on any card to add that exercise to your daily checklist.
3. **Launch Pose Trainer** — click the camera icon on an exercise card:
   - Grant camera access when the browser prompts.
   - Use the **flip camera** button to switch between front and rear cameras.
   - Click **Start Session**. The MediaPipe pose landmarker loads entirely in-browser — no video data is sent to any server.
   - A skeleton overlay appears on the video feed. Joints are highlighted **green** for correct form and **red** when a correction is needed.
   - Rep count and a live form feedback label update in real time.
   - Click **Stop** to end the session. Completed reps and estimated calories burned are saved to your account.

---

### Progress

Your fitness history.

- **Workout log** — every session completed via Pose Trainer appears here with date, exercise name, reps, and calories burned.
- **Calorie summary** — a chart of daily calorie burn built from logged sessions.
- **Goals** — type a new goal and click **Add Goal**. Goals are stored in the database and persist across sessions. Click the delete icon to remove a goal.

---

### Explore (Gym Locator)

Find gyms near you.

1. Allow the browser to share your location, or type an address into the search box.
2. Nearby gyms are returned from the Google Maps Places API and shown as cards with name, address, and rating.
3. Click **View on Map** on any result to open Google Maps directions in a new tab.

> Requires valid `VITE_GOOGLE_MAPS_KEY` (frontend) and `GOOGLE_MAPS_API_KEY` (backend) environment variables.

---

### Profile

Update your personal information.

- Edit display name, nickname, height, weight, birthdate, sex, and fitness activity level.
- Upload a profile picture — click the avatar image to open the file picker. Images are stored on Cloudinary and the URL is saved to your account.
- To change your password, log out and use the **Reset Password** link on the Login screen.
- Click **Save** to write changes to the database.

---

### Navigation bar

Visible on every page except Login:

| Item | Action |
|---|---|
| TrainRec logo / title | Go to Dashboard |
| Dashboard / Workouts / Progress / Explore / Profile links | Navigate to that section |
| Sun/Moon icon | Toggle light and dark mode |
| Logout button | Clear session token and return to Login |
