Microservice Importer
Standalone-tjänst för import och konvertering av dokument till Markdown-format. Primärt fokus på PDF-filer — textbaserad extraction samt OCR för skannade dokument. Webb-skrapning finns som sekundär funktion för referens och framtida integration.
Kan användas helt oberoende som fristående microservice.
Viktigt!! Kod- och byggpraxis!
Säkerställ att inga absoluta Windows-sökvägar används i koden, för att stödja bygg och drift på Linux/Ubuntu
Features
Dokument-Import via PDF
- Textbaserad extraction — Snabb och precis för digitalt skapade PDFs
- OCR-detektering — Identifierar skannade bild-PDFs och rapporterar tydligt (OCR-stöd under utveckling)
- Automatisk konvertering:
- Titeln extraheras från filnamnet
- Texten struktureras till Markdown-stycken
- Metadata sparas (antal sidor, teckenantal, producent, skapelsedatum)
- Filstorlek: Max 50 MB per fil
- Format: Multipart/form-data uppladdning
Webb-skrapning (sekundär funktion)
- Skrapa från ICA.se — JSON-LD structured data + HTML-parsing
- Generisk parser — Fallback för andra webbplatser
- Automatisk extraction: Namn, beskrivning, ingredienser, instruktioner
Parse-Markdown endpoint
Tolka Markdown-format utan databaskomplikationer. Användbar för API-integration utan lokal DB.
Arkitektur
Backend (NestJS 10.3, TypeScript 5.4.5)
Port: 3001
src/
├── app.module.ts # Root module
├── main.ts # Startpunkt
├── common/
│ ├── filters/
│ │ └── global-exception.filter.ts # Centraliserad felhantering (svenska meddelanden)
│ └── utils/
│ └── normalize-name.ts # Namnormalisering (åäö-handling)
├── document-import/ # PDF-import & konvertering (primär funktion)
│ ├── document-import.controller.ts # POST /api/document-import
│ ├── document-import.service.ts # Filvalidering, parser-routing
│ ├── document-import.module.ts
│ └── parsers/
│ ├── document.parser.ts # Abstrakt bas-klass
│ └── pdf.parser.ts # PDF-extraction via pdf-parse
├── quick-import/ # Webb-skrapning (sekundär funktion)
│ ├── quick-import.controller.ts # POST /api/quick-import
│ ├── quick-import.service.ts # Scraping-logik, parser-selection
│ ├── quick-import.module.ts
│ └── parsers/
│ ├── base.parser.ts # Abstrakt bas-klass
│ ├── ica.parser.ts # ICA.se-specifik (JSON-LD prioritet)
│ └── generic.parser.ts # Fallback för alla webbplatser
└── recipes/ # Markdown-tolkning (utan DB)
├── recipes.controller.ts # POST /api/recipes/parse-markdown
├── recipes.service.ts
├── recipes.module.ts
└── dto/
└── parse-markdown.dto.ts
Viktigt: Backend har INGEN databaskonfiguration — stateless service.
Frontend (Next.js 16.2, React 19.2, TypeScript 5.4.5)
Port: 3000
app/
├── layout.tsx # Root layout
├── page.tsx # Home page
├── Navigation.tsx # Minimal nav (Home + Import)
├── import/page.tsx # PRIMARY FEATURE — Drag-and-drop filuppladdning
├── api/
│ ├── document-import-proxy/route.ts # Proxy: multipart/form-data → backend
│ └── parse-markdown-proxy/route.ts # Proxy: Markdown-tolkning → backend
└── lib/
├── api.ts # Centraliserad API-access (fetchJson)
└── error-handler.ts # parseErrorResponse (svenska meddelanden)
Quick-Start
Prerequisites
- Node.js 22.x
- Docker & Docker Compose (valfritt)
Local Development
# 1. Installera backend
cd backend
npm install
npm run start:dev
# Backend kör på http://localhost:3001
# 2. (I ny terminal) Installera frontend
cd frontend
npm install
npm run dev
# Frontend kör på http://localhost:3000
Öppna http://localhost:3000 → Gå till /import → Klistra in URL
Docker
# Bygg och starta
docker compose up -d
# Frontend: http://localhost:3000
# Backend: http://localhost:3001
Stoppa:
docker compose down
API-dokumentation
POST /api/document-import
Syfte: Ladda upp en PDF och returnera Markdown-text
Request: multipart/form-data med fältet file (PDF, max 50 MB)
curl -X POST http://localhost:3001/api/document-import \
-F "file=@dokument.pdf"
Response (Success 200):
{
"markdown": "# Dokument\n\nInnehåll från PDFen...",
"title": "Dokument",
"documentType": "pdf",
"metadata": {
"pageCount": 5,
"characterCount": 12400,
"producer": "Adobe PDF Library",
"creationDate": "D:20260101120000"
}
}
Response (Error 400):
{
"statusCode": 400,
"message": "Kunde inte läsa dokumentet: PDFen verkar vara en skannad bild utan textlager.",
"timestamp": "2026-04-12T10:30:00.000Z"
}
Error-scenarier:
400— Ingen fil bifogad400— Fel filtyp (ej PDF)400— Filen överstiger 50 MB400— Lösenordsskyddad PDF400— Skannad bild-PDF utan textlager (OCR ej implementerat ännu)
POST /api/quick-import
Syfte: Skrapa webbsida och returnera Markdown (sekundär funktion)
Request:
{
"input": "https://ica.se/recept/kottfarssas-1234"
}
Response (Success 200):
{
"markdown": "# Köttfärssås\n\nEn klassisk...",
"source": "ica"
}
Error-scenarier:
400— Tomt input, inte en URL400— HTML-parsing misslyckades503— Network-fel
POST /api/recipes/parse-markdown
Syfte: Tolka Markdown-format utan databas
Request:
{
"markdown": "# Titel\n\n## Ingredienser\n- 500 g mjöl\n\n## Tillvägagångssätt\nBlanda..."
}
Response (Success 200):
{
"name": "Titel",
"description": "",
"instructions": "Blanda...",
"ingredients": [
{ "rawName": "mjöl", "quantity": 500, "unit": "g", "note": null }
]
}
Parser-arkitektur
Dokument-parsers (document-import/parsers/)
Abstrakt bas DocumentParser som alla dokumenttyp-specifika parsers ärver från:
abstract class DocumentParser {
abstract parse(buffer: Buffer, filename: string): Promise<ParsedDocument>;
protected textToMarkdown(text: string, title: string): string {
// Slår ihop sammanhängande textrader, bevarar stycken
}
}
PDF Parser (pdf.parser.ts)
Hanterar textbaserade PDFs via pdf-parse.
Strategi:
- Extrahera text med
pdf-parse - Kontrollera att text hittades (annars: skannad PDF-varning)
- Konvertera text → Markdown via
textToMarkdown() - Returnera titel (från filnamn), innehåll och metadata
Felhantering:
- Lösenordsskyddade PDFs → tydligt felmeddelande
- Skannade bild-PDFs → informativt felmeddelande om OCR
Webb-parsers (quick-import/parsers/)
Abstrakt bas RecipeParser med canHandle(url) + parse(html). Implementationer:
ica.parser.ts— ICA.se, prioriterar JSON-LD structured datageneric.parser.ts— Fallback för alla webbplatser, försöker JSON-LD sedan HTML
Deployment
Docker Compose (Recommended)
cd microservice-importer
docker compose up -d
Services:
importer-api— NestJS backend (port 3001)importer-frontend— Next.js frontend (port 3000)
Stoppa:
docker compose down
Loggar:
docker compose logs -f importer-api
docker compose logs -f importer-frontend
Manuell Docker build
# Backend
docker build -f backend/Dockerfile -t importer-api:local .
docker run -p 3001:3001 importer-api:local
# Frontend (ny terminal)
docker build -f frontend/Dockerfile -t importer-frontend:local .
docker run -p 3000:3000 importer-frontend:local
Environment variables
Konfigureras i docker compose eller .env:
Backend:
PORT=3001
NODE_ENV=production
Frontend:
NEXT_PUBLIC_API_URL_INTERNAL=http://importer-api:3001
Integration med andra tjänster
Microservicen kan anropas som extern API från andra applikationer:
const IMPORTER_URL = process.env.MICROSERVICE_IMPORTER_URL || 'http://localhost:3001';
// PDF-konvertering
const formData = new FormData();
formData.append('file', pdfFile);
const response = await fetch(`${IMPORTER_URL}/api/document-import`, {
method: 'POST',
body: formData,
});
const { markdown, title, metadata } = await response.json();
Tekniska detaljer
Backend Stack
- NestJS 10.3 — REST API & modular architecture
- TypeScript 5.4.5 — Type safety
- Node.js 22.x — Runtime
- pdf-parse 1.1.x — PDF text extraction
- tesseract.js 5.x — OCR (förberett, ej aktivt ännu)
- multer — Multipart file upload handling
- class-validator — DTO validation (svenska felmeddelanden)
- Ingen databas — Stateless service
Frontend Stack
- Next.js 16.2 — React framework (App Router)
- React 19.2 — UI components
- TypeScript 5.4.5
- Inline CSS — Minimal styling, inga framework-beroenden
Error Handling
- Centraliserad
GlobalExceptionFilter(svenska meddelanden) - Konsistent JSON-responsformat:
{ statusCode, message, timestamp, path } - HTTP status codes: 200, 400, 503
Framtida utbyggnader
- PDF-import — textbaserad extraction
- OCR för skannade bild-PDFs (Tesseract.js förberett)
- Word (.docx) import
- Batch-processing (flera filer samtidigt)
- Strukturerad data-extraction (tabeller, listor)
- Stöd för fler webbplatser i webb-skraparen (mat.se, kokaihop.se, etc.)
- Caching av konverterade dokument
- Rate limiting
Licens
MIT
Support
- Git Repo — Gitea på
192.168.50.2:2222/nilsjohan/microservice-importer