package daemon import ( "context" "fmt" "os" "os/signal" "syscall" "github.com/spf13/cobra" "go.uber.org/zap" "go.uber.org/zap/zapcore" "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/app" "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config" "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/storage/database" ) // createBootstrapLogger creates a simple console logger for use during application bootstrap // This is used before the main application logger is initialized func createBootstrapLogger() *zap.Logger { encoderConfig := zapcore.EncoderConfig{ TimeKey: "ts", LevelKey: "level", NameKey: "logger", CallerKey: "", FunctionKey: zapcore.OmitKey, MessageKey: "msg", StacktraceKey: "", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.CapitalColorLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.StringDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } core := zapcore.NewCore( zapcore.NewConsoleEncoder(encoderConfig), zapcore.AddSync(os.Stdout), zapcore.InfoLevel, ) return zap.New(core) } // DaemonCmd returns the daemon command func DaemonCmd() *cobra.Command { var noAutoMigrate bool cmd := &cobra.Command{ Use: "daemon", Short: "Start the MaplePress backend server", Long: `Start the MaplePress backend server. By default, the server will automatically run database migrations on startup. This ensures the database schema is always up-to-date with the application code. For cloud-native deployments (Kubernetes, Docker, etc.), this is the recommended approach. To disable auto-migration, use the --no-auto-migrate flag.`, RunE: func(cmd *cobra.Command, args []string) error { // Create bootstrap logger for startup messages logger := createBootstrapLogger() defer logger.Sync() // Load configuration cfg, err := config.Load() if err != nil { return err } // Run migrations automatically (unless disabled) if !noAutoMigrate { logger.Info("⏳ Running database migrations...") migrator := database.NewMigrator(cfg, logger) if err := migrator.Up(); err != nil { return fmt.Errorf("failed to run migrations: %w", err) } logger.Info("✓ Database migrations completed successfully") } else { logger.Warn("⚠️ Auto-migration disabled, skipping database migrations") } // Initialize application via Wire logger.Info("⏳ Initializing application dependencies...") application, err := app.InitializeApplication(cfg) if err != nil { return err } logger.Info("✓ Application dependencies initialized") logger.Info("") // Start server ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Handle graceful shutdown sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) errChan := make(chan error, 1) go func() { errChan <- application.Run(ctx) }() select { case err := <-errChan: return err case <-sigChan: return application.Shutdown(ctx) } }, } // Add flags cmd.Flags().BoolVar(&noAutoMigrate, "no-auto-migrate", false, "Disable automatic database migrations on startup") return cmd }