# Architecture & Quick Wins (Maintainability First) Last updated: 2026-03-13 (implemented baseline quick wins + P1 tooling + duplicate-route cleanup) ## Product North Star Maintainability work should support the product mission, not drift away from it. Tilbudgivern's core mission is: - let carpenters create a strong quote draft in the field with very few inputs - reuse as much real history as possible from Tilbudgivern and Ordrestyring - use Smart Packages as editable operational templates - use AI to improve wording and structure, not to invent facts This means architecture decisions should favor: - structured project data over free-text-only AI flows - reusable local historical data over one-off API calls - mobile-friendly, low-friction request/response shapes - clear persistence of package choice, suggestion source, and quote learning signals ## 1) Current Architecture Snapshot ### Runtime topology - **Frontend:** React app in `frontend/src`, built to `frontend/build`. - **Backend:** Unified Express + Socket.IO server in `backend/unified-server.js`. - **Database:** MariaDB/MySQL via `mysql2` pools. - **Service layer:** Domain modules in `backend/src/services` (pricing, geometry, OpenAI, Ordrestyring, PDF, imports). - **Route layer:** Mixed model: - many inline handlers inside `backend/unified-server.js` - mounted routers from `backend/src/routes` and `backend/routes`. ### Request/data flow 1. Browser UI (React) issues Axios API calls. 2. Express middleware applies CORS, security headers, request/session logging. 3. Route handler executes inline logic or delegates to a service. 4. Service calls DB/external systems (Ordrestyring/OpenAI/etc.). 5. Response returns JSON to UI. 6. Socket.IO optionally emits project updates for real-time collaboration. 7. Non-API requests are served from `frontend/build/index.html`. ## 2) Key Findings (Maintainability Risks) 1. **Monolithic API surface** - `backend/unified-server.js` is still ~11,634 lines with ~200+ `/api` route registrations. - High change collision risk and difficult ownership boundaries. 2. **Mixed route ownership** - Same domains are handled inline and via mounted routers. - Example: `analytics`, `customer-projects`, `calendar`, and `ordrestyring` now have dedicated routers, while adjacent domain logic still lives inline in `backend/unified-server.js`. - The active duplicate registrations called out in the first pass have now been removed, but ownership is still split across `backend/unified-server.js`, `backend/src/routes`, and `backend/routes`. 3. **Runtime loading patterns** - Multiple handler-time `require(...)` calls increase hidden coupling and make dependency flow harder to reason about. - A bootstrap service container now centralizes core startup wiring, but legacy handler-level dependencies still exist in parts of `backend/unified-server.js`. 4. **Script drift in root package** - The immediate script drift has been fixed, but root scripts still proxy into nested packages and can drift again if backend/frontend package commands change without updating the root wrapper. 5. **CI lint gate is weak** - CI now runs a real lint gate, but the frontend stage is still warning-tolerant. - The repo has 25 existing frontend lint warnings that should be cleared before tightening enforcement to fail on warnings. ## 3) Prioritized Quick Wins ### P0 (Do first) 1. **Fix root scripts (high impact, low effort)** - Update root `package.json` scripts to valid entrypoints/commands. - Definition of done: `npm run dev`, `npm start`, and `npm test` all execute real targets. 2. **Consolidate health route ownership (high impact, low effort)** - Choose one owner (`backend/src/routes/healthDashboard` router or inline block) and remove duplication. - Definition of done: one route source of truth; no endpoint behavior regressions. 3. **Start modular extraction from unified server (high impact, medium effort)** - Extract one domain first (recommended: `health` + `analytics`), preserving existing API contracts. - Definition of done: extracted router passes existing tests and route smoke checks. ### P1 (Next) 1. **Introduce service bootstrap/container** - Initialize dependencies once at startup, then inject/use references instead of ad-hoc lazy `require`. - Definition of done: startup wiring is explicit; handlers stop resolving core services dynamically. - Status: baseline implemented via `backend/src/services/bootstrapServiceContainer.js`. 2. **Add API surface inventory check** - Add a script that lists all registered `/api/*` endpoints and flags duplicates. - Definition of done: inventory output is generated in CI or as a local validation step. - Status: implemented via `scripts/api-inventory.js`; use `npm run api:inventory` for summary and `npm run api:inventory:full` for the full route table. Current baseline: 275 endpoints, no duplicate method+path registrations detected. 3. **Strengthen CI quality gate** - Add actual lint scripts in frontend/backend and make lint a required CI signal. - Keep security audits informative but separate from core merge-blocking checks. - Status: implemented as a baseline gate. Backend uses syntax linting, frontend uses ESLint, and CI runs `npm run lint`. ## 4) Guardrails for Refactoring - Preserve current external API contracts (`/api/*` paths and response shapes) during quick-win refactors. - Prefer “extract without redesign” in first pass. - Validate each extraction with: - `cd backend && npm test -- --coverage --passWithNoTests` - `cd tests && PLAYWRIGHT_BASE_URL=http://localhost:4032 npx playwright test` (smoke subset acceptable initially)