Files
cannamanage/docs/sprint-6/cannamanage-sprint6-testplan.md
T
Patrick Plate 3232d2f7fd
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
feat(sprint-6): Phase 2 — DSGVO consent management
- V6 migration: consents table with audit columns
- Consent entity, repository, service (grant/revoke/check)
- ConsentController: GET/POST/DELETE consent endpoints
- DSGVO export (Art. 15): full personal data JSON download
- DSGVO deletion (Art. 17): anonymization + account deactivation
- Frontend: consent banner (modal, cannot dismiss), privacy settings page
- React Query hooks for consent + DSGVO operations
- Full i18n (de/en) for consent and DSGVO namespaces
2026-06-12 22:22:48 +02:00

29 KiB

Testplan: CannaManage Sprint 6 — Production Readiness

Datum: 2026-06-12 Modul: cannamanage (all modules) Autor: Patrick Plate Status: Entwurf v1 Basis: cannamanage-sprint6-plan.md (v1)


Testübersicht

ID Beschreibung Typ Klasse/Tool Status
T-01 ConsentService: accept consent Unit ConsentServiceTest
T-02 ConsentService: revoke consent Unit ConsentServiceTest
T-03 ConsentService: check consent status Unit ConsentServiceTest
T-04 ConsentService: re-prompt on new version Unit ConsentServiceTest
T-05 DsgvoService: export user data (ZIP) Unit DsgvoServiceTest
T-06 DsgvoService: erasure request (anonymize) Unit DsgvoServiceTest
T-07 DsgvoService: retain legally required data Unit DsgvoServiceTest
T-08 StripeService: create customer Unit StripeServiceTest
T-09 StripeService: create checkout session (SEPA) Unit StripeServiceTest
T-10 StripeService: create billing portal session Unit StripeServiceTest
T-11 StripeService: handle webhook invoice.paid Unit StripeServiceTest
T-12 StripeService: handle webhook payment_failed Unit StripeServiceTest
T-13 StripeService: handle webhook subscription.deleted Unit StripeServiceTest
T-14 StripeWebhookController: reject invalid signature Unit StripeWebhookControllerTest
T-15 SubscriptionFilter: block expired subscription Unit SubscriptionFilterTest
T-16 SubscriptionFilter: allow active subscription Unit SubscriptionFilterTest
T-17 SubscriptionFilter: allow trial period Unit SubscriptionFilterTest
T-18 AuditService: log event Unit AuditServiceTest
T-19 AuditService: immutability (no update/delete) Integration AuditServiceIntegrationTest
T-20 AuditService: JSON details serialization Unit AuditServiceTest
T-21 AuditService: server-generated timestamp (Europe/Berlin) Unit AuditServiceTest
T-22 AuditController: paginated list with filters Integration AuditControllerIntegrationTest
T-23 AuditController: PDF export Integration AuditControllerIntegrationTest
T-24 GrowCalendarService: create grow entry Unit GrowCalendarServiceTest
T-25 GrowCalendarService: update stage transition Unit GrowCalendarServiceTest
T-26 GrowCalendarService: link harvest to batch Unit GrowCalendarServiceTest
T-27 GrowCalendarService: reject invalid stage progression Unit GrowCalendarServiceTest
T-28 NotificationService: quota warning at 80% Unit NotificationServiceTest
T-29 NotificationService: batch recall notification Unit NotificationServiceTest
T-30 NotificationService: new distribution notification Unit NotificationServiceTest
T-31 Flyway V6: consent + audit_event tables created Integration FlywayMigrationTest
T-32 Flyway V7: stripe columns added to club Integration FlywayMigrationTest
T-33 Flyway V8: grow_entry table created Integration FlywayMigrationTest
T-34 Flyway V9: notification table created Integration FlywayMigrationTest
T-35 Consent flow E2E: login → banner → accept → app access E2E Playwright
T-36 Consent flow E2E: login → banner → reject → logout E2E Playwright
T-37 Billing page E2E: display plan + upgrade CTA E2E Playwright
T-38 Audit log page E2E: filter + pagination + PDF download E2E Playwright
T-39 Grow calendar E2E: create entry + drag resize E2E Playwright
T-40 Notification bell E2E: receive + display + mark read E2E Playwright
T-41 PWA manifest: installable, correct icons E2E Lighthouse
T-42 Production smoke test: full user journey Manual Production
T-43 Backup/restore: pg_dump + restore verification Manual Production
T-44 TLS verification: SSL Labs A+ rating Manual SSL Labs
T-45 Load test: 100 concurrent users, p95 < 500ms Performance k6

