Add supplements, kettlebell, calendar, push notifications, and PWA support

- Supplement tracking: CRUD endpoints, /today, /logs, Supplements page
- Kettlebell workouts: session tracking, analytics endpoint, ActiveSession page
- Calendar module: events CRUD, calendar components
- Push notifications: VAPID keys, PushSubscription model, APScheduler reminders,
  service worker with push/notificationclick handlers, Profile notifications UI
- PWA: vite-plugin-pwa, manifest, icons, service worker generation
- Frontend: TypeScript types, API modules, ConfirmModal, toast notifications
- Auth fixes: password hashing, nutrition endpoint auth
- CLAUDE.md: project documentation and development guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-03-20 18:57:03 -06:00
parent bd91eb4171
commit f279907ae3
61 changed files with 9256 additions and 85 deletions

88
CLAUDE.md Normal file
View File

@@ -0,0 +1,88 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development Commands
### Start Everything
```bash
./develop.sh # starts PostgreSQL (Docker), backend (uvicorn), and frontend (vite) together
```
### Backend
```bash
cd backend
source .venv/bin/activate
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
ruff check . # lint
ruff format . # format
pytest # run tests
```
### Frontend
```bash
cd frontend
npm run dev # dev server on :5173
npm run build # production build
npm run lint # ESLint
```
### Database
```bash
docker compose up -d # start PostgreSQL with pgvector on :5432
```
## Architecture
Full-stack health/fitness tracker with AI-powered nutrition analysis and plan generation.
**Stack:** FastAPI (Python) + React 19 (TypeScript) + PostgreSQL/pgvector + DSPy + OpenAI GPT-4o
### Backend (`/backend`)
- `app/main.py` — FastAPI app, CORS config, router mounting
- `app/api/v1/endpoints/` — Route handlers: `login`, `users`, `nutrition`, `health`, `plans`
- `app/models/` — SQLModel ORM models (User, HealthMetric, HealthGoal, FoodLog, FoodItem, Plan)
- `app/ai/` — DSPy modules: `nutrition.py` (food analysis + image analysis), `plans.py` (personalized plan generation)
- `app/core/ai_config.py` — DSPy LM configuration (GPT-4o mini)
- `app/api/deps.py` — FastAPI dependencies for auth and DB session injection
### Frontend (`/src`)
- `App.tsx` — React Router routes; all routes except `/login` are wrapped in `ProtectedRoute`
- `api/client.ts` — Axios instance with base URL from `VITE_API_URL`; Bearer token auto-attached via interceptor from localStorage
- `context/AuthContext.tsx` — Auth state (token, user); token persisted to localStorage
- `pages/` — One page component per route (Dashboard, Nutrition, Health, Plans, Profile)
- `components/catalyst/` — Reusable UI component library (buttons, inputs, tables, dialogs, etc.)
### Auth Flow
OAuth2 password flow → JWT (HS256, 8-day expiry) → stored in localStorage → Axios interceptor injects header on every request.
### AI Modules (DSPy)
Both AI modules use chain-of-thought (`dspy.ChainOfThought`) via GPT-4o mini:
- **Nutrition:** Analyzes food text/images → macro breakdown accounting for hidden calories (oils, sauces)
- **Plans:** Generates personalized diet + exercise plans from user profile data
### Environment Variables
See `.env.example`. Required: `DATABASE_URL`, `OPENAI_API_KEY`, `SECRET_KEY`, `POSTGRES_*` vars. Frontend uses `VITE_API_URL` (defaults to `http://localhost:8000/api/v1`).
## Push Notifications
### Testing push notifications
**Always use the production build** — never test push notifications against `npm run dev`. The dev server's hot-reloading reinstalls the service worker on every reload, which invalidates push subscriptions (FCM returns 410 Gone).
```bash
cd frontend
npm run build
npx serve dist -p 5173 -s # -s = SPA mode (falls back to index.html)
```
Then in the browser:
1. DevTools → Application → Service Workers → Unregister any old SW
2. Hard-refresh (`Cmd+Shift+R`) to install the fresh `sw.js`
3. Profile → Notifications → toggle ON to create a fresh subscription
4. Use "Send test" button or trigger via backend
### If push notifications stop working
- Check `chrome://gcm-internals/` — Connection State must be **CONNECTED** (not CONNECTING)
- If disconnected, fully quit and restart Chrome (`Cmd+Q`)
- Clear stale DB subscriptions: `docker compose exec db psql -U user -d healthyfit -c "DELETE FROM pushsubscription;"`
- Re-subscribe after restarting