# Tilbudgivern - Cursor Rules ## Project Context This is **Tilbudgivern**, an AI-powered quote calculator for Danish carpenters (tømrere). The application generates professional quotes for roofing and construction work. ## Tech Stack - Frontend: React 18 + Material-UI (served from `frontend/build/`) - Backend: Node.js/Express unified server (`backend/unified-server.js`) - Database: MariaDB on localhost:3306, database `tilbudgivern` - AI: OpenAI GPT-4 API - Process Manager: PM2 (`tilbudgivern-unified`) - Tests: Playwright, Selenium, Jest ## Key Architecture ### Unified Server Single server file `backend/unified-server.js` handles: - Static frontend serving - All API endpoints (port 4032) - WebSocket connections (Socket.IO) - Structured logging with correlation IDs ### Smart Packages 15 pre-configured roofing packages with: - Auto-calculation from geometry (tagareal, rygningslængde) - Materials with prices + labor hours - Tables: `smart_packages`, `package_tasks`, `package_materials` ### 7 Roof Types sadeltag, valmtag, koebenhavnertag, fladt_tag, pulttag, tag_med_kviste, mansard ## Code Patterns ### Backend Services ```javascript // Use structured logging const logger = require('./src/utils/logger'); logger.logInfo('Context', 'Message', { correlationId: req.correlationId, metadata: {} }); logger.logError('Context', error, { correlationId: req.correlationId }); // Use asyncHandler for routes const { asyncHandler } = require('./src/middleware/errorHandler'); router.get('/endpoint', asyncHandler(async (req, res) => { ... })); ``` ### API Response Format ```javascript // Success res.json({ success: true, data: result }); // Error res.status(400).json({ success: false, error: { code: 'VAL_001', message: 'Danish error message' } }); ``` ### React Components - Functional components with hooks - Material-UI for UI consistency - Follow patterns in `frontend/src/components/` ## Danish Language UI and code comments are in Danish. Key terms: - Tilbud = Quote, Tømrer = Carpenter, Tag = Roof - Materiale = Material, Pakke = Package, Pris = Price - Tagrende = Gutter, Nedløb = Downspout, Spær = Rafters ## Important Files - `backend/unified-server.js` - Main server (~400K lines) - `backend/src/services/openaiService.js` - AI quote generation - `backend/src/services/smartPackageManagementService.js` - Package CRUD - `backend/src/routes/smartPackagesRoutes.js` - Package API - `frontend/src/components/InlineSmartPackage.js` - Package wizard - `frontend/src/components/EnhancedGeometry.js` - Roof geometry with SVG ## External APIs ### Ordrestyring (GraphQL) - Endpoint: `https://beta7-api.ordrestyring.dk/graphql` - Token: `ORDRESTYRING_API_TOKEN` - Used for: customers, cases, offers, calendar ### Material Imports - Bygma: Price book import - Stark: CSV import via `/api/stark/upload` ## Commands ```bash npm run dev # Dev server with hot reload npm run build # Build frontend pm2 restart tilbudgivern-unified # Restart npm run test:pw # Playwright tests cd backend && npm test # Jest tests ``` ## Environment Required in `backend/.env`: - OPENAI_API_KEY - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME Optional: - ORDRESTYRING_API_TOKEN - OPENAI_ADMIN_KEY