docs: plan carpenter walkthrough fixes
This commit is contained in:
597
.hermes/plans/2026-08-18_133633-carpenter-walkthrough-fixes.md
Normal file
597
.hermes/plans/2026-08-18_133633-carpenter-walkthrough-fixes.md
Normal file
@@ -0,0 +1,597 @@
|
||||
# Tømrer-gennemgang Fixes Implementation Plan
|
||||
|
||||
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Gør det månedlige mobile tømrerflow stabilt, statusmæssigt entydigt og reelt klar til PDF/Ordrestyring, mens opdateringen af STARK-priser behandles som et separat dataleverance-spor med Jannick.
|
||||
|
||||
**Architecture:** Ret først de deterministiske UI-state-fejl (PDF freshness og fælles readiness-model), derefter performance i projektindlæsningen og til sidst materialekoblingsflowet. Materiale-id'er må kun komme fra den eksisterende masterdatabase og kræver brugerbekræftelse ved tvetydige matches. STARK-import udføres først, når Jannick leverer en frisk fil; kode- og datarisiko blandes ikke sammen.
|
||||
|
||||
**Tech Stack:** React 18, Jest/React Testing Library, Node/Express, MySQL, Playwright, eksisterende `smartPackageMaterialMatchService`, PM2/GitHub Actions.
|
||||
|
||||
---
|
||||
|
||||
## Nuværende baseline
|
||||
|
||||
Produktionstesten på projekt 392 viste:
|
||||
|
||||
- Mobilflowet virker uden vandret overflow.
|
||||
- Geometri, økonomi og PDF genereres korrekt.
|
||||
- Kontrolleret total: `177.781,60 kr. inkl. moms`.
|
||||
- PDF-preview: 2 A4-sider, 109.141 bytes, gyldigt `%PDF-`.
|
||||
- Loading-overlayet brugte op til ca. 5,7 sekunder i en kold gennemgang.
|
||||
- En ny PDF blev straks markeret som forældet.
|
||||
- Final Review blokeres af 11 materialer uden `material_id`.
|
||||
- ProjectFlow viste 12 ukoblede materialer, mens Final Review viste 11.
|
||||
- Topstatus viste `4/4 trin gennemført`, samtidig med at afsendelse var blokeret.
|
||||
- STARK-prislisten viste seneste dato `26.11.2025`; Alex afklarer nye priser med Jannick.
|
||||
|
||||
QA-rapport og evidens:
|
||||
|
||||
- `/home/alex/dogfood-output/tilbudsgivern-2026-08-18/report.md`
|
||||
- `/home/alex/dogfood-output/tilbudsgivern-2026-08-18/carpenter-audit.pdf`
|
||||
- `/home/alex/dogfood-output/tilbudsgivern-2026-08-18/screenshots/pdf-state-after-generation.png`
|
||||
- `/home/alex/dogfood-output/tilbudsgivern-2026-08-18/screenshots/loading-overlay-after-5s.png`
|
||||
|
||||
---
|
||||
|
||||
## Spor A — Kodefixes, som kan udføres nu
|
||||
|
||||
### Task 1: Lås regressionsbaselinen med målrettede tests
|
||||
|
||||
**Objective:** Gør de fire observerede kode-/UX-fejl reproducerbare, før produktionskode ændres.
|
||||
|
||||
**Files:**
|
||||
- Modify: `frontend/src/components/FinalReview.test.js`
|
||||
- Create: `frontend/src/utils/projectReadiness.test.js`
|
||||
- Create: `frontend/src/components/ProjectFlow.test.js`
|
||||
- Modify: `tests/monthly-carpenter-audit.spec.js`
|
||||
|
||||
**Step 1: Skriv en fejlende PDF freshness-test**
|
||||
|
||||
Test at en PDF er `fresh` umiddelbart efter generering, og først bliver `stale`, når et input ændres efter genereringen.
|
||||
|
||||
**Step 2: Kør testen og bekræft RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
CI=true npm test -- --watchAll=false src/components/FinalReview.test.js
|
||||
```
|
||||
|
||||
Expected: FAIL — PDF bliver markeret stale på grund af `pdfUrl`-effekten.
|
||||
|
||||
**Step 3: Skriv fejlende readiness-tests**
|
||||
|
||||
Dæk:
|
||||
|
||||
- samme antal ukoblede materialer i ProjectFlow og Final Review
|
||||
- forskellen mellem `flowComplete`, `readyForReview` og `readyToSend`
|
||||
- `4/4 gennemført` må ikke betyde `klar til afsendelse`, når blokeringer findes
|
||||
|
||||
**Step 4: Skriv fejlende loading/performance-test**
|
||||
|
||||
Mock seks uafhængige ressourcekald med forsinkelse og bekræft, at de ikke må afvikles serielt.
|
||||
|
||||
**Step 5: Commit tests alene**
|
||||
|
||||
```bash
|
||||
git add frontend/src/components/FinalReview.test.js \
|
||||
frontend/src/utils/projectReadiness.test.js \
|
||||
frontend/src/components/ProjectFlow.test.js \
|
||||
tests/monthly-carpenter-audit.spec.js
|
||||
git commit -m "test: lock carpenter walkthrough regressions"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Ret PDF freshness med en deterministisk input-signatur
|
||||
|
||||
**Objective:** En netop genereret PDF skal være frisk, og kun reelle inputændringer må gøre den stale.
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/src/utils/pdfSourceSignature.js`
|
||||
- Create: `frontend/src/utils/pdfSourceSignature.test.js`
|
||||
- Modify: `frontend/src/components/FinalReview.js:367-371,1198-1280,1348-1369`
|
||||
- Modify: `frontend/src/components/FinalReview.test.js`
|
||||
|
||||
**Step 1: Skriv en ren signaturfunktion**
|
||||
|
||||
`buildPdfSourceSignature` skal serialisere de normaliserede værdier, som faktisk sendes til `/api/pdf/generate`:
|
||||
|
||||
- tilbudstekst og kundebeskrivelse
|
||||
- normaliseret geometri
|
||||
- materialer: id, navn, antal, enhed og pris
|
||||
- udlejning
|
||||
- arbejdsopgaver og timer
|
||||
- gemt økonomimodel
|
||||
|
||||
Ignorér React object identity, tidsstempler og UI-only state.
|
||||
|
||||
**Step 2: Verificér RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
CI=true npm test -- --watchAll=false src/utils/pdfSourceSignature.test.js
|
||||
```
|
||||
|
||||
Expected: FAIL — modulet findes endnu ikke.
|
||||
|
||||
**Step 3: Implementér minimal signatur**
|
||||
|
||||
Gem `generatedPdfSignature` sammen med `pdfUrl` efter et succesfuldt response. Beregn:
|
||||
|
||||
```js
|
||||
const isPdfStale = Boolean(pdfUrl && generatedPdfSignature !== currentPdfSignature);
|
||||
```
|
||||
|
||||
Fjern effekten på `FinalReview.js:1357-1369`, som inkluderer `pdfUrl` i dependencies og derfor straks kalder `setIsPdfStale(true)` efter generering.
|
||||
|
||||
**Step 4: Kør fokuserede tests**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
CI=true npm test -- --watchAll=false \
|
||||
src/utils/pdfSourceSignature.test.js \
|
||||
src/components/FinalReview.test.js
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add frontend/src/utils/pdfSourceSignature.js \
|
||||
frontend/src/utils/pdfSourceSignature.test.js \
|
||||
frontend/src/components/FinalReview.js \
|
||||
frontend/src/components/FinalReview.test.js
|
||||
git commit -m "fix: keep newly generated PDF preview fresh"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Parallelisér og mål projektindlæsningen
|
||||
|
||||
**Objective:** Fjern unødvendig seriel ventetid og hold loading-overlayet under en dokumenteret SLA.
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/src/services/projectHydrationService.js`
|
||||
- Create: `frontend/src/services/projectHydrationService.test.js`
|
||||
- Modify: `frontend/src/components/ProjectFlow.js:222-265,311-595,807-839`
|
||||
- Modify: `frontend/src/components/ProjectFlow.test.js`
|
||||
- Modify: `frontend/src/utils/quoteFlowTelemetry.js`
|
||||
- Modify: `tests/monthly-carpenter-audit.spec.js`
|
||||
|
||||
**Step 1: Skriv en timing-test**
|
||||
|
||||
Mock geometri, arbejdsløn, materialer, udlejning og pakker med kendte delays. Bekræft at samlet tid svarer omtrent til det langsomste kald, ikke summen.
|
||||
|
||||
**Step 2: Kør RED**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
CI=true npm test -- --watchAll=false src/services/projectHydrationService.test.js
|
||||
```
|
||||
|
||||
**Step 3: Implementér parallel hydration**
|
||||
|
||||
Efter ét projekt-check hentes følgende med `Promise.allSettled` og fælles `AbortController`:
|
||||
|
||||
- `/api/customer-projects/:id/geometry`
|
||||
- `/api/customer-projects/:id/labor`
|
||||
- `/api/customer-projects/:id/materials`
|
||||
- `/api/customer-projects/projects/:id/rentals`
|
||||
- `/api/customer-projects/:id/packages`
|
||||
|
||||
Bevar nuværende session fallbacks. Ignorér resultater fra et tidligere projekt, hvis brugeren skifter projekt under indlæsningen.
|
||||
|
||||
**Step 4: Fjern dobbelt projekt-verificering**
|
||||
|
||||
`selectExistingProject` har allerede hentet projektet før `loadProjectData`; send det verificerede payload videre i stedet for at hente samme projekt igen.
|
||||
|
||||
**Step 5: Tilføj performance telemetry**
|
||||
|
||||
Registrér:
|
||||
|
||||
- `project_hydration_started`
|
||||
- `project_hydration_ready`
|
||||
- varighed og langsomste ressource
|
||||
|
||||
Ingen kunde-fritekst må logges.
|
||||
|
||||
**Step 6: Acceptance**
|
||||
|
||||
- Kold mobilindlæsning: mål p95 over fem runs.
|
||||
- Mål: overlay væk på `< 5.000 ms`; stretch `< 3.000 ms`.
|
||||
- Ved overskridelse skal UI vise hvilken ressource, der stadig indlæses, i stedet for et generisk overlay.
|
||||
|
||||
**Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add frontend/src/services/projectHydrationService.js \
|
||||
frontend/src/services/projectHydrationService.test.js \
|
||||
frontend/src/components/ProjectFlow.js \
|
||||
frontend/src/components/ProjectFlow.test.js \
|
||||
frontend/src/utils/quoteFlowTelemetry.js \
|
||||
tests/monthly-carpenter-audit.spec.js
|
||||
git commit -m "perf: parallelize project hydration"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Indfør én fælles readiness-model
|
||||
|
||||
**Objective:** ProjectFlow og Final Review skal vise samme antal, samme blokeringer og tydelige niveauer for færdighed.
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/src/utils/projectReadiness.js`
|
||||
- Create: `frontend/src/utils/projectReadiness.test.js`
|
||||
- Modify: `frontend/src/components/ProjectFlow.js:118-191,807-812`
|
||||
- Modify: `frontend/src/components/FinalReview.js:220-290`
|
||||
- Modify: `frontend/src/components/FinalReview.test.js`
|
||||
|
||||
**Step 1: Definér eksplicitte tilstande**
|
||||
|
||||
Returnér mindst:
|
||||
|
||||
```js
|
||||
{
|
||||
completedSteps,
|
||||
totalSteps,
|
||||
flowComplete,
|
||||
readyForReview,
|
||||
readyToSend,
|
||||
blockingChecks,
|
||||
attentionChecks,
|
||||
unlinkedMaterialCount
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: Brug samme materialekilde**
|
||||
|
||||
ProjectFlow må ikke tælle fra et gammelt `packageData.materials`, mens Final Review tæller fra persisted/editable materials. Normalisér én gang og brug samme projektlinjer som kilde.
|
||||
|
||||
**Step 3: Ret teksten**
|
||||
|
||||
Eksempel:
|
||||
|
||||
- `4/4 trin gennemført`
|
||||
- `Klar til review — ikke klar til afsendelse`
|
||||
- `11 materialer kræver kobling`
|
||||
|
||||
Vis aldrig `Alt er klar`, når `readyToSend === false`.
|
||||
|
||||
**Step 4: Verificér tests**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
CI=true npm test -- --watchAll=false \
|
||||
src/utils/projectReadiness.test.js \
|
||||
src/components/FinalReview.test.js \
|
||||
src/components/ProjectFlow.test.js
|
||||
```
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add frontend/src/utils/projectReadiness.js \
|
||||
frontend/src/utils/projectReadiness.test.js \
|
||||
frontend/src/components/ProjectFlow.js \
|
||||
frontend/src/components/FinalReview.js \
|
||||
frontend/src/components/FinalReview.test.js \
|
||||
frontend/src/components/ProjectFlow.test.js
|
||||
git commit -m "fix: unify carpenter flow readiness status"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Byg et sikkert materiale-koblingsflow
|
||||
|
||||
**Objective:** Tømreren skal kunne løse ukoblede materialer uden at opfinde eller automatisk godkende forkerte masterdata-id'er.
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/services/smartPackageMaterialMatchService.js`
|
||||
- Modify: `backend/__tests__/smartPackageMaterialMatchService.test.js`
|
||||
- Modify: `backend/src/services/projectMaterialService.js`
|
||||
- Modify: `backend/src/__tests__/projectMaterialService.test.js`
|
||||
- Modify: `backend/src/routes/customerProjects.js`
|
||||
- Create: `backend/__tests__/projectMaterialMatchingRoute.test.js`
|
||||
- Create: `frontend/src/components/MaterialLinkReview.js`
|
||||
- Create: `frontend/src/components/MaterialLinkReview.test.js`
|
||||
- Modify: `frontend/src/components/FinalReview.js:268-274,1733-1743`
|
||||
|
||||
**Step 1: Tilføj read-only match-preview endpoint**
|
||||
|
||||
Forslag:
|
||||
|
||||
```text
|
||||
POST /api/customer-projects/projects/:projectId/materials/match-preview
|
||||
```
|
||||
|
||||
Input: konkrete projektmateriale-id'er. Output pr. linje:
|
||||
|
||||
- kandidatens master `material_id`
|
||||
- SKU, navn, enhed, leverandør og pris
|
||||
- score og status: `matched_sku`, `matched_name`, `ambiguous`, `unmatched`
|
||||
|
||||
Ingen writes i preview-kaldet.
|
||||
|
||||
**Step 2: Test sikkerhedskontrakten**
|
||||
|
||||
- SKU exact match må foreslås med score 1.
|
||||
- Tvetydige navne må ikke auto-godkendes.
|
||||
- Ukendte materialer forbliver ukoblede.
|
||||
- Kun aktive materialer med brugbar pris må foreslås.
|
||||
|
||||
**Step 3: Udvid projektmateriale-update sikkert**
|
||||
|
||||
`ProjectMaterialService.updateProjectMaterial` skal kunne gemme:
|
||||
|
||||
- `material_id`
|
||||
- `price_source`
|
||||
- `price_source_updated_at`
|
||||
|
||||
Brug parameteriseret SQL og verify, at id'et findes i mastertabellen før update.
|
||||
|
||||
**Step 4: Byg review-UI**
|
||||
|
||||
Fra blokeringen i Final Review åbner `Ret koblinger` en mobilvenlig liste:
|
||||
|
||||
- original projektlinje
|
||||
- bedste kandidat og score
|
||||
- søg/ændr kandidat
|
||||
- `Bekræft` pr. linje
|
||||
- batch-knap kun for eksplicit valgte linjer
|
||||
|
||||
High-confidence forslag er forslag, ikke skjulte automatiske writes.
|
||||
|
||||
**Step 5: Genberegn readiness efter save**
|
||||
|
||||
Efter en bekræftet kobling genindlæses projektmaterialerne, og både ProjectFlow og Final Review bruger den fælles readiness-model.
|
||||
|
||||
**Step 6: Verificér**
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
npm test -- --runInBand \
|
||||
__tests__/smartPackageMaterialMatchService.test.js \
|
||||
src/__tests__/projectMaterialService.test.js \
|
||||
__tests__/projectMaterialMatchingRoute.test.js
|
||||
|
||||
cd ../frontend
|
||||
CI=true npm test -- --watchAll=false \
|
||||
src/components/MaterialLinkReview.test.js \
|
||||
src/components/FinalReview.test.js
|
||||
```
|
||||
|
||||
**Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/src/services/smartPackageMaterialMatchService.js \
|
||||
backend/__tests__/smartPackageMaterialMatchService.test.js \
|
||||
backend/src/services/projectMaterialService.js \
|
||||
backend/src/__tests__/projectMaterialService.test.js \
|
||||
backend/src/routes/customerProjects.js \
|
||||
backend/__tests__/projectMaterialMatchingRoute.test.js \
|
||||
frontend/src/components/MaterialLinkReview.js \
|
||||
frontend/src/components/MaterialLinkReview.test.js \
|
||||
frontend/src/components/FinalReview.js
|
||||
git commit -m "feat: add reviewed project material linking flow"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Spor B — Nye STARK-priser med Jannick
|
||||
|
||||
### Task 6: Modtag, valider og importer ny STARK-prisliste
|
||||
|
||||
**Objective:** Opdatér prisgrundlaget uden at blande en ekstern dataleverance ind i kodefixene.
|
||||
|
||||
**Owner:** Alex + Jannick for dataleverancen; implementer/operatør for validering og import.
|
||||
|
||||
**Existing Files/Endpoints:**
|
||||
- `backend/src/routes/starkImport.js`
|
||||
- `backend/src/services/starkImportService.js`
|
||||
- `POST /api/stark/upload`
|
||||
- `GET /api/stark/status`
|
||||
- `GET /api/stark/import-history`
|
||||
|
||||
**Input fra Jannick:**
|
||||
|
||||
- Frisk STARK CSV
|
||||
- Prisens gyldighedsdato
|
||||
- Bekræftelse af netto/brutto-fortolkning
|
||||
- Enhedsdefinitioner
|
||||
- Eventuelle udgåede produkter
|
||||
|
||||
**Step 1: Preflight uden produktionswrite**
|
||||
|
||||
Kopiér filen til et isoleret testmiljø og verificér:
|
||||
|
||||
- mindst fem semikolonseparerede kolonner
|
||||
- unik SKU/produktnummer
|
||||
- gyldige positive priser
|
||||
- kendte enheder
|
||||
- ingen uventet massiv produktdeaktivering
|
||||
|
||||
**Step 2: Tag database-backup**
|
||||
|
||||
Backup mindst:
|
||||
|
||||
- `stark_materials_cache`
|
||||
- aktive `material_prices` for STARK
|
||||
- importhistorik
|
||||
|
||||
**Step 3: Importér med eksisterende endpoint/service**
|
||||
|
||||
Upload filen via `POST /api/stark/upload`. Gem `batchId`, statistik, errors og warnings.
|
||||
|
||||
**Step 4: Post-import gates**
|
||||
|
||||
`GET /api/stark/status` skal vise:
|
||||
|
||||
- `latest_import` svarende til den nye levering
|
||||
- forventet produktantal og kategorier
|
||||
- ingen nul-/negative priser i aktive produkter
|
||||
|
||||
Sammenlign 20 repræsentative tagmaterialer før/efter. Afvigelser over en aftalt procent kræver manuel godkendelse.
|
||||
|
||||
**Step 5: Opdatér readiness-advarslen**
|
||||
|
||||
Final Review skal læse samme statusendpoint og vise en konkret freshness-policy, fx:
|
||||
|
||||
- grøn: ≤ 30 dage
|
||||
- gul: 31–60 dage
|
||||
- blokerende/rød: > 60 dage, hvis fast pris skal sendes
|
||||
|
||||
Den endelige grænse aftales med Alex/Jannick.
|
||||
|
||||
**Step 6: Dokumentér importen**
|
||||
|
||||
Gem batch-id, filhash, gyldighedsdato, rækkeantal og godkender uden at committe selve prisfilen, hvis den er fortrolig.
|
||||
|
||||
---
|
||||
|
||||
## Spor C — Samlet regression, rollout og drift
|
||||
|
||||
### Task 7: Gør månedlig tømrer-audit til release-gate
|
||||
|
||||
**Objective:** Bevis at det observerede produktionsflow er stabilt efter rettelserne.
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/monthly-carpenter-audit.spec.js`
|
||||
- Modify: `.github/workflows/ci.yml`
|
||||
- Create: `docs/qa/CARPENTER_WALKTHROUGH_RELEASE_GATE.md`
|
||||
|
||||
**Step 1: Opdatér testen uden at skjule performanceproblemer**
|
||||
|
||||
Testen skal logge faktisk hydration-tid og fejle på en eksplicit SLA i stedet for Playwrights implicitte 5-sekunders expect-timeout.
|
||||
|
||||
**Step 2: Tilføj acceptance checks**
|
||||
|
||||
- ingen 5xx API-responses
|
||||
- ingen console errors
|
||||
- én fælles unlinked-material count
|
||||
- ny PDF viser `PDF er opdateret`
|
||||
- PDF preview starter med `%PDF-`
|
||||
- PDF er højst 3 sider
|
||||
- ingen vandret mobil-overflow
|
||||
- ingen afsendelse, hvis readiness er blokeret
|
||||
- afsendelse kan aktiveres, når alle materiale-id'er og prisfreshness er i orden
|
||||
|
||||
**Step 3: Kør fem gange**
|
||||
|
||||
```bash
|
||||
cd tests
|
||||
for i in 1 2 3 4 5; do
|
||||
PLAYWRIGHT_BASE_URL=http://127.0.0.1:4032 \
|
||||
npx playwright test monthly-carpenter-audit.spec.js --project=chromium --reporter=list || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
Expected: 5/5 PASS og dokumenteret p95 hydration-tid.
|
||||
|
||||
**Step 4: CI-gate**
|
||||
|
||||
Gør tømrer-audit blokerende for relevante PR'er. Fjern `continue-on-error` for denne gate. Artifact-upload må fortsat være best-effort.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/monthly-carpenter-audit.spec.js \
|
||||
.github/workflows/ci.yml \
|
||||
docs/qa/CARPENTER_WALKTHROUGH_RELEASE_GATE.md
|
||||
git commit -m "ci: gate releases on carpenter walkthrough"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Samlet kvalitetssikring og produktion
|
||||
|
||||
**Objective:** Verificér hele systemet og deploy uden at miste rollback-muligheden.
|
||||
|
||||
**Step 1: Fuld lokal gate**
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
npm run test-minimal
|
||||
cd frontend && CI=true npm test -- --watchAll=false
|
||||
cd ../tests && npx playwright test monthly-carpenter-audit.spec.js --project=chromium --reporter=list
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- backend: alle suites grønne
|
||||
- frontend: alle suites grønne
|
||||
- tømrer-audit: PASS
|
||||
- PDF: frisk status, gyldig og ≤ 3 sider
|
||||
|
||||
**Step 2: Uafhængigt code review**
|
||||
|
||||
Kør security scan og independent staged-diff review. Ingen blocking security- eller logic findings må være åbne.
|
||||
|
||||
**Step 3: PR og CI**
|
||||
|
||||
Opret én kode-PR for Spor A/C. Hold STARK-dataimportens driftslog separat. CI skal være grøn før merge.
|
||||
|
||||
**Step 4: Deploy**
|
||||
|
||||
- backup database
|
||||
- merge til `main`
|
||||
- byg frontend
|
||||
- restart PM2 uden `--update-env`
|
||||
- verificér `/api/health` og produktion HTTP 200
|
||||
|
||||
**Step 5: Produktionstest**
|
||||
|
||||
Genkør auditprojekt 392. Kontrollér:
|
||||
|
||||
- samme material count overalt
|
||||
- ingen ukoblede linjer efter review
|
||||
- frisk STARK-status efter Jannicks fil
|
||||
- PDF frisk efter generering
|
||||
- Ordrestyring-knap kun aktiv ved `readyToSend`
|
||||
|
||||
**Step 6: Rollback-kriterier**
|
||||
|
||||
Rollback ved:
|
||||
|
||||
- 5xx i tømrerflow
|
||||
- ændret økonomisk total uden godkendt datagrundlag
|
||||
- mistede projektmaterialer
|
||||
- PDF uden `%PDF-` eller > 3 sider
|
||||
- falsk `readyToSend`
|
||||
|
||||
---
|
||||
|
||||
## Prioriteret rækkefølge
|
||||
|
||||
1. **PDF freshness** — lille, deterministisk og direkte testfejl.
|
||||
2. **Fælles readiness-model** — fjerner 11/12- og “klar/blokeret”-forvirringen.
|
||||
3. **Projektindlæsning/performance** — parallelisering og måling.
|
||||
4. **Materiale-koblingsflow** — løser den reelle Ordrestyring-blokering sikkert.
|
||||
5. **Jannicks STARK-fil** — valider/importér som separat datagave.
|
||||
6. **Release-gate og samlet produktionstest**.
|
||||
|
||||
## Risici og beslutninger
|
||||
|
||||
- **Ingen automatisk materiale-id-gætning:** Tvetydige matches kræver menneskelig bekræftelse.
|
||||
- **Ingen skjult prisopdatering:** Jannicks fil importeres først efter backup, validering og afvigelseskontrol.
|
||||
- **Performance måles koldt og varmt:** En enkelt hurtig cachet gennemgang er ikke bevis.
|
||||
- **Readiness skal være fail-closed:** Ukoblede materialer eller forældet prisgrundlag må ikke fremstilles som afsendelsesklar.
|
||||
- **PDF-signatur må være stabil:** Brug normaliserede forretningsværdier, ikke React object references.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- Månedlig tømrer-audit passerer 5/5.
|
||||
- Ingen API-/konsolfejl.
|
||||
- Hydration p95 er under aftalt SLA.
|
||||
- PDF er frisk efter generering og stale først efter en reel ændring.
|
||||
- ProjectFlow og Final Review viser samme unlinked-material count.
|
||||
- Projekt 392 kan få alle relevante materialer koblet via bekræftet review.
|
||||
- Ny STARK-status er verificeret efter Jannicks leverance.
|
||||
- Ordrestyring-afsendelse er kun mulig, når `readyToSend === true`.
|
||||
- Fuld lint, build, backend, frontend og Playwright gate er grøn.
|
||||
Reference in New Issue
Block a user