Status: Offen | Bestanden | Fehlgeschlagen | ⏭️ Übersprungen


Testfälle

Typ: Unit Klasse: de.cannamanage.service.ConsentServiceTest Methode: testAcceptConsent()

Vorbedingungen:

  • User existiert in der DB
  • Kein vorhandener Consent-Eintrag für diesen User + Typ + Version

Szenarien:

# Eingabe Erwartetes Ergebnis
a Gültiger User, PRIVACY_POLICY, Version "2026-06-v1" Consent-Entity gespeichert mit IP, User-Agent, Timestamp
b User mit bereits akzeptiertem Consent (gleiche Version) Exception: ConsentAlreadyAcceptedException
c User mit revoked Consent (gleiche Version) Neuer Consent-Eintrag erstellt (re-accept möglich)

Nachbedingungen:

  • Audit-Log-Eintrag CONSENT_ACCEPTED erstellt
  • Consent in DB mit korrektem Timestamp

Typ: Unit Klasse: de.cannamanage.service.ConsentServiceTest Methode: testRevokeConsent()

Vorbedingungen:

  • User hat aktiven Consent (acceptedAt != null, revokedAt == null)

Szenarien:

# Eingabe Erwartetes Ergebnis
a User mit aktivem Consent revokedAt gesetzt, Audit-Log CONSENT_REVOKED
b User ohne aktiven Consent Exception: NoActiveConsentException

Nachbedingungen:

  • Nachfolgende API-Aufrufe blockiert (Consent-Check schlägt fehl)

Typ: Unit Klasse: de.cannamanage.service.ConsentServiceTest Methode: testCheckConsentStatus()

Vorbedingungen:

  • Verschiedene Consent-Zustände in DB

Szenarien:

# Eingabe Erwartetes Ergebnis
a User mit aktivem Consent (aktuelle Version) true
b User ohne Consent false
c User mit revoked Consent false
d User mit Consent alter Version (neue Version verfügbar) false (re-prompt nötig)

T-04: ConsentService — re-prompt on new version

Typ: Unit Klasse: de.cannamanage.service.ConsentServiceTest Methode: testRePromptOnNewVersion()

Vorbedingungen:

  • User hat Consent für Version "2026-06-v1"
  • System-Consent-Version ist jetzt "2026-09-v2"

Szenarien:

# Eingabe Erwartetes Ergebnis
a Check mit aktueller Version "2026-09-v2" false — user muss neue Version akzeptieren
b Nach Accept der neuen Version true

T-05: DsgvoService — export user data (ZIP)

Typ: Unit Klasse: de.cannamanage.service.DsgvoServiceTest Methode: testExportUserData()

Vorbedingungen:

  • User mit Profildaten, Distributions, Quota-History, Consent-Einträgen

Szenarien:

# Eingabe Erwartetes Ergebnis
a User mit vollständigen Daten ZIP enthält: profile.json, distributions.json, quota-history.json, consents.json
b User ohne Distributions ZIP enthält leere distributions.json (leeres Array)
c User mit gelöschtem Account Exception: UserNotFoundException

Nachbedingungen:

  • Audit-Log-Eintrag DATA_EXPORT_REQUESTED
  • ZIP-Datei ist valides ZIP-Format

T-06: DsgvoService — erasure request

Typ: Unit Klasse: de.cannamanage.service.DsgvoServiceTest Methode: testErasureRequest()

Vorbedingungen:

  • User mit vollständigen Daten, aktiven Sessions

Szenarien:

