diff --git a/apps/api-server/internal/handlers/analytics_handlers.go b/apps/api-server/internal/handlers/analytics_handlers.go new file mode 100644 index 0000000..b34419d --- /dev/null +++ b/apps/api-server/internal/handlers/analytics_handlers.go @@ -0,0 +1,169 @@ +package handlers + +import ( + "net/http" + "strconv" + "time" + + "github.com/gin-gonic/gin" +) + +// AnalyticsHandler handles analytics-related HTTP requests +type AnalyticsHandler struct{} + +// NewAnalyticsHandler creates a new analytics handler +func NewAnalyticsHandler() *AnalyticsHandler { + return &AnalyticsHandler{} +} + +// ChurnPrediction represents a churn prediction response +type ChurnPrediction struct { + ProfileID string `json:"profile_id"` + RiskLevel string `json:"risk_level"` + RiskScore float64 `json:"risk_score"` + PredictedChurnDate string `json:"predicted_churn_date,omitempty"` + Reasons []string `json:"reasons"` + Recommendations []string `json:"recommendations"` + LastUpdated time.Time `json:"last_updated"` +} + +// ChurnMetrics represents churn metrics +type ChurnMetrics struct { + Period string `json:"period"` + TotalSubscribers int64 `json:"total_subscribers"` + ChurnedSubscribers int64 `json:"churned_subscribers"` + ChurnRate float64 `json:"churn_rate_pct"` + MonthlyChurnRate float64 `json:"monthly_churn_rate_pct"` + AnnualChurnRate float64 `json:"annual_churn_rate_pct"` + AverageTenureDays float64 `json:"average_tenure_days"` + RiskDistribution map[string]int64 `json:"risk_distribution"` + GeneratedAt time.Time `json:"generated_at"` +} + +// PredictChurn predicts churn for a profile +func (h *AnalyticsHandler) PredictChurn(c *gin.Context) { + var req struct { + ProfileID string `json:"profile_id" binding:"required"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // Simulated churn prediction + prediction := ChurnPrediction{ + ProfileID: req.ProfileID, + RiskLevel: "medium", + RiskScore: 45.5, + PredictedChurnDate: time.Now().AddDate(0, 2, 0).Format("2006-01-02"), + Reasons: []string{ + "Decreased usage over last 30 days", + "No recent plan upgrades", + "Support tickets increased", + }, + Recommendations: []string{ + "Offer loyalty discount", + "Proactive customer outreach", + "Personalized plan recommendation", + }, + LastUpdated: time.Now(), + } + + c.JSON(http.StatusOK, prediction) +} + +// GetAtRiskCustomers returns customers at risk of churning +func (h *AnalyticsHandler) GetAtRiskCustomers(c *gin.Context) { + riskLevel := c.DefaultQuery("risk_level", "high") + limitStr := c.DefaultQuery("limit", "100") + limit, _ := strconv.Atoi(limitStr) + if limit > 1000 { + limit = 1000 + } + + // Simulated at-risk customers + customers := make([]ChurnPrediction, 0) + for i := 0; i < min(limit, 10); i++ { + customers = append(customers, ChurnPrediction{ + ProfileID: "profile-" + strconv.Itoa(i+1), + RiskLevel: riskLevel, + RiskScore: 70.0 + float64(i)*2, + PredictedChurnDate: time.Now().AddDate(0, 0, 30+i*7).Format("2006-01-02"), + Reasons: []string{"Low engagement", "Billing issues"}, + Recommendations: []string{"Retention offer", "Account review"}, + LastUpdated: time.Now(), + }) + } + + c.JSON(http.StatusOK, customers) +} + +// MarketMetrics represents market analytics +type MarketMetrics struct { + Period string `json:"period"` + TotalMarketSize int64 `json:"total_market_size"` + OurSubscribers int64 `json:"our_subscribers"` + MarketShare float64 `json:"market_share_pct"` + GrowthRate float64 `json:"growth_rate_pct"` + ByCountry map[string]any `json:"by_country"` + GeneratedAt time.Time `json:"generated_at"` +} + +// GetMarketMetrics returns market penetration metrics +func (h *AnalyticsHandler) GetMarketMetrics(c *gin.Context) { + period := c.DefaultQuery("period", "monthly") + + metrics := MarketMetrics{ + Period: period, + TotalMarketSize: 5500000000, // Global mobile subscribers ~5.5B + OurSubscribers: 150000, + MarketShare: 0.0027, + GrowthRate: 12.5, + ByCountry: map[string]any{ + "US": map[string]any{ + "market_size": 330000000, + "our_subs": 45000, + "penetration": 0.014, + "growth_rate": 8.5, + }, + "UK": map[string]any{ + "market_size": 67000000, + "our_subs": 25000, + "penetration": 0.037, + "growth_rate": 15.2, + }, + "DE": map[string]any{ + "market_size": 83000000, + "our_subs": 30000, + "penetration": 0.036, + "growth_rate": 11.8, + }, + }, + GeneratedAt: time.Now(), + } + + c.JSON(http.StatusOK, metrics) +} + +// MaintenanceMetrics represents predictive maintenance metrics +type MaintenanceMetrics struct { + Period string `json:"period"` + TotalAssets int64 `json:"total_assets"` + HealthyAssets int64 `json:"healthy_assets"` + AssetsNeedingAttention int64 `json:"assets_needing_attention"` + Uptime float64 `json:"uptime_pct"` + MeanTimeToFailure float64 `json:"mean_time_to_failure_hours"` + MeanTimeToRepair float64 `json:"mean_time_to_repair_hours"` + GeneratedAt time.Time `json:"generated_at"` +} + +// PricingMetrics represents pricing optimization metrics +type PricingMetrics struct { + Period string `json:"period"` + TotalRevenue float64 `json:"total_revenue"` + ARPU float64 `json:"arpu"` + PriceElasticity float64 `json:"price_elasticity"` + CompetitiveIndex float64 `json:"competitive_index"` + OptimizationROI float64 `json:"optimization_roi_pct"` + GeneratedAt time.Time `json:"generated_at"` +}