Files
Novault-backend/cmd/server/main.go

151 lines
4.4 KiB
Go
Raw Normal View History

2026-01-25 21:59:00 +08:00
package main
import (
"context"
"log"
"os"
"path/filepath"
"accounting-app/internal/cache"
"accounting-app/internal/config"
"accounting-app/internal/database"
"accounting-app/internal/mq"
2026-01-25 21:59:00 +08:00
"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/)
2026-01-25 21:59:00 +08:00
filepath.Join("..", "..", ".env"), // Explicit path
}
var envDir string
2026-01-25 21:59:00 +08:00
for _, envPath := range envPaths {
if err := godotenv.Load(envPath); err == nil {
log.Printf("Loaded base environment from: %s", envPath)
envDir = filepath.Dir(envPath)
2026-01-25 21:59:00 +08:00
break
}
}
// Load specific environment file if APP_ENV is set (e.g. .env.dev, .env.prod)
// This allows switching environments by just changing APP_ENV in .env
if appEnv := os.Getenv("APP_ENV"); appEnv != "" {
targetEnvFile := ".env." + appEnv
targetEnvPath := targetEnvFile
if envDir != "" && envDir != "." {
targetEnvPath = filepath.Join(envDir, targetEnvFile)
}
if err := godotenv.Overload(targetEnvPath); err == nil {
log.Printf("Loaded specific environment config from: %s", targetEnvPath)
} else {
log.Printf("Note: Specific environment file %s not found or could not be loaded", targetEnvPath)
}
}
2026-01-25 21:59:00 +08:00
// 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)
log.Printf("Warning: Recurring transaction MQ system disabled (requires Redis)")
2026-01-25 21:59:00 +08:00
// 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)
// Initialize and start MQ task system for recurring transactions
recurringTaskSystem, err := mq.InitRecurringTaskSystem(
ctx,
redisClient.Client(),
db,
cfg.MQPollInterval, // Poll interval from config
cfg.MQWorkerCount, // Worker count from config
)
if err != nil {
log.Printf("Warning: Failed to initialize recurring task system: %v", err)
} else {
// Start MQ worker in background
go recurringTaskSystem.Start(ctx)
log.Println("Recurring transaction MQ system started")
}
2026-01-25 21:59:00 +08:00
}
// 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)
}
}