# Eingabe Erwartetes Ergebnis
a Gültiger User Name → "GELÖSCHT", Email → hash, Distributions anonymisiert (Mengen erhalten, Personenbezug entfernt)
b User mit aktivem Consent Alle Consents revoked
c User mit aktiver Session Alle Sessions invalidiert

Nachbedingungen:

  • Audit-Log-Eintrag DATA_ERASURE_REQUESTED
  • Aggregat-Daten für Compliance erhalten (Gesamtmengen pro Monat)
  • Kein Personenbezug mehr herstellbar

T-07: DsgvoService — retain legally required data

Typ: Unit Klasse: de.cannamanage.service.DsgvoServiceTest Methode: testRetainLegallyRequiredData()

Vorbedingungen:

  • User mit Distributions (steuerrelevant, 10-Jahres-Aufbewahrungspflicht)

Szenarien:

# Eingabe Erwartetes Ergebnis
a Erasure-Request für User mit Distributions Distributions anonymisiert (member_id → null oder "ANON"), aber Zeilen + Mengen erhalten
b Erasure-Request für User ohne Distributions Vollständige Löschung aller Daten

T-08: StripeService — create customer

Typ: Unit (mit Stripe Mock) Klasse: de.cannamanage.service.StripeServiceTest Methode: testCreateCustomer()

Vorbedingungen:

  • Club und Owner existieren
  • Stripe API gemockt

Szenarien:

# Eingabe Erwartetes Ergebnis
a Club "Grüner Daumen", Owner email "owner@test.de" Stripe Customer erstellt mit email + metadata (club_id, user_id)
b Club bereits mit stripe_customer_id Exception: CustomerAlreadyExistsException

Nachbedingungen:

  • club.stripeCustomerId gesetzt

T-09: StripeService — create checkout session

Typ: Unit (mit Stripe Mock) Klasse: de.cannamanage.service.StripeServiceTest Methode: testCreateCheckoutSession()

Vorbedingungen:

  • Club hat stripe_customer_id
  • Price ID existiert

Szenarien:

# Eingabe Erwartetes Ergebnis
a Starter plan, SEPA Session mit mode=subscription, payment_methods=[sepa_debit,card,paypal], trial=14 days
b Pro plan Session mit korrektem price_id
c Club ohne stripe_customer_id Exception: NoStripeCustomerException

T-10: StripeService — billing portal session

Typ: Unit (mit Stripe Mock) Klasse: de.cannamanage.service.StripeServiceTest Methode: testCreateBillingPortalSession()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Club mit activem Subscription Portal-Session-URL zurückgegeben
b Club ohne Subscription Exception oder leere Portal-Session

T-11: StripeService — webhook invoice.paid

Typ: Unit Klasse: de.cannamanage.service.StripeServiceTest Methode: testHandleInvoicePaid()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Gültiges invoice.paid Event Club subscription_status → ACTIVE, Audit-Log PAYMENT_RECEIVED
b Event für unbekannten Customer Logged + ignoriert (kein Fehler)

T-12: StripeService — webhook payment_failed

Typ: Unit Klasse: de.cannamanage.service.StripeServiceTest Methode: testHandlePaymentFailed()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Gültiges invoice.payment_failed Event Club subscription_status → PAST_DUE, Audit-Log PAYMENT_FAILED
b Wiederholter Fehlschlag Status bleibt PAST_DUE (idempotent)

T-13: StripeService — webhook subscription.deleted

Typ: Unit Klasse: de.cannamanage.service.StripeServiceTest Methode: testHandleSubscriptionDeleted()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Gültiges customer.subscription.deleted Event Club subscription_status → CANCELED, Audit-Log SUBSCRIPTION_CANCELED

T-14: StripeWebhookController — reject invalid signature

Typ: Unit Klasse: de.cannamanage.api.controller.StripeWebhookControllerTest Methode: testRejectInvalidSignature()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Request ohne Stripe-Signature Header 400 Bad Request
b Request mit ungültiger Signatur 400 Bad Request
c Request mit gültiger Signatur 200 OK, Event verarbeitet

