Revert "New features (#67)"

This reverts commit 88909d0627.
This commit is contained in:
Nutcase
2026-05-03 13:44:09 +03:00
committed by GitHub
parent 104fff31ac
commit 261b44e172
123 changed files with 569 additions and 16694 deletions
-69
View File
@@ -5,7 +5,6 @@ import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/nutcas3/telecom-platform/apps/api-server/internal/handlers"
"github.com/nutcas3/telecom-platform/apps/api-server/internal/middleware"
"github.com/nutcas3/telecom-platform/apps/api-server/internal/rbac"
)
@@ -74,9 +73,6 @@ func registerV1Routes(router *gin.Engine, d *serverDeps) {
registerBillingRoutes(apiProtected, d)
registerConfigRoutes(apiProtected, d)
registerChaosRoutes(apiProtected, d)
registerAnalyticsRoutes(apiProtected)
registerSecurityRoutes(apiProtected)
registerCurrencyRoutes(apiProtected)
}
}
@@ -199,68 +195,3 @@ func registerSubscriberRoutes(api *gin.RouterGroup, d *serverDeps) {
w.POST("/:id/suspend", d.subscriberH.SuspendSubscriber)
w.POST("/:id/terminate", d.subscriberH.TerminateSubscriber)
}
func registerAnalyticsRoutes(api *gin.RouterGroup) {
h := handlers.NewAnalyticsHandler()
analytics := api.Group("/analytics")
// Churn Analysis
churn := analytics.Group("/churn")
churn.POST("/predict", h.PredictChurn)
churn.GET("/metrics", h.GetChurnMetrics)
churn.GET("/at-risk", h.GetAtRiskCustomers)
// Market Analytics
market := analytics.Group("/market")
market.GET("/metrics", h.GetMarketMetrics)
market.GET("/competitors", h.GetCompetitors)
market.GET("/opportunities", h.GetMarketOpportunities)
// Predictive Maintenance
maintenance := analytics.Group("/maintenance")
maintenance.GET("/metrics", h.GetMaintenanceMetrics)
maintenance.GET("/assets", h.GetAssetsHealth)
maintenance.GET("/alerts", h.GetMaintenanceAlerts)
maintenance.POST("/predict/:asset_id", h.PredictFailure)
// Pricing Optimization
pricing := analytics.Group("/pricing")
pricing.GET("/metrics", h.GetPricingMetrics)
pricing.POST("/optimize", h.OptimizePricing)
pricing.GET("/elasticity", h.GetPriceElasticity)
}
func registerSecurityRoutes(api *gin.RouterGroup) {
h := handlers.NewSecurityHandler()
security := api.Group("/security")
// Fraud Detection
fraud := security.Group("/fraud")
fraud.POST("/analyze", h.AnalyzeTransaction)
fraud.POST("/alerts", h.GetFraudAlerts)
fraud.PUT("/alerts/:id", h.UpdateAlertStatus)
fraud.GET("/metrics", h.GetFraudMetrics)
fraud.GET("/patterns", h.GetFraudPatterns)
// SIM Swap Protection
simswap := security.Group("/simswap")
simswap.POST("/verify", h.VerifySIMSwap)
simswap.GET("/history/:profile_id", h.GetSIMSwapHistory)
}
func registerCurrencyRoutes(api *gin.RouterGroup) {
h := handlers.NewCurrencyHandler()
currencyGroup := api.Group("/currency")
currencyGroup.POST("/convert", h.ConvertCurrency)
currencyGroup.GET("/exchange/:from/:to", h.GetExchangeRate)
currencyGroup.GET("/exchange/:from/:to/history", h.GetExchangeRateHistory)
currencyGroup.GET("/currencies", h.GetSupportedCurrencies)
currencyGroup.POST("/exchange/refresh", h.RefreshExchangeRates)
currencyGroup.POST("/billing", h.ProcessBilling)
currencyGroup.GET("/billing/history/:profile_id", h.GetBillingHistory)
currencyGroup.GET("/billing/summary/:profile_id", h.GetBillingSummary)
currencyGroup.POST("/billing/refund/:transaction_id", h.ProcessRefund)
currencyGroup.GET("/billing/analytics", h.GetBillingAnalytics)
}
@@ -1,169 +0,0 @@
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"`
}
@@ -1,260 +0,0 @@
package handlers
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func (h *AnalyticsHandler) GetChurnMetrics(c *gin.Context) {
period := c.DefaultQuery("period", "monthly")
metrics := ChurnMetrics{
Period: period,
TotalSubscribers: 150000,
ChurnedSubscribers: 2250,
ChurnRate: 1.5,
MonthlyChurnRate: 1.5,
AnnualChurnRate: 18.0,
AverageTenureDays: 425,
RiskDistribution: map[string]int64{
"low": 120000,
"medium": 22500,
"high": 6000,
"critical": 1500,
},
GeneratedAt: time.Now(),
}
c.JSON(http.StatusOK, metrics)
}
// GetCompetitors returns competitor analysis
func (h *AnalyticsHandler) GetCompetitors(c *gin.Context) {
competitors := []map[string]any{
{
"name": "AT&T",
"market_share": 35.5,
"subscribers": 200000000,
"strengths": []string{"Network coverage", "Brand recognition", "Enterprise focus"},
"weaknesses": []string{"High prices", "Customer service"},
"threat_level": "high",
},
{
"name": "Verizon",
"market_share": 32.0,
"subscribers": 180000000,
"strengths": []string{"Network quality", "5G leadership"},
"weaknesses": []string{"Limited international", "Premium pricing"},
"threat_level": "high",
},
{
"name": "T-Mobile",
"market_share": 21.3,
"subscribers": 120000000,
"strengths": []string{"Competitive pricing", "Innovation", "Customer experience"},
"weaknesses": []string{"Rural coverage"},
"threat_level": "medium",
},
}
c.JSON(http.StatusOK, gin.H{"competitors": competitors})
}
// GetMarketOpportunities returns market opportunities
func (h *AnalyticsHandler) GetMarketOpportunities(c *gin.Context) {
opportunities := []map[string]any{
{
"id": "opp-1",
"type": "5G Migration",
"country": "US",
"potential_subs": 50000000,
"required_investment": 1000000000,
"expected_roi": 25.0,
"time_to_market": 24,
"confidence": 85.0,
},
{
"id": "opp-2",
"type": "IoT Services",
"country": "UK",
"potential_subs": 20000000,
"required_investment": 500000000,
"expected_roi": 30.0,
"time_to_market": 18,
"confidence": 78.0,
},
{
"id": "opp-3",
"type": "Enterprise 5G",
"country": "DE",
"potential_subs": 15000000,
"required_investment": 750000000,
"expected_roi": 20.0,
"time_to_market": 30,
"confidence": 72.0,
},
}
c.JSON(http.StatusOK, gin.H{"opportunities": opportunities})
}
// GetMaintenanceMetrics returns predictive maintenance metrics
func (h *AnalyticsHandler) GetMaintenanceMetrics(c *gin.Context) {
period := c.DefaultQuery("period", "monthly")
metrics := MaintenanceMetrics{
Period: period,
TotalAssets: 1250,
HealthyAssets: 1180,
AssetsNeedingAttention: 70,
Uptime: 99.95,
MeanTimeToFailure: 8760, // 1 year
MeanTimeToRepair: 4, // 4 hours
GeneratedAt: time.Now(),
}
c.JSON(http.StatusOK, metrics)
}
// GetAssetsHealth returns assets health status
func (h *AnalyticsHandler) GetAssetsHealth(c *gin.Context) {
assets := []map[string]any{
{"id": "server-1", "name": "Web Server 1", "type": "server", "health_score": 85.0, "status": "healthy"},
{"id": "server-2", "name": "Web Server 2", "type": "server", "health_score": 92.0, "status": "healthy"},
{"id": "db-1", "name": "Primary Database", "type": "database", "health_score": 78.0, "status": "warning"},
{"id": "db-2", "name": "Replica Database", "type": "database", "health_score": 95.0, "status": "healthy"},
{"id": "net-1", "name": "Core Switch", "type": "network", "health_score": 88.0, "status": "healthy"},
}
c.JSON(http.StatusOK, gin.H{"assets": assets})
}
// GetMaintenanceAlerts returns maintenance alerts
func (h *AnalyticsHandler) GetMaintenanceAlerts(c *gin.Context) {
alerts := []map[string]any{
{
"id": "alert-1",
"asset_id": "db-1",
"type": "predictive",
"severity": "medium",
"title": "Database disk space warning",
"description": "Disk usage at 78%, predicted to reach 90% in 14 days",
"timestamp": time.Now().Add(-2 * time.Hour),
},
{
"id": "alert-2",
"asset_id": "server-3",
"type": "preventive",
"severity": "low",
"title": "Scheduled maintenance due",
"description": "Server maintenance overdue by 7 days",
"timestamp": time.Now().Add(-24 * time.Hour),
},
}
c.JSON(http.StatusOK, gin.H{"alerts": alerts})
}
// PredictFailure predicts failure for an asset
func (h *AnalyticsHandler) PredictFailure(c *gin.Context) {
assetID := c.Param("asset_id")
prediction := map[string]any{
"asset_id": assetID,
"failure_probability": 0.15,
"predicted_failure": time.Now().AddDate(0, 3, 0).Format("2006-01-02"),
"confidence": 82.5,
"risk_factors": []string{
"Age approaching end of lifecycle",
"Increased error rate",
"Temperature fluctuations",
},
"recommendations": []string{
"Schedule preventive maintenance",
"Monitor closely",
"Prepare replacement parts",
},
}
c.JSON(http.StatusOK, prediction)
}
// GetPricingMetrics returns pricing optimization metrics
func (h *AnalyticsHandler) GetPricingMetrics(c *gin.Context) {
period := c.DefaultQuery("period", "monthly")
metrics := PricingMetrics{
Period: period,
TotalRevenue: 4500000,
ARPU: 30.0,
PriceElasticity: -1.2,
CompetitiveIndex: 75.0,
OptimizationROI: 15.5,
GeneratedAt: time.Now(),
}
c.JSON(http.StatusOK, metrics)
}
// OptimizePricing optimizes pricing for rate plans
func (h *AnalyticsHandler) OptimizePricing(c *gin.Context) {
var req struct {
RatePlanIDs []string `json:"rate_plan_ids"`
Strategy string `json:"strategy"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
results := make([]map[string]any, 0)
for _, planID := range req.RatePlanIDs {
results = append(results, map[string]any{
"rate_plan_id": planID,
"strategy": req.Strategy,
"current_price": 29.99,
"optimal_price": 32.99,
"price_change_pct": 10.0,
"expected_revenue": 165000,
"expected_demand": 5000,
"confidence": 85.0,
"reasoning": []string{
"Market analysis suggests price increase tolerance",
"Competitor prices are higher",
"Strong value proposition",
},
"risks": []string{
"Potential short-term churn increase",
},
"recommendations": []string{
"Implement gradually over 2 months",
"Monitor churn closely",
},
})
}
c.JSON(http.StatusOK, gin.H{"results": results})
}
// GetPriceElasticity returns price elasticity data
func (h *AnalyticsHandler) GetPriceElasticity(c *gin.Context) {
elasticity := map[string]any{
"overall_elasticity": -1.2,
"by_segment": map[string]float64{
"enterprise": -0.8,
"smb": -1.1,
"consumer": -1.5,
},
"by_price_range": map[string]float64{
"0-20": -1.8,
"20-50": -1.2,
"50-100": -0.9,
"100+": -0.6,
},
"generated_at": time.Now(),
}
c.JSON(http.StatusOK, elasticity)
}
@@ -1,293 +0,0 @@
package handlers
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// CurrencyHandler handles currency and billing HTTP requests
type CurrencyHandler struct{}
// NewCurrencyHandler creates a new currency handler
func NewCurrencyHandler() *CurrencyHandler {
return &CurrencyHandler{}
}
// ConvertCurrency converts between currencies
func (h *CurrencyHandler) ConvertCurrency(c *gin.Context) {
var req struct {
From string `json:"from" binding:"required"`
To string `json:"to" binding:"required"`
Amount float64 `json:"amount" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Simulated exchange rates
rates := map[string]float64{
"USD": 1.0,
"EUR": 0.92,
"GBP": 0.79,
"JPY": 149.50,
"CAD": 1.36,
"AUD": 1.53,
"CHF": 0.88,
}
fromRate := rates[req.From]
toRate := rates[req.To]
if fromRate == 0 || toRate == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Unsupported currency"})
return
}
// Convert to USD first, then to target currency
usdAmount := req.Amount / fromRate
converted := usdAmount * toRate
rate := toRate / fromRate
c.JSON(http.StatusOK, gin.H{
"from": req.From,
"to": req.To,
"amount": req.Amount,
"converted": converted,
"rate": rate,
"timestamp": time.Now(),
})
}
// GetExchangeRate returns exchange rate between currencies
func (h *CurrencyHandler) GetExchangeRate(c *gin.Context) {
from := c.Param("from")
to := c.Param("to")
rates := map[string]float64{
"USD": 1.0,
"EUR": 0.92,
"GBP": 0.79,
"JPY": 149.50,
"CAD": 1.36,
"AUD": 1.53,
"CHF": 0.88,
}
fromRate := rates[from]
toRate := rates[to]
if fromRate == 0 || toRate == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Unsupported currency"})
return
}
rate := toRate / fromRate
c.JSON(http.StatusOK, gin.H{
"from": from,
"to": to,
"rate": rate,
"timestamp": time.Now(),
})
}
// GetExchangeRateHistory returns exchange rate history
func (h *CurrencyHandler) GetExchangeRateHistory(c *gin.Context) {
from := c.Param("from")
to := c.Param("to")
// Simulated historical rates
history := make([]map[string]any, 0)
baseRate := 0.92 // EUR/USD base
for i := 30; i >= 0; i-- {
date := time.Now().AddDate(0, 0, -i)
variation := (float64(i%5) - 2) * 0.005 // Small daily variation
history = append(history, map[string]any{
"from": from,
"to": to,
"rate": baseRate + variation,
"timestamp": date.Format("2006-01-02"),
})
}
c.JSON(http.StatusOK, gin.H{"history": history})
}
// GetSupportedCurrencies returns list of supported currencies
func (h *CurrencyHandler) GetSupportedCurrencies(c *gin.Context) {
currencies := []map[string]any{
{"code": "USD", "name": "US Dollar", "symbol": "$"},
{"code": "EUR", "name": "Euro", "symbol": "€"},
{"code": "GBP", "name": "British Pound", "symbol": "£"},
{"code": "JPY", "name": "Japanese Yen", "symbol": "¥"},
{"code": "CAD", "name": "Canadian Dollar", "symbol": "C$"},
{"code": "AUD", "name": "Australian Dollar", "symbol": "A$"},
{"code": "CHF", "name": "Swiss Franc", "symbol": "CHF"},
{"code": "CNY", "name": "Chinese Yuan", "symbol": "¥"},
{"code": "INR", "name": "Indian Rupee", "symbol": "₹"},
{"code": "KRW", "name": "South Korean Won", "symbol": "₩"},
}
c.JSON(http.StatusOK, gin.H{"currencies": currencies})
}
// RefreshExchangeRates refreshes exchange rates from external sources
func (h *CurrencyHandler) RefreshExchangeRates(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "refreshed",
"updated_at": time.Now(),
"source": "external_api",
"rates_count": 10,
})
}
// ProcessBilling processes a billing transaction
func (h *CurrencyHandler) ProcessBilling(c *gin.Context) {
var req struct {
ProfileID string `json:"profile_id" binding:"required"`
Amount float64 `json:"amount" binding:"required"`
Currency string `json:"currency" binding:"required"`
Description string `json:"description"`
Type string `json:"type"` // charge, credit, refund
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.Type == "" {
req.Type = "charge"
}
transaction := map[string]any{
"id": "txn-" + time.Now().Format("20060102150405"),
"profile_id": req.ProfileID,
"amount": req.Amount,
"currency": req.Currency,
"type": req.Type,
"description": req.Description,
"status": "completed",
"created_at": time.Now(),
}
c.JSON(http.StatusCreated, transaction)
}
// GetBillingHistory returns billing history for a profile
func (h *CurrencyHandler) GetBillingHistory(c *gin.Context) {
profileID := c.Param("profile_id")
transactions := []map[string]any{
{
"id": "txn-001",
"profile_id": profileID,
"amount": 29.99,
"currency": "USD",
"type": "charge",
"description": "Monthly subscription",
"status": "completed",
"created_at": time.Now().AddDate(0, 0, -1),
},
{
"id": "txn-002",
"profile_id": profileID,
"amount": 15.00,
"currency": "USD",
"type": "charge",
"description": "Data top-up",
"status": "completed",
"created_at": time.Now().AddDate(0, 0, -15),
},
{
"id": "txn-003",
"profile_id": profileID,
"amount": 29.99,
"currency": "USD",
"type": "charge",
"description": "Monthly subscription",
"status": "completed",
"created_at": time.Now().AddDate(0, -1, -1),
},
}
c.JSON(http.StatusOK, gin.H{"transactions": transactions})
}
// GetBillingSummary returns billing summary for a profile
func (h *CurrencyHandler) GetBillingSummary(c *gin.Context) {
profileID := c.Param("profile_id")
period := c.DefaultQuery("period", "monthly")
summary := map[string]any{
"profile_id": profileID,
"period": period,
"total_amount": 74.98,
"currency": "USD",
"transaction_count": 3,
"breakdown": map[string]float64{
"subscription": 59.98,
"data_topup": 15.00,
},
"average_transaction": 24.99,
"generated_at": time.Now(),
}
c.JSON(http.StatusOK, summary)
}
// ProcessRefund processes a refund for a transaction
func (h *CurrencyHandler) ProcessRefund(c *gin.Context) {
transactionID := c.Param("transaction_id")
var req struct {
Reason string `json:"reason" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
refund := map[string]any{
"id": "ref-" + time.Now().Format("20060102150405"),
"original_transaction": transactionID,
"amount": 29.99,
"currency": "USD",
"reason": req.Reason,
"status": "completed",
"created_at": time.Now(),
}
c.JSON(http.StatusOK, refund)
}
// GetBillingAnalytics returns billing analytics
func (h *CurrencyHandler) GetBillingAnalytics(c *gin.Context) {
period := c.DefaultQuery("period", "monthly")
analytics := map[string]any{
"period": period,
"total_revenue": 4500000,
"total_transactions": 150000,
"average_transaction": 30.0,
"by_type": map[string]float64{
"subscription": 3500000,
"data_topup": 750000,
"voice_topup": 150000,
"other": 100000,
},
"by_currency": map[string]float64{
"USD": 3000000,
"EUR": 1000000,
"GBP": 500000,
},
"growth_rate": 12.5,
"churn_impact": -150000,
"generated_at": time.Now(),
}
c.JSON(http.StatusOK, analytics)
}
@@ -1,314 +0,0 @@
package handlers
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// SecurityHandler handles security-related HTTP requests
type SecurityHandler struct{}
// NewSecurityHandler creates a new security handler
func NewSecurityHandler() *SecurityHandler {
return &SecurityHandler{}
}
// FraudAlert represents a fraud alert
type FraudAlert struct {
ID string `json:"id"`
Type string `json:"type"`
Severity string `json:"severity"`
ProfileID string `json:"profile_id"`
Description string `json:"description"`
RiskScore float64 `json:"risk_score"`
Evidence []string `json:"evidence"`
IPAddress string `json:"ip_address"`
Timestamp time.Time `json:"timestamp"`
Status string `json:"status"`
ActionsTaken []string `json:"actions_taken"`
Metadata map[string]any `json:"metadata"`
}
// FraudMetrics represents fraud detection metrics
type FraudMetrics struct {
Period string `json:"period"`
TotalAlerts int64 `json:"total_alerts"`
ResolvedAlerts int64 `json:"resolved_alerts"`
FalsePositives int64 `json:"false_positives"`
ResolutionRate float64 `json:"resolution_rate_pct"`
FalsePositiveRate float64 `json:"false_positive_rate_pct"`
ByType map[string]int64 `json:"by_type"`
BySeverity map[string]int64 `json:"by_severity"`
GeneratedAt time.Time `json:"generated_at"`
}
// AnalyzeTransaction analyzes a transaction for fraud
func (h *SecurityHandler) AnalyzeTransaction(c *gin.Context) {
var req map[string]any
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
profileID, _ := req["profile_id"].(string)
ipAddress, _ := req["ip_address"].(string)
// Simulated fraud analysis
riskScore := 25.0 // Low risk by default
// Check for suspicious patterns
if amount, ok := req["amount"].(float64); ok && amount > 1000 {
riskScore += 20
}
alert := FraudAlert{
ID: "alert-" + time.Now().Format("20060102150405"),
Type: "transaction_analysis",
Severity: getSeverityFromScore(riskScore),
ProfileID: profileID,
Description: "Transaction analyzed for fraud indicators",
RiskScore: riskScore,
Evidence: []string{
"Transaction amount within normal range",
"IP address matches historical pattern",
"Device fingerprint recognized",
},
IPAddress: ipAddress,
Timestamp: time.Now(),
Status: "analyzed",
ActionsTaken: []string{"Logged for monitoring"},
Metadata: req,
}
c.JSON(http.StatusOK, alert)
}
// GetFraudAlerts returns fraud alerts with filtering
func (h *SecurityHandler) GetFraudAlerts(c *gin.Context) {
var filter struct {
Type string `json:"type"`
Severity string `json:"severity"`
Status string `json:"status"`
Limit int `json:"limit"`
}
c.ShouldBindJSON(&filter)
if filter.Limit == 0 || filter.Limit > 100 {
filter.Limit = 50
}
// Simulated alerts
alerts := []FraudAlert{
{
ID: "alert-001",
Type: "account_takeover",
Severity: "high",
ProfileID: "profile-123",
Description: "Multiple failed login attempts from new IP",
RiskScore: 85.0,
Evidence: []string{"10 failed logins", "New IP address", "Different country"},
IPAddress: "192.168.1.100",
Timestamp: time.Now().Add(-2 * time.Hour),
Status: "new",
},
{
ID: "alert-002",
Type: "payment_fraud",
Severity: "medium",
ProfileID: "profile-456",
Description: "Unusual payment pattern detected",
RiskScore: 55.0,
Evidence: []string{"Large transaction", "New payment method"},
IPAddress: "10.0.0.50",
Timestamp: time.Now().Add(-5 * time.Hour),
Status: "investigating",
},
{
ID: "alert-003",
Type: "sim_swap",
Severity: "critical",
ProfileID: "profile-789",
Description: "SIM swap attempt detected",
RiskScore: 95.0,
Evidence: []string{"SIM change request", "No prior notification", "High-value account"},
IPAddress: "172.16.0.25",
Timestamp: time.Now().Add(-30 * time.Minute),
Status: "blocked",
},
}
// Filter alerts
filtered := make([]FraudAlert, 0)
for _, alert := range alerts {
if filter.Type != "" && alert.Type != filter.Type {
continue
}
if filter.Severity != "" && alert.Severity != filter.Severity {
continue
}
if filter.Status != "" && alert.Status != filter.Status {
continue
}
filtered = append(filtered, alert)
if len(filtered) >= filter.Limit {
break
}
}
c.JSON(http.StatusOK, filtered)
}
// UpdateAlertStatus updates a fraud alert status
func (h *SecurityHandler) UpdateAlertStatus(c *gin.Context) {
alertID := c.Param("id")
var req struct {
Status string `json:"status" binding:"required"`
Actions []string `json:"actions"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"id": alertID,
"status": req.Status,
"actions_taken": req.Actions,
"updated_at": time.Now(),
})
}
// GetFraudMetrics returns fraud detection metrics
func (h *SecurityHandler) GetFraudMetrics(c *gin.Context) {
period := c.DefaultQuery("period", "monthly")
metrics := FraudMetrics{
Period: period,
TotalAlerts: 1250,
ResolvedAlerts: 1100,
FalsePositives: 125,
ResolutionRate: 88.0,
FalsePositiveRate: 10.0,
ByType: map[string]int64{
"account_takeover": 350,
"subscription_fraud": 200,
"payment_fraud": 400,
"usage_anomaly": 200,
"sim_swap": 100,
},
BySeverity: map[string]int64{
"low": 400,
"medium": 500,
"high": 250,
"critical": 100,
},
GeneratedAt: time.Now(),
}
c.JSON(http.StatusOK, metrics)
}
// GetFraudPatterns returns detected fraud patterns
func (h *SecurityHandler) GetFraudPatterns(c *gin.Context) {
patterns := []map[string]any{
{
"id": "pattern-1",
"name": "Velocity Attack",
"description": "Multiple rapid transactions from same source",
"frequency": "high",
"indicators": []string{"High transaction rate", "Same IP", "Different accounts"},
"mitigation": "Rate limiting, IP blocking",
},
{
"id": "pattern-2",
"name": "Account Enumeration",
"description": "Systematic probing of account existence",
"frequency": "medium",
"indicators": []string{"Sequential account checks", "Automated requests"},
"mitigation": "CAPTCHA, rate limiting",
},
{
"id": "pattern-3",
"name": "SIM Swap Attack",
"description": "Unauthorized SIM card replacement",
"frequency": "low",
"indicators": []string{"Sudden SIM change", "No customer contact", "High-value target"},
"mitigation": "Multi-factor verification, cooling period",
},
}
c.JSON(http.StatusOK, gin.H{"patterns": patterns})
}
// VerifySIMSwap verifies a SIM swap request
func (h *SecurityHandler) VerifySIMSwap(c *gin.Context) {
var req struct {
ProfileID string `json:"profile_id" binding:"required"`
MSISDN string `json:"msisdn" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Simulated SIM swap verification
c.JSON(http.StatusOK, gin.H{
"profile_id": req.ProfileID,
"msisdn": req.MSISDN,
"verified": true,
"risk_score": 15.0,
"risk_level": "low",
"last_sim_swap": time.Now().AddDate(-1, 0, 0).Format("2006-01-02"),
"checks_passed": []string{
"Identity verified",
"No recent SIM changes",
"Account in good standing",
},
})
}
// GetSIMSwapHistory returns SIM swap history for a profile
func (h *SecurityHandler) GetSIMSwapHistory(c *gin.Context) {
profileID := c.Param("profile_id")
history := []map[string]any{
{
"id": "swap-001",
"profile_id": profileID,
"old_iccid": "8901234567890123456",
"new_iccid": "8901234567890123457",
"timestamp": time.Now().AddDate(-1, 0, 0),
"reason": "Device upgrade",
"verified": true,
"status": "completed",
},
{
"id": "swap-002",
"profile_id": profileID,
"old_iccid": "8901234567890123455",
"new_iccid": "8901234567890123456",
"timestamp": time.Now().AddDate(-2, 0, 0),
"reason": "Lost device",
"verified": true,
"status": "completed",
},
}
c.JSON(http.StatusOK, gin.H{"history": history})
}
func getSeverityFromScore(score float64) string {
switch {
case score >= 80:
return "critical"
case score >= 60:
return "high"
case score >= 40:
return "medium"
default:
return "low"
}
}