Status: Draft (QA)
Issue: CAR-14
Datum: 2026-07-03
Owner: QA / DEV
PRD-Reference: PRD-001 v0.7
Feature: ... gruppiertBackground: enthält gemeinsame Preconditions (Singleton-Tenant)Scenario: (nicht Example:) dokumentiertExamples: verwenden explizite Schlüsselwort-Syntax (| field | value |)Feature: F1.1 Email/Password Login
Background:
Given the system is operating normally
And no user is currently authenticated
Scenario: AC-001 — Erfolgreicher Login mit gültigen Credentials
Given a User with email "sarah@meinladen.de" and password "Sicher!23" exists
And the user's account is active
When the user submits login with email "sarah@meinladen.de" and password "Sicher!23"
Then the response status is 200
And the response contains a valid JWT access token
And the response contains a valid JWT refresh token (HTTP-only cookie)
And the user's role and company_id are encoded in the token claims
Scenario: AC-002 — Login schlägt fehl bei falschem Passwort
Given a User with email "sarah@meinladen.de" and password "Sicher!23" exists
When the user submits login with email "sarah@meinladen.de" and password "Falsch!45"
Then the response status is 401
And the response contains no JWT tokens
And the response contains error "Invalid credentials"
Scenario: AC-003 — Login schlägt fehl bei nicht existierendem User
Given no user with email "unbekannt@test.de" exists
When the user submits login with email "unbekannt@test.de" and password "Irgendwas!"
Then the response status is 401
And the response contains error "Invalid credentials"
Scenario: AC-004 — Login schlägt fehl bei leerem Email-Feld
When the user submits login with email "" and password "Sicher!23"
Then the response status is 400
And the response contains validation error for field "email"
Scenario: AC-005 — Login schlägt fehl bei ungültigem Email-Format
When the user submits login with email "kein-email" and password "Sicher!23"
Then the response status is 400
And the response contains validation error for field "email"
Scenario: AC-006 — Refresh Token wird akzeptiert und liefert neuen Access Token
Given a User with email "sarah@meinladen.de" and password "Sicher!23" exists
And the user has previously logged in and holds a valid refresh token
When the user submits a refresh request with the refresh token
Then the response status is 200
And the response contains a new valid JWT access token
And the previous access token is invalidated
Scenario: AC-007 — Refresh Token läuft ab → 401
Given a User with email "sarah@meinladen.de" and password "Sicher!23" exists
And the user holds an expired refresh token
When the user submits a refresh request with the expired refresh token
Then the response status is 401
And the response contains error "Token expired"
Scenario: AC-008 — Geburtsland/Company-Binding bei Login
Given a User with email "sarah@meinladen.de" and password "Sicher!23" belongs to Company "Mein Laden GmbH"
When the user submits login with email "sarah@meinladen.de" and password "Sicher!23"
Then the JWT access token contains the company_id of "Mein Laden GmbH"
And the user can only access resources belonging to that company
Feature: F1.2 User Registration
Background:
Given the system is operating normally
Scenario: AC-010 — Erfolgreiche Registration mit Email-Verifikation
When a prospective user submits registration with:
| email | password | company_name |
| sarah@test.de | Sicher!23 | Mein Laden GmbH |
Then the response status is 201
And a User record is created with email "sarah@test.de"
And a Company record is created with name "Mein Laden GmbH"
And the user is assigned the role "admin" for that company
And an verification email is sent to "sarah@test.de"
And the user's account is in status "pending_verification"
Scenario: AC-011 — Registration mit bereits existierender Email → Fehler
Given a User with email "sarah@test.de" already exists
When a prospective user submits registration with:
| email | password | company_name |
| sarah@test.de | Sicher!23 | Mein Laden GmbH |
Then the response status is 409
And the response contains error "Email already registered"
Scenario: AC-012 — Registration mit schwachem Passwort → Fehler
When a prospective user submits registration with:
| email | password | company_name |
| sarah@test.de | 12345 | Mein Laden GmbH |
Then the response status is 400
And the response contains validation error for field "password"
And the error message indicates password complexity requirements
Scenario: AC-013 — Email-Verifikation erfolgreich
Given a User with email "sarah@test.de" exists with status "pending_verification"
And a valid verification token was sent to "sarah@test.de"
When the user submits email verification with the valid token
Then the response status is 200
And the user's account status changes to "active"
And the verification token is invalidated
Scenario: AC-014 — Email-Verifikation mit ungültigem Token → Fehler
Given a User with email "sarah@test.de" exists
When the user submits email verification with token "invalid-token-xyz"
Then the response status is 400
And the response contains error "Invalid or expired verification token"
Feature: F1.3 Password Reset Flow
Background:
Given the system is operating normally
Scenario: AC-020 — Password Reset Email angefordert
Given a User with email "sarah@test.de" exists
When the user requests a password reset for "sarah@test.de"
Then the response status is 200
And a password reset email is sent to "sarah@test.de"
And a reset token is stored with 1-hour expiry
Scenario: AC-021 — Password Reset für nicht-existierenden User gibt 200 zurück (Security)
Given no user with email "unbekannt@test.de" exists
When the user requests a password reset for "unbekannt@test.de"
Then the response status is 200
And no email is sent (preventing email enumeration)
Scenario: AC-022 — Passwort mit gültigem Token zurücksetzen
Given a User with email "sarah@test.de" exists
And a valid password reset token was sent to "sarah@test.de"
When the user submits new password "NeuesPasswort!99" with the valid token
Then the response status is 200
And the user's password is updated to match "NeuesPasswort!99"
And all existing sessions are invalidated
And the reset token is invalidated
Scenario: AC-023 — Passwort-Reset mit abgelaufenem Token → Fehler
Given a User with email "sarah@test.de" exists
And an expired password reset token was sent to "sarah@test.de"
When the user submits new password "NeuesPasswort!99" with the expired token
Then the response status is 400
And the response contains error "Token expired"
And the password remains unchanged
Feature: F2.1 Role-Based Access Control — Roles & Permissions
Background:
Given Company "Testladen GmbH" exists
And Store "Filiale Berlin" belongs to Company "Testladen GmbH"
And the following users exist for Company "Testladen GmbH":
| email | role |
| admin@testladen.de | admin |
| manager@testladen.de | manager |
| sales@testladen.de | sales |
Scenario: AC-030 — Admin kann alle Ressourcen verwalten
Given the user "admin@testladen.de" is authenticated as "admin" for Company "Testladen GmbH"
When the user attempts to create a new Store for Company "Testladen GmbH"
Then the request is allowed
And the user attempts to delete any User in the company
Then the request is allowed
And the user attempts to access the Billing/Settings section
Then the request is allowed
Scenario: AC-031 — Manager kann keine Admin-Operationen durchführen
Given the user "manager@testladen.de" is authenticated as "manager" for Company "Testladen GmbH"
When the user attempts to delete another User in the company
Then the request is denied with 403 Forbidden
And the user attempts to change company billing settings
Then the request is denied with 403 Forbidden
And the user attempts to delete a Store
Then the request is denied with 403 Forbidden
Scenario: AC-032 — Sales kann nur POS-Operationen durchführen
Given the user "sales@testladen.de" is authenticated as "sales" for Company "Testladen GmbH"
When the user attempts to process a sale at the POS
Then the request is allowed
And the user attempts to create a Product
Then the request is denied with 403 Forbidden
And the user attempts to view reporting dashboard
Then the request is denied with 403 Forbidden
Scenario: AC-033 — Unauthenticated User wird auf Login redirectet
Given no user is authenticated
When the user attempts to access any protected endpoint
Then the response status is 401
And the response contains error "Authentication required"
Scenario: AC-034 — User aus anderem Company wird abgelehnt (Tenant Isolation)
Given Company "Anderer Laden GmbH" exists
And a User "other@andererladen.de" with role "admin" belongs to Company "Anderer Laden GmbH"
And the user "other@andererladen.de" is authenticated
When the user attempts to access resources of Company "Testladen GmbH"
Then the request is denied with 403 Forbidden
And the response contains error "Access denied"
Feature: F2.2 Role Assignment & Management
Background:
Given Company "Testladen GmbH" exists
And User "admin@testladen.de" with role "admin" exists in Company "Testladen GmbH"
And User "manager@testladen.de" exists in Company "Testladen GmbH"
Scenario: AC-040 — Admin kann Rolle eines Users ändern
Given the user "admin@testladen.de" is authenticated as "admin"
When the admin changes the role of "manager@testladen.de" from "none" to "manager"
Then the request is allowed with 200
And User "manager@testladen.de" now has role "manager"
Scenario: AC-041 — Manager kann keine Rollen ändern
Given the user "admin@testladen.de" is authenticated as "admin"
And User "manager@testladen.de" has role "manager"
And the user "manager@testladen.de" is authenticated as "manager"
When the manager attempts to change the role of any user
Then the request is denied with 403 Forbidden
Scenario: AC-042 — Admin kann User aus der Company entfernen
Given the user "admin@testladen.de" is authenticated as "admin"
When the admin removes User "manager@testladen.de" from the company
Then the request is allowed with 200
And User "manager@testladen.de" no longer has access to Company "Testladen GmbH"
Scenario: AC-043 — User kann eigene Rolle nicht ändern
Given the user "admin@testladen.de" is authenticated as "admin"
When the admin attempts to change their own role to "sales"
Then the request is denied with 400
And the response contains error "Cannot change own role"
Feature: F3.1 Company Management
Background:
Given the system is operating normally
Scenario: AC-050 — Company-Admin kann Company-Daten bearbeiten
Given a Company "Mein Laden GmbH" exists
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
And the user "admin@meinladen.de" is authenticated
When the admin updates company details:
| field | value |
| name | Mein Laden GmbH II |
| theme | {"primary": "#000"} |
Then the response status is 200
And Company "Mein Laden GmbH" now has name "Mein Laden GmbH II"
Scenario: AC-051 — Nicht-Admin kann Company-Daten nicht bearbeiten
Given a Company "Mein Laden GmbH" exists
And User "manager@meinladen.de" with role "manager" belongs to Company "Mein Laden GmbH"
And the user "manager@meinladen.de" is authenticated
When the user attempts to update company details
Then the request is denied with 403 Forbidden
Scenario: AC-052 — Company mit ungültigen Daten → Validation Error
Given User "admin@meinladen.de" is authenticated as "admin"
When the admin attempts to update company with name ""
Then the response status is 400
And the response contains validation error for field "name"
Feature: F3.2 Store Management
Background:
Given Company "Mein Laden GmbH" exists
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
And User "manager@meinladen.de" with role "manager" belongs to Company "Mein Laden GmbH"
Scenario: AC-060 — Admin kann neuen Store anlegen
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a new Store with:
| name | address | timezone | currency |
| Filiale 1 | Hauptstraße 1, 10115 Berlin | Europe/Berlin | EUR |
Then the response status is 201
And a Store record exists with name "Filiale 1"
And the Store is linked to Company "Mein Laden GmbH"
Scenario: AC-061 — Manager kann keinen Store anlegen
Given the user "manager@meinladen.de" is authenticated as "manager"
When the manager attempts to create a new Store
Then the request is denied with 403 Forbidden
Scenario: AC-062 — Admin kann Store bearbeiten
Given Store "Filiale 1" belongs to Company "Mein Laden GmbH"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin updates Store "Filiale 1" with name "Filiale Zentrum"
Then the response status is 200
And Store "Filiale 1" now has name "Filiale Zentrum"
Scenario: AC-063 — Admin kann Store deaktivieren (Soft Delete)
Given Store "Filiale 1" belongs to Company "Mein Laden GmbH"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin deactivates Store "Filiale 1"
Then the response status is 200
And Store "Filiale 1" is no longer accessible in active store lists
But Store "Filiale 1" still exists in the database with deleted_at set
Scenario: AC-064 — Store-Auswahl bei Multi-Store Company
Given Company "Mein Laden GmbH" has 3 Stores
And User "manager@meinladen.de" is authenticated as "manager"
And User "manager@meinladen.de" is assigned to all 3 stores
When the user requests the list of accessible stores
Then the response contains exactly 3 stores
And each store belongs to Company "Mein Laden GmbH"
Feature: F4.1 User Management (CRUD)
Background:
Given Company "Mein Laden GmbH" exists
And Store "Filiale 1" belongs to Company "Mein Laden GmbH"
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
And User "manager@meinladen.de" with role "manager" belongs to Company "Mein Laden GmbH"
Scenario: AC-070 — Admin kann neuen User einladen
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates an invitation for "neuer@test.de" with role "sales" for Store "Filiale 1"
Then the response status is 201
And an invitation email is sent to "neuer@test.de"
And a User record in status "pending" is created
Scenario: AC-071 — Admin kann alle Users der Company auflisten
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin requests the list of all users in Company "Mein Laden GmbH"
Then the response status is 200
And the list contains exactly the 2 existing users
And each user has their assigned role
Scenario: AC-072 — Manager kann keine Users anderer Stores sehen
Given Company "Mein Laden GmbH" has Store "Filiale 1" and Store "Filiale 2"
And User "alice@meinladen.de" (role "manager") is assigned only to "Filiale 1"
And User "bob@meinladen.de" (role "sales") is assigned only to "Filiale 2"
And the user "alice@meinladen.de" is authenticated as "manager"
When the manager requests the list of all users
Then the response only contains users assigned to "Filiale 1"
Scenario: AC-073 — Admin kann User bearbeiten (Rolle ändern)
Given User "manager@meinladen.de" has role "manager"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin changes User "manager@meinladen.de" from role "manager" to role "sales"
Then the response status is 200
And User "manager@meinladen.de" now has role "sales"
Scenario: AC-074 — Admin kann User deaktivieren
Given User "manager@meinladen.de" belongs to Company "Mein Laden GmbH"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin deactivates User "manager@meinladen.de"
Then the response status is 200
And User "manager@meinladen.de" can no longer log in
But the user record is not deleted from the database
Scenario: AC-075 — Deaktivierter User erhält 401 bei Login
Given User "deactivated@test.de" exists with status "deactivated"
When the user submits login with email "deactivated@test.de" and password "Sicher!23"
Then the response status is 401
And the response contains error "Account deactivated"
Feature: F5.1 Product Stammdaten — CRUD
Background:
Given Company "Mein Laden GmbH" exists
And Category "Bekleidung" belongs to Company "Mein Laden GmbH"
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
Scenario: AC-080 — Admin kann Produkt mit allen Pflichtfeldern anlegen
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Product with:
| name | sku_code | price | category | attributes |
| T-Shirt Rot | TS-001-R | 29.99 | Bekleidung| {"size": "M", "color": "red"} |
Then the response status is 201
And a Product record exists with name "T-Shirt Rot"
And the product has status "active"
And the product's tenant_id matches Company "Mein Laden GmbH"
Scenario: AC-081 — Produktanlage ohne Pflichtfeld "name" → Fehler
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Product with:
| sku_code | price |
| TS-001 | 29.99 |
Then the response status is 400
And the response contains validation error for field "name"
Scenario: AC-082 — Produkt mit Fashion-spezifischen Attributen (Size, Color, Season)
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Product with Fashion-Attributes:
| name | sku_code | price | size | color | season |
| Winterjacke M | WJ-001 | 149.99 | M | navy | Winter23 |
Then the response status is 201
And the Product's attributes contain size "M"
And the Product's attributes contain color "navy"
And the Product's attributes contain season "Winter23"
Scenario: AC-083 — Admin kann Produkt bearbeiten
Given Product "T-Shirt Rot" exists with price 29.99
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin updates Product "T-Shirt Rot" with price 34.99
Then the response status is 200
And Product "T-Shirt Rot" now has price 34.99
And updated_at timestamp is refreshed
Scenario: AC-084 — Admin kann Produkt deaktivieren (Soft Delete)
Given Product "T-Shirt Rot" exists
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin deactivates Product "T-Shirt Rot"
Then the response status is 200
And Product "T-Shirt Rot" does not appear in the active product catalog
But the record still exists with deleted_at set
Scenario: AC-085 — Manager kann Produkte anlegen
Given User "manager@meinladen.de" with role "manager" belongs to Company "Mein Laden GmbH"
And the user "manager@meinladen.de" is authenticated as "manager"
When the manager creates a Product with name "Hose Blau" and sku "HB-001"
Then the request is allowed with 201
Scenario: AC-086 — Sales kann keine Produkte anlegen
Given User "sales@meinladen.de" with role "sales" belongs to Company "Mein Laden GmbH"
And the user "sales@meinladen.de" is authenticated as "sales"
When the sales user attempts to create a Product
Then the request is denied with 403 Forbidden
Scenario: AC-087 — User aus Company A sieht keine Produkte aus Company B
Given Company "Anderer Laden GmbH" exists
And Product "Exklusiv-Hose" belongs to Company "Anderer Laden GmbH"
And User "admin@meinladen.de" is authenticated as "admin" for Company "Mein Laden GmbH"
When the user searches for products
Then Product "Exklusiv-Hose" is NOT in the results
Feature: F5.2 Category Management
Background:
Given Company "Mein Laden GmbH" exists
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
And Category "Oberteile" exists in Company "Mein Laden GmbH"
Scenario: AC-090 — Admin kann Hauptkategorie anlegen
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Category "Hosen" with slug "hosen"
Then the response status is 201
And a Category record exists with name "Hosen" and slug "hosen"
And the category's tenant_id matches Company "Mein Laden GmbH"
Scenario: AC-091 — Admin kann Unterkategorie anlegen (Parent-ID)
Given Category "Oberteile" exists with slug "oberteile"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Category "T-Shirts" with slug "t-shirts" and parent_id of "Oberteile"
Then the response status is 201
And Category "T-Shirts" has parent_id pointing to "Oberteile"
And a product can be assigned to "T-Shirts" and appears under "Oberteile" in the category tree
Scenario: AC-092 — Kategorie mit ungültigem Parent-ID → Fehler
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin attempts to create a Category with non-existent parent_id "999"
Then the response status is 400
And the response contains error "Parent category not found"
Scenario: AC-093 — Manager kann Kategorien nicht löschen
Given User "manager@meinladen.de" with role "manager" belongs to Company "Mein Laden GmbH"
And the user "manager@meinladen.de" is authenticated as "manager"
When the manager attempts to delete Category "Oberteile"
Then the request is denied with 403 Forbidden
Feature: F5.3 SKU Management & Stock Quantity
Background:
Given Company "Mein Laden GmbH" exists
And Store "Filiale 1" belongs to Company "Mein Laden GmbH"
And Store "Filiale 2" belongs to Company "Mein Laden GmbH"
And Product "T-Shirt" with SKU "TS-001" exists
And User "admin@meinladen.de" with role "admin" belongs to Company "Mein Laden GmbH"
Scenario: AC-100 — SKU-Code muss pro Company eindeutig sein
Given another Product with SKU "TS-001" already exists in Company "Mein Laden GmbH"
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin creates a Product with SKU "TS-001"
Then the response status is 409
And the response contains error "SKU already exists in this company"
Scenario: AC-101 — Bestand kann pro Store unterschiedlich sein
Given Product "T-Shirt" (SKU "TS-001") exists
And the user "admin@meinladen.de" is authenticated as "admin"
When the admin sets stock quantity for SKU "TS-001" at Store "Filiale 1" to 50
And the admin sets stock quantity for SKU "TS-001" at Store "Filiale 2" to 0
Then the response status is 200
And Store "Filiale 1" shows stock_qty = 50 for SKU "TS-001"
And Store "Filiale 2" shows stock_qty = 0 for SKU "TS-001"
Scenario: AC-102 — Bestandsauskunft für nicht-existierenden SKU → leer
Given the user "admin@meinladen.de" is authenticated as "admin"
When the admin queries stock for SKU "UNBEKANNT-999"
Then the response status is 200
And the stock quantity is 0
And no inventory record is created
Feature: F6 Authentication Security & Edge Cases
Background:
Given the system is operating normally
Scenario: AC-110 — Mehr als 5 fehlgeschlagene Login-Versuche → Account temporär gesperrt (30 min)
Given a User with email "sarah@test.de" and password "Sicher!23" exists
When the user fails to log in 6 times consecutively with wrong password
Then the account is locked for 30 minutes
And the next login attempt with correct password returns 429
And the response contains error "Account temporarily locked"
Scenario: AC-111 — JWT-Token Manipulation → 401
Given a User is authenticated with a valid JWT
When the user modifies the JWT payload (changing role to "admin")
And the user sends a request with the modified token
Then the response status is 401
And the response contains error "Invalid token signature"
Scenario: AC-112 — Rate Limiting bei Login — mehr als 20 Versuche/Minute → 429
When an anonymous user attempts to log in 21 times within 1 minute
Then the 21st request returns 429 Too Many Requests
And the response contains error "Rate limit exceeded"
Scenario: AC-113 — XSS im Email-Feld bei Registration → escaped
When a prospective user submits registration with email "<script>alert(1)</script>@test.de"
Then the response status is 400
And the system does not store the raw script in the database
Scenario: AC-114 — SQL Injection in Login-Feld → Parameterized Query
When an anonymous user submits login with email "' OR '1'='1" and password "anything"
Then the request is handled safely via parameterized queries
And the response status is 401 (no SQL error leaked)
Scenario: AC-115 — Access Token läuft nach 15 Minuten ab
Given a User has a valid access token issued 16 minutes ago
When the user sends a request with that access token
Then the response status is 401
And the response contains error "Token expired"
Feature: F7 Multi-Tenant Data Isolation
Background:
Given Company "Laden A GmbH" exists
And Company "Laden B GmbH" exists
Scenario: AC-120 — User aus Company A sieht keine Daten von Company B
Given Product "Exklusiv-A" belongs to Company "Laden A GmbH"
And Product "Exklusiv-B" belongs to Company "Laden B GmbH"
And User "user-a@ladenia.de" is authenticated for Company "Laden A GmbH"
When the user searches for products
Then only Product "Exklusiv-A" appears in results
And Product "Exklusiv-B" is not returned
Scenario: AC-121 — User mit Zugriff auf mehrere Stores sieht nur eigene Stores
Given Company "Laden A GmbH" has Store "Store-A1" and Store "Store-A2"
And User "manager-a@ladenia.de" (role "manager") is assigned only to Store "Store-A1"
When the user requests accessible stores
Then only Store "Store-A1" is returned
And Store "Store-A2" is not accessible
Scenario: AC-122 — Row-Level Security — direkte DB-Abfrage ohne Tenant-ID → 0 Rows
Given Company "Laden A GmbH" exists
And Company "Laden B GmbH" exists
When a DB query is executed without tenant_id filter (simulating misconfigured RLS)
Then the database-level Row-Level Security policy blocks the query
And no cross-tenant data is accessible at the database layer
Scenario: AC-123 — API-Response enthält niemals Daten aus anderem Tenant
Given User "attacker@malicious.de" attempts to access Company "Laden B" resources via IDOR
When the user sends GET /api/companies/laden-b-uuid/stores
Then the response is 403 Forbidden
And no store data from "Laden B" is leaked in the response
| Feature | Must-Have Szenarien | Edge-Case Szenarien | Total |
|---|---|---|---|
| F1.1 Login | 3 | 5 | 8 |
| F1.2 Registration | 1 | 3 | 4 |
| F1.3 Password Reset | 1 | 3 | 4 |
| F2.1 RBAC Roles | 3 | 1 | 4 |
| F2.2 Role Assignment | 2 | 2 | 4 |
| F3.1 Company Mgmt | 1 | 2 | 3 |
| F3.2 Store Mgmt | 3 | 1 | 4 |
| F4.1 User CRUD | 3 | 2 | 5 |
| F5.1 Products | 3 | 4 | 7 |
| F5.2 Categories | 2 | 2 | 4 |
| F5.3 SKU/Stock | 1 | 3 | 4 |
| F6 Security | 2 | 4 | 6 |
| F7 Multi-Tenant | 1 | 3 | 4 |
| Total | 25 | 35 | 60 |
Ziel: ≥ 80% Coverage = 48/60 Szenarien automatisiert. Alle Critical-Path-Szenarien (AC-001, AC-030, AC-050, AC-060, AC-070, AC-080, AC-087) müssen in CI.
Hinzugefügt: 2026-07-03 von PM (95ed75cd)
Issue: CAR-22 — Sprint-2 Stories + Gherkin AK
Feature: S2-F1 Product CRUD
Background:
Given Company "Testladen GmbH" exists
And Store "Hauptfiliale" belongs to Company "Testladen GmbH"
And the authenticated user is an Admin of Company "Testladen GmbH"
Scenario: SP-AC001 — Admin erstellt ein Product mit Pflichtfeldern
When the Admin submits a create product request with:
| name | sku | price | category |
| Baumwoll-T-Shirt | TST-001 | 29.99 | Bekleidung |
Then the response status is 201
And a Product record exists with name "Baumwoll-T-Shirt" and sku "TST-001"
And the product belongs to Company "Testladen GmbH"
Scenario: SP-AC002 — Product-Name ist Pflichtfeld
When the Admin submits a create product request with:
| sku | price |
| TST-002 | 19.99 |
Then the response status is 400
And the response contains validation error for field "name"
Scenario: SP-AC003 — SKU muss eindeutig sein pro Company
Given a Product with sku "TST-001" belongs to Company "Testladen GmbH"
When the Admin submits a create product request with:
| name | sku | price |
| andere Ware | TST-001 | 9.99 |
Then the response status is 409
And the response contains error "SKU already exists in this company"
Scenario: SP-AC004 — Admin liest alle Products einer Company
Given Products "TST-001" and "TST-002" belong to Company "Testladen GmbH"
When the Admin requests all products for Company "Testladen GmbH"
Then the response status is 200
And the response contains exactly 2 products
Scenario: SP-AC005 — Admin updated ein Product
Given a Product with name "Baumwoll-T-Shirt" and sku "TST-001" exists
When the Admin submits an update request for product "TST-001" with:
| name | price |
| Premium Baumwoll-T-Shirt | 34.99 |
Then the response status is 200
And the Product name is now "Premium Baumwoll-T-Shirt"
And the Product price is now 34.99
Scenario: SP-AC006 — Admin löscht ein Product (soft delete)
Given a Product with sku "TST-001" exists
When the Admin submits a delete request for product "TST-001"
Then the response status is 200
And the Product is marked as deleted (not returned in active product list)
Scenario: SP-AC007 — Manager kann Products lesen aber nicht erstellen/löschen
Given User "manager@test.de" has role "manager" at Store "Hauptfiliale"
When the Manager requests all products for Company "Testladen GmbH"
Then the response status is 200
And the products are returned
When the Manager submits a create product request with:
| name | sku | price |
| Neue Ware | TST-999 | 9.99 |
Then the response status is 403
And the response contains error "Access denied"
Scenario: SP-AC008 — Sales Rolle hat nur Leserechte für Products
Given User "sales@test.de" has role "sales" at Store "Hauptfiliale"
When the Sales user requests all products for Company "Testladen GmbH"
Then the response status is 200
And the products are returned
When the Sales user submits a create product request with:
| name | sku | price |
| Test | TST-888 | 1.00 |
Then the response status is 403
And the response contains error "Access denied"
Feature: S2-F2 Category CRUD + Hierarchie
Background:
Given Company "Testladen GmbH" exists
And the authenticated user is an Admin of Company "Testladen GmbH"
Scenario: SP-AC010 — Admin erstellt eine Hauptkategorie
When the Admin submits a create category request with:
| name | parent_id |
| Bekleidung | null |
Then the response status is 201
And a Category record exists with name "Bekleidung"
And the category has no parent (is a root category)
Scenario: SP-AC011 — Admin erstellt eine Unterkategorie
Given a Category "Bekleidung" exists
When the Admin submits a create category request with:
| name | parent_id |
| T-Shirts | {category_id} |
Then the response status is 201
And a Category record exists with name "T-Shirts"
And the category's parent is "Bekleidung"
Scenario: SP-AC012 — Kategorie-Hierarchie wird korrekt zurückgegeben
Given Categories "Bekleidung" → "T-Shirts" → "Basic Shirts" exist
When the Admin requests the category tree
Then the response status is 200
And the category "Bekleidung" contains child "T-Shirts"
And "T-Shirts" contains child "Basic Shirts"
Scenario: SP-AC013 — Kategorie mit ungültigem parent_id → Fehler
When the Admin submits a create category request with:
| name | parent_id |
| Orphan | nonexistent-id-123 |
Then the response status is 400
And the response contains error "Parent category not found"
Scenario: SP-AC014 — Kategorie wird gelöscht → Children werden zu Root
Given Categories "Bekleidung" → "T-Shirts" exist
When the Admin deletes category "Bekleidung"
Then the response status is 200
And category "T-Shirts" now has no parent (becomes a root category)
Scenario: SP-AC015 — Category wird einem Product zugewiesen
Given a Category "Bekleidung" exists
And a Product "TST-001" exists
When the Admin assigns category "Bekleidung" to product "TST-001"
Then the response status is 200
And the Product "TST-001" has category "Bekleidung"
Feature: S2-F3 Product Attributes (Size, Color, Season)
Background:
Given Company "Testladen GmbH" exists
And the authenticated user is an Admin of Company "Testladen GmbH"
Scenario: SP-AC020 — Admin vergibt Size-Attribute (einzeln)
Given a Product "TST-001" exists
When the Admin adds attribute "size" with value "M" to product "TST-001"
Then the response status is 200
And the Product "TST-001" has attribute size = "M"
Scenario: SP-AC021 — Admin vergibt mehrere Size-Attribute (Multi-Select)
Given a Product "TST-001" exists
When the Admin adds attribute "size" with values "S", "M", "L", "XL" to product "TST-001"
Then the response status is 200
And the Product "TST-001" has size variants: S, M, L, XL
Scenario: SP-AC022 — Admin vergibt Color-Attribute
Given a Product "TST-001" exists
When the Admin adds attribute "color" with values "schwarz", "weiß" to product "TST-001"
Then the response status is 200
And the Product "TST-001" has color variants: schwarz, weiß
Scenario: SP-AC023 — Admin vergibt Season-Attribute
Given a Product "TST-001" exists
When the Admin adds attribute "season" with value "Frühjahr/Sommer 2025" to product "TST-001"
Then the response status is 200
And the Product "TST-001" has season attribute = "Frühjahr/Sommer 2025"
Scenario: SP-AC024 — Ungültiges Attribut → Fehler
Given a Product "TST-001" exists
When the Admin adds attribute "invalid_attribute" with value "test" to product "TST-001"
Then the response status is 400
And the response contains error "Unknown attribute type"
Scenario: SP-AC025 — Season-Attribut ist optional (Product ohne Saison)
Given a Product "TST-001" exists
When the Admin creates a product without season attribute
Then the response status is 201
And the Product has no season constraint (ganzjährig verfügbar)
Scenario: SP-AC026 — Product wird nach Size gefiltert
Given Products "TST-S" (size=S) and "TST-M" (size=M) exist
When the user requests products filtered by size "M"
Then the response contains only the product with size "M"
Feature: S2-F4 SKU-Varianten (Größe × Farbe)
Background:
Given Company "Testladen GmbH" exists
And the authenticated user is an Admin of Company "Testladen GmbH"
And a Category "Bekleidung" exists
Scenario: SP-AC030 — Admin erstellt SKU-Varianten automatisch (Matrix)
Given a Product "TST-001" exists with attributes:
| size | color |
| S, M | schwarz |
When the Admin triggers SKU generation for product "TST-001"
Then the response status is 200
And the following SKU variants exist:
| sku | size | color |
| TST-001-S-S | S | schwarz |
| TST-001-M-S | M | schwarz |
Scenario: SP-AC031 — Admin erstellt vollständige Größe-Farbe-Matrix
Given a Product "TST-001" exists with attributes:
| size | color |
| S, M, L | schwarz, weiß |
When the Admin triggers SKU generation for product "TST-001"
Then the response status is 200
And exactly 6 SKU variants are created (3 sizes × 2 colors)
Scenario: SP-AC032 — SKU-Variante erhält eigenen Preis
Given a Product "TST-001" exists with SKU variant "TST-001-S-S"
When the Admin sets price 39.99 for SKU variant "TST-001-S-S"
Then the response status is 200
And the SKU variant "TST-001-S-S" has price 39.99
Scenario: SP-AC033 — SKU-Variante erhält eigenen Bestand
Given a Product "TST-001" exists with SKU variant "TST-001-S-S"
When the Admin sets stock quantity 50 for SKU variant "TST-001-S-S"
Then the response status is 200
And the SKU variant "TST-001-S-S" has stock quantity 50
Scenario: SP-AC034 — Bestand einer Variante wird reduziert ( Verkauf)
Given SKU variant "TST-001-S-S" has stock quantity 50
When the system reduces stock for SKU "TST-001-S-S" by 1 (sale)
Then the SKU variant "TST-001-S-S" now has stock quantity 49
Scenario: SP-AC035 — Bestand = 0 → Variante ist ausverkauft
Given SKU variant "TST-001-S-S" has stock quantity 1
When the system reduces stock for SKU "TST-001-S-S" by 1 (sale)
Then the SKU variant "TST-001-S-S" has stock quantity 0
And the variant is marked as out_of_stock
Scenario: SP-AC036 — Verkauf mit unzureichendem Bestand → Fehler
Given SKU variant "TST-001-S-S" has stock quantity 0
When the system attempts to reduce stock for SKU "TST-001-S-S" by 1
Then the response status is 409
And the response contains error "Insufficient stock"
Scenario: SP-AC037 — SKU-Variante wird aus dem Sortiment entfernt
Given SKU variant "TST-001-S-S" exists
When the Admin deactivates SKU variant "TST-001-S-S"
Then the response status is 200
And the SKU variant is not returned in active variant list
Feature: S2-F5 Product Images (S3 Upload)
Background:
Given Company "Testladen GmbH" exists
And the authenticated user is an Admin of Company "Testladen GmbH"
And a Product "TST-001" exists
Scenario: SP-AC040 — Admin läd Product-Bild hoch
When the Admin uploads an image for product "TST-001" with:
| file | is_primary |
| img.jpg | true |
Then the response status is 201
And the image is stored in S3
And the image URL is returned in the response
And the image is marked as primary
Scenario: SP-AC041 — Admin setzt mehrere Bilder (Galerie)
Given a primary image exists for product "TST-001"
When the Admin uploads a second image for product "TST-001" with is_primary=false
Then the response status is 201
And the product now has 2 images
And the first image remains primary
Scenario: SP-AC042 — Primäres Bild wird ausgetauscht
Given product "TST-001" has a primary image
When the Admin uploads a new image and sets it as primary
Then the response status is 200
And the new image is primary
And the old primary image is demoted to non-primary
Scenario: SP-AC043 — Bild-Upload ohne Auth → 401
Given the user is unauthenticated
When the user uploads an image for product "TST-001"
Then the response status is 401
Scenario: SP-AC044 — Falsches Dateiformat → Fehler
When the Admin uploads a non-image file (e.g., .pdf) for product "TST-001"
Then the response status is 400
And the response contains error "Only image files (JPEG, PNG, WebP) are allowed"
Scenario: SP-AC045 — Bild zu groß (> 10MB) → Fehler
When the Admin uploads an image larger than 10MB for product "TST-001"
Then the response status is 413
And the response contains error "File size exceeds 10MB limit"
| Feature | Happy Path | Edge Cases | Total |
|---|---|---|---|
| S2-F1 Product CRUD | 4 | 4 | 8 |
| S2-F2 Categories | 4 | 2 | 6 |
| S2-F3 Attributes | 5 | 2 | 7 |
| S2-F4 SKU-Varianten | 4 | 3 | 7 |
| S2-F5 Product Images | 4 | 2 | 6 |
| Sprint 2 Total | 21 | 13 | 34 |
Erstellt: 2026-07-03 von PM (95ed75cd)
Issue: CAR-22 — Sprint-2 Stories + Gherkin AK (ergänzt CAR-14 Sprint-1 AK)
Roadmap: PM-ROADMAP-Phase1.md (CPTO approved)