feat(docs): update NEXT_STEPS, README, and technical descriptions with recent improvements and known limitations

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-04-22 22:19:04 +02:00
parent 71bc162015
commit 2411906682
7 changed files with 174 additions and 136 deletions
+104
View File
@@ -0,0 +1,104 @@
# Import Image Debug Log (2026-04-22)
## Kontext
Målet var att få med receptbild vid URL-import (exempel: ICA-länk) i både Next-frontend och Flutter.
## Verifierat läge just nu
- Backend `quick-import` lyckas hämta och spara bild:
- Loggar visar: `Bild optimerad och sparad: /images/<uuid>.jpg`
- Bild saknas ändå i slutresultatet i UI efter import/spara.
## Viktiga fynd
1. Ursprungligt problem i Next-importflödet:
- Endast `prefilled_markdown` sparades i sessionStorage.
- `prefilled_image_url` saknades.
- Fixat i båda importvägar:
- `frontend/app/recipes/import/ImportFilePage.tsx`
- `frontend/app/import/ImportTabsClient.tsx`
2. Flutter-flödet tappade `imageUrl` i router-extra:
- Extra skickades först som bara markdown.
- Fixat så både markdown + imageUrl skickas och läses robust.
3. Backend förbättringar gjorda:
- Robustare JSON-LD-iterering i parsers (alla script-block, inte bara första).
- Normalisering av bild-URL (stöd för `//...` och relativa URL:er).
- `imageWarning` tillagt i quick-import-svar.
- Fallback till extern URL om lokal nedladdning misslyckas.
- Recept-delete raderar nu lokal bildfil för `/images/...`.
4. Indikation att server kan köra äldre build:
- Nya diagnostikloggar syntes inte i de delade loggutdragen.
- Trolig orsak: containrar ej uppdaterade med senaste kod.
## Filer som ändrats under passet
### Flutter
- `flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart`
- `flutter/lib/features/inventory/presentation/inventory_screen.dart`
- `flutter/lib/core/ui/product_picker_field.dart`
- `flutter/lib/features/import/domain/quick_import_result.dart`
- `flutter/lib/features/import/data/import_repository.dart`
- `flutter/lib/features/import/data/import_providers.dart`
- `flutter/lib/features/import/presentation/recipe_import_tab.dart`
- `flutter/lib/features/import/presentation/import_screen.dart`
- `flutter/lib/features/recipes/presentation/create_recipe_screen.dart`
- `flutter/lib/core/router/app_router.dart`
- `flutter/lib/core/ui/app_shell.dart`
- `flutter/pubspec.yaml`
### Backend
- `backend/src/quick-import/quick-import.service.ts`
- `backend/src/quick-import/parsers/ica.parser.ts`
- `backend/src/quick-import/parsers/generic.parser.ts`
- `backend/src/common/utils/download-image.ts`
- `backend/src/recipes/recipes.service.ts`
### Next frontend
- `frontend/app/recipes/import/ImportFilePage.tsx`
- `frontend/app/import/ImportTabsClient.tsx`
- `frontend/app/api/quick-import-proxy/route.ts`
- `frontend/app/recipes/write/WriteRecipePage.tsx`
## Diagnostikloggar tillagda (att leta efter)
### Backend (`recipe-api`)
- `Bildkandidat från parser: ...`
- `Normaliserad bild-URL: ...`
- `Incoming imageUrl from client: ...`
- `Final imageUrl persisted to DB: ...`
### Frontend server (`recipe-frontend`)
- `[QuickImportProxy] backend response ...`
### Browser console
- `[ImportFilePage:*] quick-import response ...`
- `[ImportTabsClient:*] quick-import response ...`
- `[WriteRecipePage] prefilled values ...`
- `[WriteRecipePage] create payload imageUrl ...`
## Rekommenderad start imorgon
1. Rebuild + recreate containrar:
```bash
docker compose build recipe-api recipe-frontend recipe-flutter
docker compose up -d --force-recreate recipe-api recipe-frontend recipe-flutter
```
2. Kör en import av samma ICA-länk.
3. Hämta loggar med filter:
```bash
docker logs --since 15m recipe-api | grep -E "QuickImportService|RecipesService|Bildkandidat|Normaliserad bild-URL|Incoming imageUrl|Final imageUrl|imageWarning"
docker logs --since 15m recipe-frontend | grep -E "QuickImportProxy|ImportFilePage|ImportTabsClient|WriteRecipePage|quick-import response|sessionStorage snapshot|create payload imageUrl"
```
4. I browser DevTools:
- Network: svar för `/api/quick-import-proxy` (imageUrl, imageWarning)
- Network: payload för `POST /api/recipes` (imageUrl)
- Console: rader från `Import*` och `WriteRecipePage`.
## Säkerhetsnotering
En JWT råkade postas i klartext under felsökningen. Behandla den som komprometterad:
- logga ut/in för ny token
- rotera hemligheter vid behov om detta är produktion.
## Kort hypotes (nuvarande)
`quick-import` får fram och sparar bild, men värdet tappas troligen i klientflödet före `POST /api/recipes` eller så kör servern inte senaste build med loggar/fixar.
+23 -3
View File
@@ -6,9 +6,6 @@
---
## Status — senast genomgånget: 2026-04-21
| Funktion | Status |
|---|---|
| Inventorie (CRUD, konsumtion, historik) | ✅ Klart |
| Recept (skapa, visa, importera, matchning) | ✅ Klart |
@@ -55,6 +52,29 @@
| Avancerad AI-integration (veckoplanering, receptförslag) | ❌ Planerad |
| EAN-skanning via Open Food Facts API | ❌ Planerad |
## Status — senast genomgånget: 2026-04-22
### Nyheter och förbättringar
- **User-scope för pantry och matplan** — Alla baslager- och matplansdata är nu per användare. Backend och Prisma-schema är migrerade.
- **Robust bildimport** — Bild-URL normaliseras, laddas ner och optimeras i backend. Bilden kopplas till receptet och raderas vid delete. Diagnostikloggning på alla steg.
- **Importflöde** — Quick-import och receipt-import har förbättrats med robust multipart-hantering, timeout, och felhantering. Markdown och bild-url skickas hela vägen till UI.
- **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.
---
## Nästa steg
1. Slutför kvittoimport (granskningssteg och bulk-spara i Flutter).
2. Fortsatt flytt av UI-strängar till ARB (inventarie, pantry, recept).
3. Smoke-test på testdomän och avstämning.
4. Planera och påbörja avancerad AI-integration och EAN-skanning.
---
## Beslut 2026-04-22 — Pantry och matplan på user-nivå
-44
View File
@@ -35,25 +35,9 @@ Inventariet är en **aktiv förrådsbok** över varor du just nu har hemma. Här
- Bäst före-datum
- Om förpackningen är öppnad
När du lagar mat kan du registrera hur mycket du förbrukat, och inventariet uppdateras. **Inventariet är punkten i tid — det speglar verkligheten.**
#### Baslager — ”vad du alltid har hemma”
Baslagret är en **permanent lista** över varor du alltid räknar med att ha hemma, oavsett vad inventariet säger. Tänk salt, olja, socker, svartpeppar, mjolk, ägg — varor som nästan aldrig tar slut helt, eller som du alltid köper på direkt när de tar slut.
Baslagret **påverkar inköpslistan**: varor i baslagret markeras automatiskt som tillgängliga i matplanens inköpslista — du behöver inte föra in dem i inventariet för att det ska fungera.
#### Praktiskt flöde
| Situation | Använd |
|---|---|
| Du köpte 2 kg pasta idag | **Inventariet** — lägg till med mängd och bäst före |
| Salt ingår alltid i dina recept | **Baslager** — lägg till en gång, släpp sen |
| Du vill se vad du behöver köpa | **Matplanen** — inköpslistan jämför mot båda |
| Du tog slut på mjolk | Ta bort från inventariet (baslagret påverkas inte) |
---
### Recept
- **Skapa och redigera recept** — med namn, beskrivning, portionsantal, ingredienser (kvantitet och enhet) och instruktioner i Markdown-format
- **Portionsjustering** — ange antal portioner vid skapandet; matplanen räknar automatiskt om ingrediensmängder om du lagar fler eller färre portioner
- **Receptjämförelse mot inventorie** — se direkt vilka ingredienser du har hemma, vad som saknas och om enheter är inkompatibla
- **Importera recept från Markdown** — klistra in ett recept i enkelt format, låt systemet matcha ingredienser, granska och spara med ett klick
@@ -61,50 +45,22 @@ Baslagret **påverkar inköpslistan**: varor i baslagret markeras automatiskt so
- **Intelligenta matchningar** — Levenshtein-baserad likhetsbedömning hittar rätt produkt även vid osäker stavning
- **Enhetskonvertering** — automatisk konvertering mellan viktenheter (g/kg), volymenheter (ml/dl) och portionsenheter (tsk/msk)
### Matplanering
- **Veckovy** — planera veckans måltider dag för dag med ett enkelt receptval
- **Portionsjustering per dag** — välj hur många portioner du vill laga för varje dag; avviker du från receptets grundportioner visas en återställningsknapp
- **Inköpslista** — genereras automatiskt utifrån veckans planerade recept; ingrediensmängder skalas proportionellt om portioner justerats
- **Inventariejämförelse** — jämför inköpslistans ingredienser mot vad du faktiskt har hemma (aggregerat per vecka)
### Kvittoimport
- **Fotografera eller ladda upp kvitto** — JPEG, PNG, WebP, HEIC och PDF stöds (max 15 MB)
- **AI-tolkning via Mistral** — Mistral AI extraherar varunamn och mängder direkt från kvittobilden
- **Alias-matchning** — kvittots produktnamn matchas mot kända alias (t.ex. "ICA Kvarg Jordg" → "Kvarg") och mot befintliga produkter
- **Granska och lägg till** — se tolkningsresultatet, justera kvantitet och enhet, och lägg till direkt i inventariet
- **AI-kategorisuggestion (premium)** — för varor som inte matchas mot befintliga produkter visas ett AI-förslag på kategori (t.ex. "✨ Mejeri och ägg > Kvarg och fil") som hjälp när användaren väljer produkt manuellt
### Admin: Produkter
> Obs: Destruktiva åtgärder (merge, ta bort, återställ, bulk-uppdatera, återställ all data) kräver admin-roll.
**Admin: Produkter (fliken Databas i /profil)**
Produktadmin är nu uppdelad i tre undertabbar:
- **📦 Varor** — lista och redigera aktiva produkter
- ** Skapa / Slå ihop** — skapa ny produkt, återställ produktdatabas, slå ihop dubbletter
- **🗑️ Papperskorg** — visa mjukraderade produkter, återställ eller radera permanent
Funktioner:
- Redigera produkter — uppdatera namn, canonical name, kategori (hierarkisk dropdown) och varumärke inline
- Kategoritilldelning — välj kategori ur ett 3-nivåträd (huvudkategori → underkategori → typ)
- Bulk-kategorisering — filtrera fram okategoriserade produkter, markera flera och sätt kategori på alla markerade
- AI-kategorisering per produkt och bulk — "✨ Fråga AI" för kategori
- Hitta dubbletter och slå ihop produkter (merge)
- Förhandsvisning av merge
- Ta bort (mjukradera) och återställ produkter
- **Papperskorg:** Återställ eller radera produkter permanent
- Återställ all produktdata (reset)
> Obs: Destruktiva åtgärder (merge, ta bort, återställ, permanent radering, bulk-uppdatera, återställ all data) kräver admin-roll.
### Väntande produktförslag
- **Produktförslags-kö** — produkter med status `pending` samlas på sidan `/admin/products/pending` (länk "⏳ Förslag" i navigeringen)
- **Godkänn eller avvisa** — admin kan godkänna (status → `active`) eller avvisa (status → `rejected`) varje förslag med ett klick
### Användarprofil och administration (fliksida)
Profilsidan `/profil` är en flikbaserad administrationsyta. Antalet flikar beror på rollen:
**Alla inloggade användare:**
- **Min profil** — redigera förnamn, efternamn och e-postadress
- **Databas** — hantera inventarie och baslager (se nedan)
+11 -46
View File
@@ -10,58 +10,23 @@ Recipe App är en fullstack-applikation för hantering av hemmavaror, recept
---
## Versionsinformation
| Delsystem | Teknik | Version |
|-------------|----------------|-----------------|
| Frontend | Next.js | 16.2 |
| | React | 19.2 |
| | TypeScript | 5.4.5 |
| | Node | 22.x (@types/node 22.15.29) |
| Backend | NestJS | 10.3 |
| | Prisma | 6.12.0 |
| | TypeScript | 5.4.5 |
| | Node | 22.x (@types/node 22.15.29) |
| Databas | MariaDB | 11 |
| Proxy | Caddy | 2.x |
| Container | Docker | 24+ |
| Converter | Node.js (TypeScript) | Noll externa beroenden |
---
## Utvecklingsmiljö och deployment
## Nyheter och förbättringar (2026-04-22)
### Infrastruktur
- **User-scope för pantry och matplan** — Prisma-schema, backend och API är migrerade så att alla baslager- och matplansdata är per användare. JWT används för filtrering i alla endpoints.
- **Robust bildimport** — Bild-URL normaliseras, laddas ner och optimeras i backend. Fallback till extern URL om nedladdning misslyckas. Bilden kopplas till receptet och raderas vid delete. Diagnostikloggning på alla steg.
- **Importflöde** — Quick-import och receipt-import har förbättrats med robust multipart-hantering, timeout, och felhantering. Markdown och bild-url skickas hela vägen till UI.
- **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.
**Utvecklingsmiljön är en remote server** med följande struktur:
### 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.
- **Server:** Dedikerad maskin med Docker installerat
- **SSH-baserad utveckling:** All utveckling, bygge och körning av applikationen sker via SSH-kommandon på servern
- **Lokal förberedelse:** Mindre arbetsuppgifter kan förberedas lokalt och sedan pushas till servern för slutförande
### Arbetsflöde
```
Lokal maskin
│
├─── Git-ändringar (commit) ──┐
│ │
└─── Push till Gitea-server ──→ Privat Gitea-instans
(i Docker-container)
│
↓
Remote server
│
├─── git pull ────────────────┤
│ │
└─── docker compose build ─────┤
│ │
└─── docker compose up ───────┘
```
### Git-server (Gitea)
- **Gitea** körs i en Docker-container på servern
---
- **Privat git-server** för denna applikation
- Ändringar pushas lokalt till denna server:
```bash
+19
View File
@@ -33,5 +33,24 @@ Planned migration sequence is documented in [next_steps_flutter.md](../next_step
2. If login fails: verify username/password (not email).
3. If recipes do not load: report browser console/network errors to the dev team.
## Release expectation
This frontend is available for iterative testing. Feature parity with the current production frontend is delivered step by step.
---
## Nyheter och förbättringar (2026-04-22)
- **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. Bilden sparas och kopplas till receptet vid import.
- **User-scope för pantry och matplan** — Alla baslager- och matplansdata är nu per användare (inte globala). Backend och Prisma-schema är migrerade.
- **UI/UX-förbättringar** — Produktval med bottenark (ProductPickerField), swipe-för-±1 på inventarielistan (SwipeableInventoryTile), och förbättrad felhantering.
- **Felsökningslogg** — Se `../IMPORT_IMAGE_DEBUG_2026-04-22.md` för detaljerad felsökningshistorik kring bildimport.
## 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.
---
-37
View File
@@ -75,27 +75,16 @@ Adminfloden migreras efter att ovanstaende ar verifierat.
### Analys (2026-04-22)
**Två separata flöden — samma skärm med flikar:**
#### 6a — Recept-import
- Endpoint: `POST /api/quick-import`
- Lägen: (1) filuppladdning med `multipart/form-data`, fält `file`, max 10 MB,
accepterade typer: PDF, PNG, JPG, JPEG, WEBP, BMP;
(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.
- **Kräver**: `CreateRecipeScreen` måste utökas med en valfri `initialMarkdown`-parameter
som skickas via GoRouter `extra` (undviker persistent state-provider för tillfällig data).
#### 6b — Kvitto-import
- Endpoint: `POST /api/receipt-import`
- Läge: filuppladdning, `multipart/form-data`, fält `file`, max 15 MB,
typer: JPEG, PNG, WebP, HEIC/HEIF, PDF.
- Svar: `ParsedReceiptItem[]` med fälten `rawName`, `quantity`, `unit`,
`price?`, `matchedProductId?`, `matchedProductName?`,
`suggestedProductId?`, `suggestedProductName?`, `categorySuggestion?`.
- På lyckat resultat: granskningssteg där användaren bekräftar/skippar rader
och väljer produkt (via `ProductPickerField`), sedan bulk-spara till inventarie.
- Komplexitetsgrad: hög — granskningsvyn är det tyngsta steget.
**Nytt paket som krävs:**
@@ -114,15 +103,10 @@ flutter/lib/features/import/
presentation/
import_screen.dart # TabBar: "Recept" | "Kvitto"
recipe_import_tab.dart # Fas 6a — fil + URL, laddningsindikator
receipt_import_tab.dart # Fas 6b — fil, parse, granskning, spara
```
**Router och shell:**
- Ny route `/import` inuti `ShellRoute` i `app_router.dart`.
- Ny nav-destination "Importera" med ikon `Icons.upload_file_outlined` i `app_shell.dart`,
placeras efter "Baslager" och innan "Profil".
**Felhantering:**
- 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.
@@ -133,32 +117,12 @@ flutter/lib/features/import/
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).
5. Registrera route, lägg till nav-destination, verifiera end-to-end.
6. Bygg `receipt_import_tab.dart` (fas 6b — granskningssteg sist).
### Deluppgifter
- [x] Lägg till `file_picker: ^8.0.0` i `pubspec.yaml`.
- [x] Utöka `CreateRecipeScreen` med optional `initialMarkdown` via GoRouter `extra`.
- [x] Skapa `domain/quick_import_result.dart` och `domain/parsed_receipt_item.dart`.
- [x] Skapa `data/import_repository.dart` med multipart-upload + JSON URL-metoder.
- [x] Skapa `data/import_providers.dart`.
- [x] Bygg `presentation/recipe_import_tab.dart` (fil + URL, lång laddningsindikator).
- [x] Bygg `presentation/import_screen.dart` med TabBar.
- [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).
- [ ] Verifiera kvitto-import end-to-end (fil → parse → granska → inventarie).
## Fas 7 - Profil/admin parity
- Profil for alla anvandare.
- Role-aware navigation och skydd for adminytor.
- Adminfunktioner migreras sist for att minimera risk i karnfloden.
## Contract-first per feature
For varje feature:
1. Verifiera request/response mot befintligt backendkontrakt.
2. Mappa modeller robust (null-safe, fallback-falt, typskillnader).
3. Kontrollera felbanor innan UI-polish.
Ingen ad-hoc backendforandring goras for att "fa Flutter att funka".
@@ -167,7 +131,6 @@ Backend-andringar for user-scope i pantry/matplan ar explicit beslutade och ska
## Kvalitetsgrind (Definition of Done)
En feature ar klar nar allt nedan ar uppfyllt:
1. API-floden fungerar for bade success och fel.
2. Auth/rollskydd fungerar (inklusive 401/403).
3. Loading/empty/error ar konsekvent hanterat.
4. Navigation in/ut ur feature fungerar utan specialfall.
+17 -6
View File
@@ -178,9 +178,20 @@ Om `test.gynther.se` slutar svara efter städning med `--remove-orphans`, starta
- `docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter`
## Nasta tekniska steg
Fortsatt migrering enligt prioritering i [next_steps_flutter.md](next_steps_flutter.md):
1. Fortatt lokalisering av inventarie/pantry/recept-strangar till ARB.
2. Matplan parity mot nu user-scopat API.
3. Import parity.
4. Profil/admin parity.
---
## 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.
---