13 KiB
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-19
| 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 |
| Avancerad AI-integration (veckoplanering, receptförslag) | ❌ Planerad |
| EAN-skanning via Open Food Facts API | ❌ Planerad |
Notering 2026-04-20
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
- Säkerhet & Data
- DevOps & Stabilitet
- Testning & Kvalitet
- Funktionella förbättringar
- Risker & Flaskhalsar
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
imageUrlreturnerar
2. Seed-data ✅
Klart. db/seeds/seed_all.sql är den enda sanningskällan för kategorier och produkter.
Filen:
- TRUNCATEar
Categoryoch nollställerProduct.categoryId - Bygger hela kategoriträdet (nivå 1–3) 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_treeseedar kategorier en gång, men seed_all.sql skriver över dem seed_all.sqlkö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.tssom körs viaprisma db seed— standard NestJS/Prisma-mönster, kan inkluderas i deploy.sh - Alt C: Lägg till
seed_all.sqlsom ett steg ideploy.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ältetrole String @default("user")lades till påUser-modellen @Roles('admin')-dekoratorn (auth/decorators/roles.decorator.ts) — använderSetMetadataför att markera endpointsRolesGuard(auth/roles.guard.ts) — registrerad globalt somAPP_GUARD; läser rollmetadata, kastar 403 om rätt roll saknas- JWT inkluderar nu
role—jwt.strategy.tsreturnerar{userId, username, role},auth.service.tssignerar medrolei payload - Bootstrap-användare (
users/admin-bootstrap.service.ts) —OnApplicationBootstrapskapar/uppdaterar Nadmin, Padmin, user1 och user2 vid varje uppstart via miljövariabler - Skyddade produkt-endpoints —
@Roles('admin')påmerge,delete,restore,reset-all,bulk-update,backfill-canonicaliproducts.controller.ts
Backend-endpoints för användarhantering (alla kräver admin-roll):
GET /api/users— lista alla användarePATCH /api/users/:id/role— ändra rollPOST /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ösenordPATCH /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/usersomdirigerar 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.
openedochsuitableForbehö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
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 testerbase.parser.ts(parseIngredientLine) — 12 testerrecipes.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— produktnamnproduct.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:
- Backend-endpoint —
GET /api/products/ean/:code— slår upp i Open Food Facts, returnerar normaliserat produktförslag (namn, kategori, näringsvärden) utan att spara - Frontend-import — nytt fält i produktformuläret (eller separat import-flöde): ange EAN → knapp "Hämta" → formuläret förifylls
- Alternativt: kamerabaserad skanning i mobil webbläsare via
BarcodeDetectorAPI (eller externt bibliotek somzxing-js) - Kategorimappning — Open Food Facts-kategorier är på engelska/franska; en mappningstabell eller fuzzy-matchning mot systemets kategorier behövs
- Näringsdata — om
product.nutrimentsfinns 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