Skip to content

About

API para gestão de treinos. Este projeto foi desenvolvido com o propósito de compor meu portfólio e consolidar habilidades em Node.js, Express e MongoDB, com ênfase em lógica de negócios e autenticação JWT. A partir dessa base, implementei novas funcionalidades e construí um frontend dedicado do zero em React, motivado por uma necessidade pessoal.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🏋️ Gym API


📋 About

A RESTful API for gym workout management, originally built as a portfolio project and later extended to cover my own personal training needs. The API handles workout plans (manual or AI-generated), an exercise library, and personal record (PR) tracking.

Built with Node.js and Express, it features schema validation via Zod, JWT authentication, rate limiting, and transactional email via Brevo. AI-assisted plan generation is powered by Google Gemini. Code quality is enforced through ESLint, Prettier, and EditorConfig. Integrated with a React frontend — check it out live: superfrango.grdev.app.br


🛠 Tech Stack

Layer Technology
Runtime Node.js (JavaScript)
Framework Express.js
Database MongoDB + Mongoose
Authentication JSON Web Token (JWT)
Validation Zod
AI Google Gemini (@google/genai)
Email Brevo API (via Axios)
Image Upload Cloudinary
Security Express Rate Limit + bcrypt
Containerization Docker + Docker Compose
CI/CD GitHub Actions
Code Quality ESLint + Prettier + EditorConfig

🗂️ Project Structure

gym-app-api/
├── .github/
│   └── workflows/
│       └── deploy.yml            # GitHub Actions CI/CD pipeline
├── src/
│   ├── configs/
│   │   └── cloudinary.js         # Cloudinary SDK configuration
│   ├── exercises/
│   │   ├── controllers/          # Request handlers for /exercises routes
│   │   └── routes/               # Route definitions for /exercises
│   ├── history/
│   │   ├── controllers/          # Session logging, history & PR queries
│   │   └── routes/               # Route definitions for /workouts
│   ├── middleware/
│   │   ├── authMiddleware.js     # JWT verification middleware
│   │   ├── middleware.js         # API key auth (catalog write routes)
│   │   └── rateLimit.js          # Rate limiting rules (global, login, AI)
│   ├── models/
│   │   ├── Exercise.js           # Mongoose model: exercise library
│   │   ├── User.js               # Mongoose model: user accounts
│   │   ├── WorkoutHistory.js     # Mongoose model: logged sessions & PRs
│   │   └── WorkoutPlan.js        # Mongoose model: workout plans (manual & AI)
│   ├── services/
│   │   └── emailService.js       # Brevo email dispatch logic
│   ├── users/
│   │   ├── controllers/          # Request handlers for /users routes
│   │   └── routes/               # Route definitions for /users
│   └── workoutPlans/
│       ├── controllers/          # CRUD for plans + AI generation
│       ├── prompts/
│       │   └── prompt.js         # Gemini prompt template
│       └── routes/               # Route definitions for /workout-plans
├── .dockerignore                 # Files excluded from Docker build context
├── .editorconfig                 # Editor formatting rules (indent, charset, EOL)
├── .env.example                  # Environment variable reference template
├── eslint.config.js              # ESLint flat config
├── .gitignore
├── .prettierrc                   # Prettier formatting preferences
├── app.js                        # Express app & middleware setup
├── docker-compose.yml            # Multi-container orchestration config
├── Dockerfile                    # Production image build instructions
├── package.json
└── server.js                     # Application entry point (DB connect + listen)

✨ Features & Security

  • Workout plans — build structured multi-day plans, reorder days and exercises, rename, and share via code
  • AI-assisted generation — Google Gemini builds a full plan (days, exercises, sets/reps) from goal, weekly days and gender; the plan is returned to the client for review and only saved once the user confirms
  • Exercise library — a shared catalogue of exercises by muscle group, used both for manual creation and as the source the AI must pick exercises from
  • PR & history tracking — log sessions, query personal bests per exercise (accent/case-insensitive exact match), and browse full or per-exercise history
  • Email verification — account activation and password recovery via Brevo
  • Image uploads — profile pictures stored on Cloudinary
  • JWT authentication — stateless token-based auth on all protected routes
  • API key authentication — timing-safe comparison guarding the exercise catalog's write routes
  • Rate limiting — global cap on all routes, a tighter cap on auth routes, and a per-user cap on AI generation
  • Schema validation — all incoming payloads validated with Zod before hitting controllers
  • Code quality — consistent formatting enforced by ESLint + Prettier + EditorConfig across the entire codebase

📡 API Endpoints

🔒 Routes marked with this lock require the header: Authorization: Bearer <jwt_token> 🔑 Routes marked with this key require the header: x-api-key: <api_key>

All request and response bodies use JSON unless otherwise noted. The API also exposes two public service endpoints:

Route Method Description
/ GET Confirms that the API is running
/health GET Health check with status and a Unix timestamp in ms

Authentication & Users — /users

Route Method Auth Payload Description
/register POST ❌ {"name","email","password"} Create a new account
/verify-email POST ❌ {"email","code"} Verify email address
/login POST ❌ {"email","password"} Returns a JWT token
/forgot-password POST ❌ {"email"} Send recovery code
/reset-password POST ❌ {"code","email","password"} Set a new password
/update-password POST 🔒 {"oldPassword","newPassword"} Change password while logged in
/upload-profile-image POST 🔒 multipart/form-data (profileImg) Upload profile picture to Cloudinary

Workout Plans — /workout-plans

