package main import ( "context" "log" "os" "path/filepath" "accounting-app/internal/cache" "accounting-app/internal/config" "accounting-app/internal/database" "accounting-app/internal/repository" "accounting-app/internal/router" "accounting-app/internal/service" "github.com/gin-gonic/gin" "github.com/joho/godotenv" ) func main() { // Load .env file from project root (try multiple locations) envPaths := []string{ ".env", // Current directory "../.env", // Parent directory (when running from backend/) "../../.env", // Two levels up (when running from backend/cmd/server/) filepath.Join("..", "..", ".env"), // Explicit path } for _, envPath := range envPaths { if err := godotenv.Load(envPath); err == nil { log.Printf("Loaded environment from: %s", envPath) break } } // Load configuration cfg := config.Load() // Initialize database connection (no migrations or seeding) db, err := database.Initialize( cfg.DBHost, cfg.DBPort, cfg.DBUser, cfg.DBPassword, cfg.DBName, cfg.DBCharset, ) if err != nil { log.Fatalf("Failed to connect to database: %v", err) } // Get underlying SQL DB for cleanup sqlDB, err := db.DB() if err != nil { log.Fatalf("Failed to get underlying database: %v", err) } defer sqlDB.Close() // Initialize YunAPI client (needed for both Redis and non-Redis modes) exchangeRateRepo := repository.NewExchangeRateRepository(db) yunAPIClient := service.NewYunAPIClientWithConfig( cfg.YunAPIURL, cfg.YunAPIKey, cfg.MaxRetries, exchangeRateRepo, ) // Create context for scheduler ctx, cancel := context.WithCancel(context.Background()) defer cancel() var r *gin.Engine // Try to initialize Redis connection // If Redis is available, use the new V2 exchange rate system with caching // If Redis is not available, fall back to the old system // Requirements: 3.1 (sync on start) redisClient, err := cache.NewRedisClient(cfg) if err != nil { // Redis not available - fall back to old system log.Printf("Warning: Redis connection failed (%v), falling back to non-cached exchange rate system", err) // Use old scheduler scheduler := service.NewExchangeRateScheduler(yunAPIClient, cfg.SyncInterval) go scheduler.Start(ctx) // Setup router without Redis r = router.Setup(db, yunAPIClient, cfg) } else { // Redis is available - use new V2 system with caching log.Println("Redis connected successfully, using cached exchange rate system") defer redisClient.Close() // Setup router with Redis support (returns engine and sync scheduler) var syncScheduler *service.SyncScheduler r, syncScheduler = router.SetupWithRedis(db, yunAPIClient, redisClient, cfg) // Start the new SyncScheduler in background // This will perform initial sync immediately (Requirement 3.1) go syncScheduler.Start(ctx) } // Get port from config or environment port := cfg.ServerPort if envPort := os.Getenv("PORT"); envPort != "" { port = envPort } // Start server log.Printf("Starting server on port %s...", port) if err := r.Run(":" + port); err != nil { log.Fatalf("Failed to start server: %v", err) } }