- Replace BadRequestException with UnauthorizedException for authentication failures in flyer-import and flyer-selection controllers - Add bulk selection endpoint in FlyerSelectionController for creating multiple selections in one request - Update FlyerSelectionModule to include new FlyerSelectionMatcherService and FlyerSelectionSyncController - Extend FlyerSelectionService with createMany method for bulk operations - Add new DTOs for bulk selection and receipt matching functionality - Update ReceiptImportService to accept FlyerSelectionService dependency and track successful rows - Extend SaveReceiptResponse with flyerAutoSync field for receipt-to-flyer matching results - Add new API paths for flyer import and selection endpoints - Update Flutter UI to include Flyer import tab and adjust tab controller length - Add new domain models and repository methods for flyer import functionality - Update test files to include new FlyerSelectionService dependency - Modify .kilo plan documentation to reflect current system architecture
7.4 KiB
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
FlyerSelectionoch sätterstatus=bought - användaren bara behöver ingripa vid osäker matchning
Detta följer båda underlagen:
- ingen befintlig flyer-UX i
/importännu (behöver byggas) - 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:
- markera planerade flyer-varor
- 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
- Input: kvittorader (normaliserad struktur),
-
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
- Query:
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:
productIdexact (högsta prio)- normalized name exact
- alias/ordöverlap (token)
- quantity/unit-stöd som förstärkning (inte ensam källa)
Regler:
- En
FlyerSelectionkan bara konsumeras en gång per commit. - Confidence-trösklar:
>=0.90: auto-commit-kandidat0.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
receiptImportBatchIdska inte dubbeluppdatera.
Fas 2: Flutter UX i /import (ny flyer-tab)
2.1 Lägg till FlyerImportTab
Uppdatera ImportScreen så tabbar blir:
- Recept
- Kvitto
- Flyer
Skapa:
flutter/lib/features/import/presentation/flyer_import_tab.dartflutter/lib/features/import/data/flyer_import_repository.dartflutter/lib/features/import/data/flyer_import_providers.dartflutter/lib/features/import/domain/flyer_item.dartflutter/lib/features/import/domain/flyer_selection.dart
2.2 Flyer-tabens minimalklick-flöde
Steg i UI:
- Upload flyerfil
- Visa parserader med förvald checkbox för matchade varor
- Primär CTA:
Planera markerade(bulk-create/upsert) - Direkt visning av statuschips (
planned/bought/skipped)
Klickoptimering:
- Förifyll
plannedQuantity/plannedUnitfrå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:
- importera kvitto som idag
- anropa
receipt-match-preview - annotera UI-rader med matchstatus (icon/chip)
- vid
Lägg till markerade: anropareceipt-match-commitparallellt/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öpta1 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)rawNamenormalizedNameproductId(om redan mappad)quantityunitprice
4.2 UX-copy
Konsekventa texter i UI:
Automatchad mot flyerOsäker matchningEj matchad
4.3 WeekKey-hantering
Fallback-ordning vid matchning:
- explicit
sessionId - explicit
weekKey - 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:
FlyerImportTablistning/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/Inventorysker i flyer-planeringsfas.
Fas 6: Gradvis lansering
- Backend-endpoints bakom feature flag:
flyerReceiptAutoSyncEnabled - Aktivera för intern/test-användare först
- Mät:
- andel auto-match
- andel ambiguous
- manuell override-frekvens
- Finjustera thresholds innan full rollout
Implementeringsordning (konkret)
- Backend: matcher + preview/commit endpoints
- Backend: idempotens + spårbarhetsfält + migration
- Flutter: ny
FlyerImportTab+ repository/providers - Flutter: integrera preview/commit i
ReceiptImportTab - Tester backend + Flutter
- 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
/importhar en fungerandeFlyerImportTab.- Kvittoimport auto-synkar mot
FlyerSelectionmed minimal friktion. planned -> boughtuppdateras 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.