# Nästa steg > Förslag på vad vi kan ta tag i nästa gång vi öppnar projektet. > Se [README.md](README.md) för funktionsöversikt och [TEKNISK_BESKRIVNING.md](TEKNISK_BESKRIVNING.md) för teknisk detaljerinformation. > Se [AI-FUNKTIONER.md](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 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: ```bash 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](produktlansering.md#1-säkerhet--data) - [DevOps & Stabilitet](produktlansering.md#2-devops--stabilitet) - [Testning & Kvalitet](produktlansering.md#3-testning--kvalitet) - [Funktionella förbättringar](produktlansering.md#4-funktionella-förbättringar) - [Risker & Flaskhalsar](produktlansering.md#5-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 `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å 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_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 `role`** — `jwt.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')` på `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-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 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