Files
recipe-app/migrering-MSI.md
T
Nils-Johan Gynther 8200045438
Test Suite / test (24.15.0) (push) Has been cancelled
feat: enhance user-scoped AI functionality with admin toggles and premium features
2026-05-06 09:29:16 +02:00

12 KiB
Raw Blame History

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:

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.tsPOST /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 (DocumentImportModuleDocumentServiceModule)
  • 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