feat: Sprint 14 — Marketing & Monetization
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
This commit is contained in:
Patrick Plate
2026-06-18 20:27:54 +02:00
parent 52d23053e7
commit dad798a904
24 changed files with 2485 additions and 212 deletions
@@ -51,6 +51,12 @@ public class Club extends AbstractTenantEntity {
@Column(name = "allowed_email_pattern", length = 255)
private String allowedEmailPattern;
@Column(name = "storage_used_bytes", nullable = false)
private Long storageUsedBytes = 0L;
@Column(name = "storage_limit_bytes", nullable = false)
private Long storageLimitBytes = 5_368_709_120L; // 5 GB default
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 50)
private ClubStatus status = ClubStatus.ACTIVE;
@@ -99,4 +105,10 @@ public class Club extends AbstractTenantEntity {
public ClubStatus getStatus() { return status; }
public void setStatus(ClubStatus status) { this.status = status; }
public Long getStorageUsedBytes() { return storageUsedBytes; }
public void setStorageUsedBytes(Long storageUsedBytes) { this.storageUsedBytes = storageUsedBytes; }
public Long getStorageLimitBytes() { return storageLimitBytes; }
public void setStorageLimitBytes(Long storageLimitBytes) { this.storageLimitBytes = storageLimitBytes; }
}