package models import ( "time" "github.com/google/uuid" ) // SubscriptionStatus represents the status of a subscription type SubscriptionStatus string const ( StatusTrialing SubscriptionStatus = "trialing" StatusActive SubscriptionStatus = "active" StatusPastDue SubscriptionStatus = "past_due" StatusCanceled SubscriptionStatus = "canceled" StatusExpired SubscriptionStatus = "expired" ) // PlanID represents the available plan IDs type PlanID string const ( PlanBasic PlanID = "basic" PlanStandard PlanID = "standard" PlanPremium PlanID = "premium" ) // TaskType represents the type of task type TaskType string const ( TaskTypeCorrection TaskType = "correction" TaskTypeLetter TaskType = "letter" TaskTypeMeeting TaskType = "meeting" TaskTypeBatch TaskType = "batch" TaskTypeOther TaskType = "other" ) // CarryoverMonthsCap is the maximum number of months tasks can accumulate const CarryoverMonthsCap = 5 // Subscription represents a user's subscription type Subscription struct { ID uuid.UUID `json:"id"` UserID uuid.UUID `json:"user_id"` StripeCustomerID string `json:"stripe_customer_id"` StripeSubscriptionID string `json:"stripe_subscription_id"` PlanID PlanID `json:"plan_id"` Status SubscriptionStatus `json:"status"` TrialEnd *time.Time `json:"trial_end,omitempty"` CurrentPeriodEnd *time.Time `json:"current_period_end,omitempty"` CancelAtPeriodEnd bool `json:"cancel_at_period_end"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // BillingPlan represents a billing plan with its features and limits type BillingPlan struct { ID PlanID `json:"id"` StripePriceID string `json:"stripe_price_id"` Name string `json:"name"` Description string `json:"description"` PriceCents int `json:"price_cents"` // Price in cents (990 = 9.90 EUR) Currency string `json:"currency"` Interval string `json:"interval"` // "month" or "year" Features PlanFeatures `json:"features"` IsActive bool `json:"is_active"` SortOrder int `json:"sort_order"` } // PlanFeatures represents the features and limits of a plan type PlanFeatures struct { // Task-based limits (primary billing unit) MonthlyTaskAllowance int `json:"monthly_task_allowance"` // Tasks per month MaxTaskBalance int `json:"max_task_balance"` // Max accumulated tasks (allowance * CarryoverMonthsCap) // Legacy fields for backward compatibility (deprecated, use task-based limits) AIRequestsLimit int `json:"ai_requests_limit,omitempty"` DocumentsLimit int `json:"documents_limit,omitempty"` // Feature flags FeatureFlags []string `json:"feature_flags"` MaxTeamMembers int `json:"max_team_members,omitempty"` PrioritySupport bool `json:"priority_support"` CustomBranding bool `json:"custom_branding"` BatchProcessing bool `json:"batch_processing"` CustomTemplates bool `json:"custom_templates"` // Premium: Fair Use (no visible limit) FairUseMode bool `json:"fair_use_mode"` } // Task represents a single task that consumes 1 unit from the balance type Task struct { ID uuid.UUID `json:"id"` AccountID uuid.UUID `json:"account_id"` TaskType TaskType `json:"task_type"` CreatedAt time.Time `json:"created_at"` Consumed bool `json:"consumed"` // Always true when created // Internal metrics (not shown to user) PageCount int `json:"-"` TokenCount int `json:"-"` ProcessTime int `json:"-"` // in seconds } // AccountUsage represents the task-based usage for an account type AccountUsage struct { ID uuid.UUID `json:"id"` AccountID uuid.UUID `json:"account_id"` PlanID PlanID `json:"plan"` MonthlyTaskAllowance int `json:"monthly_task_allowance"` CarryoverMonthsCap int `json:"carryover_months_cap"` // Always 5 MaxTaskBalance int `json:"max_task_balance"` // allowance * cap TaskBalance int `json:"task_balance"` // Current available tasks LastRenewalAt time.Time `json:"last_renewal_at"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // UsageSummary tracks usage for a specific period (internal metrics) type UsageSummary struct { ID uuid.UUID `json:"id"` UserID uuid.UUID `json:"user_id"` UsageType string `json:"usage_type"` // "task", "page", "token" PeriodStart time.Time `json:"period_start"` TotalCount int `json:"total_count"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // UserEntitlements represents cached entitlements for a user type UserEntitlements struct { ID uuid.UUID `json:"id"` UserID uuid.UUID `json:"user_id"` PlanID PlanID `json:"plan_id"` TaskBalance int `json:"task_balance"` MaxBalance int `json:"max_balance"` Features PlanFeatures `json:"features"` UpdatedAt time.Time `json:"updated_at"` // Legacy fields for backward compatibility with old entitlement service AIRequestsLimit int `json:"ai_requests_limit"` AIRequestsUsed int `json:"ai_requests_used"` DocumentsLimit int `json:"documents_limit"` DocumentsUsed int `json:"documents_used"` } // StripeWebhookEvent tracks processed webhook events for idempotency type StripeWebhookEvent struct { StripeEventID string `json:"stripe_event_id"` EventType string `json:"event_type"` Processed bool `json:"processed"` ProcessedAt time.Time `json:"processed_at"` CreatedAt time.Time `json:"created_at"` } // BillingStatusResponse is the response for the billing status endpoint type BillingStatusResponse struct { HasSubscription bool `json:"has_subscription"` Subscription *SubscriptionInfo `json:"subscription,omitempty"` TaskUsage *TaskUsageInfo `json:"task_usage,omitempty"` Entitlements *EntitlementInfo `json:"entitlements,omitempty"` AvailablePlans []BillingPlan `json:"available_plans,omitempty"` } // SubscriptionInfo contains subscription details for the response type SubscriptionInfo struct { PlanID PlanID `json:"plan_id"` PlanName string `json:"plan_name"` Status SubscriptionStatus `json:"status"` IsTrialing bool `json:"is_trialing"` TrialDaysLeft int `json:"trial_days_left,omitempty"` CurrentPeriodEnd *time.Time `json:"current_period_end,omitempty"` CancelAtPeriodEnd bool `json:"cancel_at_period_end"` PriceCents int `json:"price_cents"` Currency string `json:"currency"` } // TaskUsageInfo contains current task usage information // This is the ONLY usage info shown to users type TaskUsageInfo struct { TasksAvailable int `json:"tasks_available"` // Current balance MaxTasks int `json:"max_tasks"` // Max possible balance InfoText string `json:"info_text"` // "Aufgaben verfuegbar: X von max. Y" TooltipText string `json:"tooltip_text"` // "Aufgaben koennen sich bis zu 5 Monate ansammeln." } // EntitlementInfo contains feature entitlements type EntitlementInfo struct { Features []string `json:"features"` MaxTeamMembers int `json:"max_team_members,omitempty"` PrioritySupport bool `json:"priority_support"` CustomBranding bool `json:"custom_branding"` BatchProcessing bool `json:"batch_processing"` CustomTemplates bool `json:"custom_templates"` FairUseMode bool `json:"fair_use_mode"` // Premium only } // StartTrialRequest is the request to start a trial type StartTrialRequest struct { PlanID PlanID `json:"plan_id" binding:"required"` } // StartTrialResponse is the response after starting a trial type StartTrialResponse struct { CheckoutURL string `json:"checkout_url"` SessionID string `json:"session_id"` } // ChangePlanRequest is the request to change plans type ChangePlanRequest struct { NewPlanID PlanID `json:"new_plan_id" binding:"required"` } // ChangePlanResponse is the response after changing plans type ChangePlanResponse struct { Success bool `json:"success"` Message string `json:"message"` EffectiveDate string `json:"effective_date,omitempty"` } // CancelSubscriptionResponse is the response after canceling type CancelSubscriptionResponse struct { Success bool `json:"success"` Message string `json:"message"` CancelDate string `json:"cancel_date"` ActiveUntil string `json:"active_until"` } // CustomerPortalResponse contains the portal URL type CustomerPortalResponse struct { PortalURL string `json:"portal_url"` } // ConsumeTaskRequest is the request to consume a task (internal) type ConsumeTaskRequest struct { UserID string `json:"user_id" binding:"required"` TaskType TaskType `json:"task_type" binding:"required"` } // ConsumeTaskResponse is the response after consuming a task type ConsumeTaskResponse struct { Success bool `json:"success"` TaskID string `json:"task_id,omitempty"` TasksRemaining int `json:"tasks_remaining"` Message string `json:"message,omitempty"` } // CheckTaskAllowedResponse is the response for task limit checks type CheckTaskAllowedResponse struct { Allowed bool `json:"allowed"` TasksAvailable int `json:"tasks_available"` MaxTasks int `json:"max_tasks"` PlanID PlanID `json:"plan_id"` Message string `json:"message,omitempty"` } // EntitlementCheckResponse is the response for entitlement checks (internal) type EntitlementCheckResponse struct { HasEntitlement bool `json:"has_entitlement"` PlanID PlanID `json:"plan_id,omitempty"` Message string `json:"message,omitempty"` } // TaskLimitError represents the error when task limit is reached type TaskLimitError struct { Error string `json:"error"` CurrentBalance int `json:"current_balance"` Plan PlanID `json:"plan"` } // UsageInfo represents current usage information (legacy, prefer TaskUsageInfo) type UsageInfo struct { AIRequestsUsed int `json:"ai_requests_used"` AIRequestsLimit int `json:"ai_requests_limit"` AIRequestsPercent float64 `json:"ai_requests_percent"` DocumentsUsed int `json:"documents_used"` DocumentsLimit int `json:"documents_limit"` DocumentsPercent float64 `json:"documents_percent"` PeriodStart string `json:"period_start"` PeriodEnd string `json:"period_end"` } // CheckUsageResponse is the response for legacy usage checks type CheckUsageResponse struct { Allowed bool `json:"allowed"` CurrentUsage int `json:"current_usage"` Limit int `json:"limit"` Remaining int `json:"remaining"` Message string `json:"message,omitempty"` } // TrackUsageRequest is the request to track usage (internal) type TrackUsageRequest struct { UserID string `json:"user_id" binding:"required"` UsageType string `json:"usage_type" binding:"required"` Quantity int `json:"quantity"` } // GetDefaultPlans returns the default billing plans with task-based limits func GetDefaultPlans() []BillingPlan { return []BillingPlan{ { ID: PlanBasic, Name: "Basic", Description: "Perfekt fuer den Einstieg - Gelegentliche Nutzung", PriceCents: 990, // 9.90 EUR Currency: "eur", Interval: "month", Features: PlanFeatures{ MonthlyTaskAllowance: 30, // 30 tasks/month MaxTaskBalance: 30 * CarryoverMonthsCap, // 150 max FeatureFlags: []string{"basic_ai", "basic_documents"}, MaxTeamMembers: 1, PrioritySupport: false, CustomBranding: false, BatchProcessing: false, CustomTemplates: false, FairUseMode: false, }, IsActive: true, SortOrder: 1, }, { ID: PlanStandard, Name: "Standard", Description: "Fuer regelmaessige Nutzer - Mehrere Klassen und regelmaessige Korrekturen", PriceCents: 1990, // 19.90 EUR Currency: "eur", Interval: "month", Features: PlanFeatures{ MonthlyTaskAllowance: 100, // 100 tasks/month MaxTaskBalance: 100 * CarryoverMonthsCap, // 500 max FeatureFlags: []string{"basic_ai", "basic_documents", "templates", "batch_processing"}, MaxTeamMembers: 3, PrioritySupport: false, CustomBranding: false, BatchProcessing: true, CustomTemplates: true, FairUseMode: false, }, IsActive: true, SortOrder: 2, }, { ID: PlanPremium, Name: "Premium", Description: "Sorglos-Tarif - Vielnutzer, Teams, schulischer Kontext", PriceCents: 3990, // 39.90 EUR Currency: "eur", Interval: "month", Features: PlanFeatures{ MonthlyTaskAllowance: 1000, // Very high (Fair Use) MaxTaskBalance: 1000 * CarryoverMonthsCap, // 5000 max (not shown to user) FeatureFlags: []string{"basic_ai", "basic_documents", "templates", "batch_processing", "team_features", "admin_panel", "audit_log", "api_access"}, MaxTeamMembers: 10, PrioritySupport: true, CustomBranding: true, BatchProcessing: true, CustomTemplates: true, FairUseMode: true, // No visible limit }, IsActive: true, SortOrder: 3, }, } } // CalculateMaxTaskBalance calculates max task balance from monthly allowance func CalculateMaxTaskBalance(monthlyAllowance int) int { return monthlyAllowance * CarryoverMonthsCap }