# Plan: Fortsatt implementation av FlyerImport (autoflöde + UX i `/import` Flutter) ## Målbild Implementera ett komplett flyer-flöde med så få klick som möjligt där: - användaren markerar planerade inköp i `FlyerImportTab` - kvittoimporten matchar automatiskt mot öppna `FlyerSelection` och sätter `status=bought` - användaren bara behöver ingripa vid osäker matchning Detta följer båda underlagen: 1) ingen befintlig flyer-UX i `/import` ännu (behöver byggas) 2) maximal automation i punkt 3 (sync med kvittoimport) --- ## Principer för “så få klick som möjligt” - Default är automation: matcha och uppdatera utan extra dialoger. - UI ska vara “review first, edit only when needed”. - Endast två manuella åtgärder i happy path: 1. markera planerade flyer-varor 2. importera kvitto - Manuell override ska finnas men inte blockera flödet. --- ## Fas 1: Backend-kontrakt för auto-sync ### 1.1 Nya/utökade endpoints Implementera i `backend/src/flyer-selection`: - `POST /flyer-selections/receipt-match-preview` - Input: kvittorader (normaliserad struktur), `weekKey` (optional), `sessionId` (optional) - Output: matchförslag per kvittorad + confidence + reasonCodes + kandidat-selection - Används för transparent UI-annotering före commit - `POST /flyer-selections/receipt-match-commit` - Input: samma payload + optional overrides - Output: antal uppdaterade selections, listor över `bought`, `unmatched`, `ambiguous` - Utför transaktionell statusuppdatering (`planned -> bought`) - `GET /flyer-selections/open` - Query: `weekKey`, `retailer`, pagination - Returnerar öppna selections (`status=planned`) för snabb klienthämtning Notering: Behåll befintliga CRUD-rutter under `/flyer-sessions/:sessionId/selections`. ### 1.2 Matchningsmotor (service-nivå) I `FlyerSelectionService` lägg till en intern matcher med prioriterad strategi: 1. `productId` exact (högsta prio) 2. normalized name exact 3. alias/ordöverlap (token) 4. quantity/unit-stöd som förstärkning (inte ensam källa) Regler: - En `FlyerSelection` kan bara konsumeras en gång per commit. - Confidence-trösklar: - `>=0.90`: auto-commit-kandidat - `0.70-0.89`: ambiguous (kräver override för commit) - `<0.70`: unmatched - Returnera alltid `matchedVia`, `confidence`, `reasonCodes`. ### 1.3 Datamodell-justeringar (om behövs) Nuvarande schema räcker i stort, men planera följande icke-blockerande förbättringar: - `FlyerSelection`: - `boughtAt DateTime?` - `boughtSource String?` (t.ex. `receipt_auto`, `receipt_manual`) - `receiptImportBatchId String?` för spårbarhet - Index: - `(userId, status, updatedAt)` för snabb hämtning av öppna poster Migration i separat steg efter kod. ### 1.4 Säkerhet och robusthet - Validera alltid user-scope i alla nya endpoints. - Rate-limit på match-endpoints (liknande befintlig throttle-nivå). - Transaktion (`prisma.$transaction`) för commit så statusuppdatering blir atomisk. - Idempotens: commit med samma `receiptImportBatchId` ska inte dubbeluppdatera. --- ## Fas 2: Flutter UX i `/import` (ny flyer-tab) ### 2.1 Lägg till `FlyerImportTab` Uppdatera `ImportScreen` så tabbar blir: 1. Recept 2. Kvitto 3. Flyer Skapa: - `flutter/lib/features/import/presentation/flyer_import_tab.dart` - `flutter/lib/features/import/data/flyer_import_repository.dart` - `flutter/lib/features/import/data/flyer_import_providers.dart` - `flutter/lib/features/import/domain/flyer_item.dart` - `flutter/lib/features/import/domain/flyer_selection.dart` ### 2.2 Flyer-tabens minimalklick-flöde Steg i UI: 1. Upload flyerfil 2. Visa parserader med förvald checkbox för matchade varor 3. Primär CTA: `Planera markerade` (bulk-create/upsert) 4. Direkt visning av statuschips (`planned/bought/skipped`) Klickoptimering: - Förifyll `plannedQuantity/plannedUnit` från flyerdata. - Batch-upsert selections i ett enda API-anrop. - Visa inline varningar istället för modaler där möjligt. ### 2.3 Statusöversikt I flyer-tabben visa sektioner: - `Planerade` (öppna) - `Nyligen köpta` (autouppdaterade från kvitto) - `Ej matchade vid senaste kvitto` (för snabb manuell hantering) --- ## Fas 3: Integrera auto-sync i `ReceiptImportTab` ### 3.1 Hook efter receipt parse I befintlig `_submit()` i `receipt_import_tab.dart`: 1. importera kvitto som idag 2. anropa `receipt-match-preview` 3. annotera UI-rader med matchstatus (icon/chip) 4. vid `Lägg till markerade`: anropa `receipt-match-commit` parallellt/sekventiellt med saveReceipt ### 3.2 Zero-click commit i happy path Defaultbeteende vid `Lägg till markerade`: - auto-committa alla matcher med confidence `>=0.90` - lämna ambiguous som `planned` - visa en kompakt snackbar: - `2 planerade markerades som köpta` - `1 kräver manuell kontroll` Ingen extra dialog i standardfall. ### 3.3 Manuell override (endast vid behov) Lägg till valfri expandrad i resultatlistan: - “Föreslagen flyer-match” + knapp `Bekräfta ändå` - används endast för ambiguous fall --- ## Fas 4: API- och UI-detaljer för låg friktion ### 4.1 Payload-standard (receipt -> matcher) Standardisera kvittorad till: - `rowId` (lokalt index eller UUID) - `rawName` - `normalizedName` - `productId` (om redan mappad) - `quantity` - `unit` - `price` ### 4.2 UX-copy Konsekventa texter i UI: - `Automatchad mot flyer` - `Osäker matchning` - `Ej matchad` ### 4.3 WeekKey-hantering Fallback-ordning vid matchning: 1. explicit `sessionId` 2. explicit `weekKey` 3. server beräknar aktuell `weekKey` Detta minimerar klientlogik och fel. --- ## Fas 5: Test och kvalitetssäkring ### 5.1 Backend - Unit-tester för matcher-regler och confidence-nivåer - Service-tester för commit-idempotens - Controller-e2e för user-scope + throttling + felkoder - Prisma-transaktionsscenarion (dubbelklick/duplicerat commit) ### 5.2 Flutter - Widget-tester för: - `FlyerImportTab` listning/bulk-planering - kvitto-rad med automatch-chip - Integrationstester för `ReceiptImportTab` + auto-sync callback ### 5.3 Acceptanskriterier (måste uppfyllas) - Happy path kräver max 2 aktiva klick från planering till auto-bought. - Minst 90% av high-confidence-matchningar autouppdateras korrekt i test-fixtures. - Inga writes till `Product/Inventory` sker i flyer-planeringsfas. --- ## Fas 6: Gradvis lansering 1. Backend-endpoints bakom feature flag: `flyerReceiptAutoSyncEnabled` 2. Aktivera för intern/test-användare först 3. Mät: - andel auto-match - andel ambiguous - manuell override-frekvens 4. Finjustera thresholds innan full rollout --- ## Implementeringsordning (konkret) 1. Backend: matcher + preview/commit endpoints 2. Backend: idempotens + spårbarhetsfält + migration 3. Flutter: ny `FlyerImportTab` + repository/providers 4. Flutter: integrera preview/commit i `ReceiptImportTab` 5. Tester backend + Flutter 6. Feature flag rollout --- ## Risker och mitigering - Felmatchningar: håll konservativ tröskel och auto-commit bara vid hög confidence. - Dubbla commits: idempotensnyckel + transaktion. - UX-brus: visa detaljer först vid ambiguous, inte i happy path. - Prestanda: batcha matchning och undvik N+1-frågor via prefetch av öppna selections. --- ## Definition of Done - `/import` har en fungerande `FlyerImportTab`. - Kvittoimport auto-synkar mot `FlyerSelection` med minimal friktion. - `planned -> bought` uppdateras automatiskt för high-confidence. - Ambiguous fall kan hanteras manuellt utan att blockera flödet. - Tester gröna och feature flag klar för kontrollerad utrullning.