Files
recipe-app/NEXT_STEPS.md
T

14 KiB
Raw Blame History

Nästa steg

Förslag på vad vi kan ta tag i nästa gång vi öppnar projektet.
Se README.md för funktionsöversikt och TEKNISK_BESKRIVNING.md för teknisk detaljerinformation.
Se AI-FUNKTIONER.md för planerade AI-funktioner.


Status — senast genomgånget: 2026-04-21

Funktion Status
Inventorie (CRUD, konsumtion, historik) Klart
Recept (skapa, visa, importera, matchning) Klart
Receptredigering och borttagning (JWT-autentisering) Klart
Snabbimport (URL/PDF/bild/ICA) Klart
Kvittoimport (Mistral AI, OCR, alias) Klart
Matplanering (veckovy, inköpslista) Klart
Matplan — portionsjustering per dag Klart
Matplan — inventariejämförelse (backend) Klart
Matplan — inventariejämförelse (frontend-vy) Klart (/⚠️/ integrerat i inköpslistan)
Baslager (lista, lägg till, ta bort) Klart
Admin: Produkter (edit, merge, duplicate, restore, reset) Klart
Admin: Bulk-kategorisering Klart
Receptredigering (frontend UX) Klart
Receptbilder (upload URL) Klart
Autentisering (JWT, Auth.js v5, User-modell) Klart
Klient-side JWT via useAuthFetch() Klart
SessionProvider i root layout Klart
Användarprofil (firstName, lastName, email) Klart
Produktkategorier — hierarkisk struktur (3 nivåer) Klart
Kategori-seed (seed_all.sql, komplett träd, enda sanningskällan) Klart
Kategoritilldelning i admin-UI Klart
Taggning av produkter Klart
Näringsvärden på produkter Klart (schema + API)
Seed produktdata med kategoritilldelning Klart (seed_all.sql)
Användarspecifika produkter (UserProduct) ⚠️ Schema klart, UI basic
Användarroller (user / admin) Klart
Användarhantering i admin-UI Klart
Profilsida med flikar (Min profil / Användare / Databas) Klart
Teknisk skuld — oanvända InventoryItem-fält Klart (migration 20260418)
Teknisk skuld — redirect-routes städade Klart
Premium-plan (isPremium på User, Free/Paid-dropdown) Klart
AI-modul (AiService, Mistral-kategorisering, fallback) Klart
Admin: AI-kategorisering per produkt ("Fråga AI") Klart
Admin: AI-bulk-kategorisering av okategoriserade produkter Klart
Produktstatus (pending / active / rejected) Klart
Admin: Väntande produktförslag (pending-sida) Klart
Kvittoimport — AI-kategorisuggestion för premium-användare Klart
Säkerhetshuvuden — Caddy (globala headers) Klart
Säkerhetshuvuden — Next.js CSP Klart
Säkerhetshuvuden — NestJS Helmet (backup) Klart (aktiveras vid nästa rebuild)
Buggfix: "Vad behöver jag köpa" — flimmer och scroll Klart
Startsida — produktadmin-länk borttagen Klart
Avancerad AI-integration (veckoplanering, receptförslag) Planerad
EAN-skanning via Open Food Facts API Planerad

Notering 2026-04-20

Notering 2026-04-21

  • Rollskydd i frontend (middleware) och backend (admin på endpoints) är nu heltäckande.
  • Rate limiting, CORS-låsning och JWT_SECRET-krav är på plats.
  • Konsol-loggar borttagna ur backend.
  • Kvar: Kryptering av PII (e-post, namn i databasen), automatisering av seed_all.sql vid fresh install.

Den senaste versionen av db/seeds/seed_all.sql är pushad till utvecklingsmiljön, men har ännu inte körts på databasen. Nästa gång vi vill uppdatera kategoriträdet måste seed-scriptet köras manuellt:

docker exec -i recipe-db mariadb -uroot -p"$DB_PASS" recipe_app < db/seeds/seed_all.sql

Se även TEKNISK_BESKRIVNING.md för detaljer om seed-processen.


Vägen till produktlansering


Prioriterade förbättringar

1. ICA-skraparen missar receptbild

Problem: Vid import av ICA-recept via URL hämtas inte receptbilden korrekt.

  • Felsök parsern i recipe-document-converter/src/parser.ts — kontrollera att ICA:s bild-selektor fortfarande matchar sidans HTML-struktur
  • ICA kan ha ändrat klassnamn eller lazy-load-mekanism sedan skraparen skrevs
  • Verifiera med ett konkret ICA-recept-URL och logga vad imageUrl returnerar

2. Seed-data

Klart. db/seeds/seed_all.sql är den enda sanningskällan för kategorier och produkter.

