054a19ed7c
feat: add AI categorization for products and enhance user management - Integrated AI service for category suggestions in receipt import and product management. - Added premium subscription feature for users with corresponding API endpoints. - Implemented admin interface for managing pending product suggestions. - Enhanced user management to include premium status and corresponding UI updates. - Updated database schema to support new fields for premium status and product status.
183 lines
10 KiB
Markdown
183 lines
10 KiB
Markdown
# 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-19
|
|
|
|
| Funktion | Status |
|
|
|---|---|
|
|
| Inventorie (CRUD, konsumtion, historik) | ✅ Klart |
|
|
| Recept (skapa, visa, importera, matchning) | ✅ 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 |
|
|
| Användarprofil (firstName, lastName, email) | ✅ Klart |
|
|
| Produktkategorier — hierarkisk struktur (3 nivåer) | ✅ Klart |
|
|
| Kategori-seed (supplement, idempotent) | ✅ Klart |
|
|
| Kategoritilldelning i admin-UI | ✅ Klart |
|
|
| Taggning av produkter | ✅ Klart |
|
|
| Näringsvärden på produkter | ✅ Klart (schema + API) |
|
|
| Seed produktdata med kategoritilldelning | ⚠️ Script klart, ej aktiverat i init |
|
|
| 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 |
|
|
|
|
---
|
|
|
|
## Prioriterade förbättringar
|
|
|
|
### 1. Seed-data (002-seed-products.sql)
|
|
**Mål:** Möjliggöra demo och ny server utan manuell datainmatning.
|
|
|
|
`db/init/002-seed-products.sql` är inaktiverad (`.disabled`) tills produkterna har rätt `categoryId`. Skript för kategorimappning finns i `db/seeds/`:
|
|
- Kör `db/seeds/categories_supplement.sql` → lägger till saknade kategorier
|
|
- Kör `db/seeds/seed_product_categories.sql` → kopplar ~190 produkter till rätt kategori
|
|
- Verifiera att mappningarna ser rätt ut i admin-UI (filtrera på okategoriserade)
|
|
- Generera en ny `002-seed-products.sql` med korrekt `categoryId` per rad (via `SELECT` mot live-db)
|
|
- Ta bort `.disabled`-suffixet och testa fresh install
|
|
|
|
### 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
|
|
|
|
---
|
|
|
|
## 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
|