package main import ( "context" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" "github.com/joho/godotenv" "go.uber.org/zap" "veza-backend-api/internal/api" // TODO: Réactiver internal/api/handlers après stabilisation du noyau // "veza-backend-api/internal/api/handlers" "veza-backend-api/internal/config" // TODO: Réactiver services après stabilisation du noyau // "veza-backend-api/internal/services" ) // @title Veza Backend API // @version 1.2.0 // @description Backend API for Veza platform. // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.url http://www.veza.app/support // @contact.email support@veza.app // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @host localhost:8080 // @BasePath /api/v1 // @securityDefinitions.apikey BearerAuth // @in header // @name Authorization // @description Type "Bearer" followed by a space and JWT token. func main() { // Charger les variables d'environnement depuis le fichier .env if err := godotenv.Load(); err != nil { log.Printf("⚠️ Impossible de charger le fichier .env: %v", err) } // Configuration du logger logger, err := zap.NewProduction() if err != nil { log.Fatalf("Impossible d'initialiser le logger: %v", err) } defer logger.Sync() logger.Info("🚀 Démarrage du serveur Veza Backend API (Architecture Moderne)") // Charger la configuration cfg, err := config.NewConfig() if err != nil { logger.Fatal("❌ Impossible de charger la configuration", zap.Error(err)) } // Valider la configuration if err := cfg.Validate(); err != nil { logger.Fatal("❌ Configuration invalide", zap.Error(err)) } logger.Info("✅ Configuration validée avec succès") // La base de données est déjà initialisée dans config.NewConfig() db := cfg.Database if db == nil { logger.Fatal("❌ Base de données non initialisée") } defer db.Close() // Initialiser la base de données (migrations, etc.) if err := db.Initialize(); err != nil { logger.Fatal("❌ Impossible d'initialiser la base de données", zap.Error(err)) } // TODO: Réactiver les services après stabilisation du noyau et alignement des signatures // Initialiser les services // authService := services.NewAuthService(db, &cfg.JWT, logger) // oauthService := services.NewOAuthService(db, cfg, logger) // chatService := services.NewChatService(db, logger) // twoFactorService := services.NewTwoFactorService(db, logger) // rbacService := services.NewRBACService(db, logger) // TODO: Réactiver les handlers après stabilisation du noyau et alignement des services // Initialiser les handlers // handlers.InitHandlers(authService, logger) // handlers.InitOAuthHandlers(oauthService, authService, logger) // handlers.InitChatHandlers(chatService, logger) // handlers.InitTwoFactorHandlers(twoFactorService, authService, logger) // handlers.InitRBACHandlers(rbacService, logger) // Configuration de Gin selon l'environnement gin.SetMode(gin.DebugMode) // TODO: Utiliser cfg.LogLevel pour déterminer le mode // Créer le router Gin router := gin.New() // Configuration des routes avec la nouvelle architecture apiRouter := api.NewAPIRouter(db, cfg) // Instantiate APIRouter if err := apiRouter.Setup(router); err != nil { logger.Fatal("❌ Erreur lors de la configuration des routes", zap.Error(err)) } // Configuration du serveur HTTP port := fmt.Sprintf("%d", cfg.AppPort) if port == "0" { port = "8080" } server := &http.Server{ Addr: fmt.Sprintf(":%s", port), Handler: router, // TODO: Ajouter ReadTimeout et WriteTimeout si nécessaire } // Canal pour écouter les signaux du système quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // Démarrer le serveur dans une goroutine go func() { logger.Info("🌐 Serveur HTTP démarré", zap.String("port", port), ) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { logger.Fatal("❌ Erreur du serveur HTTP", zap.Error(err)) } }() logger.Info("✅ Serveur Veza Backend API prêt à recevoir des requêtes") logger.Info("📋 Endpoints disponibles:") logger.Info(" - GET /health - Health check global") logger.Info(" - POST /api/v1/auth/register - Inscription utilisateur") logger.Info(" - POST /api/v1/auth/login - Connexion utilisateur") logger.Info(" - POST /api/v1/auth/refresh - Renouvellement de token") logger.Info(" - POST /api/v1/auth/logout - Déconnexion utilisateur") logger.Info(" - GET /api/v1/profile - Profil utilisateur") logger.Info(" - PUT /api/v1/profile - Mise à jour profil") logger.Info(" - GET /api/v1/health/detailed - Health check détaillé") // Attendre un signal d'arrêt <-quit logger.Info("🔄 Arrêt du serveur en cours...") // Créer un contexte avec timeout pour l'arrêt gracieux ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // TODO: Utiliser config pour timeout defer cancel() // Arrêt gracieux du serveur if err := server.Shutdown(ctx); err != nil { logger.Error("❌ Erreur lors de l'arrêt du serveur", zap.Error(err)) } else { logger.Info("✅ Serveur arrêté proprement") } }