# TODO — nächster Schritt (Brands / Artikelfelder) **dashback** hat die HTTP-Routen geliefert (siehe `../dashback/TODO.md`). Alle Endpoints stehen. `companyId` kommt **immer aus der Auth-Session** (nicht aus `?companyId=`), gesteuert über `google_auth.setSelectedCompany`. Hier die UI bauen. ## Endpoints | UI-Bedarf | HTTP | Request | Response | | --- | --- | --- | --- | | Brand-Liste | `GET /api/brand` | – | `{ brands: Brand[] }` | | Brand anlegen / updaten | `PUT /api/brand` | `{ name, gsprpinfo? }` | `{ brand: Brand }` | | Brand löschen | `DELETE /api/brand/:id` | – | `204` | | EANs setzen (replace-all) | `PUT /api/article/:sku/eans` | `{ eans: string[] }` | `{ article }` (Detail) | | Brand setzen / entfernen | `PUT /api/article/:sku/brand` | `{ brandId: number \| null }` | `{ article }` (Detail) | | Gewicht setzen | `PUT /api/article/:sku/weight` | `{ weight: number }` | `{ article }` (Detail) | | Kategorien setzen (replace-all) | `PUT /api/article/:sku/categories` | `{ categoryIds: number[] }` | `{ article }` (Detail) | | Kategorie umbenennen | `PATCH /api/category/:id` | `{ name }` | `{ category: { id, name, slug } }` | | Kategorie-Reihenfolge | `PUT /api/category/order` | `{ parentId, categoryIds: number[] }` | `{ categoryIds }` | | Detail liefert neue Felder | `GET /api/article/:sku` | – | `{ article }` mit `eans`, `categoryIds`, `weight`, `brand` | `Brand` = `{ id, name, gsprpinfo \| null }`. Alle PUT/PATCH-Endpoints der Artikel liefern dasselbe Shape wie `GET /api/article/:sku`. ## Umsetzung ### API-Client (`src/api/index.js`) - Alle Calls über den bestehenden Client (`credentials: 'include'`) — Frontend spricht nur HTTP, nie direkt den Store. - Neuen Methoden für: `brand.list` / `brand.upsert` / `brand.delete` und `article.setEansBySku` / `article.setBrandIdBySku` / `article.setWeightBySku` / `article.setCategoryIdsBySku` sowie `category.rename`. - **Kein `companyId` in Request/Pfad/Query senden** — die Company kommt aus der Session. ### Brand-UI - **Liste**: lädt `GET /api/brand` und zeigt `name` (+ optional `gsprpinfo`). - **Anlegen/Updaten**: ein Formular (Name + optional GSPRP-Info). Upsert matcht per `name` — gleicher Name ⇒ Update, sonst Create. Leeres/fehlendes `name` ⇒ API `400 Invalid brand`. - **Löschen**: Bestätigung; `409 Brand in use` als Fehler anzeigen (Brand ist noch an Artikeln). - Hängt an `selectedCompanyId`: bei Company-Wechsel Liste neu laden / leeren. ### Artikel-Detail-Felder - **EANs**: Mehrfach-Eingabe (Liste). Replace-all: leere Liste löscht alle. `400 Invalid eans` bei leeren/duplizierten Einträgen. - **Brand**: Dropdown aus `GET /api/brand`; „Keine Brand“ ⇒ `brandId: null`. Deal nur mit Brands derselben Company (sonst `404 Brand not found`). - **Gewicht**: Zahlenfeld, `>= 0`. `400 Invalid weight` sonst. - **Kategorien**: Mehrfachauswahl aus der Category-Tree; nur Kategorien derselben Company (sonst `400 Invalid categoryIds`). Leere Liste entfernt alle. - **Kategorie umbenennen**: Inline/Formular im Category-Tree → `PATCH /api/category/:id` mit `{ name }`. Leeres `name` ⇒ `400 Name required`. Nach Save das zurückgegebene `{ id, name, slug }` im Baum aktualisieren. - **Kategorie-Reihenfolge (Drag & Drop)**: nach Sortierung → `PUT /api/category/order` mit `{ parentId, categoryIds }` (die neuen Kind-IDs in gewünschter Reihenfolge). `parentId` ist der aktuelle Elternknoten. `400 Invalid category order` bei falscher Menge/Duplikaten; nur Children desselben Elternteils angeben. - Nach jedem Save das zurückgegebene Detail-Objekt in den Store übernehmen. ### Fehlerbehandlung - Fehler als Toast/Formular-Fehler abbilden: - `Brand in use` (409), `Invalid eans` / `Invalid weight` / `Invalid categoryIds` / `Invalid brand` (400) - `Brand not found` / `Article not found` / `Category not found` (404) - `Name required` (400) bei leerem Kategorienamen - `No company selected` (400) → Company-Wechsel-Flow - `Not authorized` (403) ## Referenz - API-Doku: `../dashback/docs/api/README.md` und `../dashback/docs/api/routes/` - `brand/list.md`, `brand/upsert.md`, `brand/delete.md` - `article/set-eans.md`, `article/set-brand.md`, `article/set-weight.md`, `article/set-categories.md` - `category/rename.md` - Company-Scope: `google_auth.setSelectedCompany` (Store) — siehe `../dashdbschema/README.md`.