Files
cannamanage/docs/sprint-14/cannamanage-sprint14-testplan.md
T
Patrick Plate dad798a904
Deploy to TrueNAS / deploy (push) Failing after 33s
feat: Sprint 14 — Marketing & Monetization
- Landing page with hero, feature grid, trust signals
- Split-layout login redesign (admin + portal)
- Pricing page with storage tiers (5GB/50GB/unlimited)
- StorageQuotaService backend (V36 migration, 402 on exceeded)
- Frontend storage integration + 402 error handling
- StorageController uses TenantContext for tenant isolation
- onTierChange() hook for subscription tier updates
2026-06-18 20:28:35 +02:00

17 KiB
Raw Blame History

Testplan: Sprint 14 — Marketing & Monetization

Date: 2026-06-18 Author: Patrick Plate / Lumen (Planner) Status: v2 Basis: cannamanage-sprint14-plan.md


Test Overview

ID Description Type Class/Tool Status
T-01 Landing page renders all sections E2E Playwright
T-02 Landing page responsive (mobile) E2E Playwright
T-03 Landing page dark/light mode E2E Playwright
T-04 Landing page CTA links work E2E Playwright
T-05 Marketing nav shows Features link E2E Playwright
T-06 Admin login — split layout on desktop E2E Playwright
T-07 Admin login — full-width on mobile E2E Playwright
T-08 Admin login — form still functional E2E Playwright
T-09 Portal login — member-themed split E2E Playwright
T-10 Portal login — form functional E2E Playwright
T-11 Pricing — storage tiers displayed E2E Playwright
T-12 Pricing — comparison table with storage row E2E Playwright
T-13 Pricing — FAQ storage entry visible E2E Playwright
T-14 Storage usage — correct calculation Unit StorageQuotaServiceTest
T-15 Storage quota — allows upload under limit Unit StorageQuotaServiceTest
T-16 Storage quota — rejects upload over limit Unit StorageQuotaServiceTest
T-17 Storage quota — increment on upload Unit StorageQuotaServiceTest
T-18 Storage quota — decrement on delete Unit StorageQuotaServiceTest
T-19 Storage quota — decrement floors at zero Unit StorageQuotaServiceTest
T-20 Storage quota — tier limit mapping Unit StorageQuotaServiceTest
T-21 Storage quota — near-limit detection (80%) Unit StorageQuotaServiceTest
T-22 Storage quota — near-limit detection (95%) Unit StorageQuotaServiceTest
T-23 GET /api/v1/storage/usage — authenticated Integration StorageControllerTest
T-24 GET /api/v1/storage/usage — unauthenticated 401 Integration StorageControllerTest
T-25 GET /api/v1/storage/usage — correct DTO shape Integration StorageControllerTest
T-26 Document upload — quota check integrated Integration DocumentServiceTest
T-27 Document upload — 402 on quota exceeded Integration DocumentControllerTest
T-28 Document delete — usage decremented Integration DocumentServiceTest
T-29 Flyway V36 — migration applies cleanly Integration Flyway boot test
T-30 Flyway V36 — backfill calculates correctly Integration SQL verification
T-31 StorageQuotaExceededException — 402 response format Unit GlobalExceptionHandlerTest
T-32 i18n — all marketing.home keys resolve (de + en) Unit Lint / next-intl

Status: Open | Passed | Failed | ⏭️ Skipped


Test Cases

T-01: Landing Page Renders All Sections

Type: E2E Tool: Playwright Script: e2e/marketing/landing-page.spec.ts

Preconditions:

  • App running at localhost:3000
  • No authentication required (public page)

Scenarios:

# Action Expected Result
a Navigate to / Page loads without errors
b Check hero section Headline text visible, CTA buttons present
c Check feature grid 6 feature cards visible with titles and descriptions
d Check trust signals At least 4 trust badges visible
e Check final CTA "Kostenlos testen" button visible

Postconditions:

  • All i18n keys resolve (no raw key strings visible)
  • No console errors

T-02: Landing Page Responsive (Mobile)

