This file has been removed as all relevant information has been migrated.
# Prisma P3009 recovery (MySQL, migrationer)

**Problem:**
Prisma migrationer kan fastna i failed state (P3009) om en migration körts med fel SQL-citering (t.ex. "User" istället för `User` i MySQL) eller om deploy avbryts mitt i en migrering.

**Symptom:**
```
migrate found failed migrations in the target database, new migrations will not be applied. The `20260506144000_add_ai_engine_enabled` migration ... failed
```

**Lösning/playbook:**
1. Rätta migrationsfilen så att den använder backticks (`) för tabell- och kolumnnamn (MySQL-stil).
2. Kör:
	```bash
	docker exec recipe-api sh -lc "cd /app && npx prisma migrate resolve --rolled-back 20260506144000_add_ai_engine_enabled --schema prisma/schema.prisma"
	docker exec recipe-api sh -lc "cd /app && npx prisma migrate deploy --schema prisma/schema.prisma"
	```
3. Om deploy klagar på duplicate column (dvs kolumnen finns redan):
	```bash
	docker exec recipe-api sh -lc "cd /app && npx prisma migrate resolve --applied 20260506144000_add_ai_engine_enabled --schema prisma/schema.prisma"
	docker exec recipe-api sh -lc "cd /app && npx prisma migrate deploy --schema prisma/schema.prisma"
	```
4. Verifiera status:
	```bash
	docker exec recipe-api sh -lc "cd /app && npx prisma migrate status --schema prisma/schema.prisma"
	```

**Lessons learned:**
- Kontrollera alltid SQL-citering i migrationsfiler (MySQL kräver backticks, inte dubbla citattecken).
- Vid P3009: använd `migrate resolve` för att markera migrationen som rolled-back eller applied beroende på DB-läge.
- Kör alltid migrationskommandon i rätt container/miljö för att undvika env- och version-mismatch.

# Session 2026-05-06: Migreringar för user-scoped AI och premium

Denna session:
- Lade till `aiEngineEnabled` på User i Prisma-schema och migrerade databasen (manuell SQL vid behov).
- Implementerade endpoint och logik för admin att toggla AI per användare.
- Säkerställde att alla AI-funktioner är user-scoped och premiumstyrda.
- Lessons learned: Vid DB-connectivity-problem krävs ibland manuell migration och resolve (se driftsekvens i TEKNISK_BESKRIVNING.md).

Se även:
- [TEKNISK_BESKRIVNING.md](TEKNISK_BESKRIVNING.md) för drift- och migreringsdetaljer.

# Migrering: Import-funktion → microservice-importer

## Status: ✅ GENOMFÖRD 2026-04-30

## Dokumentstatus (2026-05-03)

### Målgrupp
Detta dokument är för systemadministratörer och utvecklare som ansvarar för integrationen mellan recipe-app och microservice-importer.

### Tillägg efter genomförd migrering
- Kvittoparsningens regelbaserade tolkning har förbättrats för multipack och enheter.
- Brödrelaterade kategoriregler och contradiction guards har utökats för högre träffsäkerhet.
- Klientens kvittosession i Flutter är nu persistent utan att ändra backendkontrakt eller införa serverlagring av sessionen.
- Kategoriträdet i seed-data har utökats med `Korvbröd` under `Fastfoodbröd`.
- **PDF-fix (2026-05-03):** `pdf-parse` använder `require()` istället för ESM-import; `pdfjs-dist/legacy/build/pdf.js` är fallback vid parsningsfel — löser `DOMMatrix is not defined` i Node.js Alpine-miljö.
- **Felkods-forwarding (2026-05-03):** `receipt-import.service.ts` returnerar nu `ServiceUnavailableException` (503) vid 503/429 från importer-api istället för `BadRequestException` (400).
- **Reproducerbart bygge (2026-05-03):** `package-lock.json` spåras i git; Dockerfile för importer-api kör `npm ci`.
- **AI-optimering (2026-05-03):** `looksLikeReceiptProductLine()` filtrerar PDF-rader utan siffra innan Mistral-anrop — minskar onödiga API-anrop vid kvittoimport.

- **Scope:** quick-import, parse-markdown, receipt-import
- **Arkitektur:** Backend-till-backend — recipe-app NestJS-backend anropar microservice-importer internt via HTTP. Frontend ändras inte.
- **OCR:** Implementerat i microservice-importer (tesseract.js + Alpine apk-paket)
- **Infra:** `importer-api`-tjänst i `recipe-app/compose.yml`, port 3001 intern
- **Driftsatt:** 2026-04-30, alla containers Healthy

---

## Fas 1 — Utöka microservice-importer ✅

**1. OCR-stöd och multipart i quick-import** ✅
- `QuickImportService.importFromUpload()` tillagd — hanterar PDF (pdf-parse) och bild (tesseract.js)
- `quick-import.controller.ts` utökat med `FileInterceptor`, `@HttpCode(200)`
- `Dockerfile` uppdaterad: `apk add tesseract-ocr tesseract-ocr-data-swe tesseract-ocr-data-eng`

**2. `imageUrl` i quick-import-svaret** ✅
- `imageUrl?: string` tillagd i `ParsedRecipe`-interfacet (`base.parser.ts`)
- ICA-parsern extraherar nu `recipe.image` (string/array/objekt-varianter)
- `QuickImportResult` utökad med `imageUrl?`, `imageWarning?`, source `'image'`
- `normalizeImageUrl()` hanterar protokollrelativa URL:er (`//cdn.ica.se/...`)

**3. Ny `ReceiptParsingModule`** ✅
- `backend/src/receipt-parsing/receipt-parsing.service.ts` — Mistral AI-parsning av kvitto (bild/PDF)
- `backend/src/receipt-parsing/receipt-parsing.controller.ts` — `POST /api/receipt-import/parse`, `@HttpCode(200)`, tillåter `application/octet-stream`
- `backend/src/receipt-parsing/receipt-parsing.module.ts`
- Registrerad i `app.module.ts`

**4. Health-endpoint** ✅
- `GET /api/health` → `{status: "ok"}` inline i `app.module.ts`

**5. Bugfixar i document-service** ✅
- `document-service.module.ts`: korrigerade importvägar + klassnamn (`DocumentImportModule` → `DocumentServiceModule`)
- `services/document-import.service.ts`: parsersökväg `./parsers/` → `../parsers/`
- Borttagna dubbletter: `services/web-scraping.module.ts`, `services/document-service.module.ts`

---

## Fas 2 — Anpassa recipe-app backend ✅

**5. Refaktorera `QuickImportService`** ✅
- All lokal parsning (ICA, pdf-parse, tesseract) borttagen
- Delegerar URL-import: `POST importer-api:3001/api/quick-import` (JSON)
- Delegerar filuploading: `POST importer-api:3001/api/quick-import` (FormData, `new Uint8Array(file.buffer)`)
- `downloadAndOptimizeImage()` behålls lokalt (körs efter microservice returnerat `imageUrl`)
- `IMPORTER_SERVICE_URL` env-variabel med fallback `http://importer-api:3001`

**6. Refaktorera `ReceiptImportService`** ✅
- AI-parsning (Mistral, pdf-parse) borttagen ur recipe-app
- Delegerar till `POST importer-api:3001/api/receipt-import/parse` (FormData)
- `matchProducts()` och `enrichWithAiCategories()` behålls (DB-krav)
- `RECEIPT_IMPORT_MODEL`-konstanten flyttad till `ai.controller.ts` (lokal konstant)

**7. Refaktorera `RecipesService.parseMarkdown()`** ✅
- Delegerar markdown-parsning till `POST importer-api:3001/api/recipes/parse-markdown`
- Fallback till lokal `parseRecipeMarkdown()` vid driftavbrott
- Levenshtein-produktmatchning behålls lokalt

---

## Fas 3 — Infrastruktur ✅

**8. `importer-api` i `recipe-app/compose.yml`** ✅
- Build-context: `../microservice-importer`, dockerfile `backend/Dockerfile`
- Image: `recipe-importer-api:local`, `pull_policy: never`
- Nätverk: `recipe-internal` (ej exponerad externt)
- Env: `MISTRAL_API_KEY`, `PORT=3001`
- Healthcheck: `wget -qO- http://127.0.0.1:3001/api/health`
- `recipe-api` får `depends_on: importer-api: condition: service_healthy`

---

## Relevanta filer som ändrades

| Fil | Förändring |
|---|---|
| `microservice-importer/backend/src/web-scraping-service/parsers/base.parser.ts` | `imageUrl?` i `ParsedRecipe` |
| `microservice-importer/backend/src/web-scraping-service/parsers/ica.parser.ts` | Extraherar `recipe.image` |
| `microservice-importer/backend/src/web-scraping-service/services/quick-import.service.ts` | Omskriven: OCR, PDF, imageUrl, importFromUpload |
| `microservice-importer/backend/src/web-scraping-service/controllers/quick-import.controller.ts` | FileInterceptor, HttpCode(200) |
| `microservice-importer/backend/src/web-scraping-service/web-scraping.module.ts` | Fixade importvägar + klassnamn |
| `microservice-importer/backend/src/document-service/document-service.module.ts` | Fixade importvägar + klassnamn |
| `microservice-importer/backend/src/document-service/services/document-import.service.ts` | Fixad parsersökväg |
| `microservice-importer/backend/src/receipt-parsing/` | Ny modul (service, controller, module) |
| `microservice-importer/backend/src/app.module.ts` | ReceiptParsingModule + HealthController |
| `microservice-importer/backend/Dockerfile` | apk add tesseract-ocr |
| `recipe-app/backend/src/quick-import/quick-import.service.ts` | Delegerar till importer-api |
| `recipe-app/backend/src/receipt-import/receipt-import.service.ts` | AI-del delegeras, matchning behålls |
| `recipe-app/backend/src/recipes/recipes.service.ts` | parseMarkdown delegeras, matchning behålls |
| `recipe-app/backend/src/ai/ai.controller.ts` | RECEIPT_IMPORT_MODEL lokal konstant |
| `recipe-app/compose.yml` | importer-api-tjänst tillagd |

---

## Avgränsningar (oförändrade)

- **Frontend ändras inte** — samma proxy-routes, samma API-kontrakt
- **Auth stannar i recipe-app backend** — microservice-importer exponeras bara internt
- **Bildoptimering** behålls i recipe-app (`downloadAndOptimizeImage` vid `RecipesService.create()`)
- `matchProducts()` och `enrichWithAiCategories()` stannar i recipe-app (DB-krav)


---

## Fas 1 — Utöka microservice-importer

*Steg 1–3 är oberoende och kan utföras parallellt.*

**1. Lägg till OCR-stöd (tesseract.js)**
Ny `ImageParser` i `backend/src/web-scraping-service/parsers/`. Controllern
`quick-import.controller.ts` utökas att acceptera `multipart/form-data` för
bilder vid sidan av JSON-body för URL-anrop.

**2. Lägg till `imageUrl` i quick-import-svaret**
`quick-import.service.ts` returnerar idag `{ markdown, source }`. Komplettera
med `imageUrl?` (original-URL från skrapad sida).

**3. Ny `ReceiptParsingModule` – stateless kvittoparsning**
Ny modul `backend/src/receipt-parsing/` med endpoint `POST /api/receipt-import/parse`.
- PDF → text via `pdf-parse`; bild → base64
- Anropar Mistral AI med kvitto-prompt
- Returnerar: `[{ rawName, quantity, unit, price, brand, origin }]`
- Ingen databaskoppling — rent stateless

---

## Fas 2 — Anpassa recipe-app backend

*Beror på Fas 1. Steg 5–7 kan utföras parallellt.*

**4. Lägg till `HttpModule` + `IMPORTER_SERVICE_URL`**
recipe-app backend registrerar NestJS:s `HttpModule` (axios-wrapper).
`IMPORTER_SERVICE_URL` sätts som env-variabel (`http://importer-api:3001` i Docker).

**5. Refaktorera `QuickImportService`**
Ta bort lokal ICA-parsning, pdf-parse och tesseract — anropa istället
microservice-importer `POST /api/quick-import` (eller `POST /api/document-import`
för PDF). `QuickImportModule` behåller sin controller och DTO (API-kontrakt oförändrat).

**6. Refaktorera `ReceiptImportService`**
- AI-parsning → delegeras till `POST $IMPORTER_URL/api/receipt-import/parse`
- Produktmatchning (Levenshtein mot `Product`, `ReceiptAlias`) — behålls i recipe-app (DB-krav)
- Slår ihop och returnerar samma svar som idag till frontend

**7. Refaktorera `RecipesService.parseMarkdown()`**
- Anropar `POST $IMPORTER_URL/api/recipes/parse-markdown` → `{ name, ingredients[], ... }`
- Kör befintlig Levenshtein-produktmatchning mot `Product`-tabellen i recipe-app
- Returnerar sammansatt svar — API-kontraktet mot frontend oförändrat

**8. Ta bort lokala parsningsberoenden**
Ta bort `pdf-parse`, `tesseract.js`, `node-fetch` etc. ur recipe-app backend
`package.json` när steg 5–7 är verifierade.

---

## Fas 3 — Infrastruktur

*Kan påbörjas parallellt med Fas 1.*

**9. Länka microservice-importer i recipe-app:s Docker Compose**
Lägg till `importer-api`-tjänst i `recipe-app/compose.yml` (byggs från
`../microservice-importer/backend`). Delar `recipe-network` med recipe-app
backend. Sätt `IMPORTER_SERVICE_URL=http://importer-api:3001` i recipe-app
backend-tjänstens env.

---

## Relevanta filer

| Fil | Förändring |
|---|---|
| `microservice-importer/backend/src/web-scraping-service/` | Ny ImageParser, imageUrl i svar |
| `microservice-importer/backend/src/` | Ny `receipt-parsing/` modul |
| `recipe-app/backend/src/quick-import/quick-import.service.ts` | Ersätt lokal parsning med HTTP-anrop |
| `recipe-app/backend/src/receipt-import/receipt-import.service.ts` | AI-del delegeras, matchning behålls |
| `recipe-app/backend/src/recipes/recipes.service.ts` | parseMarkdown delegeras, matchning behålls |
| `recipe-app/backend/src/app.module.ts` | Registrera HttpModule |
| `recipe-app/backend/package.json` | Ta bort pdf-parse, tesseract.js |
| `recipe-app/compose.yml` | Lägg till importer-api tjänst |
| `recipe-app/frontend/` | **Ändras inte** |

---

## Verifiering

1. `POST /api/quick-import` (recipe-app backend) med ICA-URL → samma svar som idag
2. `POST /api/quick-import` med PDF-fil → samma svar
3. `POST /api/recipes/parse-markdown` med markdown → ingredienser med produkt-ID:n
4. `POST /api/receipt-import` med kvittobild → matchade items med DB-produkt-ID:n
5. Autentisering fungerar (hanteras av recipe-app backend som tidigare)
6. `docker compose up` startar microservice-importer som intern tjänst

---

## Avgränsningar

- **Frontend ändras inte** — samma proxy-routes, samma API-kontrakt
- **Auth stannar i recipe-app backend** — microservice-importer exponeras bara internt på Docker-nätverket
- **Bildoptimering vid sparande** behålls i recipe-app (sker vid `RecipesService.create()`, inte vid import)
- `receipt-import` splittad: AI-del → microservice, produktmatchning + DB → recipe-app backend

## 2026-05-10: Admin-inventarie (CRUD, merge, filter, sortering, preview, säkerhet), user-scope, IDOR-skydd, säkerhetshärdning, optimeringar och utökad testtäckning är nu genomförda och dokumenterade i README, TEKNISK_BESKRIVNING, SÄKERHETSHÄRDNINGSPLAN och SESSIONLOGGAR.

## 2026-05-10: Admin-inventarie (CRUD, merge, filter, sortering, preview, säkerhet), user-scope, IDOR-skydd, säkerhetshärdning, optimeringar och utökad testtäckning är nu genomförda och dokumenterade i README, TEKNISK_BESKRIVNING, SÄKERHETSHÄRDNINGSPLAN och SESSIONLOGGAR.