T-15: SubscriptionFilter — block expired subscription

Typ: Unit Klasse: de.cannamanage.api.security.SubscriptionFilterTest Methode: testBlockExpiredSubscription()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Club mit status CANCELED 402 Payment Required
b Club mit status PAST_DUE (>grace period) 402 Payment Required
c Actuator/health endpoint Kein Filter (immer erlaubt)
d Webhook endpoint Kein Filter (immer erlaubt)

T-16: SubscriptionFilter — allow active subscription

Typ: Unit Klasse: de.cannamanage.api.security.SubscriptionFilterTest Methode: testAllowActiveSubscription()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Club mit status ACTIVE Request durchgelassen
b Club mit status PAST_DUE (innerhalb Grace Period) Request durchgelassen (mit Warning-Header)

T-17: SubscriptionFilter — allow trial period

Typ: Unit Klasse: de.cannamanage.api.security.SubscriptionFilterTest Methode: testAllowTrialPeriod()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Club mit status TRIALING, trial_ends_at > now Request durchgelassen
b Club mit status TRIALING, trial_ends_at < now 402 Payment Required

T-18: AuditService — log event

Typ: Unit Klasse: de.cannamanage.service.AuditServiceTest Methode: testLogEvent()

Szenarien:

# Eingabe Erwartetes Ergebnis
a DISTRIBUTION_CREATED, actor, entity, description AuditEvent in DB gespeichert mit allen Feldern
b System-Event (kein Actor) actorId=null, actorName="SYSTEM"
c Event mit Details (JSON) details-Feld enthält serialisiertes JSON

Nachbedingungen:

  • createdAt server-generiert (nicht aus Request)

T-19: AuditService — immutability

Typ: Integration Klasse: de.cannamanage.service.AuditServiceIntegrationTest Methode: testImmutability()

Vorbedingungen:

  • AuditEvent in DB gespeichert

Szenarien:

# Eingabe Erwartetes Ergebnis
a UPDATE auf audit_event Zeile via EntityManager Exception (Hibernate @Immutable verhindert Update)
b DELETE auf audit_event Zeile via EntityManager Exception oder ignoriert
c Native SQL UPDATE DB-Trigger verhindert Änderung (wenn implementiert)

T-20: AuditService — JSON details serialization

Typ: Unit Klasse: de.cannamanage.service.AuditServiceTest Methode: testJsonDetailsSerialization()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Map mit before/after Werten Valides JSON in details-Feld
b null details details-Feld ist null (nicht "null" String)
c Komplexes Objekt mit verschachtelten Feldern Korrekt serialisiert, deserialisierbar

T-21: AuditService — server-generated timestamp

Typ: Unit Klasse: de.cannamanage.service.AuditServiceTest Methode: testServerGeneratedTimestamp()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Event ohne explizites Timestamp createdAt = Instant.now() (±1s Toleranz)
b Event mit manipuliertem createdAt im Request Ignoriert — Server überschreibt via @PrePersist

T-22: AuditController — paginated list with filters

Typ: Integration Klasse: de.cannamanage.api.controller.AuditControllerIntegrationTest Methode: testPaginatedListWithFilters()

Vorbedingungen:

  • 100+ Audit-Events in DB (verschiedene Typen, Zeiträume, Akteure)

Szenarien:

# Eingabe Erwartetes Ergebnis
a GET /audit?page=0&size=50 50 Events, Pagination-Metadaten korrekt
b GET /audit?type=DISTRIBUTION_CREATED Nur Distribution-Events
c GET /audit?from=2026-06-01&to=2026-06-30 Nur Events im Juni
d GET /audit?actor=Patrick Nur Events von Patrick
e GET /audit?search=Northern+Lights Full-text Suche in description

T-23: AuditController — PDF export

Typ: Integration Klasse: de.cannamanage.api.controller.AuditControllerIntegrationTest Methode: testPdfExport()

Szenarien:

