Files
tilbudgivern/docs/architecture-quickwins.md
2026-07-05 08:10:59 +00:00

5.5 KiB

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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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)