Route Method Auth Payload Description
/ POST 🔒 {"name","days":[...]} Create a plan manually
/ GET 🔒 — List all plans for the user
/:planId DELETE 🔒 — Delete a plan
/:planId/name PUT 🔒 {"name"} Rename a plan
/:planId/reorder PUT 🔒 {"daysOrder":[...]} Reorder days
/:planId/days POST 🔒 {"name","exercises":[]} Add a day
/:planId/days/:dayName PUT 🔒 {"name"} Rename a day
/:planId/days/:dayName DELETE 🔒 — Remove a day
/:planId/days/:dayName/reorder PUT 🔒 {"dayName","exercisesOrder":[...]} Reorder exercises within a day by exercise IDs
/:planId/days/:dayName/exercises POST 🔒 {"dayName","exerciseId","sets","reps","weight"} Add a library exercise to a day
/:planId/days/:dayName/exercises/:exerciseName PUT 🔒 {"sets"?,"reps"?,"weight"?} Edit an exercise's training parameters
/:planId/days/:dayName/exercises/:exerciseName DELETE 🔒 — Remove an exercise
/copy/:shareCode POST 🔒 — Copy a shared plan into your own account
/generate POST 🔒 {"dias","foco","genero"} AI-generate a plan (see below) — not persisted, returns {"plan"} for the client to review and save via POST /

/generate is limited to 3 requests per minute per user. dias accepts 3–6, foco is one of hipertrofia/força/resistência, genero is masculino/feminino.

Adding an exercise requires a valid catalogue exerciseId. The API resolves its canonical name and muscle group, rejects duplicates within the same day, and keeps legacy plans without IDs compatible. New plans are also validated against the catalogue before they are saved.

Workouts (history & PRs) — /workouts

Route Method Auth Payload Description
/log POST 🔒 {"exercises":[...]} Log a completed workout session
/pr GET 🔒 — Personal record for an exercise (?exercise=)
/history GET 🔒 — Latest 20 logged sessions
/history/:exerciseName GET 🔒 — Full history for one exercise
/history DELETE 🔒 {"confirm":"CONFIRM"} Permanently delete the user's entire history

Exercises — /exercises

Route Method Auth Payload Description
/ GET 🔒 — List the full exercise catalogue
/ POST 🔑 {"name","muscle"} Register a single exercise
/bulk POST 🔑 [{"name","muscle"}, ...] Bulk-register exercises
/:id DELETE 🔑 — Remove an exercise

🔧 Environment Variables

Variable Required Purpose
PORT Yes HTTP port used by the server
DATABASE_URL Yes MongoDB connection string
JWT_SECRET Yes Secret used to sign and verify JWTs
CLIENT_URL Yes Allowed CORS origin; accepts comma-separated URLs
API_KEY Yes¹ Protects exercise catalogue write operations
API_AI_KEY Yes² Google Gemini API key used to generate plans
BREVO_API_KEY Yes³ Brevo API key for verification and recovery emails
BREVO_EMAIL Yes³ Verified sender address used by Brevo
CLOUDINARY_CLOUD_NAME Yes⁴ Cloudinary cloud identifier
CLOUDINARY_API_KEY Yes⁴ Cloudinary API key
CLOUDINARY_API_SECRET Yes⁴ Cloudinary API secret
NODE_ENV No Set to production to suppress application console output

¹ Required for catalogue writes. ² Required for AI generation. ³ Required for email flows. ⁴ Required for profile-image uploads.


⚙️ CI/CD Pipeline

The project uses GitHub Actions to automate build and deploy on every push to master.

Push to master
    │
    ▼
Build Docker image
    │
    ▼
Push to Docker Hub
    │
    ▼
SSH into VPS → pull new image → recreate container

Required repository secrets

Secret Description
DOCKERHUB_USERNAME Docker Hub username
DOCKERHUB_TOKEN Docker Hub access token
SSH_HOST VPS public IP
SSH_USER SSH user
SSH_KEY Full private SSH key

Add them under Settings → Secrets and variables → Actions.


🚀 Running Locally

Prerequisites

  • Node.js 22+ (the Docker image uses Node.js 22 Alpine)
  • MongoDB running locally or a connection string (e.g. MongoDB Atlas)
  • Accounts for Brevo, Cloudinary and Google AI Studio (Gemini) — optional for full feature coverage

Steps

# 1. Clone the repository
git clone https://github.com/Geovanni-dev/gym-app-api.git
cd gym-app-api

# 2. Install dependencies
npm install

# 3. Create your .env file from the template
cp .env.example .env
# Add CLIENT_URL, API_KEY and API_AI_KEY to the copied file;
# the current template does not include them yet.

# 4. Start the development server
npm run dev

Once started, open http://localhost:3000/health to verify that the API's HTTP layer is available independently of the database connection.

Available scripts

Command Purpose
npm run dev Start the API with Nodemon
npm test Run the Jest test suite
npm run lint Check the codebase with ESLint
npm run lint:fix Automatically fix supported lint issues
npm run format Format the codebase with Prettier

🐳 Docker

# Build and start the container in the background
docker compose up -d

# Stream logs
docker compose logs -f

# Stop and remove the container
docker compose down

🌐 Deployment

Hosted on a VPS with fully automated deploys via GitHub Actions. Every push to master rebuilds the image, pushes it to Docker Hub, and updates the running container on the server with zero manual steps.


📄 License

MIT © Geovani Rodrigues

About

API para gestão de treinos. Este projeto foi desenvolvido com o propósito de compor meu portfólio e consolidar habilidades em Node.js, Express e MongoDB, com ênfase em lógica de negócios e autenticação JWT. A partir dessa base, implementei novas funcionalidades e construí um frontend dedicado do zero em React, motivado por uma necessidade pessoal.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

Contributors

Languages