# Eingabe Erwartetes Ergebnis
a GET /audit/export?format=pdf&from=2026-06-01&to=2026-06-30 Valides PDF, Content-Type application/pdf
b Export mit 0 Events PDF mit "Keine Einträge im Zeitraum" Meldung
c Export mit 1000+ Events PDF generiert ohne OutOfMemory (streamed)

T-24: GrowCalendarService — create grow entry

Typ: Unit Klasse: de.cannamanage.service.GrowCalendarServiceTest Methode: testCreateGrowEntry()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Strain "Northern Lights", SEEDLING, startDate=today, plantCount=10 GrowEntry gespeichert, Audit-Log
b Ohne strain_id Validation-Fehler
c endDate vor startDate Validation-Fehler

T-25: GrowCalendarService — stage transition

Typ: Unit Klasse: de.cannamanage.service.GrowCalendarServiceTest Methode: testStageTransition()

Szenarien:

# Eingabe Erwartetes Ergebnis
a SEEDLING → VEGETATIVE Erfolgreich, stage aktualisiert
b SEEDLING → FLOWERING (Stufe übersprungen) Erlaubt (flexible Progression)
c HARVEST → SEEDLING (Rückwärts) Erlaubt (Korrektur möglich)

Typ: Unit Klasse: de.cannamanage.service.GrowCalendarServiceTest Methode: testLinkHarvestToBatch()

Szenarien:

# Eingabe Erwartetes Ergebnis
a GrowEntry im HARVEST-Stage + existierende Batch linkedBatch gesetzt, Audit-Log HARVEST_LINKED_TO_BATCH
b GrowEntry nicht im HARVEST-Stage Nur im HARVEST/DRYING/CURING-Stage erlaubt
c Batch bereits mit anderem GrowEntry verknüpft Warnung (aber erlaubt — ein Batch kann mehrere Grows haben)

T-27: GrowCalendarService — reject invalid stage

Typ: Unit Klasse: de.cannamanage.service.GrowCalendarServiceTest Methode: testRejectInvalidStage()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Stage = null Validation-Fehler
b Stage = ungültiger String (API-Ebene) 400 Bad Request

T-28: NotificationService — quota warning

Typ: Unit Klasse: de.cannamanage.service.NotificationServiceTest Methode: testQuotaWarning()

Vorbedingungen:

  • SimpMessagingTemplate gemockt

Szenarien:

# Eingabe Erwartetes Ergebnis
a userId=42, percentUsed=80 Message an /user/42/queue/notifications mit type=QUOTA_WARNING
b userId=42, percentUsed=95 Gleiche Nachricht (Schwellwert-Logik liegt im Aufrufer)

T-29: NotificationService — batch recall

Typ: Unit Klasse: de.cannamanage.service.NotificationServiceTest Methode: testBatchRecallNotification()

Szenarien:

# Eingabe Erwartetes Ergebnis
a clubId=1, batchName="Northern Lights #7" Message an /topic/club/1/notifications mit type=BATCH_RECALL

T-30: NotificationService — new distribution

Typ: Unit Klasse: de.cannamanage.service.NotificationServiceTest Methode: testNewDistributionNotification()

Szenarien:

# Eingabe Erwartetes Ergebnis
a memberId=7, "Northern Lights", 5.0g Message an /user/7/queue/notifications mit type=DISTRIBUTION

Typ: Integration Klasse: de.cannamanage.FlywayMigrationTest Methode: testV6ConsentAndAuditTables()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Migration V6 ausführen Tabellen consent und audit_event existieren
b consent: unique constraint (user_id, consent_type, version) Duplikat-Insert schlägt fehl
c audit_event: JSONB column für details INSERT mit JSON-Wert funktioniert

T-32: Flyway V7 — stripe columns

Typ: Integration Klasse: de.cannamanage.FlywayMigrationTest Methode: testV7StripeColumns()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Migration V7 ausführen Spalten stripe_customer_id, subscription_status, subscription_plan, trial_ends_at in club
b Existierende Clubs NULL-Werte für neue Spalten (keine Default-Pflicht)

T-33: Flyway V8 — grow_entry table

