Files
dashfront/TODO.md
2026-08-03 00:22:46 +02:00

5.4 KiB
Raw Blame History

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 (Frontend fertig, Backend-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.