package handlers import ( "bookra/apps/auth-service/internal/config" "bookra/apps/auth-service/internal/db" "net/http" "strings" "github.com/gin-gonic/gin" ) // AdminDashboard provides a visual management interface for the auth service type AdminDashboard struct { cfg *config.Config db *db.DB } func NewAdminDashboard(cfg *config.Config, database *db.DB) *AdminDashboard { return &AdminDashboard{cfg: cfg, db: database} } // RegisterRoutes registers admin routes func (a *AdminDashboard) RegisterRoutes(r *gin.Engine) { admin := r.Group("/admin") { admin.GET("", a.RenderDashboard) admin.GET("/api/config", a.GetConfig) admin.GET("/api/prices", a.GetPrices) admin.GET("/api/stats", a.GetStats) } } // GetConfig returns current configuration (sanitized) func (a *AdminDashboard) GetConfig(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "appEnv": a.cfg.AppEnv, "port": a.cfg.Port, "frontendURL": a.cfg.FrontendURL, "neonAuthURL": a.cfg.NeonAuthURL, "smtpConfigured": gin.H{ "host": a.cfg.SMTPHost, "port": a.cfg.SMTPPort, "from": a.cfg.EmailFrom, }, "googleOAuthConfigured": a.cfg.GoogleClientID != "", "stripeConfigured": a.cfg.StripeCheckoutReady(), "stripeSecretConfigured": a.cfg.StripeSecretConfigured(), "stripeWebhookConfigured": a.cfg.StripeWebhookConfigured(), "stripePricesConfigured": a.cfg.StripeHasAnyPriceConfigured(), }) } // GetPrices returns configured Stripe prices func (a *AdminDashboard) GetPrices(c *gin.Context) { prices := []gin.H{} planNames := map[string]string{ "starter": "Starter Plan", "pro": "Pro Plan", "business": "Business Plan", "monthly": "Monthly Plan", "growth": "Growth Plan (Pro alias)", "multi-location": "Multi-Location (Business alias)", } currencies := []string{"czk", "usd"} for planCode, priceID := range a.cfg.StripePriceIDs { if strings.TrimSpace(priceID) == "" { continue } // Parse plan:currency format parts := strings.Split(planCode, ":") displayName := planNames[planCode] currency := "" if len(parts) == 2 { planCode = parts[0] currency = parts[1] displayName = planNames[planCode] + " (" + strings.ToUpper(currency) + ")" } if displayName == "" { displayName = planCode } prices = append(prices, gin.H{ "planCode": planCode, "currency": currency, "priceID": priceID, "displayName": displayName, "configured": true, }) } c.JSON(http.StatusOK, gin.H{ "prices": prices, "currencies": currencies, "stripeConfigured": a.cfg.StripeCheckoutReady(), "secretConfigured": a.cfg.StripeSecretConfigured(), "webhookConfigured": a.cfg.StripeWebhookConfigured(), "pricesConfigured": len(prices) > 0, }) } // GetStats returns database statistics func (a *AdminDashboard) GetStats(c *gin.Context) { if a.db == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Database not available"}) return } stats, err := a.db.GetStats(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load stats: " + err.Error()}) return } c.JSON(http.StatusOK, stats) } // RenderDashboard renders the HTML admin dashboard func (a *AdminDashboard) RenderDashboard(c *gin.Context) { c.Header("Content-Type", "text/html; charset=utf-8") c.String(http.StatusOK, adminHTML) } const adminHTML = ` Bookra Auth Service Admin

Monitor users, configure billing plans, and manage service health.

-
Total Users
-
Active (7d)
-
Magic Links Sent
-
New This Week

Service Configuration

Loading configuration...

Billing Plans

Loading plans...

API Endpoints

Method Endpoint
POST/api/auth/magic-link
POST/api/auth/verify
POST/api/auth/register
POST/api/auth/login
GET/api/auth/me
GET/api/billing/subscription
POST/api/billing/checkout

Service Overview

Authentication Magic links, JWT, OAuth
Billing Stripe subscriptions
Database Neon PostgreSQL
Email SMTP transactional
`