CI - Test & Build / Lint & Type Check (push) Waiting to run
CI - Test & Build / Backend Unit Tests (push) Waiting to run
CI - Test & Build / Frontend Build (push) Waiting to run
CI - Test & Build / E2E Tests (Playwright) (push) Blocked by required conditions
CI - Test & Build / Security Scan (push) Waiting to run
CI - Test & Build / CI Summary (push) Blocked by required conditions
* feat: move login credentials to a DB-backed users table with an admin management page Replaces the hardcoded AUTH_USERNAME/AUTH_PASSWORD login check with a new auth_accounts table (bcrypt-hashed passwords, admin/user roles). Adds admin-only /api/users CRUD routes and a "Brugere" admin page in the frontend for managing logins without redeploying. Removes the unused, unmounted duplicate login route in src/routes/auth.js. * docs: add architecture codemaps with diagrams for the whole system Adds codemaps/architecture.md, backend.md, frontend.md, and data.md — Mermaid-diagrammed design documentation verified against the live codebase and database rather than assumed from CLAUDE.md. Covers the unified-server.js request flow (mounted routers + ~183 inline routes), 68 backend services grouped by domain, the frontend's state-driven view-switch (no React Router in practice despite BrowserRouter being present), and the full 122-table DB schema with the auth_accounts vs unrelated users table naming trap flagged explicitly. Links added from the root README. Co-Authored-By: Claude Sonnet 5 <[email protected]> * feat: ship canonical roof quote workflow * fix: keep migration dry-run idempotent * [verified] feat: complete Smart Pakker management * [verified] fix: ignore blank task dependencies * [verified] fix: align package duplication with schema * [verified] fix: enforce Discord status limits * [verified] fix: link Smart Pakke materials safely * [verified] fix: harden material link review * [verified] feat: improve material matching * fix: scope pitch validation to roof packages * fix: support canonical snapshots on production schema * [verified] fix: hide internal package metadata from PDF * [verified] feat: deliver sales-ready customer PDF * [verified] feat: ship sales-ready PDF with AI overview * [verified] fix: authenticate project list requests * [verified] fix: refresh project-list authentication * [verified] fix: open existing project details * [verified] fix: keep roof components searchable in builder * [verified] fix: expose all Smart Package categories * [verified] fix: authenticate project creation * [verified] feat: make Smart Pakker the universal project flow * [verified] feat: preview Smart Package contents * [verified] test: keep generic release isolated from downpipe work * feat: add first-class Smart Pakke rentals * [verified] feat: add gutter and downpipe smart packages * [verified] fix: prepare six-house gutter quote flow * [verified] fix: open generic quotes without roof geometry * [verified] fix: review generic quotes with authenticated APIs * [verified] fix: calculate generic Smart Package quotes * [verified] fix: return generic calculation breakdown * feat: checkpoint generic signed snapshot validation with red-green tests * feat: complete fail-closed generic quote approval and customer PDF flow * feat: use generic signed snapshot in final review * feat: redesign generic quote final review * fix: harden generic review summaries * feat: add auditable six-house package basis * [verified] feat: finish auditable Smart Pakke UI * [verified] fix: bind auditable quantity and price bases * [verified] fix: keep six-house basis across package versions * [verified] fix: complete smart package discovery management * [verified] fix: simplify composition and generic scope * [verified] test: keep explicit roof contracts fail closed * [verified] fix: harden generic quote snapshots * fix: make generic quote delivery customer safe * [verified] fix: secure package catalog reads * [verified] fix: close workspace provenance blockers * fix: harden customer document language boundary * [verified] fix: secure smart package internal reads * fix: version package child mutations atomically * feat: add generic customer quote text flow * [verified] fix: allow manual customer numbers * [verified] fix: expose optional roof geometry * [verified] fix: rebase hydrated packages after geometry edits * [verified] feat: add free editable site area map * [verified] fix: harden map recovery and geocoding gate * fix: bind map quantities to authoritative geometry * fix: release geocoder lock before dispatch * fix: separate roof and site geometry provenance * fix: revoke stale admin authorization * fix: migrate task geometry basis * fix: make backend CI dependency-complete * ci: seed isolated e2e login account * fix: allow clean database bootstrap * fix: skip indexes for optional tables * test: use canonical mansard geometry in e2e * [verified] fix(auth): enforce live operator boundary * fix: fail close Ordrestyring offer transport * fix(frontend): authenticate customer project requests * fix: align canonical roof type contract * [verified] fix: reconcile legacy package labor safely * [verified] fix: audit site geometry deletion * docs: add PR 31 reviewer guide * docs: synchronize Obsidian vault * docs: sync integrated reviewer guide to Obsidian * ci: seed isolated auth account explicitly * fix: close offer bootstrap and service readiness gaps * fix: authenticate protected package callers * fix: provision initial admin and disable generic send * [verified] fix: close final quote release blockers * [verified] fix: seed gutter packages before deployment --------- Co-authored-by: alexpolo1 <[email protected]> Co-authored-by: Claude Sonnet 5 <[email protected]>
83 lines
7.9 KiB
Markdown
83 lines
7.9 KiB
Markdown
<!-- generated: 2026-09-04 -->
|
|
# Backend Structure
|
|
|
|
Entry point: `backend/unified-server.js`. It mounts modular routers **and** defines ~180 routes inline in the same file (verified by grepping `app.get/post/put/patch/delete('/api/...')` occurrences). Both patterns are live in production — inline routes are not legacy cruft to be migrated, they're simply how a large share of this API is built.
|
|
|
|
## Mounted routers
|
|
|
|
| Mount path | File | Purpose |
|
|
|---|---|---|
|
|
| `/api/enhanced` | `src/routes/enhancedFeatures.js` | Roof-type package search, add package to project (loaded in a `try/catch` at startup, not top-level) |
|
|
| `/api/smart-packages` | `src/routes/smartPackagesRoutes.js` | Smart Package CRUD, management view, recalculation (also try/catch-loaded) |
|
|
| `/api/stark` | `src/routes/starkImport.js` | Stark CSV catalog upload + import history/status (also try/catch-loaded) |
|
|
| `/api/customer-projects` | `src/routes/customerProjects.js` | Customer + project CRUD, the core project lifecycle |
|
|
| `/api/ai` | `src/routes/ai.js` | AI feature flags, subscription usage, support-draft generation |
|
|
| `/api/users` | `src/routes/users.js` | **New (2026-09-04).** Admin-only user management CRUD |
|
|
| `/api/mobile` | `src/routes/mobileOrders.js` | Field/mobile intake against Ordrestyring order history |
|
|
| `/api/analytics` | `src/routes/analytics.js` | KPIs, employees, customers pulled from the Ordrestyring GraphQL layer |
|
|
| `/api/product-telemetry` | `src/routes/productTelemetry.js` | Frontend product-usage event tracking + scorecards |
|
|
| `/api/ordrestyring` | `routes/ordrestyring.js` | Quote submission, order status/list against Ordrestyring |
|
|
| `/api/ordrestyring/offers` | `routes/offers.js` | Offer creation in Ordrestyring |
|
|
| `/api/calendar` | `routes/calendar.js` | Calendar read + sync |
|
|
| `/api/ordrestyring/case` | `routes/cases.js` | Case detail / work breakdown |
|
|
| `/api/visual-reports` | `routes/visualTestReports.js` | Visual test report browsing (admin-API-key gated) |
|
|
| `/api/admin/logs` | `routes/adminLogs.js` | Structured log browsing (admin-API-key gated) |
|
|
| `/api/health` | `src/routes/healthDashboard.js` | DB/server health metrics |
|
|
| `/api/client-errors` | `routes/clientErrors.js` | Frontend error/session reporting intake |
|
|
| `/api/support` | `src/routes/supportTickets.js` | osTicket support worklist/ticket creation |
|
|
|
|
Note there are **two** routes directories: `backend/src/routes/` (newer) and `backend/routes/` (older, still actively mounted — `ordrestyring.js`, `offers.js`, `calendar.js`, `cases.js`, `adminLogs.js`, `clientErrors.js`, `visualTestReports.js`). Both are live; the split is historical, not a deprecation boundary.
|
|
|
|
## Dead route files (unmounted — do not assume these are live)
|
|
|
|
These files exist in `backend/src/routes/` but are **not required anywhere** in the codebase (verified by grepping every `require('./src/routes/<name>')` call site): `bygmaPrisbog.js`, `categories.js`, `cleanup.js`, `pricing.js`, `quotes.js`, `uploads.js`, `webPrices.js`. Same situation applied to `auth.js`, which was deleted 2026-09-04 for exactly this reason — its logic had silently diverged from the real, inline `/api/auth/login` handler in `unified-server.js`. Before editing any of these seven files, confirm first whether they're actually reachable; as of this writing, none are.
|
|
|
|
## Inline routes in unified-server.js (representative, not exhaustive)
|
|
|
|
`/api/auth/login`, `/api/auth` (legacy no-op), `/api/pdf/generate`, `/api/web-prices/search`, plus ~180 more (183 `app.<verb>('/api/...')` calls total, verified 2026-09-04) covering pricing, geometry, quote generation, PDF, and Ordrestyring glue. Grep `unified-server.js` for `app\.(get|post|put|patch|delete)\('/api/` to enumerate the current full list — it changes often enough that a static list here would go stale immediately.
|
|
|
|
## Services (`backend/src/services/`, 68 files)
|
|
|
|
Grouped by domain:
|
|
|
|
**AI / quote generation** — `openaiService.js`, `projectAiService.js`, `aiSuggestionService.js`, `aiValidationJobService.js`, `aiFeatureFlagService.js`, `codexGenerationService.js`, `codexCliValidationService.js`, `quoteRealismService.js`, `quoteTemplateService.js`, `quoteBenchmarkService.js`, `quoteEconomicsService.js`
|
|
|
|
**Smart packages** — `smartPackageService.js`, `smartPackageManagementService.js`, `smartPackageDefaultsService.js`, `smartPackageIntegrityService.js`, `smartPackageWorkspaceService.js`, `smartPackageMaterialMatchService.js`, `smartPackageExcelImportService.js`, `smartPackageExcelValidationService.js`, `historicalSmartPackageSearchService.js`, `packageService.js`, `materialPackageService.js` (an older, parallel package system — see [data.md](./data.md))
|
|
|
|
**Material pricing / import** — `starkImportService.js`, `bygmaImportService.js`, `bygmaPrisbogImportService.js`, `bygmaScraperService.js`, `haandvaerkPriserImportService.js`, `priceImportService.js`, `pricingService.js`, `materialPriceStatusService.js`, `installationManualService.js`, `webPriceService.js`
|
|
|
|
**Project lifecycle** — `customerProjectService.js`, `projectCalculationService.js`, `projectLaborService.js`, `projectMaterialService.js`, `projectExperienceService.js`, `projectFlowValidationService.js`, `projectQuoteGenerationService.js`, `roofGeometryService.js`, `advancedGeometryService.js`, `timeCalculatorService.js`, `orderSuggestionService.js`, `taskCategorizationService.js`, `planningService.js`
|
|
|
|
**Ordrestyring sync/integration** — `ordrestyringService.js`, `ordrestyringSyncService.js`, `ordrestyringQuoteService.js`, `ordrestyringMoneyService.js`, `orderStatusService.js`, `graphqlClient.js`, `enhancedOrderDataService.js`, `mobileOrderService.js`
|
|
|
|
**PDF / documents** — `pdfGenerationService.js`, `pdfResponseService.js`, `documentParserService.js`, `ocrService.js`, `excelMappingService.js`
|
|
|
|
**Auth / users** — `userService.js` (new, 2026-09-04, bcrypt + `auth_accounts`)
|
|
|
|
**Platform / infra** — `databaseService.js` (MariaDB pool + query wrapper; also runs ~37 inline `CREATE TABLE IF NOT EXISTS` statements at startup — see [data.md](./data.md)), `databaseCleanupService.js`, `bootstrapServiceContainer.js`, `dynamicImportService.js`, `productTelemetryService.js`, `googleSearchService.js`, `repositoryStatusDiscordService.js`, `supportDraftService.js`
|
|
|
|
## Request flow and auth
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Req["Incoming request"] --> R{"Router or\ninline handler?"}
|
|
R -- "mounted router" --> MW["verifyToken\n(backend/src/middleware/auth.js)"]
|
|
R -- "inline in\nunified-server.js" --> MW
|
|
MW -- "valid JWT" --> Admin{"needs admin?"}
|
|
MW -- "missing/invalid" --> Reject["401/403"]
|
|
Admin -- "yes: requireAdmin" --> Svc["Service layer\n(backend/src/services/*)"]
|
|
Admin -- "no" --> Svc
|
|
Svc --> DBS["databaseService.query()"]
|
|
DBS --> DB[("MariaDB")]
|
|
```
|
|
|
|
Not every route requires auth — `verifyToken` is applied per-router/per-endpoint, not globally. Some admin surfaces use a separate `optionalAdminApiKeyGuard` (API-key based) rather than JWT — see the `/api/visual-reports` and `/api/admin/logs` mounts above.
|
|
|
|
## Auth accounts — the `auth_accounts` / `users` naming trap
|
|
|
|
As of 2026-09-04, login credentials moved out of hardcoded env vars into a real table: **`auth_accounts`** (`id`, `username`, `password_hash` [bcrypt], `role` enum `admin`/`user`, `last_login_at`), managed by `userService.js` and `src/routes/users.js`.
|
|
|
|
**This is deliberately not called `users`.** A pre-existing, unrelated table named `users` already exists — it holds employee records synced from Ordrestyring (`first_name`, `last_name`, `init`, `email`; written by `ordrestyringSyncService.js`). It has nothing to do with login. If you're adding auth-related columns or queries, make sure you're touching `auth_accounts`, not `users`.
|
|
|
|
The live login handler is the inline `POST /api/auth/login` in `unified-server.js` (not a separate router file) — it looks up `auth_accounts` via `userService.findByUsername`, verifies with bcrypt, and issues a JWT carrying `{ username, id, role }`. `requireAdmin` middleware gates `/api/users/*` on `role === 'admin'`.
|