Filen:

  • TRUNCATEar Category och nollställer Product.categoryId
  • Bygger hela kategoriträdet (nivå 13) utan dubbletter
  • Insertar ~190 produkter (INSERT IGNORE)
  • Kopplar produkterna till rätt kategori via JOIN-subqueries

Körs manuellt: docker exec -i recipe-db mariadb -uroot -p"$DB_PASS" recipe_app < db/seeds/seed_all.sql

2. Refactor: seed_all.sql som del av fresh install

Mål: Fresh install ska inte kräva ett manuellt seed-steg.

Nuläge:

  • db/init/001-init.sql (MariaDB auto-init) skapar bara en bootstrap-check-tabell
  • Prisma-migrationen 20260417310000_add_category_tree seedar kategorier en gång, men seed_all.sql skriver över dem
  • seed_all.sql körs inte automatiskt vid deploy eller fresh install

Alternativ:

  • Alt A: Flytta seed_all.sql-logiken till db/init/001-init.sql — körs automatiskt av MariaDB-containern vid första start
  • Alt B: Skapa en prisma/seed.ts som körs via prisma db seed — standard NestJS/Prisma-mönster, kan inkluderas i deploy.sh
  • Alt C: Lägg till seed_all.sql som ett steg i deploy.sh (körs alltid, idempotent p.g.a. TRUNCATE+INSERT IGNORE)

Oavsett alternativ bör de gamla kategori-INSERTs i 20260417310000_add_category_tree/migration.sql tas bort eller kommenteras ur för att undvika förvirring.

2. Användarroller och full användarhantering

Klart.

Systemet har nu fullständig rollbaserad åtkomstkontroll och ett komplett användarhanteringsgränssnitt inbyggt i profilsidan.

Rollsystemet:

  • Prisma-migration (20260418100000_add_user_role) — fältet role String @default("user") lades till på User-modellen
  • @Roles('admin')-dekoratorn (auth/decorators/roles.decorator.ts) — använder SetMetadata för att markera endpoints
  • RolesGuard (auth/roles.guard.ts) — registrerad globalt som APP_GUARD; läser rollmetadata, kastar 403 om rätt roll saknas
  • JWT inkluderar nu rolejwt.strategy.ts returnerar {userId, username, role}, auth.service.ts signerar med role i payload
  • Bootstrap-användare (users/admin-bootstrap.service.ts) — OnApplicationBootstrap skapar/uppdaterar Nadmin, Padmin, user1 och user2 vid varje uppstart via miljövariabler
  • Skyddade produkt-endpoints@Roles('admin')merge, delete, restore, reset-all, bulk-update, backfill-canonical i products.controller.ts

Backend-endpoints för användarhantering (alla kräver admin-roll):

  • GET /api/users — lista alla användare
  • PATCH /api/users/:id/role — ändra roll
  • POST /api/users — skapa ny användare (validering: unikt användarnamn och e-post)
  • DELETE /api/users/:id — ta bort användare (skyddad: kan inte ta bort sig själv)
  • POST /api/users/:id/reset-password — genererar tillfälligt lösenord, returnerar meddelandetext + lösenord
  • PATCH /api/users/:id/email — uppdatera e-postadress

Profilsidan med flikar (/profil):

  • ?tab=profil — Min profil (alla användare)
  • ?tab=anvandare — Användare (enbart admin): skapa, ta bort, rollbyte, e-postbyte, lösenordsåterställning med kopierings-modal
  • ?tab=databas — Databas (enbart admin): produktadmin (samma innehåll som /admin/products)
  • /admin/users omdirigerar till /profil?tab=anvandare
  • Navigeringslänken "👥 Användare" går direkt till /profil?tab=anvandare

3. Matplan-vy (frontend-polish)

Klart.

Inköpslistan och inventariejämförelsen är sammanslagna till en enhetlig vy med tre statusnivåer:

  • Saknas helt — visar hur mycket som behövs köpas
  • ⚠️ Delvis hemma — visar hur mycket mer som behövs + vad som finns
  • Finns hemma — markeras nedtonat, ingen köpindikering

Listan sorteras automatiskt: saknade ingredienser överst, hemma-ingredienser underst. En sammanfattningsrad visar totalt antal per statuskategori.

4. Teknisk skuld (underhåll)

Mål: Minska komplexitet och risk för buggar.

A. CanonicalNameForm och NameForm

Filerna var redan borttagna — inga aktiva imports hittades. Inget att göra.

B. Oanvända fält på InventoryItem

Följande 6 fält togs bort via Prisma-migration (20260418000000_remove_unused_inventory_fields): priority, shelfNote, isOnSale, priceLevel, proteinType, isLeftover

  • Schema, DTOs (create + update), service och frontend-typen är städade.
  • opened och suitableFor behölls — de används i UI.

C. Validering av DTO:er i admin-actions

Redan implementerat — trim() + max 100 tecken på alla fält i actions.ts. Inget att göra.