Type: E2E Tool: Playwright (viewport: 375×812)

Scenarios:

# Viewport Expected Result
a 375×812 (iPhone) Feature grid stacks to single column
b 375×812 Hero section full-width, text wraps cleanly
c 768×1024 (iPad) Feature grid shows 2 columns
d 1280×720 (desktop) Feature grid shows 3 columns

T-03: Landing Page Dark/Light Mode

Type: E2E Tool: Playwright (colorScheme: 'dark' / 'light')

Scenarios:

# Mode Expected Result
a Dark Background is dark, text is light, no contrast issues
b Light Background is light, text is dark, cards have proper borders
c Switch Toggle theme mid-page — re-renders correctly

Type: E2E Tool: Playwright

Scenarios:

# Element Expected Navigation
a Primary CTA ("Preise ansehen") Navigates to /pricing
b Secondary CTA ("Jetzt anmelden") Navigates to /login
c Final CTA ("Kostenlos testen") Navigates to /pricing
d Header "Features" link Scrolls to #features section or navigates to /#features

Type: E2E Tool: Playwright

Scenarios:

# Page Expected
a / Header shows "Features" link
b /pricing Header shows "Features" link
c Click "Features" from /pricing Navigates to homepage features section

T-06: Admin Login — Split Layout Desktop

Type: E2E Tool: Playwright (viewport: 1280×720)

Scenarios:

# Check Expected
a Left panel visible Branding panel with logo, tagline, feature bullets visible
b Right panel visible Login form visible
c Layout proportions Left panel ~55%, right panel ~45%
d Left panel content "CannaManage" text, tagline, 3 feature highlights with icons

T-07: Admin Login — Full-Width Mobile

Type: E2E Tool: Playwright (viewport: 375×812)

Scenarios:

# Check Expected
a Left panel Hidden (hidden md:flex)
b Form panel Full width, centered vertically
c Form usability All fields accessible, submit button tappable

T-08: Admin Login — Form Still Functional

Type: E2E Tool: Playwright

Preconditions:

  • Backend running with test credentials available

Scenarios:

# Input Expected
a Valid credentials Redirects to /dashboard
b Invalid password Error message displayed
c Empty fields Validation errors shown

T-09: Portal Login — Member-Themed Split

Type: E2E Tool: Playwright (viewport: 1280×720)

Scenarios:

# Check Expected
a Left panel Member-specific messaging ("Willkommen zurück")
b Visual theme Different gradient than admin login (teal/emerald vs. primary green)
c Feature bullets Member-relevant: Abgabehistorie, Profil, Dokumente

T-10: Portal Login — Form Functional

Type: E2E Tool: Playwright

Scenarios:

# Input Expected
a Submit form Redirects to /portal/dashboard
b Invalid input Error message shown

T-11: Pricing — Storage Tiers Displayed

Type: E2E Tool: Playwright

Scenarios:

# Plan Expected Storage Display
a Starter card "5 GB Speicher" visible
b Pro card "50 GB Speicher" visible + overage note
c Enterprise card "Individueller Speicher" visible

T-12: Pricing — Comparison Table

Type: E2E Tool: Playwright

Scenarios:

# Check Expected
a Table exists Comparison table rendered below plan cards
b Storage row "Speicher" row shows 5 GB / 50 GB / Individuell
c Overage row "Überschreitung" row shows values per plan
d Responsive Table scrollable on mobile

T-13: Pricing — FAQ Storage Entry

Type: E2E Tool: Playwright

Scenarios:

# Check Expected
a FAQ section Contains storage question
b Click expand Answer mentions Starter upgrade + Pro overage pricing

T-14: Storage Usage Calculation

Type: Unit Class: cannamanage-service/src/test/java/de/cannamanage/service/StorageQuotaServiceTest.java Method: testGetUsage_calculatesCorrectly()

Scenarios:

# Setup Expected
a Club with 1 GB used, 5 GB limit { usedBytes: 1073741824, limitBytes: 5368709120, percentage: 20.0 }
b Club with 0 bytes used { usedBytes: 0, percentage: 0.0 }
c Club with exactly limit used { percentage: 100.0 }

