package server import ( "fmt" "log" "attune-heart-therapy/internal/config" "attune-heart-therapy/internal/database" "attune-heart-therapy/internal/handlers" "attune-heart-therapy/internal/services" "github.com/gin-gonic/gin" ) type Server struct { config *config.Config db *database.DB router *gin.Engine paymentHandler *handlers.PaymentHandler } func New(cfg *config.Config) *Server { // Set Gin mode based on environment gin.SetMode(gin.ReleaseMode) router := gin.New() // Add basic middleware router.Use(gin.Logger()) router.Use(gin.Recovery()) return &Server{ config: cfg, router: router, } } // Initialize sets up the database connection and runs migrations func (s *Server) Initialize() error { // Initialize database connection db, err := database.New(s.config) if err != nil { return fmt.Errorf("failed to initialize database: %w", err) } s.db = db // Run database migrations if err := s.db.Migrate(); err != nil { return fmt.Errorf("failed to run database migrations: %w", err) } // Seed database with initial data if err := s.db.Seed(); err != nil { return fmt.Errorf("failed to seed database: %w", err) } // Initialize services and handlers s.initializeServices() log.Println("Server initialization completed successfully") return nil } func (s *Server) Start() error { // Initialize database and run migrations if err := s.Initialize(); err != nil { return err } // Setup routes s.setupRoutes() // Start server addr := fmt.Sprintf("%s:%s", s.config.Server.Host, s.config.Server.Port) log.Printf("Starting server on %s", addr) return s.router.Run(addr) } // Shutdown gracefully shuts down the server func (s *Server) Shutdown() error { if s.db != nil { log.Println("Closing database connection...") return s.db.Close() } return nil } func (s *Server) setupRoutes() { // Health check endpoint s.router.GET("/health", s.healthCheck) // API v1 routes group v1 := s.router.Group("/api/v1") { // Auth routes (will be implemented in later tasks) auth := v1.Group("/auth") { auth.POST("/register", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) auth.POST("/login", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) } // Booking routes (will be implemented in later tasks) bookings := v1.Group("/bookings") { bookings.GET("/", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) bookings.POST("/", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) } // Schedule routes (will be implemented in later tasks) schedules := v1.Group("/schedules") { schedules.GET("/", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) } // Payment routes payments := v1.Group("/payments") { payments.POST("/intent", s.paymentHandler.CreatePaymentIntent) payments.POST("/confirm", s.paymentHandler.ConfirmPayment) payments.POST("/webhook", s.paymentHandler.HandleWebhook) } // Admin routes (will be implemented in later tasks) admin := v1.Group("/admin") { admin.GET("/dashboard", func(c *gin.Context) { c.JSON(501, gin.H{"message": "Not implemented yet"}) }) } } } // initializeServices sets up all services and handlers func (s *Server) initializeServices() { // Initialize repositories repos := s.db.GetRepositories() // Initialize Jitsi service jitsiService := services.NewJitsiService(&s.config.Jitsi) // Initialize payment service paymentService := services.NewPaymentService(s.config) // Initialize booking service with Jitsi integration bookingService := services.NewBookingService( repos.Booking, repos.Schedule, jitsiService, paymentService, ) // Store services for later use (if needed) _ = bookingService // Will be used when booking handlers are implemented // Initialize payment handler s.paymentHandler = handlers.NewPaymentHandler(paymentService) } // healthCheck handles the health check endpoint func (s *Server) healthCheck(c *gin.Context) { response := gin.H{ "status": "ok", "message": "Video Conference Booking System API", } // Check database connectivity if s.db != nil { if err := s.db.Health(); err != nil { response["status"] = "error" response["database"] = "disconnected" response["error"] = err.Error() c.JSON(500, response) return } response["database"] = "connected" } else { response["database"] = "not initialized" } c.JSON(200, response) }