# Technology Stack **Analysis Date:** 2026-02-15 ## Languages **Primary:** - JavaScript (ES6+) - Both frontend and backend - SQL - PostgreSQL database queries in backend **Secondary:** - HTML/CSS - Frontend UI styling ## Runtime **Environment:** - Node.js 20 (LTS) - Specified in Dockerfiles (`node:20-alpine`) **Package Manager:** - npm (Node Package Manager) - Lockfile: `package-lock.json` present in both `frontend/` and `backend/` ## Frameworks **Core:** - **React** 18.2.0 - Frontend UI library (`frontend/package.json`) - **Express.js** 4.18.2 - Backend REST API framework (`backend/package.json`) **Frontend:** - **Vite** 5.0.8 - Frontend build tool and dev server - Config: `frontend/vite.config.js` - React plugin: `@vitejs/plugin-react` 4.2.1 **Routing:** - **React Router DOM** 6.21.0 - Frontend client-side routing - Configured in `frontend/src/main.jsx` with BrowserRouter and Routes **Web Server:** - **Nginx** (Alpine) - Production frontend server - Config: `frontend/nginx.conf` - Serves static assets, proxies `/api` to backend - Gzip compression enabled ## Key Dependencies **Frontend Critical:** - `react` 18.2.0 - UI framework - `react-dom` 18.2.0 - DOM rendering - `react-router-dom` 6.21.0 - Client-side routing **Frontend Dev:** - `vite` 5.0.8 - Build tooling - `@vitejs/plugin-react` 4.2.1 - React JSX support - `@types/react` 18.2.43 - TypeScript types - `@types/react-dom` 18.2.17 - TypeScript types **Backend Critical:** - `express` 4.18.2 - HTTP server framework - `pg` 8.11.3 - PostgreSQL client library - `jsonwebtoken` 9.0.2 - JWT authentication token generation/verification - `bcryptjs` 2.4.3 - Password hashing and verification - `cors` 2.8.5 - Cross-origin resource sharing middleware **Backend Dev:** - `nodemon` 3.0.2 - Auto-restart on file changes ## Configuration **Environment:** - Database connection via environment variables: - `DB_HOST` - PostgreSQL hostname (default: `postgres`) - `DB_PORT` - PostgreSQL port (default: `5432`) - `DB_USER` - Database user (default: `postgres`) - `DB_PASSWORD` - Database password - `DB_NAME` - Database name (default: `gravl`) - `JWT_SECRET` - JWT signing key (default: `gravl-secret-key-change-in-production`) - `PORT` - Backend API port (default: `3001`) **Build:** - Frontend: `vite.config.js` - Vite configuration with React plugin - Dev server: `0.0.0.0:5173` - API proxy: `/api` routes to `http://localhost:3001` - Backend: Simple Node.js entry point at `backend/src/index.js` ## Database **Primary:** - **PostgreSQL** - Relational database - Initialized via `db/init.sql` - Accessed via `pg` Node.js client library - Tables: `users`, `programs`, `program_days`, `exercises`, `program_exercises`, `workout_logs`, `user_measurements`, `user_strength` ## Platform Requirements **Development:** - Node.js 20+ - npm 9+ - PostgreSQL 12+ - Docker and Docker Compose (for containerized development) **Production:** - Deployment target: Docker containers via Docker Compose - Frontend container: `node:20-alpine` (build) → `nginx:alpine` (production) - Backend container: `node:20-alpine` - Reverse proxy: Traefik (configured in `docker-compose.yml`) - Network: Homelab environment with internal proxy and homelab networks ## Build Process **Frontend:** 1. `npm install` - Install dependencies 2. `npm run build` - Vite builds to `dist/` directory 3. Dockerfile multi-stage build: - Stage 1: Node 20 Alpine - npm install and build - Stage 2: Nginx Alpine - Serve built assets from `/usr/share/nginx/html` **Backend:** 1. `npm install --production` - Install dependencies (production only) 2. Dockerfile: Node 20 Alpine - Copy src and run `npm start` ## Development Commands **Frontend:** - `npm run dev` - Start Vite dev server on `0.0.0.0:5173` with hot reload - `npm run build` - Production build to `dist/` - `npm run preview` - Preview production build **Backend:** - `npm run start` - Run `node src/index.js` (production) - `npm run dev` - Run with `nodemon` for auto-restart on file changes --- *Stack analysis: 2026-02-15*