From ae6d7aad1ae70fdb0e1c89c05dc6e9318387228f Mon Sep 17 00:00:00 2001 From: Nils-Johan Gynther Date: Sat, 9 May 2026 23:20:52 +0200 Subject: [PATCH] feat: implement product rename and merge endpoints for users and admins, optimize receipt import UI, and enhance deploy script --- NEXT_STEPS.md | 26 +++++--- SESSION_2026-05-09_RECEIPT_IMPORT.md | 97 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 9 deletions(-) diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md index b4cafc3c..205d791b 100644 --- a/NEXT_STEPS.md +++ b/NEXT_STEPS.md @@ -30,15 +30,23 @@ All detaljhistorik och djup teknisk bakgrund finns i respektive tekniska dokumen ## Huvudprioriteringar 1. Aliasstrategi i kvittoimport: user-scope som standard, global fallback via admin. -2. **[CLEANUP] Receipt import legacy code (2026-05-09):** Ta bort gammalt matching-kod i `backend/src/receipt-import/receipt-import.service.ts`: - - `private async matchProducts()` — ersatt av unified matcher - - `private async enrichWithAiCategories()` — ersatt av unified matcher - - `private findWordMatch()` — ersatt av `findWordMatchWithScore()` - - Kör full test suite efter borttagning för regression detection -3. Stabilisera bildimport och diagnostik i alla miljoer. -4. Lokalisera kvarvarande stora Flutter-vyer i import/inventarie. -5. Forbereda avancerad AI-integration med tydlig loggning/audit. -6. Pa borja EAN-stod via Open Food Facts. +2. ✅ **[CLEANUP] Receipt import legacy code (2026-05-09):** KLART + - Borttaget: `matchProducts()`, `enrichWithAiCategories()`, `findWordMatch()` (gammal), m.fl. + - Tester uppdaterade och gröna (66/66) + - Se `SESSION_2026-05-09_RECEIPT_IMPORT.md` för detaljer +3. ✅ **[FEATURE] Product Management & Scroll Fix (2026-05-09):** KLART + - Scroll-issue i kvittoimport fixat (7 rader nu synliga) + - Admin rename/merge endpoints implementerade + - Private rename/merge endpoints för users implementerade + - Kodduplicering i products.service.ts eliminerad (~80 rader) + - admin_products_panel optimerad (cache, parallell restore, expression switches) + - Deploy-script förbättrad med selektiv build och seed-kontroll + - Se `SESSION_2026-05-09_RECEIPT_IMPORT.md` för detaljer + - **Todo:** Deploy till prod, testa i live miljö, ev. add UI för user private rename/merge +4. Stabilisera bildimport och diagnostik i alla miljöer. +5. Lokalisera kvarvarande stora Flutter-vyer i import/inventarie. +6. Förbereda avancerad AI-integration med tydlig loggning/audit. +7. Påbörja EAN-stöd via Open Food Facts. ## Beslut som styr arbetet diff --git a/SESSION_2026-05-09_RECEIPT_IMPORT.md b/SESSION_2026-05-09_RECEIPT_IMPORT.md index c44ea2b3..951e8d62 100644 --- a/SESSION_2026-05-09_RECEIPT_IMPORT.md +++ b/SESSION_2026-05-09_RECEIPT_IMPORT.md @@ -67,3 +67,100 @@ Notering: terminalhistorik innehöll äldre felutskrifter, men senaste verifieri - [ ] 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 + +## 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)