T-15: Quota Allows Upload Under Limit

Type: Unit Class: StorageQuotaServiceTest Method: testCheckQuota_underLimit_noException()

Scenarios:

# Current Usage Limit Upload Size Expected
a 1 GB 5 GB 100 MB No exception
b 4.9 GB 5 GB 50 MB No exception (4.95 GB < 5 GB)
c 0 5 GB 5 GB No exception (exactly at limit)

T-16: Quota Rejects Upload Over Limit

Type: Unit Class: StorageQuotaServiceTest Method: testCheckQuota_overLimit_throwsQuotaExceeded()

Scenarios:

# Current Usage Limit Upload Size Expected
a 4.9 GB 5 GB 200 MB StorageQuotaExceededException thrown
b 5 GB 5 GB 1 byte StorageQuotaExceededException thrown
c 50 GB 50 GB 1 KB StorageQuotaExceededException thrown

T-17: Increment On Upload

Type: Unit Class: StorageQuotaServiceTest Method: testIncrementUsage_addsBytes()

Scenarios:

# Initial Increment Expected
a 0 1048576 (1 MB) 1048576
b 1000000 500000 1500000

T-18: Decrement On Delete

Type: Unit Class: StorageQuotaServiceTest Method: testDecrementUsage_subtractsBytes()

Scenarios:

# Initial Decrement Expected
a 5000000 1000000 4000000
b 1048576 1048576 0

T-19: Decrement Floors at Zero

Type: Unit Class: StorageQuotaServiceTest Method: testDecrementUsage_floorsAtZero()

Scenarios:

# Initial Decrement Expected
a 100 200 0 (not negative)
b 0 1000 0

T-20: Tier Limit Mapping

Type: Unit Class: StorageQuotaServiceTest Method: testGetLimitForTier()

Scenarios:

# Tier Expected Limit
a TRIAL 5 GB (5368709120)
b STARTER 5 GB (5368709120)
c PRO 50 GB (53687091200)
d ENTERPRISE Long.MAX_VALUE

T-21: Near-Limit Detection 80%

Type: Unit Class: StorageQuotaServiceTest Method: testIsNearLimit_at80Percent()

Scenarios:

# Usage Limit Threshold Expected
a 4.0 GB 5 GB 80% true (80%)
b 3.9 GB 5 GB 80% false (78%)
c 4.1 GB 5 GB 80% true (82%)

T-22: Near-Limit Detection 95%

Type: Unit Class: StorageQuotaServiceTest Method: testIsNearLimit_at95Percent()

Scenarios:

# Usage Limit Threshold Expected
a 4.75 GB 5 GB 95% true (95%)
b 4.7 GB 5 GB 95% false (94%)

T-23: Storage Endpoint — Authenticated

Type: Integration Class: cannamanage-api/src/test/java/de/cannamanage/api/controller/StorageControllerTest.java Method: testGetUsage_authenticated_returns200()

Preconditions:

  • Test user with ADMIN role and known clubId
  • Club has pre-set storageUsedBytes and storageLimitBytes

Scenarios:

# Auth Expected
a Valid ADMIN JWT 200 with { usedBytes, limitBytes, percentage }
b Valid STAFF JWT 200 with correct response

T-24: Storage Endpoint — Unauthenticated

Type: Integration Class: StorageControllerTest Method: testGetUsage_unauthenticated_returns401()

Scenarios:

# Auth Expected
a No token 401 Unauthorized
b Expired token 401 Unauthorized
c MEMBER role 403 Forbidden

T-25: Storage Endpoint — DTO Shape

Type: Integration Class: StorageControllerTest Method: testGetUsage_responseShape()

Scenarios:

# Check Expected
a JSON keys Response contains usedBytes, limitBytes, percentage
b Types usedBytes and limitBytes are numbers, percentage is double
c Percentage calculation Matches usedBytes / limitBytes * 100

