# 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).  
> För förslag på nästa steg i projektet, se [NEXT_STEPS.md](NEXT_STEPS.md).  
> För planerade AI-funktioner, se [AI-FUNKTIONER.md](AI-FUNKTIONER.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 och mer

### Baslager
- **Ständigt lager** — markera produkter du alltid räknar med att ha hemma
- **Grupperat per kategori** — produkterna i baslagret visas grupperade under kategorirubrik
- **Lägg till och ta bort** — välj från produktlistan via sökbar dropdown, ta bort med ett klick

---

### 📌 Så använder du Inventarie och Baslager

Dessa två funktioner fyller olika syften och kompletterar varandra:

#### Inventarie — ”vad du faktiskt har hemma”
Inventariet är en **aktiv förrådsbok** över varor du just nu har hemma. Här registrerar du:
- Exakt mängd (t.ex. 500 g pasta, 1,5 liter mjolk)
- Var varan förvaras (kyl, frys, skafferi)
- Bäst före-datum
- Om förpackningen är öppnad

#### Praktiskt flöde
| Du vill se vad du behöver köpa | **Matplanen** — inköpslistan jämför mot båda |
| Du tog slut på mjolk | Ta bort från inventariet (baslagret påverkas inte) |
- **Portionsjustering** — ange antal portioner vid skapandet; matplanen räknar automatiskt om ingrediensmängder om du lagar fler eller färre portioner
- **Receptjämförelse mot inventorie** — se direkt vilka ingredienser du har hemma, vad som saknas och om enheter är inkompatibla
- **Importera recept från Markdown** — klistra in ett recept i enkelt format, låt systemet matcha ingredienser, granska och spara med ett klick
- **Importera recept från PDF, bild eller länk** — stöd för PDF-textutvinning, OCR av bilder och webbimport via snabbimport
- **Intelligenta matchningar** — Levenshtein-baserad likhetsbedömning hittar rätt produkt även vid osäker stavning
- **Enhetskonvertering** — automatisk konvertering mellan viktenheter (g/kg), volymenheter (ml/dl) och portionsenheter (tsk/msk)

- **Inköpslista** — genereras automatiskt utifrån veckans planerade recept; ingrediensmängder skalas proportionellt om portioner justerats
- **Inventariejämförelse** — jämför inköpslistans ingredienser mot vad du faktiskt har hemma (aggregerat per vecka)
> Obs: Destruktiva åtgärder (merge, ta bort, återställ, bulk-uppdatera, återställ all data) kräver admin-roll.
**Admin: Produkter (fliken Databas i /profil)**

Produktadmin är nu uppdelad i tre undertabbar:
- **🗑️ Papperskorg** — visa mjukraderade produkter, återställ eller radera permanent
- Redigera produkter — uppdatera namn, canonical name, kategori (hierarkisk dropdown) och varumärke inline
- Bulk-kategorisering — filtrera fram okategoriserade produkter, markera flera och sätt kategori på alla markerade
- AI-kategorisering per produkt och bulk — "✨ Fråga AI" för kategori
- Hitta dubbletter och slå ihop produkter (merge)
- Förhandsvisning av merge
- Ta bort (mjukradera) och återställ produkter
- **Produktförslags-kö** — produkter med status `pending` samlas på sidan `/admin/products/pending` (länk "⏳ Förslag" i navigeringen)
- **Godkänn eller avvisa** — admin kan godkänna (status → `active`) eller avvisa (status → `rejected`) varje förslag med ett klick

- **Min profil** — redigera förnamn, efternamn och e-postadress
- **Databas** — hantera inventarie och baslager (se nedan)

**Enbart admin:**
- **Användare** — fullständig användarhantering:
  - Skapa ny användare (användarnamn, e-post, lösenord, roll)
  - Ändra roll via dropdown direkt i tabellen
  - Ändra **plan** (Free / Paid ✨) via dropdown — styr tillgång till premium-AI-funktioner
  - Ändra e-postadress inline
  - Återställ lösenord — genererar ett tillfälligt lösenord och visar ett kopierings-redo meddelande
  - Ta bort användare (skyddad: kan inte ta bort sig själv)
- **Databas** — produktdatabasen: redigera, merga, bulk-kategorisera och återställa produkter

### Autentisering och roller
- **Rollbaserad åtkomstkontroll** — systemet har två roller: `user` (standard) och `admin`
- **Premium-plan** — `isPremium`-flagga på användaren styr tillgång till AI-funktioner (kvittoimport AI-hints m.fl.); administreras via Plan-kolumnen i användarhanteringen
- **Automatisk bootstrap** — fyra användare skapas eller uppdateras automatiskt när backend startar, baserat på miljövariabler:
  - `Nadmin` (admin), `Padmin` (admin), `user1` (user), `user2` (user)
- **Skyddade admin-endpoints** — destruktiva produkt-endpoints och all användarhantering kräver `admin`-roll; försök utan rätt roll ger 403 Förbjuden
- **Navigering** — admin-länkarna "⚙️ Admin", "⏳ Förslag" och "👥 Användare" visas enbart för inloggade administratörer

---

## 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)

> Stacken använder lokala Docker-images, hälsokontroller och startordning mellan databasen, API:t och frontend för stabilare uppstarter och Portainer-deployer.

### Drift-snabbguide

Använd dessa kommandon konsekvent beroende på vilken del av systemet som ska vara uppe.

**Huvudappen (recept.gynther.se):**
```bash
docker compose build recipe-frontend recipe-api
docker compose up -d recipe-db recipe-api recipe-frontend
```

**Endast backend:**
```bash
docker compose build recipe-api
docker compose up -d recipe-db recipe-api
```

**Flutter-spåret (test.gynther.se):**
```bash
docker compose -f compose.yml -f compose.flutter.yml build recipe-flutter
docker compose -f compose.yml -f compose.flutter.yml up -d --no-deps recipe-flutter
```

**Viktigt:** `docker compose build ...` bygger bara image. Tjänsten startar först efter `docker compose up -d ...`.

**Om orphan-varningen:**
- Varning om orphan-containers är väntad när huvudappen körs med bara `compose.yml` men Flutter tidigare startats med `compose.flutter.yml`.
- Det är normalt ofarligt.
- Kör inte `docker compose down --remove-orphans` om du inte avser att även stoppa Flutter-spåret.

### 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/api/health

# Databasspecifik hälsokontroll
curl http://localhost:8080/api/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
- **Andra receptlänkar** — fallback till generisk HTML/JSON-LD-parser
- En lyckad import omdirigeras till "Skriv in recept" med förifylld Markdown

**Stödda källor:**
- ICA.se — Recept skrapas automatiskt
- Andra webbplatser — Generic HTML-parser (JSON-LD först, sedan HTML-fallback)
- PDF-filer — textutvinning från uppladdad PDF
- Bildfiler — OCR via Tesseract (`swe+eng`) för PNG, JPG, JPEG, WEBP och BMP

**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, bild eller ange receptlänk för automatisk tolkning

### 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-filer med inbyggd text
- Ladda upp bilder (`png`, `jpg`, `jpeg`, `webp`, `bmp`) som tolkas med OCR
- Ange URL till en receptsida eller blogg
- Låta systemet omvandla resultatet till Markdown och öppna det i redigeringsläget

> **Notering:** Importen använder PDF-textutvinning och Tesseract OCR för att ge en första receptversion som sedan kan granskas och sparas.

### 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.
