dad798a904
Deploy to TrueNAS / deploy (push) Failing after 33s
- 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
124 lines
7.2 KiB
Markdown
124 lines
7.2 KiB
Markdown
# Analysis: Sprint 14 — Marketing & Monetization
|
|
|
|
**Date:** 2026-06-18
|
|
**Author:** Patrick Plate / Lumen (Planner)
|
|
**Status:** v1
|
|
**Sprint Theme:** Marketing & Monetization
|
|
|
|
---
|
|
|
|
## 1. Problem Analysis
|
|
|
|
CannaManage is production-ready after Sprint 13's hardening. However, the public-facing marketing surfaces are minimal — there is no landing page (the root `/` currently serves the pricing page directly via the marketing layout), the login pages use a basic centered-card layout that doesn't communicate product value, and the pricing page lacks storage quota information which is a core monetization lever.
|
|
|
|
Additionally, the backend has no concept of storage quotas per tenant. Documents can be uploaded without limit, creating an unbounded cost liability on the file storage (TrueNAS/disk). Sprint 14 introduces a **StorageQuotaService** that enforces per-plan limits, making the pricing tiers meaningful at the infrastructure level.
|
|
|
|
### Sprint Goals
|
|
|
|
1. **Landing Page** — Create a professional homepage that converts visitors to signups
|
|
2. **Login Redesign** — Split-layout login pages that reinforce brand value during auth flow
|
|
3. **Pricing Rework** — Add storage tier information, update pricing model
|
|
4. **Storage Quota Backend** — Enforce plan-based storage limits on document uploads
|
|
|
|
---
|
|
|
|
## 2. Affected Components
|
|
|
|
| Component | Path | Role |
|
|
|-----------|------|------|
|
|
| Marketing layout | `cannamanage-frontend/src/app/(marketing)/layout.tsx` | Shared header/footer for marketing pages |
|
|
| Homepage (NEW) | `cannamanage-frontend/src/app/(marketing)/page.tsx` | Landing page — hero, features, trust signals |
|
|
| Pricing page | `cannamanage-frontend/src/app/(marketing)/pricing/page.tsx` | Pricing cards with storage tiers |
|
|
| Auth layout | `cannamanage-frontend/src/app/(auth)/layout.tsx` | Centered flex container for login |
|
|
| Admin login | `cannamanage-frontend/src/app/(auth)/login/page.tsx` | Admin/staff login form |
|
|
| Portal login | `cannamanage-frontend/src/app/(portal)/portal-login/page.tsx` | Member portal login form |
|
|
| PlanTier enum | `cannamanage-domain/src/main/java/de/cannamanage/domain/enums/PlanTier.java` | TRIAL, STARTER, PRO, ENTERPRISE |
|
|
| Club entity | `cannamanage-domain/src/main/java/de/cannamanage/domain/entity/Club.java` | Needs `storageUsedBytes` field |
|
|
| Document entity | `cannamanage-domain/src/main/java/de/cannamanage/domain/entity/Document.java` | Has `fileSize` field — source of truth for usage |
|
|
| DocumentService | `cannamanage-service/src/main/java/de/cannamanage/service/DocumentService.java` | Upload logic — needs quota check |
|
|
| StorageQuotaService (NEW) | `cannamanage-service/src/main/java/de/cannamanage/service/StorageQuotaService.java` | Quota calculation and enforcement |
|
|
| StorageController (NEW) | `cannamanage-api/src/main/java/de/cannamanage/api/controller/StorageController.java` | REST endpoint for storage usage |
|
|
| Flyway V36 (NEW) | `cannamanage-api/src/main/resources/db/migration/V36__storage_quota.sql` | Add storage tracking column |
|
|
| i18n messages | `cannamanage-frontend/src/messages/de.json` | New keys for landing page, pricing storage |
|
|
| Documents frontend service | `cannamanage-frontend/src/services/documents.ts` | Needs quota-exceeded error handling |
|
|
|
|
---
|
|
|
|
## 3. Current State (Ist-Zustand)
|
|
|
|
### Marketing Pages
|
|
|
|
- **No landing page** exists at `(marketing)/page.tsx` — the root `/` route likely falls through or shows a 404
|
|
- **Pricing page** has 3 tiers (Starter €19, Pro €49, Enterprise) with member limits and feature lists, but **no storage information**
|
|
- **Marketing layout** has a sticky header with logo + "Preise" + "Anmelden" links, and a footer with Produkt/Rechtliches columns
|
|
- Navigation text is hardcoded German (not i18n) in the layout
|
|
|
|
### Login Pages
|
|
|
|
- **Auth layout** is a minimal centered flex container: `fixed inset-0 z-50 flex items-center justify-center`
|
|
- **Admin login** renders a centered card with logo, email/password form, forgot password link, and portal link
|
|
- **Portal login** is nearly identical but uses portal-specific translations and mock auth
|
|
- Both pages use the same visual pattern — no split-layout, no brand messaging during auth
|
|
|
|
### Storage Backend
|
|
|
|
- **Document entity** already tracks `fileSize` (Long) per file
|
|
- **PlanTier enum** exists: TRIAL, STARTER, PRO, ENTERPRISE
|
|
- **No storage quota concept** exists anywhere — no `storage_used_bytes` column, no quota checks on upload
|
|
- **DocumentService** handles upload/download/delete but never checks cumulative storage
|
|
- Latest Flyway migration: `V35__generated_reports_add_timestamps.sql`
|
|
|
|
---
|
|
|
|
## 4. Risk Assessment
|
|
|
|
| Risk | Probability | Impact | Mitigation |
|
|
|------|-------------|--------|------------|
|
|
| Landing page doesn't convert (poor copy/design) | Medium | Medium (lost signups) | Follow proven SaaS landing page patterns; iterate based on analytics |
|
|
| Storage quota breaks existing uploads | Low | High (data loss) | Implement as soft-limit first — warn but don't block for existing over-limit tenants |
|
|
| i18n key explosion | Low | Low (maintenance) | Group new keys under `marketing.home`, `marketing.pricing.storage` namespaces |
|
|
| Split login layout breaks on mobile | Medium | Medium (can't log in) | Mobile-first design: left panel hidden on `<md` breakpoints |
|
|
| Quota calculation performance (SUM query) | Low | Medium (slow uploads) | Cache quota in `storage_used_bytes` column; recalculate on upload/delete |
|
|
|
|
---
|
|
|
|
## 5. Solution Options
|
|
|
|
### Option A: Full Sprint — All 4 Areas (Recommended)
|
|
|
|
- Landing page, login redesign, pricing update, storage quota backend
|
|
- **Effort:** ~16-20 hours
|
|
- **Pros:** Complete marketing+monetization story, enables public launch
|
|
- **Cons:** Larger scope, more testing surface
|
|
|
|
### Option B: Frontend Only — Landing + Login + Pricing (No Backend)
|
|
|
|
- Skip StorageQuotaService, just update frontend
|
|
- **Effort:** ~8-10 hours
|
|
- **Pros:** Faster delivery, lower risk
|
|
- **Cons:** Storage limits are marketing fiction without enforcement
|
|
|
|
### Option C: Backend Only — Storage Quota (No Marketing)
|
|
|
|
- Implement quota enforcement, defer marketing pages
|
|
- **Effort:** ~6-8 hours
|
|
- **Pros:** Real monetization enforcement
|
|
- **Cons:** No user-facing marketing value, can't launch publicly
|
|
|
|
---
|
|
|
|
## 6. Recommendation
|
|
|
|
**Option A** — the full sprint. The four areas are interdependent: the pricing page promises storage limits that the backend must enforce, and the landing page is the entry point that drives users to pricing. Login redesign is a low-risk polish pass that significantly improves first impressions.
|
|
|
|
The storage quota backend should be designed as an **incremental counter** (update `storage_used_bytes` on upload/delete) rather than a `SUM` query on every upload — this keeps upload latency constant regardless of document count.
|
|
|
|
---
|
|
|
|
## 7. Open Questions
|
|
|
|
- [ ] Should the landing page include a product screenshot/mockup, or is an illustration-based hero preferred?
|
|
- [ ] For portal login left panel: show rotating testimonials, or static feature highlights?
|
|
- [ ] Storage overage billing (€0.15/GB/mo for Pro) — is this just displayed in pricing, or should we build the actual billing integration now?
|
|
- [ ] Free trial — is TRIAL tier (PlanTier enum already has it) time-limited? Should landing page mention trial duration?
|