# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Tilbudgivern is an AI-powered quote calculator for the carpentry trade (tømrerfaget). It generates detailed professional quotes based on project descriptions, using OpenAI GPT-4 for AI-powered quote generation. **Tech Stack:** - Frontend: React 18 with Material-UI, served as static build - Backend: Node.js/Express unified server (~400K lines in `backend/unified-server.js`) - Database: MariaDB/MySQL (running on host, not containerized) - AI: OpenAI GPT-4 API (default budget: $9/month) - Process Manager: PM2 (process name: `tilbudgivern-unified`) ## Common Commands ### Development ```bash npm run dev # Start development server with hot reload npm run build # Build frontend for production pm2 restart tilbudgivern-unified # Restart PM2 after changes pm2 logs tilbudgivern-unified # View logs ``` ### Testing ```bash npm run test:pw # Playwright UI tests against production npm run test:pw:local # Playwright tests against local server npm run test:pw:ui # Playwright interactive UI mode npm run test:pw:headed # Playwright with visible browser npm run test:selenium # Selenium UI tests cd backend && npm test # Backend unit tests (Jest) ``` ### Single Test Execution ```bash cd tests && PLAYWRIGHT_BASE_URL=https://tilbudsgiveren.alw.dk playwright test .spec.js cd tests && PLAYWRIGHT_BASE_URL=https://tilbudsgiveren.alw.dk playwright test .spec.js --headed ``` ## Architecture ### Unified Server Pattern The application uses a unified server (`backend/unified-server.js`) that: - Serves the React frontend build from `frontend/build/` - Provides all API endpoints on port 4032 (configured in `.env`) - Handles WebSocket connections via Socket.IO - Includes structured logging with correlation IDs ### Key Backend Services (`backend/src/services/`) - `openaiService.js` - AI quote generation via GPT-4, budget tracking - `databaseService.js` - MariaDB connection pool and queries - `smartPackageManagementService.js` - Smart package CRUD (15 carpenter packages) - `ordrestyringSyncService.js` - GraphQL integration with Ordrestyring API - `pdfGenerationService.js` - Quote PDF generation via Puppeteer - `roofGeometryService.js` - Roof area calculations for 7 roof types - `starkImportService.js` - Stark material catalog import - `bygmaPrisbogImportService.js` - Bygma price book import ### Key Backend Routes (`backend/src/routes/`) - `smartPackagesRoutes.js` - Smart package management API - `customerProjects.js` - Customer and project CRUD - `quotes.js` - Quote generation and management - `pricing.js` - Price database endpoints - `starkImport.js` - Stark CSV import endpoint ### Key Frontend Components (`frontend/src/components/`) - `InlineSmartPackage.js` - Smart package wizard with step-by-step flow - `EnhancedGeometry.js` - Roof geometry input with SVG visualizations for 7 roof types - `MaterialsManager.js` - Material selection with cached API searches - `PlanningDashboard.js` - Project planning calendar - `FinalReview.js` - Quote review and Ordrestyring offer creation - `ProjectCreation.js` - Project form with autosave, validation, tooltips ### Smart Packages System 15 pre-configured carpenter packages for roofing work: - Auto-calculation based on geometry (tagareal, rygningslængde, facadelængde) - Includes materials with prices and labor hours - Categories: Tagdækning, Tagrende/Nedløb, Tagvinduer, Brædder, Specialarbejde ### Roof Types (7 supported) 1. Sadeltag (pitched roof) - default 2. Valmtag (hip roof) 3. Københavnertag (Copenhagen roof) 4. Fladtag (flat roof) 5. Pulttag (shed roof) 6. Tag med Kviste (roof with dormers) 7. Mansardtag (mansard roof) ## External Integrations ### Ordrestyring API - GraphQL endpoint: `https://beta7-api.ordrestyring.dk/graphql` - Used for: customers, cases, offers, calendar, hours tracking - Token: `ORDRESTYRING_API_TOKEN` in `.env` - API test scripts: `apitest/examples/` ### Material Suppliers - **Bygma**: Price book import, installation manuals - **Stark**: CSV catalog import via `/api/stark/upload` ## Database - MariaDB on localhost:3306 - Database: `tilbudgivern` - Key tables: `smart_packages`, `package_tasks`, `package_materials`, `materials`, `customers`, `projects` - Schema files: `database/schema_system_logs.sql` - Migrations: `database/migrations/`, `backend/migrations/` ## Environment Configuration - Main config: `backend/.env` - Required: - `OPENAI_API_KEY` - for AI features - `DB_HOST`, `DB_USER`, `DB_PASSWORD`, `DB_NAME` - database - Optional: - `ORDRESTYRING_API_TOKEN` - order management integration - `OPENAI_ADMIN_KEY` - for cost tracking API ## Logging System - Structured JSON logs with correlation IDs - Database persistence in `system_logs` table - Error codes: DB_001 (connection), DB_002 (query), VAL_001 (validation), API_001 (Ordrestyring), etc. - Admin endpoints: `/api/admin/logs` ## Deployment **This machine is the production server.** There is no separate deploy target: `backend/unified-server.js` runs directly out of this git working directory via PM2, serving the built frontend from `frontend/build/`. There is no CI/CD pipeline that deploys automatically on merge — deploying means running these steps here, on this host, after `main` has the commit you want live. ```bash git checkout main && git pull # Get the commit you want live cd frontend && npm ci && npm run build # Sync frontend deps and rebuild static assets cd ../backend && npm ci --omit=dev # Sync backend deps (skip if unchanged) pm2 restart tilbudgivern-unified # Restart the running process pm2 logs tilbudgivern-unified --lines 30 --nostream # Confirm a clean startup (no errors) curl -sf http://localhost:4032/api/health # Should return {"status":"ok",...} curl -sI https://tilbudsgiveren.alw.dk # Should return HTTP/2 200 ``` Other useful commands: ```bash pm2 status # Check process status pm2 logs tilbudgivern-unified # Tail live logs ``` Daily database backups configured via cron at 02:00, retention: 7 days. Note: `.github/workflows/deploy-prod.yml` (an SSH/rsync-to-a-remote-server pipeline) was removed — it targeted a `PROD_SERVER_HOST`/`PROD_SERVER_USER`/`PROD_SERVER_PATH`/`PROD_SSH_PRIVATE_KEY` setup that was never configured (no repo or `production`-environment secrets ever existed), and every historical run of it failed. If a real separate deploy target is ever set up, that pipeline's steps (versioned releases dir, atomic symlink swap, pre-deploy DB backup, health-check retries, smoke tests) are a reasonable starting point to resurrect from git history. ## Danish Terminology - Tilbud = Quote/Offer - Tømrer = Carpenter - Materiale = Material - Pakke = Package - Pris = Price - Tag = Roof - Spær = Rafters - Tagrende = Rain gutter - Nedløb = Downspout - Vindsked = Barge board - Sternbræt = Fascia board