diff --git a/backend/internal/bootstrap/router_bootstrap.go b/backend/internal/bootstrap/router_bootstrap.go index 2e362475..3c1072be 100644 --- a/backend/internal/bootstrap/router_bootstrap.go +++ b/backend/internal/bootstrap/router_bootstrap.go @@ -41,11 +41,11 @@ func initRouter(db *gorm.DB, svc *services) utils.Service { func initRouterInternal(db *gorm.DB, svc *services) (utils.Service, error) { // Set the appropriate Gin mode based on the environment switch common.EnvConfig.AppEnv { - case "production": + case common.AppEnvProduction: gin.SetMode(gin.ReleaseMode) - case "development": + case common.AppEnvDevelopment: gin.SetMode(gin.DebugMode) - case "test": + case common.AppEnvTest: gin.SetMode(gin.TestMode) } @@ -92,7 +92,7 @@ func initRouterInternal(db *gorm.DB, svc *services) (utils.Service, error) { controller.NewVersionController(apiGroup, svc.versionService) // Add test controller in non-production environments - if common.EnvConfig.AppEnv != "production" { + if !common.EnvConfig.AppEnv.IsProduction() { for _, f := range registerTestControllers { f(apiGroup, db, svc) } diff --git a/backend/internal/common/env_config.go b/backend/internal/common/env_config.go index ea2f2a2b..cec8df15 100644 --- a/backend/internal/common/env_config.go +++ b/backend/internal/common/env_config.go @@ -15,6 +15,7 @@ import ( _ "github.com/joho/godotenv/autoload" ) +type AppEnv string type DbProvider string const ( @@ -25,6 +26,9 @@ const ( ) const ( + AppEnvProduction AppEnv = "production" + AppEnvDevelopment AppEnv = "development" + AppEnvTest AppEnv = "test" DbProviderSqlite DbProvider = "sqlite" DbProviderPostgres DbProvider = "postgres" MaxMindGeoLiteCityUrl string = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz" @@ -34,7 +38,7 @@ const ( ) type EnvConfigSchema struct { - AppEnv string `env:"APP_ENV" options:"toLower"` + AppEnv AppEnv `env:"APP_ENV" options:"toLower"` LogLevel string `env:"LOG_LEVEL" options:"toLower"` AppURL string `env:"APP_URL" options:"toLower,trimTrailingSlash"` DbProvider DbProvider `env:"DB_PROVIDER" options:"toLower"` @@ -80,7 +84,7 @@ func init() { func defaultConfig() EnvConfigSchema { return EnvConfigSchema{ - AppEnv: "production", + AppEnv: AppEnvProduction, LogLevel: "info", DbProvider: "sqlite", FileBackend: "fs", @@ -288,3 +292,11 @@ func resolveFileBasedEnvVariable(field reflect.Value, fieldType reflect.StructFi return nil } + +func (a AppEnv) IsProduction() bool { + return a == AppEnvProduction +} + +func (a AppEnv) IsTest() bool { + return a == AppEnvTest +} diff --git a/backend/internal/common/env_config_test.go b/backend/internal/common/env_config_test.go index 397991f9..8faae952 100644 --- a/backend/internal/common/env_config_test.go +++ b/backend/internal/common/env_config_test.go @@ -192,7 +192,7 @@ func TestParseEnvConfig(t *testing.T) { t.Setenv("DB_PROVIDER", "postgres") t.Setenv("DB_CONNECTION_STRING", "postgres://test") t.Setenv("APP_URL", "https://prod.example.com") - t.Setenv("APP_ENV", "STAGING") + t.Setenv("APP_ENV", "PRODUCTION") t.Setenv("UPLOAD_PATH", "/custom/uploads") t.Setenv("KEYS_PATH", "/custom/keys") t.Setenv("PORT", "8080") @@ -203,7 +203,7 @@ func TestParseEnvConfig(t *testing.T) { err := parseEnvConfig() require.NoError(t, err) - assert.Equal(t, "staging", EnvConfig.AppEnv) // lowercased + assert.Equal(t, AppEnvProduction, EnvConfig.AppEnv) // lowercased assert.Equal(t, "/custom/uploads", EnvConfig.UploadPath) assert.Equal(t, "8080", EnvConfig.Port) assert.Equal(t, "localhost", EnvConfig.Host) // lowercased @@ -279,7 +279,7 @@ func TestPrepareEnvConfig_FileBasedAndToLower(t *testing.T) { err := prepareEnvConfig(&config) require.NoError(t, err) - assert.Equal(t, "staging", config.AppEnv) + assert.Equal(t, AppEnv("staging"), config.AppEnv) assert.Equal(t, "localhost", config.Host) assert.Equal(t, []byte(encryptionKeyContent), config.EncryptionKey) assert.Equal(t, dbConnContent, config.DbConnectionString) diff --git a/backend/internal/job/analytics_job.go b/backend/internal/job/analytics_job.go index 468d45f0..6cf2b944 100644 --- a/backend/internal/job/analytics_job.go +++ b/backend/internal/job/analytics_job.go @@ -19,7 +19,7 @@ const heartbeatUrl = "https://analytics.pocket-id.org/heartbeat" func (s *Scheduler) RegisterAnalyticsJob(ctx context.Context, appConfig *service.AppConfigService, httpClient *http.Client) error { // Skip if analytics are disabled or not in production environment - if common.EnvConfig.AnalyticsDisabled || common.EnvConfig.AppEnv != "production" { + if common.EnvConfig.AnalyticsDisabled || !common.EnvConfig.AppEnv.IsProduction() { return nil } @@ -39,7 +39,7 @@ type AnalyticsJob struct { // sendHeartbeat sends a heartbeat to the analytics service func (j *AnalyticsJob) sendHeartbeat(parentCtx context.Context) error { // Skip if analytics are disabled or not in production environment - if common.EnvConfig.AnalyticsDisabled || common.EnvConfig.AppEnv != "production" { + if common.EnvConfig.AnalyticsDisabled || !common.EnvConfig.AppEnv.IsProduction() { return nil } diff --git a/backend/internal/middleware/rate_limit.go b/backend/internal/middleware/rate_limit.go index 910b5865..210ea273 100644 --- a/backend/internal/middleware/rate_limit.go +++ b/backend/internal/middleware/rate_limit.go @@ -29,7 +29,7 @@ func (m *RateLimitMiddleware) Add(limit rate.Limit, burst int) gin.HandlerFunc { // Skip rate limiting for localhost and test environment // If the client ip is localhost the request comes from the frontend - if ip == "" || ip == "127.0.0.1" || ip == "::1" || common.EnvConfig.AppEnv == "test" { + if ip == "" || ip == "127.0.0.1" || ip == "::1" || common.EnvConfig.AppEnv.IsTest() { c.Next() return }