- JavaScript 54.4%
- Vue 44.6%
- CSS 0.4%
- Dockerfile 0.3%
- Shell 0.2%
- e2e specs assert actual page h1 headings instead of the app name - Navbar: leave token lifecycle to the auth store instead of clearing localStorage on transient /api/auth/me failures - Refresh backend/frontend lockfiles |
||
|---|---|---|
| backend | ||
| frontend | ||
| .env.prod | ||
| .gitignore | ||
| app_requirements.txt | ||
| CONTEXT.md | ||
| DEPLOYMENT.md | ||
| docker-compose.override.yml | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| env.example | ||
| LICENSE | ||
| nginx-upload-fix.conf | ||
| PRODUCTION_FIX.md | ||
| README.md | ||
| REVERSE_PROXY.md | ||
| SUMMARY.md | ||
| TEST_RESULTS.md | ||
Get Healthy
A clean, open-source fitness tracking application to help you track workouts, body measurements, and progress toward health goals.
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | Vue.js 3 + Vite + Tailwind CSS + Vue Router + Pinia |
| Backend | Node.js + Express.js + Passport.js |
| Database | PostgreSQL |
| ORM | Prisma |
| Auth | JWT (Local) + OIDC/OAuth2 (Google, GitHub, Keycloak, Authentik, Authelia) |
| API | REST |
| Deployment | Docker Compose |
Features
Authentication
- Email/password registration and login
- OIDC/OAuth2 integration (Google, GitHub, Keycloak, Authentik, Authelia, Generic OIDC)
- Password reset flow with SMTP email support
- Email verification
- First registered user automatically becomes admin
User Profile
- Display name, avatar upload
- Height, age, current weight tracking
- Preferred weight unit (lb/kg)
- Light/Dark mode with device detection
- Push notification preferences
- Full data deletion
Body Measurements
- Weight, body fat percentage
- Body measurements: waist, hips, chest, thighs, biceps, calves, shoulders, back span, neck
- Historical tracking with interactive charts
- Progress visualization over time
Workout Tracking
- Create and manage workout routines
- Routine types: Weightlifting, Aerobic, Flexibility, Combination
- Exercise types: Strength, Cardio, Flexibility
- Quick-entry UI for sets/reps/weight (mobile optimized)
- RPE (Rate of Perceived Exertion) tracking
- Continue previous incomplete workouts
- Archive workouts individually or batch (by date range or name pattern)
- View and restore archived workouts
- Exercise name autocomplete from history
Workout Templates
- Pre-built template library (StrongLifts, PPL, Couch to 5K, Starting Strength, 5K Training, HIIT, Yoga, Pilates, etc.)
- Create custom templates with workout builder
- Save workout as template
- Browse/search templates by type, goal, difficulty
Photo Journal
- Upload progress photos with categorization
- Gallery view organized by category
- Edit photo details (category, notes, date)
- Timelapse playback for progress visualization
- Full-screen photo viewer
Exercise Limits
- Set upper/lower limits per exercise
- Visual badges for limits in profile
- Quick add/delete limits from profile
Scheduling
- Schedule workouts on specific dates
- Cadence system (every X days)
- Calendar view
- Push notification reminders (HTTPS required)
Reporting & Dashboard
- Dashboard with summary charts
- Progress tracking charts
- Time-of-day analysis
- Motivational messages
- Calorie tracking
Admin
- Admin dashboard
- User management
- System statistics
- SMTP configuration and testing
- OIDC provider configuration
AI Integration
- Backend hooks for Ollama integration
- Online AI support (OpenAI/Anthropic)
Data Management
- JSON export
- CSV export
- Full data deletion
Getting Started
Prerequisites
- Node.js 18+
- Docker and Docker Compose
Quick Start (Docker)
# Clone the repository
git clone https://github.com/your-repo/get_healthy.git
cd get_healthy
# Start all services
docker-compose up -d
# Access the app
# Frontend: http://localhost:5173
# Backend API: http://localhost:3000
Development Setup
- Install dependencies:
# Backend
cd backend && npm install
# Frontend
cd ../frontend && npm install
- Start PostgreSQL with Docker:
docker-compose up -d db
- Set up the database:
cd backend
npx prisma db push
npx prisma generate
- Start the backend:
cd backend
npm run dev
- Start the frontend (in another terminal):
cd frontend
npm run dev
- Access the app:
- Frontend: http://localhost:5173
- Backend API: http://localhost:3000
Environment Variables
Backend (.env)
DATABASE_URL=postgresql://user:pass@localhost:5432/get_healthy
JWT_SECRET=your-secret-key
NODE_ENV=development
PORT=3000
FRONTEND_URL=http://localhost:5173
# OAuth / OIDC (optional - configure any combination)
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_CALLBACK_URL=http://localhost:3000/api/auth/oidc/google/callback
# GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
GITHUB_CALLBACK_URL=http://localhost:3000/api/auth/oidc/github/callback
# Keycloak OIDC
KEYCLOAK_CLIENT_ID=your-keycloak-client-id
KEYCLOAK_CLIENT_SECRET=your-keycloak-client-secret
KEYCLOAK_ISSUER=https://your-keycloak.com/realms/your-realm
KEYCLOAK_AUTHORIZATION_URL=https://your-keycloak.com/realms/your-realm/protocol/openid-connect/auth
KEYCLOAK_TOKEN_URL=https://your-keycloak.com/realms/your-realm/protocol/openid-connect/token
KEYCLOAK_USERINFO_URL=https://your-keycloak.com/realms/your-realm/protocol/openid-connect/userinfo
KEYCLOAK_CALLBACK_URL=http://localhost:3000/api/auth/oidc/keycloak/callback
# Authentik OIDC
AUTHENTIK_CLIENT_ID=your-authentik-client-id
AUTHENTIK_CLIENT_SECRET=your-authentik-client-secret
AUTHENTIK_ISSUER=https://your-authentik.com
AUTHENTIK_AUTHORIZATION_URL=https://your-authentik.com/application/o/authorize/
AUTHENTIK_TOKEN_URL=https://your-authentik.com/application/o/token/
AUTHENTIK_USERINFO_URL=https://your-authentik.com/application/o/userinfo/
AUTHENTIK_CALLBACK_URL=http://localhost:3000/api/auth/oidc/authentik/callback
# Authelia OIDC
AUTHELIA_CLIENT_ID=your-authelia-client-id
AUTHELIA_CLIENT_SECRET=your-authelia-client-secret
AUTHELIA_ISSUER=https://your-authelia.com
AUTHELIA_AUTHORIZATION_URL=https://your-authelia.com/api/oidc/authorization
AUTHELIA_TOKEN_URL=https://your-authelia.com/api/oidc/token
AUTHELIA_USERINFO_URL=https://your-authelia.com/api/oidc/userinfo
AUTHELIA_CALLBACK_URL=http://localhost:3000/api/auth/oidc/authelia/callback
# Generic OIDC Provider
OIDC_CLIENT_ID=your-oidc-client-id
OIDC_CLIENT_SECRET=your-oidc-client-secret
OIDC_ISSUER=https://your-idp.com
OIDC_AUTHORIZATION_URL=https://your-idp.com/authorize
OIDC_TOKEN_URL=https://your-idp.com/token
OIDC_USERINFO_URL=https://your-idp.com/userinfo
OIDC_CALLBACK_URL=http://localhost:3000/api/auth/oidc/generic/callback
# SMTP Configuration (optional - for password reset emails)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-smtp-user
SMTP_PASS=your-smtp-password
SMTP_FROM=your-from-email@example.com
SMTP_FROM_NAME=Get Healthy
Frontend (.env)
VITE_API_URL=http://localhost:3000/api
OIDC Setup
The application supports OAuth/OIDC authentication with both cloud providers (Google, GitHub) and self-hosted identity providers.
Supported Providers
| Provider | Type | Protocol |
|---|---|---|
| Cloud | OAuth 2.0 | |
| GitHub | Cloud | OAuth 2.0 |
| Keycloak | Self-hosted | OIDC |
| Authentik | Self-hosted | OIDC |
| Authelia | Self-hosted | OIDC |
| Generic | Self-hosted | OIDC |
Keycloak Setup
-
Create a realm in Keycloak or use an existing one
-
Create a client:
- Client ID:
get-healthy - Client Protocol:
openid-connect - Access Type:
confidential - Valid Redirect URIs:
http://localhost:3000/api/auth/oidc/keycloak/callback
- Client ID:
-
Get credentials from the Credentials tab
-
Get endpoints from: Realm Settings → Endpoints → OpenID Endpoint Configuration
-
Set environment variables (see above)
Authentik Setup
-
Create an OAuth2 Provider:
- Name:
Get Healthy - Client ID:
get-healthy(auto-generated) - Redirect URIs:
http://localhost:3000/api/auth/oidc/authentik/callback
- Name:
-
Create an Application linked to the provider
-
Set environment variables (see above)
Generic OIDC Provider
For any OIDC-compliant provider, use the generic configuration with your provider's endpoints.
SMTP Setup
SMTP settings can also be configured from the Admin panel (Email tab):
- Navigate to Admin → Email
- Enter your SMTP credentials
- Click "Test Connection" to verify
- Save settings
Common SMTP Providers:
- Gmail: smtp.gmail.com | Port 587 | Requires App Password
- Outlook: smtp-mail.outlook.com | Port 587 | TLS
- SendGrid: smtp.sendgrid.net | Port 587 | API Key
- Mailgun: smtp.mailgun.org | Port 587 | TLS
- AWS SES: email-smtp.us-east-1.amazonaws.com | Port 587 | SMTP credentials
Production Deployment
For production, update callback URLs to use your production domain:
FRONTEND_URL=https://get-healthy.example.com
GOOGLE_CALLBACK_URL=https://get-healthy.example.com/api/auth/oidc/google/callback
# etc.
Project Structure
/get_healthy
├── /frontend # Vue.js SPA
│ ├── /src
│ │ ├── /components # Reusable components (ConfirmModal, HelpIcon, etc.)
│ │ ├── /views # Page components (Dashboard, Workout, etc.)
│ │ ├── /stores # Pinia stores (auth, ui, notifications)
│ │ └── /router # Vue Router config
│ └── ...
├── /backend # Express.js API
│ ├── /src
│ │ ├── /routes # API routes
│ │ ├── /controllers # Route handlers
│ │ ├── /middleware # Express middleware
│ │ └── /utils # Utilities (passport-config, emailService, etc.)
│ └── /prisma # Database schema
├── /docker # Docker configs
├── docker-compose.yml
├── docker-compose.override.yml
└── README.md
API Endpoints
Auth
POST /api/auth/register- Register new userPOST /api/auth/login- LoginPOST /api/auth/logout- LogoutGET /api/auth/me- Get current userPOST /api/password-reset/forgot- Request password resetPOST /api/password-reset/reset- Reset password with tokenPOST /api/email/verify- Verify emailPOST /api/email/resend- Resend verification emailGET /api/auth/oidc/:provider- Initiate OIDC flowGET /api/auth/oidc/:provider/callback- OIDC callback
Profile
GET /api/profile- Get user profilePUT /api/profile- Update profile (displayName, height, age, weight, weightUnit)POST /api/profile/avatar- Upload avatarDELETE /api/profile- Delete all user data
Body Measurements
GET/POST /api/measurements- List/create measurementsGET /api/measurements/history- Measurement historyGET /api/measurements/latest- Latest measurement
Photo Journal
GET /api/photos- List all photos (optional?category=filter)GET /api/photos/categories- Get unique categoriesGET /api/photos/category/:category- Get photos by categoryGET /api/photos/:id- Get single photoPOST /api/photos- Upload photo (multipart/form-data)PUT /api/photos/:id- Update photo (category, notes, takenAt)DELETE /api/photos/:id- Delete photo
Routines
GET/POST /api/routines- List/create routinesGET/PUT/DELETE /api/routines/:id- Routine CRUDGET /api/routines/:id- Get routine with workouts
Workouts
GET/POST /api/routines/:routineId/workouts- List/create workoutsGET/PUT/DELETE /api/routines/:routineId/workouts/:id- Workout CRUDPOST /api/routines/:routineId/workouts/:id/complete- Complete workoutPOST /api/routines/:routineId/workouts/:id/archive- Archive workoutPOST /api/routines/:routineId/workouts/:id/unarchive- Restore workoutGET /api/routines/:routineId/workouts/archived- Get archived workoutsPOST /api/routines/:routineId/workouts/batch-archive- Batch archive by filter
Exercises
GET/POST /api/workouts/:workoutId/exercises- List/create exercisesPUT/DELETE /api/exercises/:id- Exercise CRUD
Sets & Logs
GET/POST /api/exercises/:exerciseId/sets- List/create setsPUT/DELETE /api/sets/:id- Set CRUDPOST /api/exercises/:exerciseId/aerobic-log- Log aerobic dataPUT/DELETE /api/cardio-logs/:id- Cardio log CRUDPOST /api/exercises/:exerciseId/flexibility-log- Log flexibility data
Templates
GET/POST /api/templates- List/create templatesGET/PUT/DELETE /api/templates/:id- Template CRUDGET /api/templates/public- Public templatesPOST /api/templates/from-workout/:workoutId- Save workout as templatePOST /api/templates/:id/start- Start workout from template
Exercise Limits
GET /api/limits- List all limitsGET /api/limits/exercise/:exerciseName- Get limits for exercisePOST /api/limits- Create/update limitPOST /api/limits/check- Check if value violates limitDELETE /api/limits/:id- Delete limit
Schedule
GET/POST /api/schedule- List/create scheduled workoutsPUT/DELETE /api/schedule/:id- Schedule CRUD
Reports
GET /api/reports/progress- Progress dataGET /api/reports/calories- Calorie dataGET /api/reports/by-time-of-day- Time analysisGET /api/reports/workout-frequency- Workout frequencyGET /api/reports/dashboard- Dashboard data
Dashboard
GET /api/dashboard- Dashboard data (alias for /api/reports/dashboard)
Export
GET /api/export/json- Export all data as JSONGET /api/export/csv- Export measurements as CSV
Admin
GET /api/admin/users- List usersPUT/DELETE /api/admin/users/:id- Update/delete userGET /api/admin/stats- System statisticsGET /api/admin/settings- Get admin settingsPUT /api/admin/settings/oidc- Update OIDC settingsPUT /api/admin/settings/smtp- Update SMTP settingsPOST /api/admin/settings/smtp/test- Test SMTP connection
AI
POST /api/ai/analyze- Analyze workout with OllamaGET /api/ai/health- Check Ollama connection
Scripts
# Backend
cd backend
npm run dev # Development server
npm start # Production server
npx prisma db push # Push schema to database
npx prisma generate # Generate Prisma client
npx prisma studio # Open Prisma Studio
npm test # Run tests (88 tests passing)
# Frontend
cd frontend
npm run dev # Development server (http://localhost:5173)
npm run build # Production build
npm test # Run tests (21 tests passing)
npm run test:e2e # Run E2E tests
npm run lint # Run ESLint
Database Schema
Core Entities
- User - id, email, password_hash, role, provider, avatar, verification
- UserProfile - user_id, display_name, height, age, weight, weight_unit, avatar_url
- BodyMeasurement - weight, body fat, waist, hips, chest, thighs, biceps, calves, etc.
- Routine - id, name, type (weightlifting/aerobic/flexibility/combination)
- Workout - id, routine_id, name, scheduled_date, completed_at, archived
- Exercise - id, workout_id, name, type (strength/cardio/flexibility)
- ExerciseSet - id, exercise_id, set_number, reps, weight, rpe, completed
- AerobicLog - duration, distance, heart_rate, calories, blood_pressure, spo2
- FlexibilityLog - duration, notes
Template Entities
- Template - id, name, description, type, goals[], difficulty, equipment[], is_public
- TemplateWorkout - id, template_id, name, order
- TemplateExercise - id, template_workout_id, name, type, default_sets, default_reps, rest_seconds
Scheduling Entities
- ScheduledWorkout - id, user_id, routine_id, scheduled_date, cadence_type, cadence_value
Limits Entities
- ExerciseLimit - id, user_id, exercise_name, limit_type (upper/lower), value, unit
Photo Journal Entities
- Photo - id, user_id, filename, original_name, category, notes, taken_at, created_at
License
GPLv3