Refactor technical documentation for clarity and updates

- Updated "teknisk_beskrivning_flutter.md" to streamline content and remove outdated sections, focusing on architecture, environment, and recent technical additions.
- Enhanced "migrering-MSI.md" with post-migration updates and clarifications for target audience.
- Revised "produktlansering.md" to serve as a release checklist, ensuring it complements existing documentation without duplication.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-05-03 17:03:20 +02:00
parent fa7f225ee5
commit 1320f936ec
10 changed files with 243 additions and 1377 deletions
+33 -99
View File
@@ -1,113 +1,47 @@
# Flutter Frontend - Användarguide
# Flutter Frontend - Anvandarguide
Detta dokument beskriver hur du använder Flutter-frontenden för Recipe App ur ett användar- och operatörsperspektiv.
Detta dokument ar for anvandare och operativa testare.
Har beskriver vi vad som fungerar i Flutter-klienten och hur den anvands i praktiken.
## Senaste ändringar (2026-04-25)
## Dokumentstatus (2026-05-03)
**Arkitektur- och UX-förbättringar:**
- Grid-vy för recept: Kolumnval (2/4/6/8) via ikon i AppShell, med Riverpod-provider och SharedPreferences.
- RecipesScreen är nu body-only, ingen egen Scaffold/AppBar.
- AppShell visar grid-ikon endast på /recipes.
- Buggfix: Produktväljaren i pantry/inventarie (ProductPickerField) — bottenark implementeras.
- Kodkvalitet: Inga absoluta Windows-sökvägar.
- Fokus: anvandarflode, inte implementation.
- Teknisk detaljniva finns i `teknisk_beskrivning_flutter.md`.
- Planering och backlog finns i `next_steps_flutter.md`.
**Nyheter och förbättringar:**
- **Fas 5: Matplan parity** — Veckovy, portionsjustering per dag, inköpslista och inventariejämförelse mot användarens pantry är nu fullt migrerade och user-scopade.
- **Fas 6a: Receptimport** — Importflöde för recept (fil/URL) är nu robust, med stöd för PDF, bild och ICA-länkar. Prefill av markdown och bild-url fungerar i Flutter.
- **Bildimport** — Backend och Flutter har förbättrats med robust bildhantering, normalisering av URL:er, fallback och diagnostikloggning.
- **User-scope för pantry och matplan** — Alla baslager- och matplansdata är nu per användare (inte globala).
- **UI/UX-förbättringar** — Produktval med bottenark (ProductPickerField), swipe-för-±1 på inventarielistan (SwipeableInventoryTile), och förbättrad felhantering.
## Vad appen ar
## Vad appen är
Flutter-webben ar en klient for Recipe App som kors i Docker och exponeras via Caddy.
Den anvands parallellt med Next-frontenden under migrering och verifiering.
Flutter-webben för Recipe App är en webbklient byggd med Flutter och körs i Docker med Caddy som proxy. Den är avsedd att ersätta den befintliga Next.js-frontenden och stödja framtida mobilklienter.
## Senaste forbattringar
## Aktuella användarflöden
- Inloggning med användarnamn och lösenord.
- Receptlista efter inloggning.
- Profil-sida (grundversion).
- Utloggning från recept- och profil-sidor.
- Kvittoimportens granskningsflode ar klart och stabiliserat.
- Pagande kvittoimport sparas i klientens session och kan atertas efter refresh/navigation.
- Tolkning av antal/forpackning i kvittorader ar forbattrad, inklusive format som `2st`.
- AI-kategoriforslag och produktforslag visas separerat for tydligare val.
## Var man kommer åt appen
- Testmiljö: `https://test.gynther.se`
## Aktuella anvandarfloden
## Inloggningsdetaljer
- Inloggning förväntar sig användarnamn, inte e-post.
- Exempel på seedad admin-användare i backend: `Nadmin`.
- Lösenordet kontrolleras av servermiljövariabeln (`ADMIN_NADMIN_PASSWORD`).
- Inloggning med anvandarnamn och losenord.
- Recept: lista, skapa, redigera, radera.
- Inventarie och baslager: skapa, redigera, konsumera.
- Matplan: veckovy, portionsjustering, inkopslista.
- Import: receptimport och kvittoimport med granskningssteg.
## Kända begränsningar
- Kvittoimport (Fas 6b) är påbörjad men granskningssteg och bulk-spara återstår.
- Bildimport kräver att containrar är uppdaterade med senaste kod — kontrollera att diagnostikloggar syns vid felsökning.
- Vissa adminfunktioner och avancerad AI-integration är planerade men ej migrerade.
## Kanda begransningar
## Felsökning (användarnivå)
1. Om sidan visar gammalt beteende efter deployment: hård uppdatering eller öppna i inkognitoläge.
2. Om inloggning misslyckas: verifiera användarnamn/lösenord (inte e-post).
- Vissa adminfunktioner och avancerad AI-integration ar planerade men ej fullt migrerade.
- Bildimport forutsatter att containrar ar uppdaterade med senaste kod.
## Felsokning (anvandarniva)
1. Om sidan visar gammalt beteende efter deploy: hard uppdatering eller inkognito.
2. Om inloggning misslyckas: verifiera anvandarnamn/losenord (inte e-post).
3. Om importfloden fastnar: rapportera webblasarkonsolens fel till utvecklingsteamet.
## Relaterade dokument
- [next_steps_flutter.md](next_steps_flutter.md)
- [teknisk_beskrivning_flutter.md](teknisk_beskrivning_flutter.md)
## Vad appen är
Detta är en Flutter Web frontend för Recipe App, som körs i Docker och exponeras via Caddy. Den är avsedd att bete sig som den befintliga webbfrontenden, men är byggd i Flutter för att stödja framtida Android- och iOS-klienter.
## Aktuella användarflöden
- Inloggning med användarnamn och lösenord.
- Receptlista efter inloggning.
- Profil-sida (grundversion).
- Utloggning från recept- och profil-sidor.
## Var man kommer åt appen
- Testmiljö: `https://test.gynther.se`
## Inloggningsdetaljer
- Inloggning förväntar sig användarnamn, inte e-post.
- Exempel på seedad admin-användare i backend: `Nadmin`.
- Lösenordet kontrolleras av servermiljövariabeln (`ADMIN_NADMIN_PASSWORD`).
## Kända begränsningar
- Kvittoimport (Fas 6b) är påbörjad men granskningssteg och bulk-spara återstår.
- Bildimport kräver att containrar är uppdaterade med senaste kod — kontrollera att diagnostikloggar syns vid felsökning.
- Vissa adminfunktioner och avancerad AI-integration är planerade men ej migrerade.
## Felsökning (användarnivå)
1. Om sidan visar gammalt beteende efter deployment: hård uppdatering eller öppna i inkognitoläge.
2. Om inloggning misslyckas: verifiera användarnamn/lösenord (inte e-post).
3. Om recept inte laddas: rapportera fel i webbläsarkonsolen/nätverksfelen till utvecklingsteamet.
## Förväntningar vid release
Denna frontend är tillgänglig för iterativ testning. Funktionell parity med den nuvarande produktionsfrontenden levereras stegvis.
## Konverteringsvägen och Onboarding
- **CTA (Call-to-Action):** Tydliga och lockande CTAs som "Se vad du kan laga med det du har hemma."
- **Förenkla onboarding:** Gästinloggning eller demo-läge, sociala inloggningar, välkomstguide, och pop-up-tips.
- **Snabb start med exempeldata:** Förifyllt exempeldata och "Snabbstart"-knapp.
- **Fokusera på "Aha!"-momentet:** Omedelbara receptförslag och automatiska inköpslistor.
- **Tydliga instruktioner och feedback:** Instruktioner för varje steg och omedelbar feedback.
- **Användarvänlig design:** Fokus på kärnfunktioner och enkelhet.
- **Möjlighet att hoppa över onboarding:** Knapp för att hoppa över onboarding.
## Testa och iterera
- Gå igenom appen som en ny användare för att identifiera eventuella problem.
- A/B-testa olika CTAs och onboarding-flöden.
- Implementera analytik för att spåra var användare hoppar av och varför.
## Anpassa till målgruppen
- Anpassa marknadsföring och CTAs till målgruppen (t.ex. familjer, matintresserade, meal preppers).
- Var tydlig med appens värdeproposition, t.ex. "Slipp slösa mat vi visar vad du kan laga med det du har hemma."
---
## Nyheter och förbättringar (2026-04-24)
- **Navigations- och UX-förbättringar:**
- Tydliga navigationslänkar mellan recept, inventarie, baslager och matplan för att förenkla användarflödet.
- Efter att ett recept redigerats, navigeras användaren nu automatiskt till receptdetaljer.
- Efter konsumtion av inventariepost navigeras användaren automatiskt tillbaka till inventarielistan.
- Efter import av recept navigeras användaren automatiskt till receptlistan.
- Mjukare scrollning i receptdetaljvyn och förbättrad bakgrundsbildshantering.
- **Kodkvalitet:**
- Säkerställt att inga absoluta Windows-sökvägar används i koden, för att stödja bygg och drift på Linux/Ubuntu.
- `next_steps_flutter.md` - roadmap och prioriteringar.
- `teknisk_beskrivning_flutter.md` - teknisk referens for drift/utveckling.
- `../README.md` - overgripande produktinformation.
+28 -449
View File
@@ -1,462 +1,41 @@
# Senaste ändringar (2026-04-24)
# Nasta steg: Flutter-migrering
**Arkitektur- och UX-förbättringar:**
- Grid-vy för recept: Kolumnval (2/4/6/8) via ikon i AppShell, med Riverpod-provider och SharedPreferences.
- RecipesScreen är nu body-only, ingen egen Scaffold/AppBar.
- AppShell visar grid-ikon endast på /recipes.
- Buggfix: Produktväljaren i pantry/inventarie (ProductPickerField) — bottenark implementeras.
- Sprint 2: Databas > Produkter visar nu en riktig adminpanel i profilflödet med sök, okategoriserat-filter och bulk-kategorisering.
- Sprint 2: Användare-fliken stödjer nu Premium av/på direkt från användarmenyn.
- Kodkvalitet: Inga absoluta Windows-sökvägar.
- Dokumentation och next_steps uppdaterade.
# Nästa steg: Flutter-migrering
Detta dokument ar Flutter-teamets roadmap och prioriteringslista.
All historik och implementationdetaljer finns i `teknisk_beskrivning_flutter.md`.
Relaterade dokument:
- [README.md](README.md)
- [teknisk_beskrivning_flutter.md](teknisk_beskrivning_flutter.md)
## Dokumentstatus (2026-05-03)
## Mål och prioriteringar för produktion
- Fokus: aktiv planering framat.
- Endast en roadmap for Flutter for att undvika dubbletter.
### Övergripande mål
- **Funktionell parity:** Säkerställa att alla kärnfunktioner är stabila och fungerar som förväntat.
- **Användarupplevelse:** Förenkla onboarding och säkerställa att användare snabbt förstår appens värde.
- **Produktionsklar:** Säkerställa att appen är redo för lansering genom att adressera kritiska buggar och förbättra prestanda.
## Klart senaste sessionerna
### Icke-förhandlingsbara ramar
- Fas 6b: granskningsflode for kvittoimport (edit, destination, merge, spara).
- Fas 6c: separering av AI-kategorichip och produktforslagschip.
- Fas 6d: klientpersistens for pagande kvittoimport + forbattrad antal/forpackningsinferens.
1. Inget ska tas bort eller ändras i `recipe-api` utom explicit beslutade backend-ändringar för användarscope i pantry och matplan.
2. Inget ska tas bort eller ändras i `recipe-frontend`.
3. Migreringen sker i Flutter-spåret som separat klient mot befintliga API-kontrakt.
4. Next-frontend körs parallellt tills Flutter har verifierad parity i kärnflöden.
## Pagande arbete
## Arbetsplan
- Robust bildimport och diagnostik i drift.
- Aliasstrategi i kvittoimport (hybrid user-scope + global fallback via admin).
- Utokad adminfunktionalitet i Flutter-sparet.
### Pågående arbete
- **Kvittoimport (Fas 6b):** ✅ Klar (2026-05-01) — Granskning, redigering, val av destination (inventarie/baslager), merge och spara implementerat.
- **Kvittoimport (Fas 6c):** ✅ Klar (2026-05-01) — Separering av AI-chip och produktsuggestions-chip, produktnamns-normalisering, och validering av AI-kategorier.
- **Bildimport:** Säkerställa att containrar är uppdaterade med senaste kod och att diagnostikloggar syns vid felsökning.
- **Adminfunktioner:** Avancerad AI-integration och ytterligare adminfunktioner planeras men är ej migrerade.
## Prioriterade nasta steg
### Tillfällig MVP-notering (att ta bort senare)
- [ ] Ta bort tillfällig diagnostikbanner i kvittoimporten när MVP är verifierad.
Banner finns i `lib/features/import/presentation/receipt_import_tab.dart` och visar felkällor för `auth/token`, `categories`, `products:list`, `products:mine`.
1. Verifiera bildimport och felhantering end-to-end i testmiljo.
2. Implementera alias-inlarning vid manuell korrigering i importflodet.
3. Forbattra UI/UX i granskningsfloden for kvittoimport.
4. Fortsatt migrering av kvarvarande adminfloden.
5. Lokalisera kvarvarande delar i import- och inventarievyer.
### Prioriterade nästa steg
1. Säkerställa robust bildimport och diagnostik.
2. Implementera hybrid alias-stöd i kvittoimport tillsammans med backend: user-scope alias som standard och global alias via admin.
3. Stödja alias-inlärning i UI vid manuell korrigering (default: user-scope), samt visa scope tydligt för admin.
4. Implementera avancerad AI-integration för produktkategorisering.
5. Utöka adminfunktioner för användarhantering och produktadministration.
6. Förbättra UI/UX för användarflöden, inklusive onboarding och profilhantering.
## Viktiga beslut
## Notering 2026-05-02 - Aliasstrategi kvittoimport
- Flutter ar separat klient mot befintliga API-kontrakt.
- Ingen klientspecifik speciallogik for datamatchning; backend ar sanningskalla.
- Next-frontenden kor parallellt tills verifierad parity ar uppnadd.
- Flutter ska följa backend-kontraktet för hybrid alias-modell.
- Ingen klientspecifik speciallogik för matchning; klienten ska bara exponera tydliga val för scope vid manuell korrigering.
- Målet är färre felträffar mellan användare och bättre precision i personliga kvittoflöden.
## Relaterade dokument
## Beslut 2026-04-22 - User-scope för pantry och matplan
- Pantry och matplan ska vara per användare, inte globala.
- Detta kräver backend-ändringar i `recipe-api` innan Flutter kan nå full parity för dessa flöden.
- Flutter ska följa de nya kontrakten när de finns på plats, utan klientspecifik speciallogik.
## Malbild för v1 (funktionell parity)
För v1 ska dessa flöden vara stabila i Flutter:
- [x] Auth: login, session, logout, auth-guard.
- [x] Recept: lista, detalj, skapa, uppdatera, ta bort.
- [x] Inventarie: lista, skapa, uppdatera, konsumera, historik.
- [x] Matplan: veckovy, val av recept per dag, portionsjustering, inköpslista, inventariejämförelse.
- [x] Import: quick-import + parse-markdown-flöde.
- [x] Produktadmin: lista, sök, sortera, filtrera, AI-kategorisering, merge, restore, inline kategori.
- [x] Användaradmin: lista, premium, e-post, skapa, ta bort, återställ lösenord.
## Arbetsordning för produktion
### Fas 1: Kritiska funktioner och buggfixar
- **Mål:** Säkerställa att alla kärnfunktioner är stabila och buggfria.
- **Åtgärder:**
- [x] **Kvittoimport (OCR, bulk-spara) — KLAR 2026-05-01:**
- [x] Granskningssteg med checkbox, redigering och destination-väljare.
- [x] Bulk-spara till inventarie (ny/merge) eller baslager (ny/hoppa-över).
- [x] `file_picker: ^8.0.0` integrerat för filval på Flutter Web.
- [ ] **UI/UX-förbättringar för adminpaneler:**
- [ ] Lägg till tydlig placeholder-text i sökfältet.
- [ ] Gör filtreringsalternativen mer visuellt tydliga.
- [ ] Lägg till bekräftelsedialog för bulk-åtgärder.
- [ ] Förbättra laddningsindikatorn för AI-kategorisering.
- [ ] **Receptvy:**
- [ ] Lägg till tydlig växlingsknapp för grid- och listvy.
- [ ] Implementera sorteringsalternativ.
- [ ] Förbättra det tomma tillståndet med en tydlig CTA.
- [ ] **Receptdetaljvy:**
- [ ] Lägg till stöd för att visa receptbilder i större format.
- [ ] Gör ingredienslistan mer läsbar.
- [ ] **Gemensamma UI-komponenter:**
- [ ] Förbättra felmeddelanden med tydliga instruktioner.
- [ ] Använd en visuellt tilltalande laddningsindikator.
- [ ] **Allmänt:**
- [ ] Säkerställa tillgänglighet med tydliga `tooltip`-texter och tillräcklig kontrast.
- [ ] Lägg till bekräftelsemeddelanden efter åtgärder.
### Fas 2: Förbättra konverteringsvägen och onboarding
- **Mål:** Säkerställa att användare snabbt får värde och förstår appens fördelar.
- **Åtgärder:**
- **CTA (Call-to-Action):**
- [ ] Skapa tydliga och lockande CTAs som "Se vad du kan laga med det du har hemma."
- [ ] Placera CTAs strategiskt i appen för att maximera synlighet.
- **Förenkla onboarding:**
- [ ] Implementera en gästinloggning eller demo-läge så att användare kan prova appen utan att registrera sig direkt.
- [ ] Minska antalet obligatoriska fält vid registrering och implementera sociala inloggningar (t.ex. Google, Facebook).
- [ ] Skapa en kort välkomstguide för nya användare som visar de viktigaste funktionerna.
- [ ] Använd pop-up-tips eller tooltips för att visa hur man använder olika funktioner.
- **Snabb start med exempeldata:**
- [ ] Låt användare börja med förifyllt exempeldata, t.ex. en standardinköpslista eller vanliga ingredienser.
- [ ] Lägg till en "Snabbstart"-knapp som automatiskt fyller i exempeldata och visar receptförslag.
- **Fokusera på "Aha!"-momentet:**
- [ ] Visa omedelbara receptförslag när användaren lägger till sina första ingredienser.
- [ ] Generera en automatisk inköpslista baserad på de recept användaren väljer.
- **Tydliga instruktioner och feedback:**
- [ ] Visa tydliga instruktioner för varje steg i onboarding-processen.
- [ ] Ge omedelbar feedback när användaren utfört en åtgärd.
- **Användarvänlig design:**
- [ ] Håll gränssnittet enkelt och fokuserat på kärnfunktioner.
- [ ] Visa endast de viktigaste funktionerna för nya användare.
- **Möjlighet att hoppa över onboarding:**
- [ ] Lägg till en knapp som låter användare hoppa över onboarding och börja använda appen direkt.
### Fas 3: Testa och iterera
- **Mål:** Identifiera friktion och förbättra konverteringsvägen.
- **Åtgärder:**
- [ ] Gå igenom appen som en ny användare för att identifiera eventuella problem.
- [ ] A/B-testa olika CTAs och onboarding-flöden för att se vad som fungerar bäst.
- [ ] Implementera analytik för att spåra var användare hoppar av och varför.
### Fas 4: Anpassa till målgruppen
- **Mål:** Se till att marknadsföring och CTAs talar direkt till målgruppen.
- **Åtgärder:**
- [ ] Anpassa marknadsföring och CTAs till målgruppen (t.ex. familjer, matintresserade, meal preppers).
- [ ] Var tydlig med appens värdeproposition, t.ex. "Slipp slösa mat vi visar vad du kan laga med det du har hemma."
### 3. Avancerade adminfunktioner
- [ ] Implementera "Visa endast ändrade rader" i produktadmin.
- [ ] Säkerställa att AI-integration för kategorisering är robust.
### 4. Dokumentation och testning
- [ ] Uppdatera `README.md` med senaste ändringar.
- [ ] Lägg till testfall för nya funktioner.
- [ ] Validera med `flutter analyze` och fixa eventuella varningar.
### 5. Övrigt
- [ ] Säkerställa att alla containrar är uppdaterade för robust bildhantering.
## Prioriterad plan (ordning)
## Fas 0 - Backend-förarbete för user-scope (KLAR 2026-04-22)
- [x] Gör `PantryItem` user-scopad (userId + productId unik per användare).
- [x] Gör matplan user-scopad och filtrera list/upsert/delete per inloggad användare.
- [x] Uppdatera matplanens inventory-jämförelse till användarspecifikt pantry.
- [x] Publicera uppdaterade API-kontrakt innan vidare Flutter-parity för matplan/baslager.
- [x] Migration 20260422130000_user_scope_pantry_meal_plan applicerad.
## Fas 1 - Stabil app-shell (KLAR 2026-04-22)
- [x] Bygg tydlig auth-gate i router.
- [x] Centralisera API-fel (401/403/500) i ett gemensamt lager (`mapErrorToUserMessage`).
- [x] Skapa gemensamma UI-komponenter för loading, empty, error.
- [x] Sätt en enhetlig navigationsstruktur (web först, mobil-redo).
- [x] Lokalisering: ARB-infrastruktur på plats (`flutter_localizations`, `l10n.yaml`, `app_sv.arb`, `synthetic-package: false`, `flutter gen-l10n` i Dockerfile).
- [x] Regressionstest för svenska strängkvalitet tillagd.
## Fas 2 - Auth parity (KLAR 2026-04-22)
- [x] Hårdna loginflödet (tydliga felmeddelanden, retries där relevant).
- [x] Verifiera token-livscykel (reload/hard refresh/logout).
- [x] Implementera automatisk hantering av utgången token (401 -> logout -> login).
## Fas 3 - Recept parity (KLAR 2026-04-22)
- [x] Lista -> detalj -> skapa -> redigera -> ta bort.
- [x] Knyt ihop med parse-markdown-proxy.
- [x] Behåll backend som enda plats för matchning, validering och affärslogik.
## Fas 4 - Inventarie parity (KLAR 2026-04-22)
- [x] Lista med filter/sortering (plats + sort via Riverpod-querystate).
- [x] Skapa och uppdatera inventariepost.
- [x] Konsumtion och konsumtionshistorik.
## Fas 5 - Matplan parity (KLAR 2026-04-22)
- [x] Veckovy med receptval per dag mot user-scopat `GET /api/meal-plan?from=&to=`.
- [x] Portionsjustering per dag.
- [x] Inköpslista och inventariejämförelse mot användarens pantry.
## Fas 6 - Import parity
### 6a — Recept-import
- [x] URL via JSON-body `{ input: string }`.
- [x] Svar: `{ markdown: string, source: 'ica'|'pdf'|'image'|'other', imageUrl?: string }`.
- [x] På lyckat resultat: navigera till `/recipes/create` med markdown-texten förifylld.
### 6b — Kvittoimport (KLAR 2026-05-01)
- [x] Endpoint: `POST /api/receipt-import`
- [x] Läge: filuppladdning, `multipart/form-data`, fält `file`, max 15 MB.
- [x] Svar: `ParsedReceiptItem[]` med fälten `rawName`, `quantity`, `unit`, `suggestedProductId?`, `suggestedProductName?`, `categorySuggestion?`.
- [x] Granskningssteg: checkboxlista med per-rad redigering (produkt, antal, enhet, destination).
- [x] Destination per rad: **Inventarie** eller **Baslager** via SegmentedButton i redigeringsdialogen.
- [x] Inventarie: ny post skapas, eller befintlig post slås ihop (PATCH quantity) med merge-förhandsvisning.
- [x] Baslager: produkt läggs till om den inte redan finns, annars hoppas den över.
- [x] AI-kategorisuggestion visas som chip (grön, `AI: kategori`) för premium-användare.
- [x] Snackbar med separat räkning: skapade/sammanslagna i inventarie + tillagda/redan-i-baslager.
## UI/UX-förbättringar (KLAR 2026-04-22)
- [x] Produktval med bottenark (ProductPickerField) i inventarie/pantry.
- [x] Swipe-för-±1 på inventarielistan (SwipeableInventoryTile med visuell ledtråd).
## Prioriterad plan (ordning)
## Fas 0 - Backend-forarbete for user-scope (KLAR 2026-04-22)
- [x] Gor `PantryItem` user-scopad (userId + productId unik per anvandare).
- [x] Gor matplan user-scopad och filtrera list/upsert/delete per inloggad anvandare.
- [x] Uppdatera matplanens inventory-jamforelse till anvandarspecifikt pantry.
- [x] Publicera uppdaterade API-kontrakt innan vidare Flutter-parity for matplan/baslager.
- [x] Migration 20260422130000_user_scope_pantry_meal_plan applicerad.
## Fas 1 - Stabil app-shell (KLAR 2026-04-22)
- [x] Bygg tydlig auth-gate i router.
- [x] Centralisera API-fel (401/403/500) i ett gemensamt lager (`mapErrorToUserMessage`).
- [x] Skapa gemensamma UI-komponenter for loading, empty, error.
- [x] Satt en enhetlig navigationsstruktur (web forst, mobil-redo).
- [x] Lokalisering: ARB-infrastruktur pa plats (`flutter_localizations`, `l10n.yaml`, `app_sv.arb`, `synthetic-package: false`, `flutter gen-l10n` i Dockerfile).
- [x] Regressionstest for svenska strangkvalitet tillagd.
## Fas 2 - Auth parity (KLAR 2026-04-22)
- [x] Hardna loginflodet (tydliga felmeddelanden, retries dar relevant).
- [x] Verifiera token-livscykel (reload/hard refresh/logout).
- [x] Implementera automatisk hantering av utgangen token (401 -> logout -> login).
## Fas 3 - Recept parity (KLAR 2026-04-22)
- [x] Lista -> detalj -> skapa -> redigera -> ta bort.
- [x] Knyt ihop med parse-markdown-proxy.
- [x] Behall backend som enda plats for matchning, validering och affarslogik.
## Fas 4 - Inventarie parity (KLAR 2026-04-22)
- [x] Lista med filter/sortering (plats + sort via Riverpod-querystate).
- [x] Skapa och uppdatera inventariepost.
- [x] Konsumtion och konsumtionshistorik.
## Fas 5 - Matplan parity (KLAR 2026-04-22)
- [x] Veckovy med receptval per dag mot user-scopat `GET /api/meal-plan?from=&to=`.
- [x] Portionsjustering per dag.
- [x] Inkoplista och inventariejamforelse mot anvandarens pantry.
## UI/UX-förbättringar (KLAR 2026-04-22)
- [x] Produktval med bottenark (ProductPickerField) i inventarie/pantry.
- [x] Swipe-för-±1 på inventarielistan (SwipeableInventoryTile med visuell ledtråd).
## Fas 6 - Import parity
### Analys (2026-04-22)
#### 6a — Recept-import
(2) URL via JSON-body `{ input: string }`.
- Svar: `{ markdown: string, source: 'ica'|'pdf'|'image'|'other', imageUrl?: string }`.
- På lyckat resultat: navigera till `/recipes/create` med markdown-texten förifylld.
- Endpoint: `POST /api/receipt-import`
- Läge: filuppladdning, `multipart/form-data`, fält `file`, max 15 MB,
- Svar: `ParsedReceiptItem[]` med fälten `rawName`, `quantity`, `unit`,
`suggestedProductId?`, `suggestedProductName?`, `categorySuggestion?`.
- På lyckat resultat: granskningssteg där användaren bekräftar/skippar rader
- Komplexitetsgrad: hög — granskningsvyn är det tyngsta steget.
**Nytt paket som krävs:**
- `file_picker: ^8.0.0` — hanterar filval på Flutter web (ger `Uint8List bytes`,
ingen filsökväg). Läggs till i `pubspec.yaml`.
**Fil-/mappstruktur:**
```
flutter/lib/features/import/
domain/
quick_import_result.dart # { markdown, source, imageUrl? }
parsed_receipt_item.dart # { rawName, quantity, unit, ... }
data/
import_repository.dart # API-anrop (multipart + JSON URL-läge)
import_providers.dart # Riverpod-providers
presentation/
import_screen.dart # TabBar: "Recept" | "Kvitto"
recipe_import_tab.dart # Fas 6a — fil + URL, laddningsindikator
**Router och shell:**
- Ny route `/import` inuti `ShellRoute` i `app_router.dart`.
placeras efter "Baslager" och innan "Profil".
- Multipart-uppladdning kan ta 530 s (OCR, LLM) — `LinearProgressIndicator`
med text "Tolkar…" under hela anropet, inte en vanlig spinner.
- Timeout via `http`-klienten: sätt `Duration(seconds: 120)` för import-anrop.
- Nätverks- och serverfel mappas via befintlig `mapErrorToUserMessage`.
**Genomförandeordning:**
1. Lägg till `file_picker` i `pubspec.yaml`.
2. Utöka `CreateRecipeScreen` med `initialMarkdown`-parameter + GoRouter extra-stöd.
3. Bygg `domain/` + `data/` (modeller, repository, providers).
4. Bygg `recipe_import_tab.dart` (fas 6a — enklare).
- [x] Registrera `/import` i router och lägg till nav-destination i AppShell.
- [ ] Verifiera recept-import end-to-end (fil + URL → create-screen).
- [ ] Bygg `presentation/receipt_import_tab.dart` (uppladdning + granskningssteg).
- Adminfunktioner migreras sist for att minimera risk i karnfloden.
1. Verifiera request/response mot befintligt backendkontrakt.
3. Kontrollera felbanor innan UI-polish.
Ingen ad-hoc backendforandring goras for att "fa Flutter att funka".
Backend-andringar for user-scope i pantry/matplan ar explicit beslutade och ska goras kontrollerat forst.
## Kvalitetsgrind (Definition of Done)
En feature ar klar nar allt nedan ar uppfyllt:
2. Auth/rollskydd fungerar (inklusive 401/403).
3. Loading/empty/error ar konsekvent hanterat.
4. Navigation in/ut ur feature fungerar utan specialfall.
5. Smoke-test i testmiljo ar godkant.
## Leveransmodell
- Leverera 1 feature i taget till testdoman.
- Demo och snabb feedback innan nasta feature.
- Hall dubbel drift (Next + Flutter) tills karnfloden ar stabila.
- Flytta trafik gradvis nar parity ar verifierad.
## Nästa konkreta sprint (rekommenderad)
1. Fas 6: Import parity (URL/PDF/bild, robust felhantering).
2. Fas 7: Profil/admin parity.
3. Fortsatt flytt av UI-strängar till ARB (inventarie, pantry, recept).
4. Smoke-test på testdomän och avstämning.
## Tumregel
- Sikta pa funktionell parity forst.
- Pixel-perfect parity tas efter stabil funktion.
## Utförda förbättringar och nästa steg (2026-04-24)
- Navigationslänkar har lagts till mellan recept, inventarie, baslager och matplan för att förenkla användarflödet.
- Efter redigering av recept och konsumtion av inventariepost sker nu automatisk navigering till relevant vy.
- Efter import av recept sker automatisk navigering till receptlistan.
- Receptdetaljvyn har fått förbättrad bakgrundsbildshantering och mjukare scrollning.
- Kodbasen har granskats för att säkerställa att inga absoluta Windows-sökvägar används.
**Nästa steg:**
- Fortsatt användartestning av nya navigationsflöden och insamling av feedback.
- Finslipa UI och tillgänglighet i samband med de nya navigationsmöjligheterna.
- Färdigställ kvittoimport och adminfunktioner enligt plan.
- Lägg till snabbfilter i Produkt-admin: "Visa endast ändrade rader" för inline-kategoribyten (planerad förbättring till nästa pass).
# Nästa steg: Flutter-migrering
Relaterade dokument:
- [README.md](README.md)
- [teknisk_beskrivning_flutter.md](teknisk_beskrivning_flutter.md)
## Mål och prioriteringar för produktion
### Övergripande mål
- **Funktionell parity:** Säkerställa att alla kärnfunktioner är stabila och fungerar som förväntat.
- **Användarupplevelse:** Förenkla onboarding och säkerställa att användare snabbt förstår appens värde.
- **Produktionsklar:** Säkerställa att appen är redo för lansering genom att adressera kritiska buggar och förbättra prestanda.
### Icke-förhandlingsbara ramar
1. Inget ska tas bort eller ändras i `recipe-api` utom explicit beslutade backend-ändringar för användarscope i pantry och matplan.
2. Inget ska tas bort eller ändras i `recipe-frontend`.
3. Migreringen sker i Flutter-spåret som separat klient mot befintliga API-kontrakt.
4. Next-frontend körs parallellt tills Flutter har verifierad parity i kärnflöden.
## Arbetsplan
### Pågående arbete
- **Kvittoimport (Fas 6b):** ✅ Klar (2026-05-01) — granskningssteg, destination-väljare, merge och spara klart.
- **Bildimport:** Säkerställa att containrar är uppdaterade med senaste kod och att diagnostikloggar syns vid felsökning.
- **Adminfunktioner:** Avancerad AI-integration och ytterligare adminfunktioner planeras men är ej migrerade.
### Prioriterade nästa steg
1. ~~Slutför kvittoimport och bulk-spara.~~ ✅ Klart (2026-05-01)
2. Säkerställa robust bildimport och diagnostik.
3. Implementera avancerad AI-integration för produktkategorisering.
4. Utöka adminfunktioner för användarhantering och produktadministration.
5. Förbättra UI/UX för användarflöden, inklusive onboarding och profilhantering.
## Plan för Implementering av Fas 6b
### 1. Slutför Kvittoimport
- **Aktiviteter:**
- Implementera parsers för kvitton (PDF, bildbaserade kvitton).
- Utveckla gränssnitt för att granska importerade kvitton.
- Implementera bulk-spara-funktionalitet för kvitton.
- **Tekniska Detaljer:**
- Använd `pdf-parse` och `tesseract.js` för att extrahera data från kvitton.
- Säkerställa att API-endpoints (`/receipt-import`) hanterar filuppladdning och returnerar strukturerad data.
### 2. Förbättra Bildhantering
- **Aktiviteter:**
- Säkerställa att `downloadAndOptimizeImage` fungerar korrekt i Docker-miljön.
- Implementera robust felhantering och diagnostikloggning för bildimport.
- **Tekniska Detaljer:**
- Använd miljövariabler för att definiera sökvägar för bildlagring.
- Säkerställa att bilder optimeras och lagras korrekt på servern.
### 3. Säkerställa Kompatibilitet med Linux/Ubuntu
- **Aktiviteter:**
- Kontrollera att alla sökvägar är relativa eller konfigurerbara via miljövariabler.
- Säkerställa att Docker-miljön är korrekt konfigurerad för att köra på Ubuntu.
- **Tekniska Detaljer:**
- Använd `path.join()` för att bygga sökvägar på ett plattformsoberoende sätt.
- Säkerställa att `IMAGE_DEST_DIR` är korrekt konfigurerad för Linux/Ubuntu.
### 4. Förbättra API-Integration
- **Aktiviteter:**
- Säkerställa att API-endpoints har korrekt felhantering och tidsgränser.
- Implementera robusta tidsgränser och återförsöksmekanismer för API-anrop.
- **Tekniska Detaljer:**
- Använd `http.Client` med korrekta tidsgränser för API-anrop.
- Implementera återförsöksmekanismer för tillfälliga fel.
## Verifiering och Testning
### 1. Enhets- och Integrationstester
- **Aktiviteter:**
- Skapa enhets- och integrationstester för nya parsers och API-endpoints.
- Säkerställa att alla tester körs i Docker-miljön.
- **Tekniska Detaljer:**
- Använd `flutter test` för att köra enhetstester.
- Använd `jest` eller `supertest` för att testa API-endpoints.
### 2. Manuell Testning
- **Aktiviteter:**
- Manuell testning av kvittoimport och bulk-spara-funktionalitet.
- Säkerställa att bildhantering fungerar korrekt i Docker-miljön.
- **Tekniska Detaljer:**
- Använd Postman eller liknande verktyg för att testa API-endpoints.
- Säkerställa att gränssnittet för kvittoimport fungerar som förväntat.
## Slutsats
För att slutföra Fas 6b krävs implementering av parsers för kvitton, förbättringar av bildhantering, och säkerställande av kompatibilitet med Linux/Ubuntu. En robust API-integration och omfattande testning är avgörande för att säkerställa att importfunktionen fungerar som förväntat i produktion.
- `README.md` - anvandarperspektiv.
- `teknisk_beskrivning_flutter.md` - teknisk referens.
- `../NEXT_STEPS.md` - overgripande roadmap for hela produkten.
+49 -427
View File
@@ -1,456 +1,78 @@
# Teknisk Beskrivning - Flutter Frontend
Viktigt att komma ihåg vid implementering av nya funktioner och kodning är att inte använda Windows-sökvägar. Använd inte `c:/dev/recipe-app/...` eftersom bygg- och testmiljön är på en remote Ubuntu-server. Utveckling sker lokalt och test samt drift sker på remote server. Säkerställ att inga absoluta Windows-sökvägar används i koden, för att stödja bygg och drift på Linux/Ubuntu.
Detta dokument ar teknisk referens for systemadministratorer och programmerare.
Mallet ar en sammanhallen teknisk sanning utan duplicerade roadmap- eller anvandarsektioner.
## Senaste ändringar (2026-05-01, session 3)
## Dokumentstatus (2026-05-03)
### Separering av AI-chip och produktsuggestions-chip
- Fokus: arkitektur, drift och kanda gotchas.
- User guide finns i `README.md`.
- Planering finns i `next_steps_flutter.md`.
**Problem:** AI-chipet visade felaktigt produktnamnsförslag som om de vore kategoriförslag, vilket skapade förvirring när användaren såg "AI-förslag: Dryck Multivitamin" (ett produktnamn) istället för en kategori.
## Viktigt om miljo
**Lösning:**
- **Blå chip** "Förslag: [produktnamn]" — när systemet hittat en trolig produkt via ordmatchning (inga AI-anrop inblandade). Klick väljer produkten.
- **Grön chip** "AI-kategori: [kategoriväg]" — när AI:n föreslagit en kategori från databasen. Klick öppnar produktpickern filtrerad på den kategorin.
Anvand inte absoluta Windows-sokvagar i kod eller scripts.
Bygg och drift sker pa Linux/Ubuntu i containeriserad miljo.
**Kodändringar:**
- `aiLabel` beräknas enbart från `categorySuggestionName`/`categorySuggestionPath` (kategoriförslag).
- Nytt fält `suggestedProductLabel` för produktsuggestions-chip.
- Separata villkor och UI-block för de två chipen i `_EditDialogState.build()`.
## Senaste tekniska tillagg
### Produktnamns-normalisering
**Problem:** Kvittonamn i VERSALER (t.ex. "APRIKOSMARMELAD 284G") såg oprofessionella ut i UI:n.
**Lösning:** Ny funktion `_normalizeProductName()` som tillämpar smarta regler:
- Token med `/` (förkortningar) lämnas i versaler: `KY/KAL/LE/TO`
- Token som börjar med siffra (mängd/storlek) görs till gemener: `284G``284g`, `12X85G``12x85g`
- Övriga token: första bokstav versal, resten gemen: `APRIKOSMARMELAD``Aprikosmarmelad`, `JUICE TROPISK``Juice Tropisk`
**Implementering:**
- Top-level-funktion i `receipt_import_tab.dart`
- Tillämpas när "Ny produkt"-fältet prefylls: `_newProductNameCtrl.text = _normalizeProductName(widget.current.productName ?? widget.item.rawName)`
### AI-kategorisering — validering i backend
**Problem:** Användaren rapporterade att AI föreslog kategorin "Dryck Multivitamin", som inte fanns i databasen.
**Undersökning:**
- Backend-AI:n (`ai.service.ts`) validerar redan att `categoryId` finns i `categories`-listan och faller tillbaka på "Övrigt" om inte.
- Problemet var att frontend visade produktnamnsförslag som om de vore kategoriförslag.
**Lösning:**
- Separering av chipen (se ovan) gör det tydligt att AI-kategoriförslag alltid kommer från databasen.
---
## Senaste ändringar (2026-05-01, session 2)
### Tvåstegs-picker: Kategori → Produkt
Problembeskrivning: AI:n kan föreslå en kategori men produktpickern sökte bara på produktnamn, vilket gav nollresultat när kategorinamnet matades in som söktext. Lösningen är ett nytt separat arbetsflöde för produktval via kategoriträdet.
**Ny widget: `lib/core/ui/category_then_product_picker.dart`**
`CategoryThenProductPicker.show()` är en statisk metod som orkestrerar hela flödet:
1. **Steg 1 — Välj kategori:** Öppnar ett bottenark (`_CategoryPickerSheet`) med hela kategoriträdet (L1 → L2 → L3). Trädet är sökbart — sökfältet filtrerar till matchande lövnoder och visar hela sökvägen som brödsmula (t.ex. *Mat > Frukt & Grönt > Äpplen*).
2. **Steg 2 — Välj produkt:** Öppnar `ProductPickerField.showSheet()` filtrerad på alla produkter som tillhör den valda kategorin **eller någon av dess ättlingar** (L1 samlar alltså in L2- och L3-produkter rekursivt via `_collectIds()`).
**Inbyggt AI-stöd:** Om `preselectedCategoryId` skickas in (från AI-förslaget) hoppar `show()` direkt till steg 2 — kategoriträdet visas aldrig. Om kategorin inte hittas i trädet faller den tillbaka till att visa trädet.
**Fallback för L1/L2-noder:** Mellanliggande noder (L1, L2) som inte är löv har en liten "Välj"-knapp till höger i raden. Klick på kategorinamnet/pilen expanderar/kollapsar som vanligt; klick på "Välj" väljer kategorin och öppnar produktpickern direkt.
**Trädknapp i redigeringsdialogen:** Bredvid det vanliga produktsökfältet finns nu en `OutlinedButton` med trädikon (🌳). Klick öppnar tvåstegs-pickern utan AI-förval.
### Skapa ny privat produkt i importflödet
Om inget i produktlistan matchar kvittoradens vara kan användaren skapa en egen produkt direkt från produktpickern.
**Flöde:**
1. Välj kategori (via trädet eller AI-direkthopp).
2. Produktpickern visas med en **"Skapa ny"**-knapp i rubrikraden.
3. En enkel dialog öppnas med ett namnfält (förfyllt med söksträngen om sådan finns).
4. Vid bekräftelse anropas `POST /products/private` — produkten skapas som privat och user-scopad.
5. Den nya produkten läggs till i den lokala produktlistan och väljs direkt.
**Privata produkter — arkitektur:**
| | Globala produkter | Privata produkter |
|---|---|---|
| Endpoint (hämta) | `GET /products` | `GET /products/mine` |
| Endpoint (skapa) | `POST /products` (admin) | `POST /products/private` (alla inloggade) |
| Synlighet | Alla användare | Bara ägaren |
| `isPrivate` | `false` | `true` |
| `normalizedName` | `normalize(name)` | `private:{userId}:{normalize(name)}` |
| Kategori | Global (admin-only) | Väljs vid skapandet, global kategori |
Importfliken laddar globala och privata produkter parallellt via `Future.wait` och slår ihop dem till en gemensam `_products`-lista. Den lokala `_localProducts`-listan i `_EditDialogState` utökas om en ny produkt skapas under dialogen, utan att en ny nätverksanrop krävs.
### Redigeringsdialog — sammanfattning av alla fält
`_EditDialog` i `receipt_import_tab.dart` innehåller nu:
- **AI-chip (grön):** Klickbar. Om AI föreslog en matchad produkt direkt → väljer den. Om AI föreslog en kategori → öppnar produktpickern filtrerad på den kategorin (utan att visa trädet).
- **Destinationsväljare:** `SegmentedButton` — Inventarie eller Baslager.
- **Produktfält + trädknapp:** `ProductPickerField` (fritext-sökning) + knapp för att öppna tvåstegs-picker.
- **Antal/Enhet:** Visas bara vid Inventarie-destination.
### Designregel bekräftad: User-scope
User-scope-principen dokumenterades formellt i båda tekniska beskrivningarna (2026-05-01). Privata produkter är det första exemplet på mönstret för resurser som är varken globala (alla ser dem) eller fullt user-owned (bara ägaren ser dem):
- `Product.isPrivate = true` + `Product.ownerId = userId`
- `normalizedName`-prefix undviker databaskollision med globala produkter
- Migration: `20260501000000_add_product_is_private
## Senaste ändringar (2026-05-01, session 1)
**Kvittoimport Fas 6b — komplett:**
- Granskningssteg i `receipt_import_tab.dart` med per-rad checkbox, redigeringsdialog och destinationsväljare.
- Destinationsväljare: **Inventarie** eller **Baslager** via `SegmentedButton<_Destination>` i redigeringsdialogen.
- Vid vald destination **Baslager** dolt antal/enhet-fält med informationstext.
- Inventarie-flöde: skapar ny post eller slår ihop (PATCH quantity) med befintlig post. Förhandsvisning av ny mängd visas i listan.
- Baslager-flöde: lägger till produkten om den inte redan finns. Befintliga baslagerprodukter visas med orange chip.
- Snackbar visar separat räkning: skapade/sammanslagna i inventarie + tillagda/hoppa-över i baslager.
- `_loadInventory()` laddar nu inventarie och baslager i parallell via `Future.wait`.
- AI-kategorisuggestion chip (grön) visas för premium-användare i granskningslistan.
## Senaste ändringar (2026-04-25)
**Arkitektur- och UX-förbättringar:**
- Grid-vy för recept: Kolumnval (2/4/6/8) via ikon i AppShell, med Riverpod-provider och SharedPreferences.
- RecipesScreen är nu body-only, ingen egen Scaffold/AppBar.
- AppShell visar grid-ikon endast på /recipes.
- Buggfix: Produktväljaren i pantry/inventarie (ProductPickerField) — bottenark implementeras.
- Kodkvalitet: Inga absoluta Windows-sökvägar.
**Tekniska förbättringar:**
- Förbättrad bildhantering med normalisering av URL:er, fallback och diagnostikloggning.
- Robustare importflöde för recept med stöd för PDF, bild och ICA-länkar.
- User-scope för pantry och matplan: Alla baslager- och matplansdata är nu per användare.
## Syfte och mål
- Isolerad Flutter-baserad frontend i separat Docker-service.
- Web först, men med arkitektur som kan återanvändas för Android/iOS.
- Stegvis migrering av funktioner från befintlig Next.js-frontend.
- Sessionpersistens i klienten for pagande kvittoimport.
- Forbattrad inferens for antal/forpackning (inklusive uttryck som `2st`).
- Tydlig separation i UI mellan AI-kategoriforslag och produktforslag.
- Ingen server-side persistens introducerad for kvittosession.
## Arkitektur
### Lager
- **Presentation:** Skärmar och widgets i `flutter/lib/features/*/presentation`.
- **State/Application:** Riverpod providers/notifiers i `flutter/lib/features/*/data`.
- **Data/API:** `ApiClient` i `flutter/lib/core/api`.
- **Platform abstraction:** Token storage interface i `flutter/lib/core/platform`.
- Presentation: `flutter/lib/features/*/presentation`
- State/Application: Riverpod providers/notifiers i `flutter/lib/features/*/data`
- Data/API: `flutter/lib/core/api`
- Platform abstraction: token storage i `flutter/lib/core/platform`
### Routing
- GoRouter i [flutter/lib/core/router/app_router.dart](flutter/lib/core/router/app_router.dart).
- Nuvarande routes:
- `/login` — loginskärm
- `/recipes` — receptlista (ShellRoute med AppShell)
- `/recipes/create` — nytt recept, utanför ShellRoute
- `/recipes/:id` — receptdetalj, utanför ShellRoute
- `/recipes/:id/edit` — redigera recept, utanför ShellRoute
- `/profile` — profil (ShellRoute med AppShell)
- `/recipes/create` måste vara listad före `/recipes/:id` i routelistan för att undvika konflikt.
- Detaljsidor (detalj, skapa, redigera) ligger utanför ShellRoute för att få full-screen med automatisk back-knapp.
- GoRouter i `flutter/lib/core/router/app_router.dart`
- ShellRoute for huvudnavigation
- Fullscreen-routes for skapa/redigera/detalj
### Auth
- Login endpoint: `POST /api/auth/login`.
- Login via `POST /api/auth/login`
- Token-falt: `accessToken`
- Auth-gate i router med redirect logik
- `guardedApiCall()` hanterar logout vid 401
## Kända fallgropar och API-gotchas
## API- och kontraktsprinciper
### Designregel: User-scope vid ny funktionalitet
- Flutter foljer backend-kontrakt, ingen lokal speciallogik for matchning.
- 2xx-svar accepteras generellt i importanrop (inte hardkodning till enbart 200).
- Kvittoimport och receptimport ar separata floden med olika svarstyper.
> **Regel:** Kontrollera alltid om ny data tillhör en specifik användare. Om ja — data **måste** ha user-scope i backend (`userId`-fält, filtrering i service) och Flutter-klienten får **inte** returnera/visa andra användares data.
>
> Resurser och deras scope:
> | Resurs | Scope |
> |---|---|
> | Produkter (globala) | Publik — `GET /products` |
> | Produkter (privata) | Per användare — `GET /products/mine`, `POST /products/private` |
> | Kategorier | Global (admin-only att skapa) |
> | Inventarie | Per användare — alltid filtrera på `userId` |
> | Baslager | Per användare — alltid filtrera på `userId` |
> | Matplan | Per användare — alltid filtrera på `userId` |
> | Recept | Per användare (ägare) eller delat |
>
> I Flutter: ladda user-scopad data med token, kombinera globala och egna produktlistor vid behov.
## Kvittoimport - tekniska noter
### Flutter Web och PDF MIME-typ
- Flutter Web skickar PDF-filer med MIME-typ `application/octet-stream` istället för `application/pdf`.
- Backend (`receipt-import.controller.ts`) måste tillåta båda: `application/pdf` och `application/octet-stream` i `ALLOWED_MIMES`.
- Symptom om detta saknas: HTTP 400 "Otillåten filtyp. Använd JPEG, PNG, WebP eller PDF."
### NestJS @Post() returnerar HTTP 201 som standard
- NestJS returnerar 201 (Created) för alla `@Post()`-endpoints som standard.
- Flutter-klienten (`ImportRepository`) accepterar nu alla 2xx-svar (`statusCode < 200 || statusCode >= 300`).
- Alternativt: lägg till `@HttpCode(200)` på backend-controllern för att returnera 200.
- Detta gjordes i `receipt-import.controller.ts` (2026-04-30).
### Kvittoimport — backend och arkitektur
- `/receipt-import` hanteras av en **dedikerad** `ReceiptImportController` och `ReceiptImportService`, **inte** av `QuickImportController`.
- `ReceiptImportService` använder **Mistral AI** för att parsa kvitton till strukturerade `ParsedReceiptItem[]` direkt — inget markdown.
- Svaret från `/receipt-import` är en array av `ParsedReceiptItem`, inte `{ markdown: "..." }`.
- `{ markdown: "..." }` är svaret från `/quick-import` (receptimport) — inte kvittoimport.
## Övrigt
- **Kvittoimport (Fas 6b):** ✅ Klar (2026-05-01) — granskningssteg, destination-väljare, merge och spara till inventarie/baslager.
- **Bildimport:** Säkerställa att containrar är uppdaterade med senaste kod och att diagnostikloggar syns vid felsökning.
- **Adminfunktioner:** Avancerad AI-integration och ytterligare adminfunktioner planeras men är ej migrerade.
## Syfte och mål
- Isolerad Flutter-baserad frontend i separat Docker-service.
- Web först, men med arkitektur som kan återanvändas för Android/iOS.
- Stegvis migrering av funktioner från befintlig Next.js-frontend.
## Relaterade dokument
- [next_steps_flutter.md](next_steps_flutter.md)
- [README.md](README.md)
- [teknisk_beskrivning.md](../TEKNISK_BESKRIVNING.md) (för backend-kontext)
## Arkitektur
### Lager
- **Presentation:** Skärmar och widgets i `flutter/lib/features/*/presentation`.
- **State/Application:** Riverpod providers/notifiers i `flutter/lib/features/*/data`.
- **Data/API:** `ApiClient` i `flutter/lib/core/api`.
- **Platform abstraction:** Token storage interface i `flutter/lib/core/platform`.
### Routing
- GoRouter i [flutter/lib/core/router/app_router.dart](flutter/lib/core/router/app_router.dart).
- Nuvarande routes:
- `/login` — loginskärm
- `/recipes` — receptlista (ShellRoute med AppShell)
- `/recipes/create` — nytt recept, utanför ShellRoute
- `/recipes/:id` — receptdetalj, utanför ShellRoute
- `/recipes/:id/edit` — redigera recept, utanför ShellRoute
- `/profile` — profil (ShellRoute med AppShell)
- `/recipes/create` måste vara listad före `/recipes/:id` i routelistan för att undvika konflikt.
- Detaljsidor (detalj, skapa, redigera) ligger utanför ShellRoute för att få full-screen med automatisk back-knapp.
### Auth
- Login endpoint: `POST /api/auth/login`.
- Backend kontrakt använder `username` + `password`.
- Token-fält i svar: `accessToken`.
- Token lagras via `ITokenStorage` (web implementation med SharedPreferences).
- Auth-gate i router: utloggad användare redirectas till `/login`, inloggad redirectas från `/login` till `/recipes`.
- Splash-skärm (`/`) visas medan auth-state läses från storage vid app-start.
- `guardedApiCall()` i `flutter/lib/core/api/guarded_api_call.dart` hanterar automatisk logout vid 401.
### API-lager
- `ApiClient` i `flutter/lib/core/api/api_client.dart` exponerar: `getJson`, `postJson`, `patchJson`, `putJson`, `deleteJson`.
- Centraliserad HTTP-felklassning: 401 -> `ApiErrorType.unauthorized`, 403 -> `forbidden`, 5xx -> `server`, nätverksfel -> `network`.
- `ApiException` i `flutter/lib/core/api/api_exception.dart` är den enda feltypen som propageras från repositories.
- `mapErrorToUserMessage(error, context)` i `flutter/lib/core/api/api_error_mapper.dart` översätter fel till lokaliserade användarmeddelanden. Tar numera `BuildContext` som andra argument för att hämta korrekt språk från `AppLocalizations`.
### Lokalisering
- Flutter `flutter_localizations` + `intl` tillagda i `pubspec.yaml` med `generate: true`.
- Konfigurationsfil: [flutter/l10n.yaml](flutter/l10n.yaml) med `synthetic-package: false`.
- Källsträngar i [flutter/lib/l10n/app_sv.arb](flutter/lib/l10n/app_sv.arb) och [flutter/lib/l10n/app_en.arb](flutter/lib/l10n/app_en.arb).
- Genererade filer hamnar i `flutter/lib/l10n/generated/` och checkas inte in.
- Hjälpare `context.l10n` i [flutter/lib/core/l10n/l10n.dart](flutter/lib/core/l10n/l10n.dart).
- `MaterialApp.router` konfigurerad med `localizationsDelegates`, `supportedLocales` och `locale: const Locale('sv')`.
- Dockerfilen kör `flutter gen-l10n` innan `flutter build web` för att generera Dart-koden i containerbygget.
- Regressionstest i [flutter/test/core/swedish_strings_regression_test.dart](flutter/test/core/swedish_strings_regression_test.dart) misslyckas om vanliga ASCII-varianter (Välj, Lägg, Försök, etc.) dyker upp igen i `lib/`.
#### Användning av lokalisering
För att lägga till en ny lokaliserad sträng:
1. Lägg till nyckeln i `app_sv.arb` (och `app_en.arb`).
2. Kör `flutter gen-l10n` lokalt (eller låt Docker-bygget göra det).
3. Använd `context.l10n.dinNyckel` i widgetkoden.
För felsträngar från API: använd alltid `mapErrorToUserMessage(error, context)` — lägg inte in hårdkodade strängar.
## Vad som är gjort
### Infrastruktur
- Ny compose override: [compose.flutter.yml](compose.flutter.yml).
- Ny Flutter-service: `recipe-flutter`.
- Service ansluten till nätverk:
- `recipe-internal` (backend access)
- `proxy` (external Caddy reachability)
- Flutter-container serverar web build via intern Caddy.
- Exponering via extern Caddy med site `test.gynther.se` -> `recipe-flutter:5000`.
- API-anrop går same-origin via `/api` och proxas internt till `recipe-api:8080`.
### Inventarie (2026-04-22)
- Filtrering per plats (alla/kyl/frys/skåfferi) via `inventoryLocationFilterProvider`.
- Sortering (namn A-Ö, bäst före stigande/fallande) via `inventorySortFilterProvider`.
- Riverpod-query (`InventoryQuery`) skickar `location` och `sort` som queryparametrar till backenden.
- Alla felmeddelanden går via `mapErrorToUserMessage(error, context)`.
### Baslager/Pantry (2026-04-22)
- Pantry-produkter grupperas nu på kategori utifrån backend-relationen `categoryRef` (rekursiv `parent`-kedja -> `categoryPath`), med fallback till legacy `product.category` och sist `Övrigt`.
- `PantryProduct` har `categoryId` och `categoryPath` som parsas från API-svaret.
### Backend: User-scope för pantry och matplan (2026-04-22)
- `PantryItem` och `MealPlanEntry` är nu user-scopade i Prisma-schemat.
- `pantry`-controller/service filtrerar alltid per `userId` från JWT.
- `meal-plan`-controller/service filtrerar alltid per `userId`; `inventoryCompare` använder inloggad användares pantry.
- Migration: `20260422130000_user_scope_pantry_meal_plan` applicerad på server.
- Next.js-frontenden krävde inga funktionella ändringar (förfrågningar går redan via auth-proxy).
## Arkitektur
### Lager
- Presentation: skarmar och widgets i `flutter/lib/features/*/presentation`.
- State/Application: Riverpod providers/notifiers i `flutter/lib/features/*/data`.
- Data/API: `ApiClient` i `flutter/lib/core/api`.
- Platform abstraction: token storage interface i `flutter/lib/core/platform`.
### Routing
- GoRouter i [flutter/lib/core/router/app_router.dart](flutter/lib/core/router/app_router.dart).
- Nuvarande routes:
- `/login` — loginskarm
- `/recipes` — receptlista (ShellRoute med AppShell)
- `/recipes/create` — nytt recept, utanfor ShellRoute
- `/recipes/:id` — receptdetalj, utanfor ShellRoute
- `/recipes/:id/edit` — redigera recept, utanfor ShellRoute
- `/profile` — profil (ShellRoute med AppShell)
- `/recipes/create` maste vara listad fore `/recipes/:id` i routelistan for att undvika konflikt.
- Detaljsidor (detalj, skapa, redigera) ligger utanfor ShellRoute for att fa full-screen med automatisk back-knapp.
### Auth
- Login endpoint: `POST /api/auth/login`.
- Backend kontrakt anvander `username` + `password`.
- Token-falt i svar: `accessToken`.
- Token lagras via `ITokenStorage` (web implementation med SharedPreferences).
- Auth-gate i router: utloggad anvandare redirectas till `/login`, inloggad redirectas fran `/login` till `/recipes`.
- Splash-skarm (`/`) visas medan auth-state lases fran storage vid app-start.
- `guardedApiCall()` i `flutter/lib/core/api/guarded_api_call.dart` hanterar automatisk logout vid 401.
### API-lager
- `ApiClient` i `flutter/lib/core/api/api_client.dart` exponerar: `getJson`, `postJson`, `patchJson`, `putJson`, `deleteJson`.
- Centralicerad HTTP-felklassning: 401 -> `ApiErrorType.unauthorized`, 403 -> `forbidden`, 5xx -> `server`, natverksfel -> `network`.
- `ApiException` i `flutter/lib/core/api/api_exception.dart` ar den enda feltypen som propageras fran repositories.
- `mapErrorToUserMessage(error, context)` i `flutter/lib/core/api/api_error_mapper.dart` oversatter fel till lokaliserade anvandarmedddelanden. Tar numera `BuildContext` som andra argument for att hämta korrekt sprak fran `AppLocalizations`.
### Lokalisering (2026-04-22)
- Flutter `flutter_localizations` + `intl` tillagda i `pubspec.yaml` med `generate: true`.
- Konfigurationsfil: [flutter/l10n.yaml](flutter/l10n.yaml) med `synthetic-package: false`.
- Kallstrangar i [flutter/lib/l10n/app_sv.arb](flutter/lib/l10n/app_sv.arb) och [flutter/lib/l10n/app_en.arb](flutter/lib/l10n/app_en.arb).
- Generade filer hamnar i `flutter/lib/l10n/generated/` och checkas inte in.
- Hjalpare `context.l10n` i [flutter/lib/core/l10n/l10n.dart](flutter/lib/core/l10n/l10n.dart).
- `MaterialApp.router` konfigurerad med `localizationsDelegates`, `supportedLocales` och `locale: const Locale('sv')`.
- Dockerfilen kor `flutter gen-l10n` innan `flutter build web` for att generera Dart-koden i containerbygget.
- Regressionstest i [flutter/test/core/swedish_strings_regression_test.dart](flutter/test/core/swedish_strings_regression_test.dart) failar om vanliga ASCII-varianter (Valj, Lagg, Forsok, etc.) dyker upp igen i `lib/`.
#### Anvandning av lokalisering
For att lagga till en ny lokaliserad strang:
1. Lagg till nyckeln i `app_sv.arb` (och `app_en.arb`).
2. Kör `flutter gen-l10n` lokalt (eller lat Docker-bygget gora det).
3. Anvand `context.l10n.dinNyckel` i widgetkoden.
For felstrangar fran API: anvand alltid `mapErrorToUserMessage(error, context)` — lagg inte in hardkodade strängar.
### Recipes
- `GET /api/recipes` — receptlista.
- `GET /api/recipes/:id` — receptdetalj inkl. ingredienser.
- `POST /api/recipes` — skapa recept.
- `PATCH /api/recipes/:id` — uppdatera recept (OBS: PATCH, inte PUT).
- `DELETE /api/recipes/:id` — ta bort recept (returnerar 204, ingen body).
- `POST /api/recipes/parse-markdown` — tolka Markdown, returnerar ParsedRecipe med ingrediensforslagslistor.
- Flutter Recipe-model: `name`-fallback till `title`, null-safe parsing av Decimal-strang till double.
### Gemensamma UI-komponenter
- `LoadingStateView`, `EmptyStateView`, `ErrorStateView` i `flutter/lib/core/ui/async_state_views.dart`.
- `AppShell` i `flutter/lib/core/ui/app_shell.dart`: responsiv NavigationRail (bred) / NavigationBar (smal), delad AppBar med logout.
## Kända API-fallgropar (viktigt!)
> **Regel:** Kontrollera alltid HTTP-metod i [TEKNISK_BESKRIVNING.md i /recipe-app] innan en ny repository-metod implementeras.
| Operation | Korrekt metod | Fel som gjorts |
|-------------------------|-----------------------------|------------------------------|
| Uppdatera recept | `PATCH /api/recipes/:id` | `PUT` — ger 404 |
| Uppdatera inventariepost| `PATCH /api/inventory/:id` | Använd PATCH |
| Uppdatera matplan | `POST /api/meal-plan` (upsert) | Ingen PUT/PATCH |
Generell regel: NestJS-backenden använder `PATCH` för partiella uppdateringar, inte `PUT`. `PUT` exponeras inte på några resurser i detta projekt.
- Granskningsflode med radredigering och destination (inventarie/baslager).
- Produktval stoder tradbaserat kategori -> produkt-flode.
- AI-kategorihint ar endast ett forslag; slutanvandaren validerar i granskningssteget.
## Drift och deploy
### Build/run
- Build argument i compose: `API_BASE_URL=/api`.
- Build command:
- `docker compose -f compose.yml -f compose.flutter.yml build recipe-flutter`
- Run command:
- `docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter`
### Rekommenderat kommandomönster
För att minska risken för fel startordning eller missförstånd mellan huvudappen och Flutter-spåret:
**När huvudappen ska vara uppe:**
- `docker compose up -d recipe-db recipe-api recipe-frontend`
**När Flutter-klienten ska vara uppe:**
- `docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter`
**När både huvudappen och Flutter testas parallellt:**
1. Starta huvudappen med `compose.yml`.
2. Starta sedan Flutter med override-filen `compose.flutter.yml`.
Viktigt:
- `docker compose build ...` bygger bara image.
- `docker compose up -d ...` krävs alltid för att containern faktiskt ska starta.
### Bygg och start (Flutter)
```bash
docker compose -f compose.yml -f compose.flutter.yml build recipe-flutter
docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter
```
### Viktiga verifieringar
- Compose merge valid:
- `docker compose -f compose.yml -f compose.flutter.yml config`
- Container reachable from external Caddy:
- `docker exec caddy wget -S -O- http://recipe-flutter:5000`
- Public endpoint:
- `curl -I https://test.gynther.se`
- Compose merge: `docker compose -f compose.yml -f compose.flutter.yml config`
- Reachability via proxy/Caddy
- Runtime-loggar for importfloden vid felsokning
## Viktiga beslut
- `compose.yml` lämnas orörd; Flutter ligger i separat override-fil.
- Flutter-web använder same-origin API (`/api`) för att undvika mixed-content.
- Intern Caddy i Flutter-container hanterar static hosting + `/api` proxy.
- Feature migration sker stegvis enligt [next_steps_flutter.md](next_steps_flutter.md).
## Kanda fallgropar
## Kända fallgropar
- Om `recipe-flutter` inte är i `proxy` nätverket blir det 502 från extern Caddy.
- Om webbläsaren visar gammal JS kan gamla API-URL:er leva kvar i cache/service worker.
- Login med e-post fungerar inte om backend förväntar sig användarnamn.
- `recipe-flutter` kan stoppas av `docker compose down --remove-orphans` om kommandot körs utan override-filen och Flutter-spåret tidigare varit uppe.
- En orphan-varning för `recipe-flutter` är normalt förväntad när man kör huvudappen med bara `compose.yml`; det betyder inte att backend eller Prisma är trasiga.
- PDF-mime kan komma som `application/octet-stream` i Flutter Web.
- Orphan-varning ar normal nar huvudstack och Flutter-stack kors separat.
- Cache/service worker kan visa gammal frontend efter deploy.
### Orphan-varning i praktiken
## Relaterade dokument
Om du ser en varning om orphan-containers under arbete med huvudappen betyder det oftast att `recipe-flutter` tidigare startats via:
- `docker compose -f compose.yml -f compose.flutter.yml up -d recipe-flutter`
och att du nu kör ett kommando som bara använder `compose.yml`.
Detta är normalt och ofarligt så länge du vet vilken stack du avser att köra.
Om `test.gynther.se` slutar svara efter städning med `--remove-orphans`, starta om Flutter-spåret med:
- `docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter`
---
## Nyheter och förbättringar (2026-04-22)
- **User-scope för pantry och matplan** — Flutter-klienten använder nu user-scopade endpoints för baslager och matplan. JWT används för filtrering i alla anrop.
- **Robust bildimport** — Bild-URL normaliseras och skickas hela vägen till UI. Flutter hanterar både markdown och bild-url vid import.
- **Importflöde** — Quick-import och receipt-import har förbättrats med robust multipart-hantering, timeout, och felhantering. Prefill av markdown och bild-url fungerar i Flutter.
- **Flutter-parity** — Matplan, inventarie, baslager och receptflöden är nu fullt migrerade till Flutter med user-scope och robust felhantering.
- **Felsökningslogg** — Se `../IMPORT_IMAGE_DEBUG_2026-04-22.md` för detaljerad felsökningshistorik kring bildimport och importflöde.
### Kända begränsningar
- Kvittoimport (Fas 6b) är påbörjad men granskningssteg och bulk-spara återstår.
- Bildimport kräver att containrar är uppdaterade med senaste kod — kontrollera att diagnostikloggar syns vid felsökning.
- Vissa adminfunktioner och avancerad AI-integration är planerade men ej migrerade.
## Nyheter och tekniska förbättringar (2026-04-24)
- **Navigationsflöden:**
- Navigationslänkar har lagts till mellan recept, inventarie, baslager och matplan för att förbättra användarupplevelsen och minska antalet klick.
- Efter redigering av recept och konsumtion av inventariepost sker nu automatisk navigering till relevant vy.
- Efter import av recept sker automatisk navigering till receptlistan.
- **UX och UI:**
- Receptdetaljvyn har fått förbättrad bakgrundsbildshantering och mjukare scrollning.
- **Plattformsoberoende kod:**
- Genomgång av kodbasen för att säkerställa att inga absoluta Windows-sökvägar används, vilket gör projektet robust för Linux/Ubuntu-baserad bygg- och driftmiljö.
Se även README.md och next_steps_flutter.md för mer detaljer om användarflöden och leveransplan.
- `README.md` - anvandarguide.
- `next_steps_flutter.md` - aktiv planering.
- `../TEKNISK_BESKRIVNING.md` - backend/systemovergripande teknik.