# Tech Stack & Build System ## Stack | Layer | Technology | |-------|-----------| | Backend | Node.js 18+, Express 5 | | Database | PostgreSQL (via `pg` pool in `backend/db.js`) | | Auth | bcryptjs, cookie-based sessions (httpOnly, 24h expiry) | | File uploads | Multer 2 (10MB limit) | | Frontend | React 19 (Create React App / react-scripts 5) | | Frontend serving | Express serves `frontend/build/` as static files on port 3001 | | UI Icons | lucide-react | | Charts | recharts | | Spreadsheet parsing | xlsx (frontend), pandas + openpyxl (backend Python scripts) | | Markdown rendering | react-markdown | | Diagrams | mermaid | ## Architecture: Single-Port Serving Express on port 3001 serves **both** the API and the production frontend build: - API routes: `/api/*` — handled by Express route handlers - Frontend: everything else — served as static files from `frontend/build/` There is no separate frontend server in production. The React dev server (`npm start` on port 3000) is only for local development with hot-reload. In production and on the dev server, you must run `npm run build` in `frontend/` after any frontend code change, then restart the backend. **After editing frontend source files:** ```bash cd frontend && npm run build # Compile new bundle into frontend/build/ # Then restart backend (or it will serve the new static files on next request) ``` The CI/CD pipeline handles this automatically — `build-frontend` stage runs before deploy. ## Common Commands ### Backend ```bash cd backend node setup.js # Initialize DB, tables, indexes, default admin user node server.js # Start backend on port 3001 (serves API + frontend build) ``` ### Frontend ```bash cd frontend npm install # Install dependencies npm run build # Production build → frontend/build/ (REQUIRED after code changes) npm start # Dev server on port 3000 (local dev only, NOT used in production) npm test # Run tests (react-scripts test) ``` ### Both servers (from project root) ```bash ./start-servers.sh # Start backend + frontend in background ./stop-servers.sh # Stop all servers ``` ### Database Migrations (run from `backend/`) ```bash node migrations/run-all.js # Runs all migrations in order (idempotent) ``` ### Python Scripts (from `backend/scripts/`) ```bash # Compliance xlsx parsing (called automatically by upload flow) python3 parse_compliance_xlsx.py # Bulk notes import python3 import_notes_from_csv.py input.csv --dry-run python3 import_notes_from_csv.py input.csv ``` Python dependencies: `pandas>=2.0.0`, `openpyxl>=3.0.0` (install via apt or venv). ## Environment Configuration - `backend/.env` — PORT, CORS_ORIGINS, SESSION_SECRET, NVD_API_KEY, Ivanti API credentials - `frontend/.env` — REACT_APP_API_BASE, REACT_APP_API_HOST - Both `.env` files are gitignored; see `.env.example` files for templates. - React env vars are baked in at **build time** — you must rebuild (`npm run build`) after changing them. ## Code Style & Lint Rules ### Unused Variables The frontend ESLint config enforces `no-unused-vars` as a warning. The CI pipeline fails if warnings exceed 25. To avoid lint failures: - **Prefix intentionally-unused variables with `_`** — this suppresses the warning. The `varsIgnorePattern: "^_"` and `argsIgnorePattern: "^_"` rules are configured in `frontend/package.json`. - Common patterns: - `const [_unused, setFoo] = useState(...)` — destructured value you don't need - `const _legacyRef = useRef(...)` — kept for future use - `function handler(_event) { ... }` — required parameter signature but unused - **Do not leave variables unprefixed if unused.** Either use them, remove them, or prefix with `_`. - This applies to all frontend code written by the agent. ### Backend No ESLint is configured for backend — the pipeline uses `node -c` syntax checking only. Keep code clean but there is no automated unused-var enforcement on the backend side. ## Ports | Environment | URL | Notes | |---|---|---| | Production | http://71.85.90.6:3001 | Express serves API + static frontend build | | Staging | http://71.85.90.9:3100 | Auto-deploy on master push | | Local dev (frontend only) | http://localhost:3000 | React dev server with hot-reload, proxies API to :3001 | ## CI/CD Pipeline ### Infrastructure | Role | Host | Notes | |---|---|---| | GitLab instance | steam-gitlab.charterlab.com | Self-hosted GitLab | | CI Runner (LXC 108) | 71.85.90.8 | Docker executor, Runner #6, project-locked | | Staging target | 71.85.90.9 | Auto-deploy on master, port 3100 | | Production target | 71.85.90.6 | Manual deploy trigger, port 3001 | ### Executor: Docker The pipeline uses **Docker executor** on Runner #6. Jobs run in isolated containers: - **Install / Lint / Test / Build stages**: `node:18` image - **Deploy stages**: `alpine:latest` image (installs `openssh-client` and `rsync` at runtime) Deploy jobs SSH from inside the Alpine container to the target hosts using a base64-encoded `$SSH_PRIVATE_KEY` stored as a GitLab CI/CD variable. ### CI/CD Variables (project-level) These are set in GitLab → Settings → CI/CD → Variables: | Variable | Purpose | |---|---| | `DATABASE_URL` | PostgreSQL connection string for backend integration tests | | `SSH_PRIVATE_KEY` | Base64-encoded private key for deploy SSH access | | `GITLAB_PAT` | Project access token for issue comments and release creation | ### Pipeline file The pipeline is defined in `.gitlab-ci.yml` at the project root. Stages: install → lint → test → build → deploy → verify.