Typ: Integration Klasse: de.cannamanage.FlywayMigrationTest Methode: testV8GrowEntryTable()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Migration V8 ausführen Tabelle grow_entry mit FK zu strain + batch
b INSERT mit gültigem strain_id Erfolgreich
c INSERT mit ungültigem strain_id FK-Violation

T-34: Flyway V9 — notification table

Typ: Integration Klasse: de.cannamanage.FlywayMigrationTest Methode: testV9NotificationTable()

Szenarien:

# Eingabe Erwartetes Ergebnis
a Migration V9 ausführen Tabelle notification existiert
b Index auf (user_id, read_at) Performante Abfrage ungelesener Notifications

Typ: E2E (Playwright) Klasse: e2e/consent-flow.spec.ts

Vorbedingungen:

  • Neuer User (kein Consent in DB)

Szenarien:

# Eingabe Erwartetes Ergebnis
a Login → Consent-Banner erscheint Modal sichtbar, "Akzeptieren" + "Ablehnen" Buttons
b Klick "Akzeptieren" Modal verschwindet, Dashboard wird geladen
c Erneuter Login (gleicher User) Kein Banner (Consent bereits akzeptiert)

Typ: E2E (Playwright) Klasse: e2e/consent-flow.spec.ts

Szenarien:

# Eingabe Erwartetes Ergebnis
a Login → Klick "Ablehnen" Redirect zu Login-Seite, Session invalidiert
b Versuch direkter Navigation zu /dashboard (ohne Consent) Redirect zu Consent-Banner

T-37: Billing Page E2E

Typ: E2E (Playwright) Klasse: e2e/billing.spec.ts

Szenarien:

# Eingabe Erwartetes Ergebnis
a Navigate zu /settings/billing (Trial-User) Pricing Cards sichtbar (Starter + Pro)
b Navigate zu /settings/billing (Active Subscriber) Aktueller Plan + "Verwalten" Button sichtbar
c Klick "Verwalten" Redirect zu Stripe Billing Portal

T-38: Audit Log Page E2E

Typ: E2E (Playwright) Klasse: e2e/audit-log.spec.ts

Szenarien:

# Eingabe Erwartetes Ergebnis
a Navigate zu /admin/audit-log Tabelle mit Events sichtbar
b Filter nach Typ "Distribution" Nur Distribution-Events angezeigt
c Klick "PDF Export" PDF-Download startet
d Pagination (Seite 2) Neue Events geladen

T-39: Grow Calendar E2E

Typ: E2E (Playwright) Klasse: e2e/grow-calendar.spec.ts

Szenarien:

# Eingabe Erwartetes Ergebnis
a Navigate zu /grow FullCalendar sichtbar mit Monatsansicht
b Klick auf Datum Create-Dialog öffnet sich
c Formular ausfüllen + speichern Neuer farbiger Block im Kalender
d Klick auf existierenden Block Detail-Panel mit Edit/Delete

T-40: Notification Bell E2E

Typ: E2E (Playwright) Klasse: e2e/notifications.spec.ts

Szenarien:

# Eingabe Erwartetes Ergebnis
a Notification empfangen (via WebSocket) Bell-Icon zeigt Badge mit Anzahl
b Klick auf Bell Dropdown mit Notification-Liste
c Klick auf einzelne Notification Als gelesen markiert, Badge decremented

T-41: PWA Manifest

Typ: E2E (Lighthouse) Tool: Lighthouse PWA Audit

Szenarien:

# Eingabe Erwartetes Ergebnis
a Lighthouse PWA Audit installable=true, manifest valid, service worker registered
b Icons vorhanden 192px + 512px PNG Icons
c Offline-Seite Netzwerk trennen → offline.html angezeigt (statt Browser-Fehler)

T-42: Production Smoke Test

Typ: Manual (Production) Tool: Browser auf cannamanage.de

Szenarien:

