Files
recipe-app/migrering-MSI.md
T
Nils-Johan Gynther 9417d30574 Update to .md-files
2026-05-01 00:28:09 +02:00

204 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Migrering: Import-funktion → microservice-importer
## Status: ✅ GENOMFÖRD 2026-04-30
- **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 13 ä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 57 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 57 ä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