d5f903db98
- 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
226 lines
7.4 KiB
Markdown
226 lines
7.4 KiB
Markdown
# 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.
|