189 lines
6.1 KiB
Markdown
189 lines
6.1 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**.
|
||
|
||
## Referenser
|
||
|
||
- [README.md](README.md)
|
||
- [NEXT_STEPS.md](next_steps_MSImporter.md)
|