fix(docs): update NEXT_STEPS, README, and TEKNISK_BESKRIVNING with user role management details and new category structure
This commit is contained in:
+39
-20
@@ -89,6 +89,8 @@ docker exec recipe-db mariadb -uroot -p"LÖSENORD" recipe_app -e "SHOW TABLES;"
|
||||
| | `app/matplan/MealPlanClient.tsx` | Veckovy, receptval per dag, portionsjustering, inköpslista, inventariejämförelse |
|
||||
| **Kvittoimport** | `app/import/page.tsx` | Server component med Navigation + flikvy |
|
||||
| | `app/import/ImportTabsClient.tsx` | Klientkomponent: kvitto/recept-flikar |
|
||||
| **Admin: Användare** | `app/admin/users/page.tsx` | Server component: hämtar alla användare, kräver admin-roll |
|
||||
| | `app/admin/users/UserAdminClient.tsx` | Klientkomponent: tabell med rollbyte-knappar, anropar `/api/admin-users/:id` |
|
||||
| **Admin: Produkter** | `app/admin/products/page.tsx` | Produktadmin-panel |
|
||||
| | `AdminProductList.tsx` | Lista produkter, sök, sortera, filter okategoriserade, bulk-select + bulk-kategorisering |
|
||||
| | `EditProductForm.tsx` | Inline redigering: name, canonicalName, kategori (hierarkisk dropdown), brand, taggar |
|
||||
@@ -106,6 +108,8 @@ Alla proxy-routes läser auth-token via `auth()` (Auth.js v5) och vidarebefordra
|
||||
|
||||
| Route | Metod | Syfte |
|
||||
|-------|-------|-------|
|
||||
| `/api/admin-users` | GET | Hämtar alla användare (kräver admin-roll i session) |
|
||||
| `/api/admin-users/[id]` | PATCH | Ändrar roll för användare med givet id (kräver admin-roll i session) |
|
||||
| `/api/auth/[...nextauth]` | GET, POST | Auth.js handlers (login, logout, session) |
|
||||
| `/api/products` | GET | Produktlista (auth-wrappat med `auth(req)`) |
|
||||
| `/api/categories` | GET | Kategorihierarki (publik, proxies `/api/categories/tree`) |
|
||||
@@ -124,8 +128,8 @@ Alla proxy-routes läser auth-token via `auth()` (Auth.js v5) och vidarebefordra
|
||||
|
||||
### Autentisering (Auth.js v5)
|
||||
|
||||
- `auth.ts` — NextAuth-konfiguration med Credentials provider
|
||||
- `middleware.ts` — Skyddar alla routes utom `/login`, `/register` och `/api/auth`
|
||||
- `auth.ts` — NextAuth-konfiguration med Credentials provider; sparar `accessToken`, `userId`, `username` och `role` i JWT-token och session
|
||||
- `proxy.ts` — Skyddar alla routes utom `/login`, `/register` och `/api/auth`; blockerar `/admin/*` om sessionens `role` inte är `admin`
|
||||
- `lib/auth-headers.ts` — `getAuthHeaders()` hämtar Bearer-token från session (server-side)
|
||||
- `lib/api.ts` — `fetchJson()` lägger automatiskt till auth-headers server-side, redirectar till `/login` vid 401
|
||||
|
||||
@@ -143,7 +147,8 @@ Alla proxy-routes läser auth-token via `auth()` (Auth.js v5) och vidarebefordra
|
||||
- **Språk:** TypeScript 5.4.5
|
||||
- **Databas:** MariaDB 11 (via Prisma 6.12.0 ORM)
|
||||
- **API:** REST, validering med class-validator
|
||||
- **Autentisering:** JWT (7 dagars token), JwtAuthGuard skyddar alla routes, `@Public()` dekorator för öppna endpoints
|
||||
- **Autentisering:** JWT (7 dagars token), `JwtAuthGuard` skyddar alla routes globalt, `RolesGuard` kontrollerar rollkrav, `@Public()` dekorator för öppna endpoints
|
||||
- **Rollbaserad behörighet:** `@Roles('admin')` dekoratorn via `SetMetadata`; `RolesGuard` kastar 403 om rätt roll saknas
|
||||
- **Felhantering:** GlobalExceptionFilter (svenska felmeddelanden)
|
||||
- **Hälsokontroll:** /health endpoints
|
||||
- **Bygg:** `nest build`, körs i Docker-container
|
||||
@@ -155,16 +160,22 @@ backend/src/
|
||||
├── app.module.ts # Root module
|
||||
├── main.ts # Startpunkt (port 8080, global prefix "api")
|
||||
├── auth/
|
||||
│ ├── auth.controller.ts # POST /api/auth/login
|
||||
│ ├── auth.service.ts # validateUser, login (JWT-signering)
|
||||
│ ├── auth.controller.ts # POST /api/auth/login, POST /api/auth/register
|
||||
│ ├── auth.service.ts # validateUser, login (JWT-signering inkl. role)
|
||||
│ ├── auth.module.ts
|
||||
│ ├── jwt.strategy.ts # Passport JWT-strategi
|
||||
│ ├── jwt.strategy.ts # Passport JWT-strategi (returnerar userId, username, role)
|
||||
│ ├── jwt-auth.guard.ts # Global guard (skyddar allt utom @Public)
|
||||
│ ├── roles.guard.ts # Guard som kontrollerar @Roles() metadata; kastar 403
|
||||
│ └── decorators/
|
||||
│ └── public.decorator.ts # @Public() – markerar öppen endpoint
|
||||
│ ├── public.decorator.ts # @Public() – markerar öppen endpoint
|
||||
│ ├── current-user.decorator.ts # @CurrentUser() – extraherar {userId, username, role}
|
||||
│ └── roles.decorator.ts # @Roles('admin') – sätter rollkrav via SetMetadata
|
||||
├── users/
|
||||
│ ├── users.controller.ts # GET/PATCH /api/users/me
|
||||
│ ├── users.service.ts # findByUsername, create, updateProfile
|
||||
│ ├── users.controller.ts # GET /api/users/me, PATCH /api/users/me
|
||||
│ │ # GET /api/users (admin), PATCH /api/users/:id/role (admin)
|
||||
│ ├── users.service.ts # findByUsername, findById, create, updateProfile
|
||||
│ │ # findAll, setRole
|
||||
│ ├── admin-bootstrap.service.ts # OnApplicationBootstrap: skapar/uppdaterar 4 seed-användare
|
||||
│ └── users.module.ts
|
||||
├── categories/
|
||||
│ ├── categories.controller.ts # GET /api/categories, GET /api/categories/tree (@Public)
|
||||
@@ -379,9 +390,11 @@ GET /api/categories/tree Hierarkiskt träd (@Public)
|
||||
|
||||
### Användar-endpoints
|
||||
```
|
||||
POST /api/auth/login Logga in, returnerar JWT (@Public)
|
||||
GET /api/users/me Hämta inloggad användares profil
|
||||
POST /api/auth/login Logga in, returnerar JWT inkl. role (@Public)
|
||||
GET /api/users/me Hämta inloggad användares profil (inkl. role)
|
||||
PATCH /api/users/me Uppdatera firstName, lastName, email
|
||||
GET /api/users Lista alla användare (kräver admin-roll)
|
||||
PATCH /api/users/:id/role Ändra roll för användare (kräver admin-roll)
|
||||
```
|
||||
|
||||
### Baslager-endpoints
|
||||
@@ -422,17 +435,29 @@ DELETE /api/receipt-alias/:id Ta bort alias
|
||||
### User
|
||||
```prisma
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
email String @unique
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
email String @unique
|
||||
firstName String?
|
||||
lastName String?
|
||||
passwordHash String
|
||||
role String @default("user") # "user" eller "admin"
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
**Bootstrap-användare:** När backend startar kör `AdminBootstrapService.onApplicationBootstrap()` och skapar eller uppdaterar fyra användare baserade på miljövariabler:
|
||||
|
||||
| Användarnamn | Roll | E-post | Miljövariabel |
|
||||
|---|---|---|---|
|
||||
| Nadmin | admin | nadmin@localhost | `ADMIN_NADMIN_PASSWORD` |
|
||||
| Padmin | admin | padmin@localhost | `ADMIN_PADMIN_PASSWORD` |
|
||||
| user1 | user | user1@localhost | `SEED_USER1_PASSWORD` |
|
||||
| user2 | user | user2@localhost | `SEED_USER2_PASSWORD` |
|
||||
|
||||
Om en användare redan finns men har fel roll rättas rollen automatiskt. Om miljövariabeln saknas hoppas den användaren över med en varning i loggen.
|
||||
|
||||
### Category
|
||||
```prisma
|
||||
model Category {
|
||||
@@ -495,16 +520,10 @@ model InventoryItem {
|
||||
unit String # Enhet (g, kg, ml, dl, st, tsk, msk, etc)
|
||||
brand String? # Varumärke
|
||||
location String? # Lagerplats (Kyl, Frys, Skafferi, etc)
|
||||
priority Int? # Prioritetsordning
|
||||
purchaseDate DateTime? # Köpdatum
|
||||
opened Boolean? # Markering för öppnad produkt
|
||||
shelfNote String? # Lagringsnot
|
||||
suitableFor String? # Lämplighetsmärkning (t.ex. "vegetarian")
|
||||
isOnSale Boolean? # Är på rea
|
||||
priceLevel Int? # Priskategori (1–5)
|
||||
bestBeforeDate DateTime? # Bäst före-datum
|
||||
proteinType String? # Proteintyp (t.ex. "beef", "chicken")
|
||||
isLeftover Boolean? # Är från tidigare lagnning
|
||||
comment String? # Fri kommentar
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
Reference in New Issue
Block a user