A full-stack MERN workout tracker: JWT auth, a secured/ownership-checked exercise API, and a modern analytics dashboard (streaks, weekly goals, 30-day trend and category breakdown charts).
Stack: MongoDB · Express · React (CRA) · Node — Tailwind CSS + shadcn/ui + lucide-react on the frontend, Zod-validated REST API on the backend.
backend/— Express API (seebackend/README.mdor below for setup)frontend/— React app (Tailwind + shadcn/ui)docker-compose.yml— run both together
# Backend
cd backend
cp .env.example .env # fill in ATLAS_URI and JWT_SECRET
npm install
npm run dev # http://localhost:5000
# Frontend (new terminal)
cd frontend
cp .env.example .env # defaults to http://localhost:5000
npm install
npm start # http://localhost:3000macOS note: port 5000 is often held by the AirPlay Receiver. If
npm run devfails withEADDRINUSE, either disable AirPlay Receiver in System Settings → General → AirDrop & Handoff, or setPORT=5050(or similar) inbackend/.envand matchingREACT_APP_API_URLinfrontend/.env.
docker compose up --buildFrontend: http://localhost:3000 · Backend: http://localhost:5050 (mapped from the container's port 5000 to dodge the AirPlay conflict above).
- Signup/login with JWT (7-day session), bcrypt-hashed passwords
- Every exercise route is authenticated and ownership-checked — a user can only ever read/edit/delete their own data
- Exercise log: category, intensity, duration, auto-estimated calories, notes; search, category filter, and pagination
- Dashboard: total workouts/minutes, current & longest streak, weekly goal progress, 30-day activity trend, category breakdown
- Profile: update weekly goal, change password, delete account
- Light/dark theme, responsive layout, toast notifications, loading skeletons throughout
If you have exercises from before this revamp, they use the legacy
username field name instead of name. Run the one-off migration once
your backend/.env is set up:
cd backend
npm run migrate