VOYAGE – Workspace Backend Dokumentation UPDATE 2026-01-21 ======================================= ZIEL ---- Ein internes Workspace-System mit Login + Webinterface und ein separates öffentliches Webblog für Content & Brand. AKTUELLER STAND --------------- Bereits implementiert: DOMAIN - Products - SKUs (Varianten) - InventoryMovements (Bestandsbuchungen) - Current Stock pro SKU (Aggregation) - Inventory Overview Endpoint (GET /api/inventory/overview) WORKSPACE UI (Next.js, minimal) - Inventory Übersicht - Tabelle mit allen SKUs + currentStock - Suche & Filter (Name, SKU, Kategorie) - Inventory Movements (+ / -) - PRODUCTION = positives Delta - SALE = negatives Delta SECURITY / LOGIN - Spring Security - Form Login (Session-basiert, kein JWT) - /api/** ist geschützt - Login per Browser (/login) - Login per curl (Cookie/JSESSIONID) - Logout invalidiert Session + löscht Cookie + Redirect ins UI Damit ist das Domain-Fundament + Zugriffsschutz + UI-taugliche API abgeschlossen. DATENBANK (AKTUELL) ------------------- Die Anwendung verwendet KEINE In-Memory DB mehr. Aktueller Stand: - H2 File-basierte Datenbank (persistent) - JDBC URL: jdbc:h2:file:./data/voyage-db;AUTO_SERVER=TRUE Eigenschaften: - Daten liegen auf der Festplatte (data/voyage-db.mv.db) - KEIN Datenverlust bei App-Restart - IDs bleiben stabil - AUTO_SERVER erlaubt parallelen Zugriff (App + H2 Console) WICHTIG – H2 PASSWORT -------------------- - Das H2 Passwort wird beim ERSTEN Start der File-DB festgelegt (falls gesetzt). - Danach MUSS es identisch bleiben. - Falsches Passwort → App startet NICHT (SQLState 28000). Empfohlene Dev-Konfiguration: - spring.datasource.username=sa - spring.datasource.password= (leer) H2 CONSOLE ---------- URL: - http://localhost:8080/h2-console Login: - JDBC URL: jdbc:h2:file:./data/voyage-db;AUTO_SERVER=TRUE - User: sa - Password: leer (oder exakt das initial gesetzte) WICHTIG: - H2 Login ≠ Workspace Login - H2 Login = DB Zugriff - Workspace Login = App Zugriff GRUNDPRINZIP ------------ Workspace (intern) und Public Website (Blog) sind strikt getrennt. - Workspace = interne Realität (Inventory, Orders, Drops, Users) - Public Web = Content, Blog, Brand (keine sensiblen Daten) ARCHITEKTUR ----------- 1) workspace-api (Spring Boot) - Products / SKUs / Inventory - Inventory Overview (aggregiert) - Auth & Rollen - persistente DB - Orders / Drops 2) workspace-ui (Next.js) - internes Dashboard - Session-Cookies - keine öffentliche Erreichbarkeit 3) public-web - öffentlich - kein Login - Blog / Brand REPO-STRUKTUR (ZIEL) ------------------- voyage/ ├── apps/ │ ├── workspace-api/ │ ├── workspace-ui/ │ └── public-web/ ├── packages/ │ ├── db/ (Schema & Migrations) │ └── shared/ (DTOs / Enums) └── docs/ ├── workspace.txt ├── inventory.txt ├── orders.txt └── drops.txt LOGIN & USER ------------ User-Modell: - UserAccount (DB) - role: ADMIN | WORKER - active: true | false ACTIVE = false: - Login gesperrt - Historie bleibt erhalten USER ROLLEN ----------- ADMIN: - User anlegen / deaktivieren - Inventory verwalten - Orders verwalten WORKER: - Inventory sehen - Inventory Movements buchen ACTIVE / INACTIVE STATT LÖSCHEN ------------------------------- GRUNDREGEL: - NIEMALS löschen, wenn Historie existiert Umsetzung: - Products haben active Flag - SKUs haben active Flag active = false: - im Workspace ausgeblendet - bleibt in DB für Historie Beispiel: - Caps werden nicht mehr verkauft - Product + SKUs inactive setzen - Inventory-Historie bleibt korrekt INVENTORY --------- Inventory wird NIE direkt geändert. Regel: - Bestand = SUM aller InventoryMovements MovementReason: - PRODUCTION (+) - SALE (-) - CORRECTION (+ / -) Vorteil: - Vollständige Historie - Audit-fähig - Fehler rückgängig machbar ORDERS (BACKEND) ---------------- Order Flow: 1) Stock-Check pro SKU 2) Order + OrderItems speichern 3) SALE InventoryMovements erzeugen (negatives Delta) 4) Alles in einer Transaction WICHTIG: - Kein negativer Bestand erlaubt - Inaktive SKUs dürfen nicht verkauft werden TECHNISCHER HINWEIS: - Entities dürfen nicht direkt als JSON zurückgegeben werden - DTOs oder @JsonIgnore nutzen - Sonst: Endlos-JSON (Order <-> Items) CURL – ADMIN USER ANLEGEN ------------------------ Voraussetzung: - Als ADMIN eingeloggt - cookies.txt enthält Session ADMIN: curl -X POST http://localhost:8080/api/admin/users \ -H "Content-Type: application/json" \ -b cookies.txt \ -d '{ "username": "admin2", "password": "admin123!", "role": "ADMIN", "active": true }' WORKER: curl -X POST http://localhost:8080/api/admin/users \ -H "Content-Type: application/json" \ -b cookies.txt \ -d '{ "username": "worker1", "password": "worker123!", "role": "WORKER", "active": true }' NÄCHSTE SCHRITTE ---------------- 1) docs/ - orders.txt finalisieren (Flows + Beispiele) - drops.txt vorbereiten 2) packages/shared/ - Enums (Role, Category, MovementReason) - DTOs statt Entities 3) packages/db/ - Flyway vorbereiten - Migrationen versionieren 4) workspace-api/ - Orders finalisieren - Cancel / Refund Flow (Reverse Movements) - Active/Inactive Endpoints - Admin User Listing 5) workspace-ui/ - Admin Page (User Management) - Active/Inactive Toggle - bessere UX für Movements MERKSÄTZE --------- - Workspace zuerst, Public später - Inventory niemals direkt ändern - SKUs sind die operative Wahrheit - Löschen ist fast immer falsch - inactive ist richtig - H2 Passwort niemals ändern ohne DB Reset