# Aktion Erwartetes Ergebnis
a Registrierung neuer Club Account erstellt, Consent-Banner erscheint
b Consent akzeptieren Zugang zur App
c Subscription (Stripe Test-Karte) Checkout → Subscription aktiv
d Mitglied anlegen Mitglied in Liste sichtbar
e Ausgabe aufzeichnen Distribution erstellt, Quota aktualisiert
f Audit-Log prüfen Alle Aktionen geloggt
g PDF Export Valides PDF heruntergeladen
h Grow-Eintrag erstellen Kalender zeigt Eintrag
i Notification empfangen Bell-Icon zeigt neue Notification

T-43: Backup/Restore Verification

Typ: Manual (Production) Tool: SSH + pg_dump/pg_restore

Szenarien:

# Aktion Erwartetes Ergebnis
a pg_dump auf Production Komprimiertes SQL-File erstellt
b Restore in leere DB Alle Tabellen + Daten wiederhergestellt
c Cron-Job Ausführung prüfen Backup-Datei < 24h alt in /backup/
d Rotation prüfen Keine Dateien > 7 Tage in /backup/

T-44: TLS Verification

Typ: Manual Tool: SSL Labs (ssllabs.com/ssltest)

Szenarien:

# Aktion Erwartetes Ergebnis
a SSL Labs Test auf cannamanage.de Rating: A+
b HSTS Header prüfen Strict-Transport-Security present, max-age ≥ 63072000
c Mixed Content prüfen Keine HTTP-Ressourcen auf HTTPS-Seite

T-45: Load Test

Typ: Performance Tool: k6

Script: scripts/load-test.js

Szenarien:

# Konfiguration Erwartetes Ergebnis
a 100 VUs, 5 min, Ramp-up 30s p95 < 500ms, 0 errors
b API endpoints: /dashboard, /members, /distributions Alle < 500ms p95
c WebSocket connections: 50 concurrent Stable, kein Disconnect

Testdaten

Seed-Daten (für Unit/Integration Tests)

  • Club: "Testverein Grüner Daumen" (id=1)
  • Users: admin@test.de (ADMIN), staff@test.de (STAFF), member@test.de (MEMBER)
  • Members: 5 Testmitglieder mit verschiedenen Quota-Ständen (0%, 50%, 80%, 95%, 100%)
  • Batches: 3 Batches (Northern Lights, Amnesia Haze, White Widow)
  • Distributions: 20 historische Distributionen
  • Strains: 5 Sorten mit THC/CBD-Werten
  • Grow Entries: 3 in verschiedenen Stages

Stripe Test-Daten

  • Stripe Test-Karte: 4242424242424242 (Erfolg)
  • Stripe Test-SEPA: DE89370400440532013000 (Erfolg)
  • Stripe Test-Karte: 4000000000000002 (Ablehnung)
  • Webhook Events: via Stripe CLI (stripe listen --forward-to localhost:8080/api/v1/webhooks/stripe)

Testabdeckung

Komponente Unit Integration E2E Manual Gesamt
ConsentService 4 0 2 0 6
DsgvoService 3 0 0 0 3
StripeService 6 0 1 0 7
StripeWebhookController 1 0 0 0 1
SubscriptionFilter 3 0 0 0 3
AuditService 4 2 1 0 7
GrowCalendarService 4 0 1 0 5
NotificationService 3 0 1 0 4
Flyway Migrations 0 4 0 0 4
PWA/Production 0 0 1 3 4
Performance 0 0 0 1 1
Summe 28 6 7 4 45

Hinweise

  • Stripe-Tests: Verwenden gemockten Stripe-Client (keine echten API-Calls in Unit-Tests). Integration mit Stripe CLI für Webhook-Testing.
  • WebSocket-Tests: SimpMessagingTemplate wird gemockt. E2E-Test prüft echte WS-Verbindung.
  • Immutability: Zusätzlich zum Hibernate @Immutable kann ein DB-Trigger empfohlen werden — Test T-19c prüft dies nur wenn implementiert.
  • DSGVO-Tests: Besonderes Augenmerk auf Datenminimierung — Tests verifizieren, dass Löschung vollständig ist UND dass legal notwendige Daten erhalten bleiben.
  • Performance-Test: k6 Script wird in Phase 7 erstellt. Baseline-Werte nach Phase 1 Deployment messen.