// Path: Backend/internal/bootstrap/bootstrap.go package bootstrap import ( "log/slog" "os" "strings" "moku-backend/internal/buildinfo" "moku-backend/internal/cache" "moku-backend/internal/config" "moku-backend/internal/database" ) type App struct { ServiceName string Config *config.Config Logger *slog.Logger BuildInfo buildinfo.Info Database *database.DB Cache *cache.Client } func New(serviceName string) (*App, error) { cfg := config.Load() logger := newLogger(cfg) db, err := database.NewPostgres(cfg.PostgresURL) if err != nil { return nil, err } valkey, err := cache.NewValkey(cfg.ValkeyURL) if err != nil { db.Close() return nil, err } return &App{ ServiceName: serviceName, Config: cfg, Logger: logger.With("service", serviceName), BuildInfo: buildinfo.Current(), Database: db, Cache: valkey, }, nil } func (a *App) Close() error { var closeErr error if a.Cache != nil { if err := a.Cache.Close(); err != nil { closeErr = err } } if a.Database != nil { a.Database.Close() } return closeErr } func newLogger(cfg *config.Config) *slog.Logger { level := slog.LevelInfo switch strings.ToLower(cfg.LogLevel) { case "debug": level = slog.LevelDebug case "warn": level = slog.LevelWarn case "error": level = slog.LevelError } options := &slog.HandlerOptions{Level: level} if cfg.IsDevelopment() { return slog.New(slog.NewTextHandler(os.Stdout, options)) } return slog.New(slog.NewJSONHandler(os.Stdout, options)) }