a1dffef708
Test Suite / test (24.15.0) (push) Has been cancelled
Added detailed section about harmonization of import fields between receipt-import, flyer-import, and inventory table. Includes key changes, benefits, and technical details about TypeScript type safety and backward compatibility. Resolves migration issues via prisma migrate resolve.
202 lines
6.7 KiB
Markdown
202 lines
6.7 KiB
Markdown
# Teknisk beskrivning av Microservice Importer
|
||
|
||
## Dokumentstatus (2026-05-12)
|
||
|
||
Detta dokument riktar sig till utvecklare och driftansvariga för microservice-importer. Det beskriver arkitektur, drift och tekniska beslut för den interna importtjänsten.
|
||
|
||
## Roll och ansvar
|
||
|
||
`importer-api` är en stateless intern tjänst för [recipe-app](../recipe-app). Den hanterar URL-skrapning, OCR, PDF-parsning, markdown-parsning och AI-kvittoparsning utan databas eller användarsessioner.
|
||
|
||
## Arkitektur
|
||
|
||
### Körmiljö
|
||
|
||
- NestJS 11
|
||
- TypeScript 5
|
||
- Node.js 22-alpine
|
||
- Port `3001` internt
|
||
- Exponeras bara på `recipe-internal`-nätverket
|
||
|
||
### Moduler
|
||
|
||
```text
|
||
src/
|
||
├── app.module.ts # Root module + HealthController (GET /api/health)
|
||
├── main.ts
|
||
├── common/
|
||
│ ├── filters/global-exception.filter.ts
|
||
│ └── utils/normalize-name.ts
|
||
├── web-scraping-service/
|
||
│ ├── web-scraping.module.ts
|
||
│ ├── controllers/quick-import.controller.ts # POST /api/quick-import
|
||
│ ├── services/quick-import.service.ts # Scraping, OCR, PDF
|
||
│ └── parsers/
|
||
│ ├── base.parser.ts # ParsedRecipe interface
|
||
│ ├── ica.parser.ts # ICA.se JSON-LD + imageUrl
|
||
│ └── generic.parser.ts
|
||
├── receipt-parsing/
|
||
│ ├── receipt-parsing.module.ts
|
||
│ ├── receipt-parsing.controller.ts # POST /api/receipt-import/parse
|
||
│ └── receipt-parsing.service.ts
|
||
├── document-service/
|
||
│ ├── document-service.module.ts
|
||
│ ├── controllers/document-import.controller.ts
|
||
│ ├── services/document-import.service.ts
|
||
│ └── parsers/
|
||
│ ├── document.parser.ts
|
||
│ └── pdf.parser.ts
|
||
└── recipes/
|
||
├── recipes.module.ts
|
||
├── recipes.controller.ts # POST /api/recipes/parse-markdown
|
||
├── recipes.service.ts
|
||
└── dto/parse-markdown.dto.ts
|
||
```
|
||
|
||
## Endpoints
|
||
|
||
| Endpoint | Funktion |
|
||
|---|---|
|
||
| `POST /api/quick-import` | URL-skrapning, bild-OCR och PDF-import |
|
||
| `POST /api/recipes/parse-markdown` | Markdown till strukturerat recept utan databas |
|
||
| `POST /api/receipt-import/parse` | Kvittobild/PDF till `ParsedReceiptItem[]` via Mistral AI |
|
||
| `GET /api/health` | Hälsokontroll för Docker healthcheck |
|
||
|
||
## Kvittoparsning
|
||
|
||
### Modell och pipeline
|
||
|
||
- Vision-input använder `mistral-small-2603`
|
||
- PDF-flödet kör `pdf-parse` eller `pdfjs-dist/legacy/build/pdf.js` som fallback
|
||
- Regelbaserad parsning körs före AI när det är möjligt
|
||
- `looksLikeReceiptProductLine()` filtrerar bort rader utan siffra så att AI bara används för sannolika produktrader
|
||
|
||
### Mängd- och enhetsregler
|
||
|
||
Följande regler är inbyggda i kvitto-prompten:
|
||
|
||
| Typ | Regel | Exempel |
|
||
|---|---|---|
|
||
| Lösvikt | `quantity` = faktisk vikt, `unit` = `kg`/`g` | `BLANDFÄRS 20%` 0.997 kg |
|
||
| Förpackad vara med storlek i namn | `quantity` = antal förpackningar, `unit` = `förp` | `MJÖLK 1,5L` × 3 |
|
||
| Multipack | `quantity=1`, `unit=förp` | `BACON 3X120G` |
|
||
| Förpackat innehåll | `quantity` = antal förpackningar, `unit` = `förp` | `BRIOCHE SESAM` × 2 |
|
||
| Lösa styckvaror | `quantity` = antal, `unit` = `st` | `BANAN` × 1 |
|
||
|
||
Tillåtna enheter: `st`, `kg`, `g`, `l`, `dl`, `cl`, `ml`, `förp`, `pak`, `burk`, `flaska`.
|
||
|
||
### Retry och stabilitet
|
||
|
||
- Mistral 429/503 backas av med `3000 * attempt` ms
|
||
- PDF-flödet använder fallback för CJS- och Node Alpine-kompatibilitet
|
||
- `GlobalExceptionFilter` ger konsekventa felobjekt
|
||
|
||
## Deployment
|
||
|
||
`importer-api` byggs och startas via [recipe-app/compose.yml](../recipe-app/compose.yml) och inte via egen compose-fil.
|
||
|
||
### Serverlayout
|
||
|
||
```text
|
||
/opt/containers/
|
||
microservice-importer/
|
||
recipe-app/
|
||
compose.yml
|
||
deploy.sh
|
||
```
|
||
|
||
### Driftsekvens
|
||
|
||
```bash
|
||
cd /opt/containers/microservice-importer && git pull
|
||
cd /opt/containers/recipe-app && git pull && ./deploy.sh
|
||
```
|
||
|
||
### Hälsokontroll
|
||
|
||
```bash
|
||
docker exec importer-api wget -qO- http://localhost:3001/api/health
|
||
```
|
||
|
||
## Tekniska detaljer
|
||
|
||
### Byggberoenden
|
||
|
||
- `pdf-parse`
|
||
- `tesseract.js`
|
||
- `@mistralai/mistralai`
|
||
- `multer` 2.1.1
|
||
|
||
### Versionsnotering
|
||
|
||
- NestJS-paket är uppgraderade till 11-serien för att ta bort sårbarheter i beroendekedjan.
|
||
- Nest CLI 11 kräver Node.js 20.11+ i CI- och byggmiljöer.
|
||
|
||
### Alpine-paket
|
||
|
||
- `tesseract-ocr`
|
||
- `tesseract-ocr-data-swe`
|
||
- `tesseract-ocr-data-eng`
|
||
|
||
### Viktiga tekniska beslut
|
||
|
||
- Tjänsten är stateless och saknar databaskonfiguration
|
||
- Importer exponeras aldrig externt, bara internt via Docker-nätverket
|
||
- Host-port 3001 är upptagen av `wetty` och får därför inte användas av tjänsten
|
||
|
||
## Parser-arkitektur
|
||
|
||
### Dokument-parsers
|
||
|
||
Abstrakt bas `DocumentParser` används för dokumenttypsspecifik parsing.
|
||
|
||
### PDF Parser
|
||
|
||
`pdf.parser.ts` hanterar textbaserade PDFs. Skannade PDFs varnas och kan falla tillbaka på OCR-vägen.
|
||
|
||
### Webb-parsers
|
||
|
||
- `ica.parser.ts` prioriterar JSON-LD och extraherar `imageUrl`
|
||
- `generic.parser.ts` är fallback för webbplatser utan specialparser
|
||
|
||
## Framtida utbyggnader
|
||
|
||
- Fler webbplats-parsers som Arla, Tasteline och Köket.se
|
||
- Word/import av `.docx`
|
||
- Swagger/OpenAPI-dokumentation
|
||
- Caching av skrapade sidor om belastningen mot externa webbplatser blir ett problem
|
||
|
||
## Quality-gates (npm scripts + CI)
|
||
|
||
Tillagda scripts i `backend/package.json`:
|
||
|
||
| Script | Kommando |
|
||
|---|---|
|
||
| `typecheck` | `tsc --noEmit` |
|
||
| `audit:high` | `npm audit --audit-level=high` |
|
||
| `quality:ci` | Kedja: typecheck → build → audit |
|
||
|
||
CI-workflow (`.github/workflows/test.yml`) uppdaterad (2026-05-12):
|
||
- Bytte `npm install` till `npm ci` för reproducerbara byggen.
|
||
- Ersatte Prisma- och test-steg (saknas i projektet) med: `typecheck` → `build` → `audit:high`.
|
||
- Tog bort `continue-on-error` på build-steget — pipeline fångar nu verkliga fel.
|
||
- `npm audit --audit-level=high` rapporterar **0 sårbarheter**.
|
||
|
||
Harmonisering av importfält (2026-05-24)
|
||
Mål: Skapa konsistens mellan kvitto-import, flyer-import och inventory-tabellen
|
||
Nyckeländringar:
|
||
ParsedReceiptItem fick categoryId för kategorisättning
|
||
FlyerImportItem fick origin som mappas från signals.originCountries[0]
|
||
originCountries array-stöd lades till i inventory för framtida användning
|
||
Fördelar: Minskat felrisk, enklare underhåll, bättre integration
|
||
Tekniska detaljer:
|
||
Typ-säkra ändringar med korrekta TypeScript-typer
|
||
Bakåtkompatibla ändringar
|
||
Löst migrationsproblem via prisma migrate resolve
|
||
|
||
|
||
## Referenser
|
||
|
||
- [README.md](README.md)
|
||
- [NEXT_STEPS.md](next_steps_MSImporter.md)
|