244 lines
8.5 KiB
Markdown
244 lines
8.5 KiB
Markdown
# Recipe App
|
||
|
||
En fullstack-applikation för hantering av hemmavaror och recept. Håll koll på vad du har hemma, spara recept och se direkt om du har allt du behöver för att laga en rätt.
|
||
|
||
> För teknisk detaljinformation, se [TEKNISK_BESKRIVNING.md](TEKNISK_BESKRIVNING.md).
|
||
|
||
---
|
||
|
||
## Funktioner
|
||
|
||
### Inventorie (Hemmavaror)
|
||
- **Lägg till, redigera och ta bort varor** — hantera produkt, kvantitet, enhet, plats, märke och bäst före-datum
|
||
- **Filtrera och sortera** — efter plats (kyl, frys, skafferi), bäst före-datum, och namn (A–Ö)
|
||
- **Konsumera varor** — registrera förbrukad mängd med eventuell kommentar
|
||
- **Konsumtionshistorik** — spåra vad som använts när och i vilken mängd
|
||
- **Utförlig information** — stöd för varumärke, lagringsnot, tillkomsttid, mera detaljer
|
||
|
||
### Recept
|
||
- **Skapa och redigera recept** — med ingredienser, kvantiteter, enheter och instruktioner (Markdown-stöd)
|
||
- **Receptjämförelse mot inventorie** — se direkt vilka ingredienser du har hemma, vad som saknas och enhetskonflikt
|
||
- **Importera recept från Markdown** — klistra in ett recept i enkelt format, låt systemet matcha ingredienser, granska och spara med ett klick
|
||
- **Intelligenta matchningar** — Levenshtein-baserad likhetsbedömning hittar rätt produkt även på osäker stavning
|
||
- **Enhetskonvertering** — automatisk konvertering mellan viktenheter (g/kg), volymenheter (ml/dl) och portionsenheter (tsk/msk)
|
||
|
||
### Admin: Produkter
|
||
- **Hantera produktnamn** — uppdatera canonical name för varje produkt (användes vid receptmatchning)
|
||
- **Hitta dubbletter** — identifiera produkter med samma normaliserade namn
|
||
- **Slå ihop produkter** — merge två produktposter, flytta alla inventarieföremål till målprodukten (källan soft-deleteras)
|
||
- **Förhandsvisning** — granska vad som kommer att hända innan merge genomförs
|
||
- **Återställ produkter** — restore tidigare raderade produkter
|
||
|
||
---
|
||
|
||
## Kom igång
|
||
|
||
### Förutsättningar
|
||
|
||
- Docker och Docker Compose
|
||
- En extern `proxy`-nätverk i Docker för Caddy (rekommenderat) eller localhost-konfiguration
|
||
|
||
### Starta applikationen
|
||
|
||
```bash
|
||
# Bygg alla images (första gånger)
|
||
docker compose build
|
||
|
||
# Starta alla tjänster i bakgrunden
|
||
docker compose up -d
|
||
```
|
||
|
||
Frontend är tillgänglig på `http://localhost:3000` (eller via Caddy proxy)
|
||
Backend API är tillgänglig på `http://localhost:8080` (eller via Caddy proxy)
|
||
|
||
### Bygg bara backend eller frontend om behövligt
|
||
|
||
```bash
|
||
# Bygg enbart backend (t.ex. efter kodändringar)
|
||
docker compose build recipe-api
|
||
|
||
# Starta bara backend (övriga tjänster fortsätter)
|
||
docker compose up -d recipe-api
|
||
|
||
# Liknande för frontend
|
||
docker compose build recipe-frontend
|
||
docker compose up -d recipe-frontend
|
||
```
|
||
|
||
### Kontrollera hälsa
|
||
|
||
```bash
|
||
# Hälsokontroll via HTTP (backend måste köra)
|
||
curl http://localhost:8080/health
|
||
|
||
# Databasspecifik hälsokontroll
|
||
curl http://localhost:8080/health/db
|
||
```
|
||
|
||
---
|
||
|
||
## Lägga till recept
|
||
|
||
### Snabbimport
|
||
|
||
På sidan "Lägg till nytt recept" finns ett **snabbimportfält** längst upp:
|
||
|
||
```
|
||
Snabbimport: Klistra in länk eller fil
|
||
[https://www.ica.se/recept/...] [→]
|
||
```
|
||
|
||
Klistra in:
|
||
- **ICA-receptlänk** — systemet skrapar automatiskt receptet och importerar det
|
||
- En länk omdirigeras till "Skriv in recept" med förifylld Markdown
|
||
|
||
**Stödda webbplatser:**
|
||
- ICA.se — Recept skrapas automatiskt
|
||
- Andra webbplatser — Generic HTML-parser (JSON-LD först, sedan HTML-fallback)
|
||
- (PDF-import under utveckling)
|
||
|
||
**Felmeddelandena vägleder dig:**
|
||
- "Länken är inte från ICA.se" — Försöker Generic parser istället
|
||
|
||
> **Notering:** Snabbimport-logiken är också tillgänglig som en **[standalone microservice](../microservice-importer/README.md)** för integrations- eller API-använding.
|
||
|
||
---
|
||
|
||
## Arkitektur: Recipe App + Microservice Importer
|
||
|
||
Recipe App är uppbyggd i två komponenter:
|
||
|
||
### Recipe App (detta repo)
|
||
**Fullstack-applikation:** Frontend (Next.js), Backend (NestJS), Databas (MariaDB)
|
||
|
||
Innehåller:
|
||
- Inventorie-hantering (CRUD, konsumtion, history)
|
||
- Recept-hantering (CRUD, matchning mot inventorie)
|
||
- Produktadmin (merge, duplicates, canonical names)
|
||
- **Quick-import** (ICA-skrapning integrerad i `/recipes/create`)
|
||
|
||
### Microservice Importer (separat repo)
|
||
**Standalone-tjänst:** Frontend (Next.js), Backend (NestJS, INGEN databas)
|
||
|
||
Innehåller:
|
||
- **URL-scraping:** ICA.se + generic HTML-parser
|
||
- **Markdown-parsing:** Samma parser-logik som recipe-app
|
||
- Eget kontrollpanel på `/import`
|
||
|
||
**Användningsfall:**
|
||
- Extern API-integration (POST `http://microservice:3001/api/quick-import`)
|
||
- Oberoende snabbimport-webb-UI
|
||
- Muligt att scalea separat från recipe-app
|
||
|
||
**Repo:** [`microservice-importer`](../microservice-importer/)
|
||
- "Kunde inte hämta recept från ICA: ..." — Länken är bruten eller receptet kunde inte parsas
|
||
- "Du måste ange en URL eller filsökväg" — Fältet var tomt
|
||
|
||
### Välja mellan alternativen
|
||
|
||
Klicka på **Lägg till nytt recept** i receptmenyn. Du får ett val mellan:
|
||
1. **Skriv in recept** — Skriv receptet i Markdown-format med ingredienser och instruktioner
|
||
2. **Importera från fil** — Ladda upp PDF, länk eller annan receptkälla (under utveckling)
|
||
|
||
### Skriv in recept (Markdown)
|
||
|
||
Navigera till **Lägg till nytt recept → Skriv in recept**
|
||
|
||
**Steg 1: Skriv receptet**
|
||
Använd detta format:
|
||
|
||
|
||
```markdown
|
||
# Köttfärssås
|
||
|
||
En klassisk köttfärssås med massa smak.
|
||
|
||
## Ingredienser
|
||
- 500 g köttfärs
|
||
- 1 st lök
|
||
- 2 msk tomatpuré
|
||
- 1 dl grädde (vispgrädde)
|
||
- salt och peppar
|
||
|
||
## Tillvägagångssätt
|
||
Hacka löken och stek den mjuk i lite olja. Tillsätt köttfärsen och bräsera tills den är genomstekt. Tillsätt tomatpuré och låt det småkoka ett par minuter innan du tillsätter grädde. Smaka av med salt och peppar.
|
||
```
|
||
|
||
**Steg 2: Granska**
|
||
Systemet:
|
||
- Tolkar receptnamn, beskrivning och instruktioner
|
||
- Försöker matcha varje ingrediens mot databasen (Levenshtein-likhet)
|
||
- Visar förslag för varje ingrediens i prioriteringsordning
|
||
|
||
Du kan:
|
||
- Redigera Namnet, beskrivning och instruktioner
|
||
- Välj rätt produkt från förslagen för varje ingrediens
|
||
- Ta bort ingredienser som inte behövs
|
||
- Ändra kvantiteter och enheter
|
||
|
||
**Steg 3: Spara**
|
||
Klicka "Spara recept" — receptet sparas med dina valida ingredienser
|
||
|
||
### Importera från fil eller länk
|
||
|
||
Navigera till **Lägg till nytt recept → Importera från fil**
|
||
|
||
I denna sektion kan du:
|
||
- Ladda upp PDF eller andra receptfiler
|
||
- Ange URL till en receptsida eller blogg
|
||
- Systemet tolkar filen/länken och föreslår ingredienser
|
||
|
||
> **Notering:** Fil- och länk-import är under utveckling. För närvarande kan du använda "Skriv in recept" för att mata in receptet manuellt.
|
||
|
||
### Receptformat — regler
|
||
|
||
| Sektion | Beskrivning |
|
||
|---------|------------|
|
||
| **H1 (# titel)** | Receptnamn |
|
||
| **Text efter H1, före ## Ingredienser** | Receptbeskrivning (valfritt) |
|
||
| **## Ingredienser** | Rubrik för ingredienslistan |
|
||
| **Ingrediensrader** | Mönster: `- ANTAL ENHET NAMN` eller `- ANTAL NAMN` (standard: st) |
|
||
| **Parentes i ingrediens** | Text i `(parentes)` sparas som ingrediensnot, t.ex. `(vispgrädde)`, `(eller crème fraiche)` |
|
||
| **## Tillvägagångssätt** (eller `## Instruktioner`) | Rubrik för tillagningsinstruktioner |
|
||
| **Text under instruktioner** | Instruktionstexten (kan fortsätta över flera rader) |
|
||
|
||
### Matchningsalgoritm
|
||
|
||
Systemet använder tre metoder för att hitta rätt produkt:
|
||
|
||
1. **Exakt match** (100 poäng)
|
||
- Ingrediensnamn matchar exakt efter normalisering (lowercase, utan skiljetecken)
|
||
|
||
2. **Delsträng-match** (70 poäng)
|
||
- Ingrediensnamn förekommer som del av produktnamnet eller vice versa
|
||
|
||
3. **Levenshtein-likhet** (40–100 poäng)
|
||
- Likhetspoäng baserat på tecknenskillnad
|
||
- Mindre än 40 poäng filtreras bort
|
||
|
||
Systemet visar upp till 5 bästa förslag per ingrediens.
|
||
|
||
---
|
||
|
||
## Projektstruktur
|
||
|
||
```
|
||
recipe-app/
|
||
├── frontend/ # Next.js (App Router)
|
||
├── backend/ # NestJS REST API
|
||
├── recipe-document-converter/ # Markdown-parserbibliotek
|
||
├── db/init/ # SQL-initialiseringsskript
|
||
├── compose.yml # Docker Compose
|
||
└── backup_recipe_app.sh # Backupskript
|
||
```
|
||
|
||
---
|
||
|
||
## Backup
|
||
|
||
```bash
|
||
bash backup_recipe_app.sh
|
||
```
|
||
|
||
Säkerhetskopierar källkod och Docker-images till konfigurerad backupmapp.
|