154 lines
5.2 KiB
Markdown
154 lines
5.2 KiB
Markdown
# External Integrations
|
|
|
|
**Analysis Date:** 2026-02-15
|
|
|
|
## APIs & External Services
|
|
|
|
**None** - No external third-party APIs currently integrated.
|
|
|
|
## Data Storage
|
|
|
|
**Databases:**
|
|
- **PostgreSQL** (Primary)
|
|
- Connection via `pg` client library (8.11.3)
|
|
- Environment variables:
|
|
- `DB_HOST` - Default: `postgres` (Docker service name)
|
|
- `DB_PORT` - Default: `5432`
|
|
- `DB_USER` - Default: `postgres`
|
|
- `DB_PASSWORD` - Required secret
|
|
- `DB_NAME` - Default: `gravl`
|
|
- ORM/Client: `pg` (node-postgres) - Direct SQL queries, no ORM
|
|
- Initialization: `db/init.sql` - Schema and seed data
|
|
- Tables: users, programs, program_days, exercises, program_exercises, workout_logs, user_measurements, user_strength
|
|
|
|
**File Storage:**
|
|
- Local filesystem only - No external file storage service
|
|
- Static assets served by Nginx from built frontend `dist/` directory
|
|
|
|
**Caching:**
|
|
- None detected - No Redis, Memcached, or other caching layer
|
|
|
|
## Authentication & Identity
|
|
|
|
**Auth Provider:**
|
|
- Custom JWT-based authentication
|
|
- Implementation: `backend/src/index.js` (lines 22-29, 35-68)
|
|
- Token generation: `jsonwebtoken` 9.0.2
|
|
- Password hashing: `bcryptjs` 2.4.3
|
|
- Secret: `JWT_SECRET` environment variable (default: `gravl-secret-key-change-in-production`)
|
|
- Token expiration: 30 days
|
|
|
|
**Auth Flow:**
|
|
1. Frontend `AuthContext` (`frontend/src/context/AuthContext.jsx`) manages user state
|
|
2. User registers or logs in via `/api/auth/register` or `/api/auth/login`
|
|
3. Backend verifies credentials, generates JWT token
|
|
4. Frontend stores token in `localStorage` as `token`
|
|
5. Subsequent requests include `Authorization: Bearer {token}` header
|
|
6. Backend `authMiddleware` validates token on protected routes
|
|
7. User profile fetched on app load via `/api/user/profile`
|
|
|
|
**Protected Routes:**
|
|
- `/api/user/profile` - GET/PUT (requires auth)
|
|
- `/api/user/measurements` - GET/POST (requires auth)
|
|
- `/api/user/strength` - GET/POST (requires auth)
|
|
- `/api/logs` - GET/POST (no auth check in code - potential security gap)
|
|
- `/api/progression/:programExerciseId` - GET (no auth check - potential security gap)
|
|
|
|
**Public Routes:**
|
|
- `/api/health` - Health check endpoint
|
|
- `/api/auth/register` - User registration
|
|
- `/api/auth/login` - User login
|
|
- `/api/programs` - List all programs
|
|
- `/api/programs/:id` - Get program details
|
|
- `/api/days/:dayId/exercises` - Get exercises for a day
|
|
- `/api/today/:programId` - Get workout for day
|
|
|
|
## Frontend-Backend Communication
|
|
|
|
**API Base URL:**
|
|
- Hardcoded as `/api` in `frontend/src/context/AuthContext.jsx` (line 2)
|
|
- Development: Proxied by Vite to `http://localhost:3001`
|
|
- Production: Proxied by Nginx to `http://gravl-backend:3001`
|
|
|
|
**CORS:**
|
|
- Enabled on backend via `cors` middleware 2.8.5
|
|
- `app.use(cors())` in `backend/src/index.js` (line 19)
|
|
|
|
**HTTP Methods:**
|
|
- POST `/api/auth/register` - Register user
|
|
- POST `/api/auth/login` - Login user
|
|
- GET `/api/user/profile` - Get user profile
|
|
- PUT `/api/user/profile` - Update user profile
|
|
- POST `/api/user/measurements` - Add measurements
|
|
- GET `/api/user/measurements` - Get measurement history
|
|
- POST `/api/user/strength` - Add strength record
|
|
- GET `/api/user/strength` - Get strength history
|
|
- GET `/api/programs` - List programs
|
|
- GET `/api/programs/:id` - Get program with days and exercises
|
|
- GET `/api/days/:dayId/exercises` - Get exercises for day
|
|
- GET/POST `/api/logs` - Get/create workout logs
|
|
- GET `/api/logs/last/:programExerciseId` - Get last workout for exercise
|
|
- GET `/api/progression/:programExerciseId` - Calculate suggested weight
|
|
|
|
**Request/Response Format:**
|
|
- Content-Type: `application/json`
|
|
- Token: Passed in `Authorization: Bearer {token}` header
|
|
- Response: JSON objects
|
|
|
|
## Monitoring & Observability
|
|
|
|
**Error Tracking:**
|
|
- None detected - No Sentry, LogRocket, or similar
|
|
|
|
**Logs:**
|
|
- Backend: `console.error()` for errors (lines 48, 65, 98, 115, 133, 147, 165, 179, 190, 228, 246, 276, 294, 327, 380, 417)
|
|
- Frontend: No error tracking integrated
|
|
- Example: `console.error('Register error:', err)` in `backend/src/index.js` (line 48)
|
|
|
|
**Database Logging:**
|
|
- None detected - SQL queries not logged
|
|
|
|
## Webhooks & Callbacks
|
|
|
|
**Incoming:**
|
|
- None detected
|
|
|
|
**Outgoing:**
|
|
- None detected
|
|
|
|
## Environment Configuration
|
|
|
|
**Required env vars for backend:**
|
|
- `DB_HOST` - PostgreSQL hostname
|
|
- `DB_PORT` - PostgreSQL port
|
|
- `DB_USER` - Database user
|
|
- `DB_PASSWORD` - Database password (REQUIRED SECRET)
|
|
- `DB_NAME` - Database name
|
|
- `JWT_SECRET` - JWT signing secret (REQUIRED SECRET for production)
|
|
- `PORT` - Backend port (optional, default 3001)
|
|
|
|
**Secrets location:**
|
|
- Docker Compose: `docker-compose.yml` (lines 8-13) - **WARNING: Password visible in file**
|
|
- Backend defaults: `backend/src/index.js` (lines 9, 14-16)
|
|
- Frontend: None (token stored in browser localStorage)
|
|
|
|
**Traefik Integration:**
|
|
- Frontend exposed via Traefik reverse proxy
|
|
- Host: `gravl.homelab.local`
|
|
- HTTP and HTTPS support configured
|
|
- Networks: `proxy` (external), `homelab` (internal Docker Compose network)
|
|
|
|
## Service Dependencies
|
|
|
|
**Backend Dependencies:**
|
|
- PostgreSQL (required)
|
|
- Traefik proxy (for production routing)
|
|
|
|
**Frontend Dependencies:**
|
|
- Backend API at `/api` (required for all authenticated operations)
|
|
- Can operate in degraded mode if API is unavailable
|
|
|
|
---
|
|
|
|
*Integration audit: 2026-02-15*
|