VOYAGE – Nächste Projektschritte (Workspace + Login + Webblog) – 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: - Products - SKUs (Varianten) - InventoryMovements (Bestandsbuchungen) - Current Stock pro SKU (Aggregation) - Inventory Overview Endpoint (GET /api/inventory/overview) - Workspace UI (Next.js, minimal) - Login-System (Spring Security, Form Login, Session) - /api/** ist geschützt (nur eingeloggt) - Login per Browser (/login) und per curl (Cookie/JSESSIONID) funktioniert - Logout invalidiert Session + löscht JSESSIONID Damit ist das Domain-Fundament + Zugriffsschutz + UI-taugliche API abgeschlossen. Wichtiger Hinweis zur Datenbank (AKTUELLER ZUSTAND) --------------------------------------------------- Die Anwendung verwendet NICHT MEHR eine In-Memory Datenbank. Aktueller Stand: - H2 File-basierte Datenbank (persistent) - JDBC URL: jdbc:h2:file:./data/voyage-db;AUTO_SERVER=TRUE - Daten liegen auf der Festplatte (data/voyage-db.mv.db) - KEIN Datenverlust bei App-Restart Wichtig: - Die DB überlebt Neustarts - IDs (productId, skuId, userId) bleiben stabil - AUTO_SERVER erlaubt parallelen Zugriff (App + H2 Console) SEHR WICHTIG: - Das H2 Passwort wird beim ERSTEN Start festgelegt - Danach MUSS es gleich bleiben - Falsches Passwort → App startet NICHT (Error 28000) Empfohlene Config: - Username: sa - Password: leer (oder exakt das beim ersten Start gesetzte) H2 Console: - URL: http://localhost:8080/h2-console - JDBC URL: jdbc:h2:file:./data/voyage-db;AUTO_SERVER=TRUE - User: sa - Password: (leer oder wie initial gesetzt) H2 Login ≠ Workspace Login (komplett getrennt) Grundprinzip ------------ Workspace (intern) und Public Website (Blog) sind zwei verschiedene Welten und sollten technisch getrennt sein. - Workspace = interne Realität (Inventory, Orders, Drops) - Public Web = Content, Blog, Brand (keine sensiblen Daten) Empfohlene Architektur ---------------------- 1) workspace-api (Spring Boot) - Products / SKUs / Inventory - Inventory Overview (aggregiert) - Auth & Rollen - persistente DB - später Orders / Drops 2) workspace-ui (Webinterface) - internes Dashboard (Next.js) - spricht mit workspace-api - nutzt Session-Cookies (Browser) 3) public-web (Blog / Brand) - öffentlich zugänglich - kein Login nötig - getrennt vom Workspace Repo-Struktur ------------- voyage/ ├─ apps/ │ ├─ workspace-api/ (Backend) │ ├─ workspace-ui/ (internes UI) │ └─ public-web/ (Blog / Brand) └─ packages/ └─ shared/ (optional: DTOs / Types) Empfohlene Reihenfolge (sehr wichtig) ------------------------------------- SCHRITT 1: Login-System für Workspace ------------------------------------ Status: ERLEDIGT ✅ Ziel: - Zugriff auf /api/** nur für eingeloggte Nutzer - Workspace nicht öffentlich zugänglich Implementiert: - Spring Security - Form Login - Session-basiert (kein JWT) - Logout mit Session-Invalidierung - Redirect zurück ins Workspace UI User-Modell: - UserAccount in DB - Rollen: ADMIN / WORKER - active Flag (true / false) Inactive User: - kann sich NICHT einloggen - bleibt für Historie erhalten SCHRITT 2: Workspace-taugliche Endpoints ---------------------------------------- Status: ERLEDIGT ✅ Implementiert: - GET /api/inventory/overview Liefert pro SKU: - Produktname - Kategorie - Größe / Farbe - Preis - Aktueller Bestand (SUM der InventoryMovements) Bedeutung: - Ein Request = komplette Inventory Tabelle - Keine Aggregation im Frontend nötig - Grundlage für UI, Low-Stock, Drops SCHRITT 3: Workspace UI (minimal starten) ----------------------------------------- Status: ERLEDIGT (MINIMAL) ✅ Implementiert: - Inventory Übersicht - Tabelle mit allen SKUs + currentStock - Suche & Filter (Name, SKU, Kategorie) - Inventory Movements (+ / -) - SALE erzeugt negatives Delta - PRODUCTION positives Delta Ergebnis: Ein echtes internes Tool, sofort nutzbar. SCHRITT 4: Active / Inactive statt Löschen ------------------------------------------ Status: IMPLEMENTIERT / EMPFOHLEN ✅ Grundregel: - NIEMALS löschen, wenn Historie existiert Umsetzung: - Products und SKUs haben active Flag - active = false: - wird im Workspace ausgeblendet - bleibt in DB für Historie Beispiel: - Caps werden nicht mehr verkauft - Product/SKUs auf inactive setzen - Inventory bleibt korrekt nachvollziehbar SCHRITT 5: Worker-User --------------------- Status: IMPLEMENTIERT (Basis) ✅ User-Typen: - ADMIN: volle Rechte, Userverwaltung - WORKER: Inventory sehen & buchen Worker anlegen: - per Admin Endpoint oder DB - Passwort wird BCrypt-gehasht - active = true notwendig Worker deaktivieren: - active = false - Login gesperrt - Daten bleiben erhalten SCHRITT 6: Public Webblog (parallel, aber getrennt) --------------------------------------------------- Status: PARALLEL MÖGLICH ✅ Empfohlener Start: - Eigenes Frontend (public-web) - Content als Markdown im Repo - Git als CMS Vorteile: - Kein Admin-UI nötig - Keine Auth - Sehr schneller Workflow Warum diese Reihenfolge sinnvoll ist ------------------------------------ - Workspace erzeugt operativen Wert - Login schützt eure Arbeit - Inventory Overview macht das System sofort nutzbar - UI basiert auf stabiler API - Blog kann unabhängig wachsen Langfristige Erweiterungen -------------------------- - Orders → automatische SALE Movements - Drops → Production → initialer Bestand - Low-Stock Alerts - Rollenfeingranularität - Flyway Migrations - Postgres als DB - Public Shop (optional) Merksätze --------- - Workspace zuerst, Public später - Login früh einbauen (erledigt) - 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 Nächster konkreter Schritt -------------------------- - Admin UI für User + Active/Inactive - Deactivate-Flow für Products & SKUs - Orders mit automatischen InventoryMovements Curls ----------------- 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 }' 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 }'