# 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). --- ## 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 ### Recept - **Skapa och redigera recept** — med namn, beskrivning, portionsantal, ingredienser (kvantitet och enhet) och instruktioner i Markdown-format - **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) ### Matplanering - **Veckovy** — planera veckans måltider dag för dag med ett enkelt receptval - **Portionsjustering per dag** — välj hur många portioner du vill laga för varje dag; avviker du från receptets grundportioner visas en återställningsknapp - **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) ### Kvittoimport - **Fotografera eller ladda upp kvitto** — JPEG, PNG, WebP, HEIC och PDF stöds (max 15 MB) - **AI-tolkning via Mistral** — Mistral AI extraherar varunamn och mängder direkt från kvittobilden - **Alias-matchning** — kvittots produktnamn matchas mot kända alias (t.ex. "ICA Kvarg Jordg" → "Kvarg") och mot befintliga produkter - **Granska och lägg till** — se tolkningsresultatet, justera kvantitet och enhet, och lägg till direkt i inventariet ### 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 ### Admin: Produkter - **Redigera produkter** — uppdatera visningsnamn, canonical name, kategori (hierarkisk dropdown) och varumärke inline direkt i listan - **Kategoritilldelning** — välj kategori ur ett 3-nivåträd (huvudkategori → underkategori → typ) som laddas dynamiskt från API:et - **Bulk-kategorisering** — filtrera fram okategoriserade produkter, markera flera (eller "välj alla synliga") och sätt kategori på alla markerade på en gång — effektivt för att kategorisera många produkter i ett svep - **Hitta dubbletter** — identifiera produkter med samma normaliserade namn - **Slå ihop produkter** — merge av två produktposter: alla inventarieföremål och receptreferenser flyttas till målprodukten, källan soft-deleteras - **Förhandsvisning** — granska vad som händer (inventarieräkningar, utfall) innan merge genomförs - **Ta bort och återställ** — soft-delete enskilda produkter, återställ med ett klick - **Återställ all produktdata** — rensningsknapp som raderar alla produkter, inventarie, taggar och kvitto-alias (behåller användare och kategorier) ### Användarprofil - **Redigera profilinformation** — uppdatera förnamn, efternamn och e-postadress under "Min profil" --- ## 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. ### 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.