241 lines
12 KiB
Markdown
241 lines
12 KiB
Markdown
# Nyheter och förbättringar (2026-05-10)
|
|
|
|
- **Admin-inventarie:** Full CRUD, merge, filter, sortering, preview och säkerhet för admin i inventarietabellen. Endast admin kan se och hantera alla användares inventarieposter via nya endpoints och adminpanel i Flutter.
|
|
- **User-scope och IDOR-skydd:** Inventory och produkter är nu strikt user-scopade. Alla operationer kräver och filtrerar på userId. Tester verifierar att åtkomst nekas vid försök till IDOR.
|
|
- **Säkerhetshärdning:** DTO-validering, guard-ordning, logging, throttling, merge abuse-skydd, och rollbaserad access är implementerat och testat.
|
|
- **Optimeringar:** DRY i service-lager, striktare query parsing, preview-cache, API-cleanup, och kodduplication eliminerad.
|
|
- **Testtäckning:** Utökade enhets-, integrations- och säkerhetstester för alla kritiska flöden.
|
|
|
|
# Sessionlogg: Receipt Import Cleanup & Optimization
|
|
|
|
Datum: 2026-05-09
|
|
|
|
## Mål under sessionen
|
|
- Rensa bort legacy/deprecated kod i receipt-import.
|
|
- Förenkla och optimera kvarvarande kod på ett säkert sätt.
|
|
- Säkerställa att kategori-förslag visas för okända varor i import-UI.
|
|
|
|
## Genomförda förändringar
|
|
|
|
### 1) Legacy/deprecated kod borttagen (backend)
|
|
Fil: `backend/src/receipt-import/receipt-import.service.ts`
|
|
- Borttaget: `inferPackageDebugFromRawName()`
|
|
- Borttaget: `cachedCategories` + `loadCategories()` + constructor-anrop
|
|
- Borttaget: `matchProducts()`
|
|
- Borttaget: `findWordMatch()` (gammal variant)
|
|
- Borttaget: `enrichWithAiCategories()`
|
|
|
|
Fil: `backend/src/receipt-import/receipt-import.controller.ts`
|
|
- Borttaget endpoint: `POST /receipt-import/refresh-categories` (obsolet efter borttagen cache-metod)
|
|
|
|
### 2) Tester uppdaterade till unified matcher
|
|
Fil: `backend/src/receipt-import/receipt-import.service.spec.ts`
|
|
- Tester migrerade från anrop av borttagna `matchProducts()` till `matchAndEnrichReceiptItem()`.
|
|
- Tester gröna efter uppdatering.
|
|
|
|
### 3) Säkra förenklingar/optimeringar (backend)
|
|
Fil: `backend/src/receipt-import/receipt-import.service.ts`
|
|
- Infört tydliga typer för matchningskontext (`MatchingContext`) och debug-objekt.
|
|
- Extraherat helpers för:
|
|
- signaltextbyggande
|
|
- enhetsmappning
|
|
- Reducerad duplicering i kategoriseringsflöde.
|
|
- In-memory index i matchningskontext för snabbare uppslag:
|
|
- `aliasByReceiptName`
|
|
- `unitMappingByKey`
|
|
- Bakåtkompatibilitet behållen via fallback när index-fält saknas.
|
|
|
|
### 4) UI-fix: kategori-förslag visades inte för okända varor
|
|
Fil: `flutter/lib/features/import/presentation/receipt_import_tab.dart`
|
|
- Fixat så kategori-förslag visas även om rad saknar matchad produkt.
|
|
- Edit-state fylls nu även för rader med endast kategori-förslag.
|
|
- Label i UI visar `Kategoriförslag` när produkt saknas.
|
|
|
|
### 5) Diagnostik tillagd (backend)
|
|
Fil: `backend/src/receipt-import/receipt-import.service.ts`
|
|
- Varningslogg om kategorier inte kunde laddas eller om listan blev tom.
|
|
- Syfte: snabbare felsökning när kategori-förslag uteblir.
|
|
|
|
## Verifiering under sessionen
|
|
- Backend build: OK (`npm run build`)
|
|
- Backend tests: OK (66/66)
|
|
- Flutter analyze (berörda filer): OK
|
|
|
|
Notering: terminalhistorik innehöll äldre felutskrifter, men senaste verifieringarna var gröna.
|
|
|
|
## Kvar att göra nästa gång
|
|
1. Deploya senaste backend + flutter till servern.
|
|
2. Re-testa receipt import med PDF i produktion.
|
|
3. Bekräfta att rader utan produkt nu visar `Kategoriförslag` direkt i listan.
|
|
4. Vid fortsatt problem: kontrollera nya varningsloggar från `prepareMatchingContext` i backend-loggar.
|
|
|
|
## Snabb fortsättning (checklista)
|
|
- [ ] Deploy backend
|
|
- [ ] Deploy flutter
|
|
- [ ] Import-test med samma PDF
|
|
- [ ] Verifiera kategori-förslag för okända varor
|
|
- [ ] Dela loggutdrag om något saknas
|
|
|
|
---
|
|
|
|
# Sessionlogg: Produkthantering & UI-optimeringar (samma dag, senare)
|
|
|
|
## Mål under denna del
|
|
- Fixa scroll-issue i kvittoimport-gränssnittet (7 rader men bara 5 synliga).
|
|
- Implementera product rename/merge för både admins och regular users.
|
|
- Eliminera kodduplicering i backend-service.
|
|
- Optimera admin-panel och deploy-process.
|
|
|
|
## Genomförda förändringar
|
|
|
|
### 1) Scroll-issue fixat i receipt import UI
|
|
Fil: `flutter/lib/features/import/presentation/receipt_import_tab.dart`
|
|
- **Problem:** `SizedBox(height: 620px, child: ListView.builder(...))` inuti `SingleChildScrollView` skapade konfligerade scroll-handlers.
|
|
- **Lösning:** Tog bort `SizedBox`-begränsningen, använd `shrinkWrap: true` och `physics: NeverScrollableScrollPhysics()` på ListView så parent `SingleChildScrollView` hanterar all scrolling.
|
|
- **Resultat:** ✅ Alla 7 rader nu synliga.
|
|
|
|
### 2) Product rename & merge för admin (backend)
|
|
Fil: `backend/src/products/products.controller.ts`
|
|
- Två nya endpoints:
|
|
- `PATCH /products/:id/canonical-name` — admin kan byta namn på vilken produkt som helst
|
|
- `POST /products/merge` — admin kan slå ihop två produkter
|
|
- Decorator: `@Roles('admin')`
|
|
|
|
### 3) Private product endpoints för vanliga users (backend)
|
|
Fil: `backend/src/products/products.controller.ts`
|
|
- Två nya parallella endpoints för user-owned private products:
|
|
- `PATCH /products/private/:id/canonical-name` — user kan byta namn på egen privat produkt
|
|
- `POST /products/private/merge` — user kan slå ihop egna privata produkter
|
|
- JWT extraction: `const userId = req.user.id` (ingen `@Roles`-behov, user kan bara redigera sin egna data)
|
|
- Security: `ForbiddenException` om produkt inte är privat eller inte ägs av user
|
|
|
|
### 4) Backend service refaktorering — kodduplicering eliminerad
|
|
Fil: `backend/src/products/products.service.ts`
|
|
- Två nya **private helper-metoder:**
|
|
- `_updateCanonicalNameCore(id, canonicalName)` — shared logik för trim + Prisma update
|
|
- `_mergeCore(sourceId, targetId)` — shared logik för transaction, inventory transfer, soft-delete
|
|
- Alla fyra public metoder (`updateCanonicalName`, `updateCanonicalNamePrivate`, `merge`, `mergePrivate`) använder nu dessa helpers
|
|
- **Exception fix:** Bytte `throw new Error(...)` till `throw new ForbiddenException(...)` för authorization-fel (korrekt HTTP 403)
|
|
- **Resultat:** ~80 rader kodduplicering eliminerad, bättre underhållbarhet
|
|
|
|
### 5) API-path konstanter för Flutter (frontend)
|
|
Fil: `flutter/lib/core/api/api_paths.dart`
|
|
- Lade till två nya constants i `ProductApiPaths`:
|
|
- `static const mergePrivate = '/products/private/merge'`
|
|
- `static String canonicalNamePrivate(int id) => '/products/private/$id/canonical-name'`
|
|
|
|
### 6) Admin repository uppdaterad (frontend)
|
|
Fil: `flutter/lib/features/admin/data/admin_repository.dart`
|
|
- Två nya metoder:
|
|
- `updateCanonicalNamePrivate(int productId, String canonicalName)` — user rename
|
|
- `mergeProductsPrivate({required sourceId, required targetId})` — user merge
|
|
- Komment: "Admin kan uppdatera vilken produkt som helst; users kan bara uppdatera sina egna privata produkter"
|
|
|
|
### 7) Admin panel optimeringar (frontend)
|
|
Fil: `flutter/lib/features/admin/presentation/admin_products_panel.dart`
|
|
- **Caching av kategorierna:** `_cachedCategoryOptions` beräknas en gång istället för varje build
|
|
- **Enklare `_nameForId()`:** Bytte från `where().toList()` till en enkel for-loop med early return
|
|
- **Parallell restore:** `_restoreSelected()` använder `Future.wait()` istället för seriebaserade await
|
|
- **Expression switch:** `_sortLabel()` förkortat från 12-radigt switch till en enda rad med expression switch
|
|
|
|
### 8) Deploy-script förbättring
|
|
Fil: `deploy.sh`
|
|
- Nya flaggor för selektiv build:
|
|
- `--backend` — bygga bara backend
|
|
- `--flutter` — bygga bara Flutter
|
|
- `--importer` — bygga bara microservice-importer
|
|
- `--pull-always` — tvinga Docker att hämta senaste base image (för prod-säkerhet)
|
|
- Default: bygger alla tre, använder `--pull=false` för snabbhet (ej prod)
|
|
- `--seed` flag för opt-in databaskällning
|
|
- Help: `./deploy.sh --help` visar användning
|
|
|
|
## Verifiering
|
|
- ✅ Backend build: OK (`npm run build`)
|
|
- ✅ Backend tests: OK
|
|
- ✅ Flutter analyze: OK (alla berörda filer)
|
|
- ✅ TypeScript-fel: Inga
|
|
- ✅ Git diff: Alla 4 filer granskat och godkänt
|
|
|
|
## Öppna uppgifter (nästa steg)
|
|
1. Deploy backend + Flutter med `./deploy.sh --backend --flutter`
|
|
2. Testa i produktion:
|
|
- Verifiera 7 rader nu synliga i receipt import
|
|
- Verifiera admin kan byta namn på produkter
|
|
- Verifiera admin kan slå ihop produkter
|
|
- Verifiera users kan redigera sina egna privata produkter
|
|
3. UI för users: Om private rename/merge ska exponeras i användar-app (backend redan klart, saknas bara UI)
|
|
4. Unit/integration tests för private endpoints
|
|
|
|
---
|
|
|
|
# Sessionlogg: Aliasstrategi i kvittoimport (samma dag, senare)
|
|
|
|
## Mål under denna del
|
|
- Göra aliasstrategin konsekvent med user-scope som standard och global fallback via admin.
|
|
- Sluta lära alias automatiskt vid manuell korrigering och kräva explicit val i UI.
|
|
- Härda backend mot brusiga eller ogiltiga alias.
|
|
|
|
## Genomförda förändringar
|
|
|
|
### 1) Gemensam aliasnormalisering och guardrails (backend)
|
|
Filer:
|
|
- `backend/src/common/utils/receipt-alias.ts`
|
|
- `backend/src/receipt-alias/receipt-alias.service.ts`
|
|
- `backend/src/receipt-import/receipt-import.service.ts`
|
|
|
|
- Infört gemensam utility för aliasnormalisering (`trim`, lowercase, kollapsad whitespace).
|
|
- Infört validering som blockerar tomma alias och brusiga alias som `rabatt`, `summa`, `pant`, `att betala`, `totalt`, m.fl.
|
|
- Receipt import och alias-API använder nu samma regler för både lookup och sparande.
|
|
|
|
### 2) Receipt import lär inte längre alias automatiskt (Flutter)
|
|
Filer:
|
|
- `flutter/lib/features/import/data/receipt_import_session.dart`
|
|
- `flutter/lib/features/import/presentation/edit_dialog.dart`
|
|
- `flutter/lib/features/import/presentation/receipt_import_tab.dart`
|
|
|
|
- Infört explicit `learnAlias`-val i edit-dialogen.
|
|
- Alias sparas nu bara om användaren aktivt markerar att kvittonamnet ska läras in.
|
|
- Valet persisteras i receipt import-sessionen så att tabbyte inte tappar användarens val.
|
|
- Om raden redan matchades via alias visas förklarande text i stället för ny aliasinlärning.
|
|
|
|
### 3) Aliasöversikter visar scope tydligare (Flutter)
|
|
Filer:
|
|
- `flutter/lib/features/admin/domain/receipt_alias.dart`
|
|
- `flutter/lib/features/profile/presentation/user_aliases_screen.dart`
|
|
- `flutter/lib/features/admin/presentation/admin_aliases_panel.dart`
|
|
|
|
- Aliasmodellen utökad med `ownerId` och `isGlobal`.
|
|
- User alias-skärmen visar nu skillnad mellan `Privat alias` och `Global fallback`.
|
|
- Delete-knapp visas bara för privata alias i användarvyn, så UI:t matchar backend-behörigheten.
|
|
- Adminpanelen visar scope även för aliasposter.
|
|
|
|
### 4) Tester för aliasflödet
|
|
Filer:
|
|
- `backend/src/receipt-import/receipt-import.service.spec.ts`
|
|
- `backend/src/receipt-alias/receipt-alias.service.spec.ts`
|
|
|
|
- Tester tillagda för normalisering av whitespace vid alias-lookup.
|
|
- Tester tillagda för alias-upsert med normalisering.
|
|
- Tester tillagda för blockering av brusalias.
|
|
- Tester tillagda för behörighetsregler kring globala alias och borttagning.
|
|
|
|
## Verifiering
|
|
- ✅ Backend tests: 31/31 gröna för berörda aliasspecar
|
|
- ✅ Flutter analyze: OK för alla berörda alias/import-filer
|
|
|
|
## Kvar att göra
|
|
1. Manuell test i appen: receipt import med explicit alias-inlärning.
|
|
2. Produktionstest: verifiera att privata alias och global fallback beter sig rätt mot riktiga kvitton.
|
|
3. Bedöm om aliasöversikterna behöver mer avancerad filtrering eller redigering senare.
|
|
|
|
## Snabb checklista för nästa session
|
|
- [ ] Deploy backend + Flutter
|
|
- [ ] Testa scroll-fix i prod
|
|
- [ ] Testa admin rename/merge
|
|
- [ ] Testa private endpoints (API-test eller manual)
|
|
- [ ] Implementera user-UI för private rename/merge (valfritt)
|
|
|
|
## 2026-05-10: Admin-inventarie (CRUD, merge, filter, sortering, preview, säkerhet), user-scope, IDOR-skydd, säkerhetshärdning, optimeringar och utökad testtäckning är nu genomförda och dokumenterade i README, TEKNISK_BESKRIVNING, SÄKERHETSHÄRDNINGSPLAN och SESSIONLOGGAR.
|
|
|
|
## 2026-05-10: Admin-inventarie (CRUD, merge, filter, sortering, preview, säkerhet), user-scope, IDOR-skydd, säkerhetshärdning, optimeringar och utökad testtäckning är nu genomförda och dokumenterade i README, TEKNISK_BESKRIVNING, SÄKERHETSHÄRDNINGSPLAN och SESSIONLOGGAR.
|