T-26: Document Upload — Quota Check Integrated

Type: Integration Class: cannamanage-service/src/test/java/de/cannamanage/service/DocumentServiceTest.java Method: testUploadDocument_checksQuotaBeforeWrite()

Scenarios:

# Setup Expected
a Club under quota, upload 1 MB Upload succeeds, storageUsedBytes incremented by file size
b Club at quota limit Upload rejected with StorageQuotaExceededException before file write

T-27: Document Upload — 402 Response

Type: Integration Class: cannamanage-api/src/test/java/de/cannamanage/api/controller/DocumentControllerTest.java Method: testUploadDocument_quotaExceeded_returns402()

Preconditions:

  • Club with storageUsedBytes = storageLimitBytes (fully used)

Scenarios:

# Action Expected
a POST multipart upload (1 byte file) 402 Payment Required
b Response body RFC 9457 ProblemDetail with currentUsage, limit, requestedBytes

T-28: Document Delete — Usage Decremented

Type: Integration Class: DocumentServiceTest Method: testDeleteDocument_decrementsUsage()

Scenarios:

# Setup Expected
a Club with 5 MB used, delete 2 MB document storageUsedBytes = 3 MB
b Club with 1 MB used, delete 1 MB document storageUsedBytes = 0

T-29: Flyway V36 — Migration Applies

Type: Integration Tool: Spring Boot test context startup

Scenarios:

# Check Expected
a Application starts V36 migration applies without error
b Column exists SELECT storage_used_bytes FROM clubs LIMIT 1 succeeds
c Default value New clubs get storage_used_bytes = 0 and storage_limit_bytes = 5368709120

T-30: Flyway V36 — Backfill

Type: Integration Tool: SQL verification after migration

Preconditions:

  • Club exists with 3 documents (sizes: 1MB, 2MB, 3MB)

Scenarios:

# Check Expected
a After migration storage_used_bytes = 6291456 (6 MB = sum of document sizes)
b Club with no docs storage_used_bytes = 0

T-31: StorageQuotaExceededException — 402 Format

Type: Unit Class: cannamanage-api/src/test/java/de/cannamanage/api/exception/GlobalExceptionHandlerTest.java Method: testStorageQuotaExceeded_returns402WithProblemDetail()

Scenarios:

# Input Expected
a StorageQuotaExceededException(1GB, 5GB, 200MB) HTTP 402, title="Storage Quota Exceeded"
b Response properties Contains currentUsage, limit, requestedBytes numeric fields

T-32: i18n Keys Resolve

Type: Unit / Lint Tool: next-intl compile check or custom script

Scenarios:

# Namespace Expected
a marketing.home.* All 20+ keys resolve in de.json
b marketing.home.* All 20+ keys resolve in en.json (English equivalents)
c marketing.pricing.faq.storage.* question + answer keys present in both locales
d marketing.pricing.plans.*.storage Storage labels present for each plan in both locales

Test Data

Backend

  • Test club: UUID 00000000-0000-0000-0000-000000000001, storageUsedBytes = 1073741824 (1 GB), storageLimitBytes = 5368709120 (5 GB)
  • Test documents: 3 documents with fileSize = 100MB, 200MB, 773741824 bytes (total = 1 GB)
  • Full quota club: UUID 00000000-0000-0000-0000-000000000002, storageUsedBytes = storageLimitBytes = 5368709120

Frontend E2E

  • Landing page, pricing, login pages are public — no auth setup needed for T-01 through T-13
  • Login form tests (T-08, T-10) require running backend with test user admin@gruener-daumen.de / TestAdmin123!

Test Coverage

Component Unit Integration E2E Total
Landing page 0 0 5 5
Login redesign 0 0 5 5
Pricing update 0 0 3 3
StorageQuotaService 9 0 0 9
StorageController 0 3 0 3
DocumentService (quota) 0 2 0 2
DocumentController (402) 0 1 0 1
Flyway migration 0 2 0 2
Exception handling 1 0 0 1
i18n verification 1 0 0 1
Total 11 8 13 32