Live at: fitforge.18-221-88-168.sslip.io — deployed on an AWS EC2 instance behind nginx, with a real Let's Encrypt HTTPS certificate.
AI-Powered Fitness Platform — a full-stack app for tracking workouts, nutrition, and body progress, with an AI coach for generating workouts and meal plans and answering fitness questions. Built phase-by-phase, one module at a time, each validated end to end before moving on. See docs/case-study.md for the engineering approach behind it.
The problem: tracking fitness usually means juggling several single-purpose apps — one for counting calories, another for logging sets and reps, a spreadsheet for weight over time — none of which talk to each other. That means no tool actually knows your full picture: what you ate today, what you lifted this week, and how your weight has trended, all at once. Any "coaching" those apps offer is generic, because it isn't reasoning over your real logged history.
Where existing apps fall short:
| Category | Strong at | Missing |
|---|---|---|
| Calorie/food-logging apps | Food/calorie logging, large food databases | Workout tracking is an afterthought; no goal-aware progress view; AI features are usually paywalled |
| Workout-logging apps | Set/rep/weight history | No nutrition tracking at all |
| AI workout-plan generators | AI-generated workout plans | No nutrition logging, no manual meal tracking |
| Micronutrient trackers | Deep micronutrient detail | No workout logging |
| Health data aggregators | Pulling data in from other apps | Don't originate structured workout/meal logs themselves; no coaching |
What FitForge does differently: one data model across workouts, nutrition, and body progress, so the AI coach can actually reason over what you've really logged — not give generic advice — and a single place to see the whole picture instead of cross-referencing three apps.
- Modular-by-domain backend architecture (
auth,workouts,nutrition,progress,profile,ai, each with the samemodels/schemas/service/routesshape) kept every feature addition isolated — new modules never risked breaking ones already shipped. - The BFF pattern (Next.js Route Handlers hold the JWTs in httpOnly cookies; the browser
never sees a token) trades a bit of request-hop complexity for meaningfully better session
security than storing tokens in
localStorage. - Third-party API dependencies need designed-for failure modes. The AI coach degrades gracefully (503 on missing key/quota, 502 on other OpenAI errors) instead of taking the whole app down when an external dependency has a bad day.
- Real infrastructure validation catches what unit tests don't. Several real issues (nginx route shadowing, a Compose port-override that silently no-op'd, a migration that raced its own auto-migrate-on-restart) only surfaced when actually running the full Docker Compose stack — not from the test suite alone.
- Production deployment is its own skill set, separate from writing the app: EC2 provisioning, Let's Encrypt via certbot's webroot method, nginx path-based routing between two services, and — as this project's iteration history shows — real deployments involve real friction (a Google Fonts fetch timing out mid-build, git checkouts drifting from what's actually running) that only surface once something is genuinely live.
- Backend: FastAPI, SQLAlchemy 2.0 (async), Alembic, Celery, Redis, PostgreSQL 16
- Frontend: Next.js (App Router), TypeScript, Tailwind CSS, shadcn/ui
- Infra: Docker Compose, nginx reverse proxy
- CI: GitHub Actions (lint, test, build)
| # | Phase | Description | Status |
|---|---|---|---|
| 1 | Foundation & Auth | Users, JWT access/refresh tokens with rotation and reuse detection, Argon2 password hashing, email verification | complete |
| 2 | Workouts | Exercise library, workout CRUD, workout-exercise ownership validation | complete |
| 3 | Nutrition | Meals, water entries, daily nutrition summary | complete |
| 4 | Progress | Body measurements, goals | complete |
| 5 | Profile | Single-row-per-user profile, wired into /auth/me |
complete |
| 6 | AI Coach | OpenAI-backed workout/meal generation and chat, with graceful degradation on API failures | complete |
| 7 | Frontend Foundation & Auth UI | Next.js BFF pattern, httpOnly cookie sessions, login/register/password-reset pages | complete |
| 8 | Frontend Workouts | Workout list/detail/create/edit pages, exercise picker | complete |
| 9 | Frontend Nutrition | Meal CRUD pages, water quick-add, daily summary | complete |
| 10 | Frontend Progress | Weight chart, measurement and goal forms | complete |
| 11 | Frontend Profile | Profile form with server-side pre-population | complete |
| 12 | Frontend AI Coach | Workout/meal generation UI, chat interface | complete |
| 13 | Frontend Dashboard | Cross-module summary cards, quick actions | complete |
| 14 | Docker & nginx | Full Compose stack, nginx path-based routing between BFF and API | complete |
| 15 | CI | GitHub Actions: lint, test, build for both backend and frontend | complete |
| 16 | Production deploy config | HTTPS via Let's Encrypt, production Compose override, deployment verification scripts | complete |
See docs/phase1.md through docs/phase16.md for what was built in each phase and how it was validated. Case study: docs/case-study.md.
git clone <repo-url> fitforge
cd fitforge
cp .env.example .envEdit .env and set a secure SECRET_KEY.
docker compose up --buildServices:
| Service | Description |
|---|---|
| nginx | http://localhost (port 80) |
| api | FastAPI backend |
| frontend | Next.js app |
| worker | Celery worker |
| beat | Celery beat scheduler |
| db | PostgreSQL 16 |
| redis | Redis 7 |
- Frontend: http://localhost
- Health: http://localhost/api/v1/health
- Readiness: http://localhost/api/v1/ready
- API docs (dev): http://localhost/api/docs
- Mailhog UI: http://localhost:8025
| Context | DATABASE_URL host |
REDIS_URL host |
|---|---|---|
| Docker Compose | db (forced in compose environment:) |
redis |
| Local pytest / uvicorn | localhost (backend/.env or tests/conftest.py) |
localhost |
CORS_ORIGINS must be comma-separated, not JSON:
CORS_ORIGINS=http://localhost:3000,http://localhost
cd backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
# Ensure PostgreSQL and Redis are running (docker compose up -d db redis), then:
export DATABASE_URL=postgresql+asyncpg://fitforge:fitforge@localhost:5432/fitforge
export REDIS_URL=redis://localhost:6379/0
export SECRET_KEY=dev-secret-key-change-me
export ENVIRONMENT=development
alembic upgrade head
uvicorn app.main:app --reload --port 8000
pytest -v
ruff check .# Register
curl -X POST http://localhost:8000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"alex@example.com","password":"SecurePass123!","password_confirm":"SecurePass123!"}'
# Login
curl -X POST http://localhost:8000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"alex@example.com","password":"SecurePass123!"}'
# Me (replace TOKEN)
curl http://localhost:8000/api/v1/auth/me \
-H "Authorization: Bearer TOKEN"cd frontend
npm install
npm run devSet NEXT_PUBLIC_API_URL=http://localhost:8000/api for direct API access during local dev.
fitforge/
├── backend/ # FastAPI application
├── frontend/ # Next.js application
├── nginx/ # Reverse proxy config
├── .github/workflows # CI pipelines
├── docs/ # Architecture, API reference, ADRs, phase write-ups, case study
└── docker-compose.yml
- docs/architecture.md — system diagrams and module layout
- docs/api.md — API reference
- docs/case-study.md — engineering case study
- docs/adr/ — architecture decision records
Proprietary — FitForge