chore(config): add agent skills and project brain documentation
This commit is contained in:
15
.agents/skills/grand-functions/SKILL.md
Normal file
15
.agents/skills/grand-functions/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: grand-functions
|
||||
description: Dokumentation und Spezifikation des CASPOS Webshops inklusive Datenmodell, Kernprozessen und Sicherheitskonzept.
|
||||
---
|
||||
|
||||
# Grand Functions - CASPOS Webshop Spezifikation
|
||||
|
||||
Dieser Skill enthält die vollständige Dokumentation und Spezifikation des CASPOS Webshops. Die Spezifikationen sind in logische Referenzdokumente unterteilt:
|
||||
|
||||
- [Projekt-Überblick & Tech-Stack](file:///c:/source/webshop/.agents/skills/grand-functions/references/overviews.md)
|
||||
- [Datenmodell & Schema](file:///c:/source/webshop/.agents/skills/grand-functions/references/schema.md)
|
||||
- [Kernprozesse](file:///c:/source/webshop/.agents/skills/grand-functions/references/processes.md)
|
||||
- [Sicherheitskonzept (RLS)](file:///c:/source/webshop/.agents/skills/grand-functions/references/security.md)
|
||||
- [Testumgebung & -abdeckung](file:///c:/source/webshop/.agents/skills/grand-functions/references/testing.md)
|
||||
|
||||
16
.agents/skills/grand-functions/references/overviews.md
Normal file
16
.agents/skills/grand-functions/references/overviews.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Projekt-Überblick & Technologie-Stack
|
||||
|
||||
## 1. Projekt-Überblick
|
||||
|
||||
Der CASPOS Webshop ist ein B2B-Portal für Vertriebspartner. Partner können hier Software-Pakete und Zusatzmodule (für POS/Kassenlösungen) konfigurieren, Anfragen für ihre Endkunden erstellen und Lizenzen verwalten.
|
||||
|
||||
---
|
||||
|
||||
## 2. Technologie-Stack
|
||||
|
||||
- **Frontend/Backend**: Next.js 15+ (App Router, React Server Components, Server Actions).
|
||||
- **Styling**: Tailwind CSS & Vanilla CSS (modernes Dark-Theme).
|
||||
- **Datenbank & Auth**: Supabase (PostgreSQL, Row Level Security - RLS, Supabase Auth).
|
||||
- **E-Mail-Versand**: SMTP-Integration für automatisierte Bestätigungen.
|
||||
- **PDF-Generierung**: `@react-pdf/renderer` zur Erzeugung von Anfragebestätigungen als PDF.
|
||||
- **Storage**: Supabase Storage (`invoices` Bucket) zur Archivierung der PDF-Dokumente.
|
||||
75
.agents/skills/grand-functions/references/processes.md
Normal file
75
.agents/skills/grand-functions/references/processes.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Kernprozesse
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Partner loggt sich ein] --> B{Firma zugewiesen?}
|
||||
B -- Nein --> C[Fehlermeldung: Kein Zutritt zum Wizard]
|
||||
B -- Ja --> D[Wizard öffnen / Konfigurieren]
|
||||
D --> E[Endkunden auswählen/anlegen]
|
||||
E --> F[Produkte & Module wählen]
|
||||
F --> G{Validierung erfolgreich?}
|
||||
G -- Nein --> H[Validierungsfehler anzeigen]
|
||||
G -- Ja --> I[Bestellung absenden]
|
||||
I --> J[Snapshot einfrieren & in DB speichern]
|
||||
J --> K[Rechnungs-PDF generieren & in Storage laden]
|
||||
K --> L[E-Mail mit PDF an Partner senden]
|
||||
L --> M[Bestellung in der Übersicht anzeigen]
|
||||
```
|
||||
|
||||
### A. Partner- & Unternehmens-Hierarchie
|
||||
1. Ein neu registrierter User hat die Rolle `partner` und ist zunächst keiner Firma zugeordnet.
|
||||
2. Der Administrator ordnet den User in der Admin-Oberfläche (`/admin/users`) einem Unternehmen (`companies`) zu.
|
||||
3. Nur wenn der User einer Firma zugewiesen ist (oder Admin ist), kann er Endkunden anlegen und Bestellungen aufgeben.
|
||||
|
||||
### B. Endkunden-Verwaltung (`/my-customers`)
|
||||
- **Firmenweite Sicht**: Da `end_customers.partner_id` on `companies.id` verweist, sehen alle Mitarbeiter desselben Unternehmens dieselben Endkunden.
|
||||
- **DSGVO Anonymisierung**: Endkunden können unwiderruflich anonymisiert werden. Dabei werden sensible Daten mit `[GELÖSCHT]` überschrieben und `is_anonymized` auf `true` gesetzt. In existierenden Bestellungen (`orders.customer_data`) bleiben die Daten zu steuerlichen Zwecken unverändert.
|
||||
|
||||
### C. Bestell-Wizard & Validierung (`/order`)
|
||||
- **Kategorie-Pflichten**: Wenn eine Produktkategorie als `is_required` definiert ist, muss ein Produkt ausgewählt werden.
|
||||
- **Abhängigkeiten (Requirements)**: Ein Modul oder Produkt kann andere Module/Produkte voraussetzen (z.B. Modul B erfordert Modul A). Das System prüft dies client- und serverseitig.
|
||||
- **Top-Down State-Management**:
|
||||
- Die Wahl eines Basis-Produkts steuert die Sichtbarkeit und Wählbarkeit aller Module (Top-Down). Modul-Auswahlen dürfen niemals die Liste der wählbaren Basis-Produkte beeinflussen (Verhinderung von UI-Deadlocks).
|
||||
- **Auto-Reset & Kaskaden-Bereinigung**: Beim Wechsel des Basis-Produkts in `selectProduct` werden inkompatible Module in anderen Kategorien automatisch über eine Kaskaden-Bereinigung (Filterung der `moduleIds` basierend auf den `exclusions` des neuen Produkts) deselektiert.
|
||||
- **Sichtbarkeits- & Wählbarkeits-Garantie**: Basis-Produkte werden im UI niemals durch Modulausschlüsse ausgeblendet. Nachgelagerte Produkte/Module, die mit dem ausgewählten Basis-Produkt inkompatibel sind, erhalten im JSX das `disabled`-Attribut und sind nicht anklickbar (Sperrung von "Kein Backoffice" bei "Small Business"). Klicks auf Module haben keinerlei Rückwirkung auf die Basis-Produkt-Auswahl.
|
||||
- **Radio-Button-Verhalten (allow_multiselect = false)**: Falls eine Kategorie keine Mehrfachauswahl erlaubt, wird bei Auswahl eines neuen Moduls das zuvor ausgewählte Modul dieser Kategorie automatisch abgewählt.
|
||||
- **Snapshot-Architektur**: Sobald eine Bestellung aufgegeben wird, werden die Kundendaten (`CustomerSnapshot`) und Produktkonfigurationen (`OrderSnapshot` samt Preisen und Modulversionen) in `orders` als JSONB-Snapshots eingefroren. Preisänderungen im Katalog haben keinen Einfluss auf bestehende Bestellungen.
|
||||
|
||||
### D. Bestellungs-Verwaltung & Statusübergang
|
||||
- **Sichtbarkeit**: Partner sehen in `/my-orders` alle Bestellungen aller Mitarbeiter ihrer Firma.
|
||||
- **Bearbeiten**: Unvollständige Bestellungen (`status != 'completed'`) können von jedem Mitarbeiter der jeweiligen Firma nachträglich editiert werden.
|
||||
- **Admin-Workflow**: Admins sehen in `/admin/orders` alle Bestellungen global, können den Status ändern (z.B. von *Eingegangen* auf *In Bearbeitung* oder *Abgeschlossen*) und PDF-Rechnungen manuell herunterladen.
|
||||
- **Statusänderungs-Mails**: Bei jedem Statusübergang wird automatisch eine Benachrichtigungs-E-Mail an den Besteller geschickt.
|
||||
|
||||
---
|
||||
|
||||
### E. Multi-Kassen-Warenkorb & Checkout-Split
|
||||
- **Endpunkt / Server Action**: `POST /api/orders/checkout` sowie Server Action `checkoutAction` in `app/actions/checkout.ts`
|
||||
- **Funktionsweise**:
|
||||
- Empfängt ein Array von `items` (Kassenkonfigurationen).
|
||||
- Validiert Auth und Partner-Firma Zuweisung.
|
||||
- Generiert einen `order_hash` zur Vermeidung von Doppelübermittlungen (Idempotenz-Guard).
|
||||
- Teilt die Konfigurationen nach `billingInterval` / `billingType` auf (Kauf vs. Abo).
|
||||
- Erstellt separate Orders in der Datenbank:
|
||||
- Typ `purchase`: Anfrage für Kauf-Lizenzen (Zahlungsart: Vormerkung/Angebot).
|
||||
- Typ `subscription`: Anfrage für Software-Abonnement (Zahlungsart: SEPA).
|
||||
- Friert für jede Order einen konsolidierten `order_data` (JSONB) und `customer_data` (JSONB) ein.
|
||||
- Triggert die PDF-Erstellung und den E-Mail-Versand unabhängig für jede generierte Order (gibt Order-IDs für Post-Processing zurück).
|
||||
|
||||
---
|
||||
|
||||
### F. PDF-Rechnungsgenerierung & Mail-Versand (Post-Processing)
|
||||
- **Entkopplung & Asynchronität**: Die Generierung der PDFs und der E-Mail-Versand sind vollständig aus dem synchronen Checkout-Flow entkoppelt. Der Checkout liefert dem Frontend sofort nach Speicherung in der DB eine Erfolgsmeldung zurück. Die Generierung und der Versand werden asynchron im Hintergrund (via unblockiertem Promise-Worker) ausgeführt, um SMTP-Latenzen abzufangen.
|
||||
- **Snapshot-Exklusivität**: Die PDF-Generierung erfolgt ausschließlich auf Basis der in `orders.order_data` und `orders.customer_data` eingefrorenen Snapshots.
|
||||
- **Layout-Unterscheidung**:
|
||||
- **Typ `purchase` (Kauf)**:
|
||||
- Generiert eine klassische **Anfragebestätigung Kauf**.
|
||||
- Weist die einmalige Gesamtsumme aus.
|
||||
- **Typ `subscription` (Abonnement)**:
|
||||
- Generiert eine **Anfragebestätigung Abonnement**.
|
||||
- Weist monatlich wiederkehrende Kosten aus.
|
||||
- **Archivierung & Benachrichtigung**:
|
||||
- Hochladen des PDFs in den Supabase Storage (`invoices` Bucket).
|
||||
- E-Mail-Versand mit PDF-Anhang an den Partner.
|
||||
|
||||
|
||||
97
.agents/skills/grand-functions/references/schema.md
Normal file
97
.agents/skills/grand-functions/references/schema.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Datenmodell & Beziehungen (Schema)
|
||||
|
||||
Das Datenbankschema besteht aus folgenden Tabellen im Schema `public`:
|
||||
|
||||
### `companies` (Unternehmen)
|
||||
- Repräsentiert die Partner-Unternehmen (Retailer).
|
||||
- `id` (UUID, Primary Key)
|
||||
- `name` (TEXT)
|
||||
- `street`, `zip`, `city`, `email` (Adressdaten)
|
||||
|
||||
### `users` (Systembenutzer)
|
||||
- Erweitert die Authentifizierungsdaten aus `auth.users`.
|
||||
- `id` (UUID, References `auth.users(id)`)
|
||||
- `role` (TEXT, standardmäßig `'partner'`, oder `'admin'`)
|
||||
- `company_id` (UUID, References `public.companies(id)`)
|
||||
|
||||
### `end_customers` (Endkunden)
|
||||
- Die Endkunden, für die die Partner Lizenzen bestellen.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `partner_id` (UUID, References `public.companies(id)`) <-- *Direkte Zuordnung zur Firma des Partners*
|
||||
- `company_name` (TEXT)
|
||||
- `first_name`, `last_name`, `street`, `zip`, `city`, `email` (Stammdaten)
|
||||
- `bank_iban`, `bank_bic`, `bank_name`, `bank_owner` (Bankdaten)
|
||||
- `is_anonymized` (BOOLEAN) <-- *Für DSGVO-Löschung*
|
||||
|
||||
### `categories` (Kategorien)
|
||||
- Steuert das Layout und Verhalten im Wizard.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `name` (TEXT)
|
||||
- `is_required` (BOOLEAN) <-- *Muss ausgewählt werden*
|
||||
- `allow_multiselect` (BOOLEAN) <-- *Mehrfachauswahl erlaubt (Checkbox statt Radio)*
|
||||
- `sort_order` (INTEGER) <-- *Sortierung im Wizard*
|
||||
- `show_in_branches` (BOOLEAN)
|
||||
- `preselect` (BOOLEAN)
|
||||
- `resets_others` (BOOLEAN)
|
||||
|
||||
### `products` (Katalogprodukte / Basis-Editionen)
|
||||
- Hauptlösungen (z.B. Basic-Kasse, Backoffice).
|
||||
- `id` (UUID, Primary Key)
|
||||
- `category_id` (UUID, References `categories`)
|
||||
- `name` (TEXT)
|
||||
- `base_price` (DECIMAL)
|
||||
- `tax_rate` (DECIMAL)
|
||||
- `billing_interval` (TEXT: `'one_time'` / `'monthly'`)
|
||||
- `show_in_branches` (BOOLEAN)
|
||||
- `allow_update_discount` (BOOLEAN) <-- *Berechtigung für Update-Rabatt*
|
||||
|
||||
### `modules` (Zusatzmodule / Erweiterungen)
|
||||
- Optionale Erweiterungen für Produkte. Repräsentiert im TypeScript-Code durch das Interface `ProductModule`.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `product_id` (UUID, References `products`)
|
||||
- `category_id` (UUID, References `categories`)
|
||||
- `name` (TEXT)
|
||||
- `price` (DECIMAL)
|
||||
- `has_quantity` (BOOLEAN)
|
||||
|
||||
### `global_inclusions` (Globale automatische Beigaben)
|
||||
- Regelt, welche Module bei Auswahl eines Produkts kostenlos enthalten sind.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `trigger_product_id` (UUID, References `products`)
|
||||
- `included_module_id` (UUID, References `modules`)
|
||||
|
||||
### `global_exclusions` (Globale Ausschlüsse)
|
||||
- Regelt Inkompatibilitäten zwischen Produkten und/oder Modulen.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `product_id` (UUID, References `products`)
|
||||
- `excluded_product_id` (UUID, References `products`, optional)
|
||||
- `excluded_module_id` (UUID, References `modules`, optional)
|
||||
|
||||
### `orders` (Bestellungen / Anfragen)
|
||||
- Gespeicherte Snapshots von Konfigurationen.
|
||||
- `id` (UUID, Primary Key)
|
||||
- `user_id` (UUID, References `auth.users(id)`)
|
||||
- `company_id` (UUID, References `public.companies(id)`)
|
||||
- `end_customer_id` (UUID, References `end_customers(id)`)
|
||||
- `order_number` (TEXT, Format: `AE-YYYY-NNNNN`)
|
||||
- `order_hash` (TEXT, Idempotenz-Guard)
|
||||
- `type` (TEXT: `'purchase'` / `'subscription'`) <-- *Wichtig für den Checkout-Split*
|
||||
- `payment_method` (TEXT) <-- *Rechnung bei Kauf, SEPA bei Abo*
|
||||
- `total_price` (DECIMAL)
|
||||
- `customer_data` (JSONB) <-- *Stammdaten zum Bestellzeitpunkt*
|
||||
- `order_data` (JSONB) <-- *Konfiguration zum Bestellzeitpunkt*
|
||||
- `pdf_url` (TEXT)
|
||||
- `status` (TEXT: `'pending'`, `'active'`, `'completed'`, `'cancelled'`)
|
||||
- `created_at` (TIMESTAMPTZ)
|
||||
|
||||
### `settings` (Systemeinstellungen)
|
||||
- Globale Shopeinstellungen (SMTP und LicServer).
|
||||
- `id` (TEXT, Primary Key, z.B. `'licserver'`, `'smtp'`)
|
||||
- `host` (TEXT)
|
||||
- `port` (INTEGER)
|
||||
- `secure` (BOOLEAN)
|
||||
- `user` (TEXT)
|
||||
- `pass` (TEXT)
|
||||
- `licserver_base_url` (TEXT)
|
||||
- `licserver_api_key` (TEXT)
|
||||
- `updated_at` (TIMESTAMPTZ)
|
||||
20
.agents/skills/grand-functions/references/security.md
Normal file
20
.agents/skills/grand-functions/references/security.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Sicherheitskonzept (RLS - Row Level Security)
|
||||
|
||||
RLS ist auf Datenbankebene in Postgres implementiert und erzwingt Datenisolierung:
|
||||
|
||||
- **Unternehmen (`companies`)**: Authentifizierte Benutzer dürfen nur die Unternehmen lesen.
|
||||
- **Endkunden (`end_customers`)**:
|
||||
- `USING (partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid()))`
|
||||
- Partner sehen und modifizieren nur Endkunden, deren `partner_id` mit der `company_id` des angemeldeten Benutzers übereinstimmt.
|
||||
- **Bestellungen (`orders`)**:
|
||||
- `USING (company_id = (SELECT company_id FROM public.users WHERE id = auth.uid()))`
|
||||
- Partner sehen und modifizieren nur Bestellungen, die ihrer Company zugewiesen sind (sie müssen einer Company zugeordnet sein).
|
||||
- Jede Bestellung wird bei der Erstellung automatisch der Company des Erstellers zugewiesen.
|
||||
- Admins haben uneingeschränkten Zugriff und können Bestellungen nachträglich anderen Companies zuweisen.
|
||||
- **Lizenzen (`licenses`)**:
|
||||
- Partner sehen nur Lizenzen von Endkunden, die ihrer Company zugeordnet sind.
|
||||
|
||||
- **Systembenutzer (`users`) & Rollen-Schutz**:
|
||||
- Authentifizierte Nutzer dürfen nur ihr eigenes Profil lesen.
|
||||
- Admins dürfen alle Benutzer lesen. Zur Vermeidung von unendlichen RLS-Rekursionen auf der Tabelle `users` wird die Admin-Zuweisung über die Security-Definer-Funktion `public.is_admin(user_id)` geprüft, welche RLS auf Datenbank-Ebene umgeht.
|
||||
- Rollenschutz-Trigger (`check_user_role_escalation`): Jegliche Änderung der Spalte `role` oder Zuweisung der Rolle `'admin'` ist auf API-Ebene für normale Nutzer gesperrt. Updates/Inserts der Rolle werden ausschließlich von der `service_role` (Backend Admin-Client) akzeptiert, um Privilegien-Eskalation zu verhindern.
|
||||
22
.agents/skills/grand-functions/references/testing.md
Normal file
22
.agents/skills/grand-functions/references/testing.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Testumgebung & Testabdeckung
|
||||
|
||||
## 1. Test-Setup
|
||||
- **Framework**: Vitest (Version ^1.6.0)
|
||||
- **Konfiguration**: [vitest.config.ts](file:///c:/source/webshop/shop/vitest.config.ts)
|
||||
- **Befehl**: `npm run test` (führt `vitest run` aus)
|
||||
|
||||
---
|
||||
|
||||
## 2. Test-Szenarien
|
||||
|
||||
### A. Frontend Wizard State-Management
|
||||
Getestet in [wizard-state.test.ts](file:///c:/source/webshop/shop/lib/wizard-state.test.ts):
|
||||
- **Auto-Reset bei Produktwechsel**: Prüft, ob nachgelagerte Module, die durch `global_exclusions` für das neue Produkt gesperrt sind, automatisch aus der Selektion fliegen.
|
||||
- **Radio-Button-Verhalten (allow_multiselect = false)**: Stellt sicher, dass in Single-Select-Kategorien nur maximal ein Modul aktiv ist und bei Auswahl eines anderen Moduls das vorherige automatisch abgewählt wird.
|
||||
|
||||
### B. Backend Checkout-Split
|
||||
Getestet in [checkout-split.test.ts](file:///c:/source/webshop/shop/lib/checkout-split.test.ts):
|
||||
- **Array-Validierung & Split (basketItems)**: Stellt sicher, dass das vollständige Array an konfigurierten Kassen (`basketItems`) validiert und verarbeitet wird (nicht nur ein Single-Produkt).
|
||||
- **Kauf-Warenkorb**: Verifiziert, dass ein reiner Kauf-Warenkorb (`one_time`/`purchase`) exakt eine Order erzeugt.
|
||||
- **Abo-Warenkorb**: Verifiziert, dass ein reiner Abo-Warenkorb (`monthly`/`subscription`) exakt eine Order erzeugt.
|
||||
- **Gemischter Warenkorb**: Stellt sicher, dass ein gemischter Warenkorb korrekt in zwei separate Bestell-Gruppen aufgeteilt wird (Kauf-Items & Abo-Items separat).
|
||||
Reference in New Issue
Block a user