Files
dashfront/TODO.md
2026-08-02 22:53:35 +02:00

70 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 }` |
| **Kategorie verschieben** (VORSCHLAG, offen) | `PATCH /api/category/:id` | `{ parentId: number }` | `{ category: { id, parentId, name, slug } }` |
| 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.
### Kategorie in Unterkategorie ablegen (Tree-Drop) — [VORSCHLAG an dashback, offen]
- **UI fertig**: oberes Drittel der Edit-Kachel zeigt links Move-Icon (`DragHandle`), rechts Tree-Icon (`AccountTree`). Beide sind Drag-Handles (`handle: .sortable-handle, .sortable-tree`). Ziehen am **Tree**-Icon sortiert die Geschwister **nicht** neu um (`handleSort` ignoriert Tree-Draggs).
- **Backend-Vorschlag** (fehlt noch in `dashback/docs/api/routes/`):
- `PATCH /api/category/:id` erweitern: optional `parentId` im Body, zusätzlich zu `name`.
- Request: `{ parentId: number }` → verschiebt die Kategorie unter den neuen Eltern. `{ name }` → nur Umbenennen (bestehend).
- Response: `{ category: { id, parentId, name, slug } }`.
- Erforderliche Validierung: Ziel-Eltern existiert (404), kein Zyklus/kein Verschieben in sich selbst oder eigene Nachkommen (400), Company-Scope (403).
- **Bis der Vertrag feststeht**: keine Frontend-Implementierung des Drops (Regel `no-assumed-api`).
### 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`.