D. Routing-städning för kvitto och import

frontend/app/kvitto/page.tsx och frontend/app/recipes/import/page.tsx är borttagna. /import täcker båda use-cases via flikar.

E. Seed-data i versionshantering

data/matvaror_sverige.csv och data/seed_products.sql behålls i git för reproducerbarhet. Inga ändringar i .gitignore.

5. Avancerad AI-integration

Mål: Smarta receptförslag och veckoplanering baserat på inventarie och kampanjdata.

AI-infrastrukturen är nu på plats (AiService, mistral-small-2603, premium-plan). Kategorisering för produkter och kvittoimport är implementerat. Nästa steg:

  • "Vad ska jag laga idag?" — Receptförslag baserat på vad som finns i inventariet; kan byggas direkt ovanpå befintliga inventory- och recipe-endpoints
  • Veckoplanering med AI — Generera ett veckoschemat baserat på inventarie, preferenser och ev. kampanjpriser (kräver extern datakälla)
  • Kräver: tydlig API-design, kostnadskontroll och modellval per use-case

AI-loggning och audit

  • detta behöver ske innan nästa Ai-integration (receptförslag, veckoplanering) implementeras, för att säkerställa att vi har en robust lösning på plats för att spåra och analysera AI-anrop och resultat
  • Utforska och utveckla lösning för loggning och audit av AI-input och output
  • Syfte: möjliggöra spårbarhet, felsökning och kvalitetssäkring av AI-funktioner
  • Implementera loggning på ett sätt som inte lagrar personuppgifter eller känslig data i klartext
  • Utvärdera om loggar ska lagras i separat databas eller fil, och hur de kan användas för analys och förbättring

Enhetsstöd och konvertering

  • Se över om vi behöver utöka antalet stödda enhetstyper (t.ex. fler volym- eller portionsenheter)
  • Utveckla och förbättra normaliseringen i recipeservice.normalizeUnit
  • Se över och testa konverteringslogiken för enheter (t.ex. edge cases, felhantering)
  • Fundera på om AI kan användas för att tolka, normalisera eller konvertera enheter och mängder smartare

Enhetstester

Jest + ts-jest är uppsatt. Tester finns för:

  • normalize-name.ts — 10 tester
  • base.parser.ts (parseIngredientLine) — 12 tester
  • recipes.service.ts (normalizeUnit, convertUnit) — 17 tester

Kör med npm test i backend/.


Planerade funktioner

Säkerhet — kryptering av känslig användardata

Mål: Kryptera känsliga fält (t.ex. e-postadresser, personuppgifter) i databasen med en hybridlösning.

Förslag på approach:

  • AES-256-GCM för symmetrisk kryptering av data i vila (kolumnnivå i MariaDB eller på applikationsnivå i Prisma middleware)
  • Nyckelhantering via miljövariabel eller extern nyckelhanteringstjänst (t.ex. HashiCorp Vault)
  • Kräver genomtänkt migrering av befintlig data och påverkar sökbarhet (krypterade fält kan inte indexeras direkt)

EAN-skanning — import via streckkod (Open Food Facts)

Mål: Låt användaren skanna eller skriva in en EAN-streckkod och få produktinformation (namn, kategori, näringsvärden) ifyllt automatiskt.

Open Food Facts är ett öppet, gratis API utan API-nyckel för grundläggande användning.

Exempelanrop (EAN 7310960010016):

GET https://world.openfoodfacts.org/api/v0/product/{ean}.json

Svaret innehåller:

  • product.product_name — produktnamn
  • product.categories — kategoristräng (kommaseparerad)
  • product.nutriments — näringsvärden (energi, protein, fett, kolhydrater, m.fl.)
  • product.code — EAN-koden bekräftad

Förslag på implementation:

  1. Backend-endpointGET /api/products/ean/:code — slår upp i Open Food Facts, returnerar normaliserat produktförslag (namn, kategori, näringsvärden) utan att spara
  2. Frontend-import — nytt fält i produktformuläret (eller separat import-flöde): ange EAN → knapp "Hämta" → formuläret förifylls
  3. Alternativt: kamerabaserad skanning i mobil webbläsare via BarcodeDetector API (eller externt bibliotek som zxing-js)
  4. Kategorimappning — Open Food Facts-kategorier är på engelska/franska; en mappningstabell eller fuzzy-matchning mot systemets kategorier behövs
  5. Näringsdata — om product.nutriments finns kan det sparas direkt i Prisma-modellens näringsvärdesfält (redan schema-klara)

Begränsningar att ha i åtanke:

  • Produkttäckning varierar — svenska dagligvaror är välrepresenterade men inte allt finns
  • Produktnamn är ofta på originalspråk; kan behöva redigeras
  • Rate limiting: för hög användning rekommenderar Open Food Facts att kontakta dem