278 Commits

Author SHA1 Message Date
Alex
8b16d35287 fix: keep Smart Packages compatible with roof material (#30)
Some checks are pending
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
Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
2026-09-02 07:19:39 +02:00
Alex
adb7e8a17a fix: enforce complete scope keyword matches (#29)
Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
2026-08-30 18:14:57 +02:00
Alex
1a00fdadfe fix: classify roof support reference services (#28)
Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
2026-08-30 17:58:10 +02:00
Alex
4f0ba89cbe fix: make material name matches safe and automatic (#27)
Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
2026-08-29 20:56:18 +02:00
Alex
c0e2010075 feat: add fail-closed quote realism checks (#26)
Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
2026-08-29 20:29:49 +02:00
Alex
817d0dac2c Merge pull request #25 from alexpolo1/fix/pdf-system-chrome
fix: use system Chrome for PDF generation
2026-08-27 12:21:14 +02:00
alexpolo1
1c44a514b4 [verified] fix: use system Chrome for PDF generation 2026-08-27 12:21:09 +02:00
Alex
ca8eb008d6 Merge pull request #24 from alexpolo1/fix/rental-baseline-after-persist
fix: retain server rental baseline after save
2026-08-27 12:10:03 +02:00
alexpolo1
4e1fd77ee5 [verified] fix: retain server rental baseline 2026-08-27 12:09:58 +02:00
Alex
a101963292 Merge pull request #23 from alexpolo1/fix/rental-reference-final-review-sync
fix: persist reference lines before Final Review
2026-08-27 12:06:11 +02:00
alexpolo1
377d61a07c [verified] fix: persist reference lines before review 2026-08-27 12:05:57 +02:00
Alex
0be74a3d95 Merge pull request #22 from alexpolo1/fix/project-rental-pricing-sync
fix: preserve rental pricing in projects
2026-08-26 19:12:30 +02:00
alexpolo1
823e072702 [verified] fix: preserve rental pricing in projects 2026-08-26 19:11:35 +02:00
Alex
dbaec62113 Merge pull request #21 from alexpolo1/fix/jannick-price-import-flow
fix: make Jannick price import usable and safe
2026-08-24 08:37:01 +02:00
alexpolo1
81b6e1ea21 fix: make Jannick price import usable and safe 2026-08-24 08:31:55 +02:00
Alex
ae11295dc6 Merge pull request #20 from alexpolo1/feat/haandvaerkpriser-import
feat: import reference task prices from haandvaerkpriser.dk
2026-08-20 15:39:24 +02:00
alexpolo1
a56a911bee feat: import reference task prices from haandvaerkpriser.dk
Support ticket #396994 (Jannick): pull prices from
haandvaerkpriser.dk for tasks we don't already price, as a starting
reference. robots.txt allows crawling /alle-priser/ and no terms of
use restrict reuse (checked before building this).

Each imported task becomes a verified 'component' Smart Package with
a single task carrying the price, filtered to only the 8 trades
Jannick asked for (Maler, Gulv, VVS & Blikkenslager, Tømrer &
Snedker, Murer, Tagrenovering, Isolering & Energi, Nedrivning &
Affald - the site has 16 categories total). This lands in the same
place as today's earlier smart-package fix, so these are immediately
selectable via the "Enkelte opgaver" picker and visible in the admin
Smart Packages list, unlike the existing price_database table which
is dead code (0 rows, its only consumer queries a column that no
longer exists, and its route isn't mounted).

Re-running the import is idempotent: a task already imported from
this source gets its price averaged with the new pull instead of
duplicating, per Jannick's request ("har vi en pris i forvejen kan
den lave et gennemsnit"). Cross-source matching against Jannick's own
manually-curated components is intentionally out of scope - automating
that risks merging unrelated tasks.

New endpoints (admin-only): GET /api/smart-packages/haandvaerkpriser-preview
(dry run, no writes) and POST /api/smart-packages/haandvaerkpriser-import.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 14:56:29 +02:00
Alex
f3da7b6ac8 Merge pull request #19 from alexpolo1/chore/retire-deploy-prod-workflow
chore: retire deploy-prod.yml, document the real PM2 deploy path
2026-08-20 14:19:53 +02:00
alexpolo1
288346c21e chore: retire deploy-prod.yml, document the real PM2 deploy path
deploy-prod.yml targeted a remote SSH deploy server via
PROD_SERVER_HOST/PROD_SERVER_USER/PROD_SERVER_PATH/PROD_SSH_PRIVATE_KEY,
but none of those secrets were ever configured (repo and production
environment secret lists are both empty) and every historical run of
the workflow failed as a result.

The actual production server is this machine: unified-server.js runs
directly out of this working directory via PM2. Removed the dead
pipeline and documented the real manual deploy steps (pull, rebuild
frontend, sync backend deps, pm2 restart, verify) in CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 14:14:57 +02:00
Alex
896d90a383 Merge pull request #18 from alexpolo1/fix/deploy-artifact-quota
fix: don't fail deploy jobs when diagnostic artifact upload hits quota
2026-08-20 14:04:53 +02:00
alexpolo1
4c4092099e fix: don't fail deploy jobs when diagnostic artifact upload hits quota
The prod deploy just failed at Unit Tests even though all 226 tests
passed - the job died on `Upload coverage report` hitting the GitHub
Actions artifact storage quota. ci.yml already treats artifact uploads
as best-effort for this exact reason (comment: "Artifact upload must
never fail the job (storage quota can be full)"), but deploy-prod.yml
and deploy-test.yml were missing the same continue-on-error on their
diagnostic report/screenshot/coverage uploads.

Leaves the actual deployable build artifact uploads (deploy-package-*)
blocking, since a failed deploy really should stop there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:49:32 +02:00
Alex
5cbf5c0690 Merge pull request #17 from alexpolo1/fix/carpenter-walkthrough
feat: add carpenter walkthrough release gate (hydration, readiness, material link review)
2026-08-20 13:43:41 +02:00
alexpolo1
081e46cb44 fix: only use local system Chromium in Playwright config outside CI
The blocking carpenter smoke test (introduced in this branch) exposed
a pre-existing gap: playwright.config.js hardcoded
executablePath: '/snap/bin/chromium' plus channel: 'chromium' for the
maintainer's local CachyOS machine. CI has no /snap/bin/chromium (it
installs its own Chromium via `playwright install --with-deps
chromium`), so every CI run was silently failing to launch the browser
- previously masked because the whole E2E step had
continue-on-error: true.

Gate both overrides behind `!process.env.CI` so local runs keep using
system Chromium and CI falls back to its own installed browser.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:37:23 +02:00
alexpolo1
9b7df90385 feat: add carpenter walkthrough release gate (hydration, readiness, material link review)
Implements the plan from the carpenter walkthrough audit: make the
project flow -> final review -> PDF path measurable and safe to gate
CI on.

- projectHydrationService loads a project's geometry/labor/materials/
  rentals/packages/calculation in parallel and reports per-resource
  timing plus the slowest resource, so hydration SLA breaches are
  visible instead of silent
- projectReadiness centralizes the blocking checks final review must
  pass before a quote can be sent (name, customer, description,
  materials/labor present, zero-price lines)
- pdfSourceSignature detects when a generated PDF is stale relative to
  the current project data, so a carpenter doesn't send an outdated
  quote
- MaterialLinkReview + new customer-projects match-preview/link
  endpoints let a user review and confirm suggested master-material
  matches instead of silently auto-linking
- ProjectFlow refactored around the new hydration/readiness utilities;
  FinalReview surfaces readiness checks and unlinked material counts
- CI: the carpenter smoke test (full-roof-quote-flow.spec.js) is now
  a blocking gate on main, with the rest of the Playwright suite
  running best-effort alongside it
- docs/qa/CARPENTER_WALKTHROUGH_RELEASE_GATE.md documents the gate and
  the monthly production audit procedure

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:20:33 +02:00
Alex
e3261ba14d Merge pull request #16 from alexpolo1/fix/carpenter-walkthrough
fix: make all verified smart packages selectable, not just 5
2026-08-20 13:19:16 +02:00
alexpolo1
db34ee96ed fix: make all verified smart packages selectable, not just 5
Root cause (from support tickets #333382 and #775903): a one-off
integrity migration archived 40 Excel-imported carpenter task packages
(is_active=0, blocked) because their material lines couldn't be
auto-linked to the material database, and even a verified component
package had nowhere to appear since the quote flow only fetched
packageType=complete_offer.

- verifyPackage now reactivates a package (is_active=1) once its
  materials/tasks pass integrity checks
- getPackageDetails/updatePackage can reach blocked-but-inactive
  packages so admins can repair them, without exposing genuinely
  deleted packages; fixes a latent bug where updatePackage's final
  UPDATE still hardcoded is_active=1 and would have silently no-op'd
- new GET /api/smart-packages/review-queue + SmartPackageReviewQueue
  admin panel to relink materials (with fuzzy-match suggestions) and
  verify archived packages in one step
- InlineSmartPackage gains an "Enkelte opgaver" à la carte picker
  (search-by-word, additive multi-select) for verified component
  packages, alongside the existing single complete-offer picker;
  geometry-based quantity/hours math extracted into
  utils/smartPackageGeometryCalculations.js so both flows share it

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:00:08 +02:00
alexpolo1
271b3fc804 docs: plan carpenter walkthrough fixes 2026-08-18 13:45:34 +02:00
Alex
436bcdeb10 Merge pull request #14 from alexpolo1/feat/daily-discord-repo-status
feat: send daily repository status to Discord
2026-08-18 13:11:20 +02:00
Alex
673c802f17 Merge pull request #13 from alexpolo1/feat/three-carpenter-offer-review
fix: harden mobile offer review flow
2026-08-18 13:06:23 +02:00
Alex
8c5b9c5ea5 Merge pull request #12 from alexpolo1/fix/pdf-max-three-pages
feat: harden field quote workflow and repository hygiene
2026-08-18 13:00:38 +02:00
alexpolo1
c3e3255aff [verified] fix: harden material and smart package errors 2026-08-18 12:50:24 +02:00
alexpolo1
8d2db6281c feat: send daily repository status to Discord 2026-08-18 10:07:59 +02:00
alexpolo1
77cddbf704 fix: harden mobile offer review flow 2026-08-18 00:49:25 +02:00
alexpolo1
6dc90a92aa security: move remaining credentials to environment 2026-08-17 09:25:03 +02:00
alexpolo1
edb73df2d6 docs: archive legacy guides and add Obsidian vault 2026-08-17 09:12:03 +02:00
alexpolo1
a2a99e1595 chore: stop tracking generated artifacts 2026-08-17 09:11:12 +02:00
alexpolo1
f9c0b7bc57 feat: harden smart package field workflow 2026-08-15 00:34:28 +02:00
alexpolo1
3ab5e8cf5e fix: resolve open smart package issues 2026-08-13 23:58:36 +02:00
alexpolo1
c6ca27dd22 feat: persist support tickets for Codex worklist 2026-08-13 14:29:15 +02:00
alexpolo1
340d15bf78 fix: align support tickets with osTicket API 2026-08-13 13:37:10 +02:00
alexpolo1
9c00074327 feat: add image attachments to support feedback 2026-08-13 13:28:29 +02:00
alexpolo1
ddc52ddc91 fix: cap quote PDFs and add compact recovery 2026-08-13 13:02:16 +02:00
Alex
d5f65f74d4 feat: mobil tømrerflow og Codex CLI-generering (#8)
Flyt brugerrettet indholdsgenerering til Codex CLI, forbedr mobilflowet og ret CI-miljøets afhængigheder og testkonfiguration.
2026-08-13 11:47:14 +02:00
Alex
faffd89fe4 Merge pull request #7 from alexpolo1/agent/smartpakke-integritet
feat: verificerede SmartPakker til tømrerens tilbudsflow
2026-08-13 10:39:43 +02:00
alexpolo1
11ad6b7f0b feat: enforce verified smart package catalog 2026-08-10 12:38:52 +02:00
alexpolo1
87d9c7bd82 test: verify mobile access notes field 2026-07-08 13:06:16 +02:00
alexpolo1
fe4f11fe32 ci: survive artifact quota, update actions, clean lint warnings
The last CI run failed only because GitHub artifact storage quota was
exhausted: backend tests and frontend build were green but their
upload-artifact steps failed the jobs.

- Mark all artifact uploads continue-on-error and cut retention to 3
  days (deploy workflows kept artifacts up to 30 days, which is what
  filled the quota)
- E2E job builds the frontend itself instead of downloading the
  frontend-build artifact, so it no longer depends on artifact storage
- Bump actions/checkout v4->v7, setup-node v4->v6, upload-artifact
  v4->v7, download-artifact v4->v8 (Node 20 runtime deprecation) and
  CI Node 18 (EOL) -> 22 to match production
- Fix all frontend lint warnings: remove unused imports/state and the
  dead Stepper-based form UI in SmartPackageForm (renderStepContent,
  parseAndAddMaterialsFromDescription were unreferenced), disable
  exhaustive-deps where the effect is intentionally scoped
2026-07-08 13:05:28 +02:00
alexpolo1
581204c235 fix: persist geometry and smart package before leaving flow steps
Both steps relied on a debounced 5-second autosave as the only path
that wrote to the database. Continuing to the next step within those
5 seconds unmounted the component, cancelled the pending timer and
silently lost the data: Final Review then showed 0 m dimensions and
'Tagtype: unknown', and package materials/tasks were missing after a
project reload.

- EnhancedGeometry: handleNext now awaits handleGeometryCalculation
  and blocks navigation if the save fails; the continue button shows
  'Gemmer geometri...' while saving
- InlineSmartPackage: 'Gem Smart Pakke' and 'Naeste: Final Review' now
  await autoSavePackageData (which syncs materials/rentals/status)
  instead of only updating parent session state; autoSavePackageData
  reports success; selecting a package marks the step as interacted so
  the periodic autosave arms correctly
- InlineSmartPackage: rentals read and similar-experience lookup use
  the correct /api/customer-projects/projects/{id}/... paths

Found by driving five different quote flows end to end: three runs
happened to win the autosave race, two lost it and persisted nothing.
2026-07-08 07:57:36 +02:00
alexpolo1
1c2ec2b1fc fix: correct rentals and similar-experience API paths
GET rentals used /api/customer-projects/{id}/rentals but the backend
route lives at /api/customer-projects/projects/{id}/rentals, so saved
rental lines were never loaded back into the flow. The
similar-experience lookup used /api/customer/projects/... and always
404'ed, so historical experience data never appeared in the smart
package step.
2026-07-08 07:57:19 +02:00
alexpolo1
7ed6494762 fix: correct design issues across desktop and mobile
- Scope global .materials-header rule to used-materials so the
  Materialer page header stacks correctly on mobile
- Collapse system status indicator to a compact dot so it no longer
  covers content
- Remove redundant current-view chip from header navigation
- Scope FinalReview button styles and switch submit gradient from red
  to green so the danger color no longer leaks into project creation
- Remove duplicate title and category chip on smart package cards
- Stop absolute positioning of logout button that clipped the logo
2026-07-08 07:32:23 +02:00