from pydantic import model_validator from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", env_nested_delimiter="__", extra="ignore", ) APP_NAME: str = "PIP - Pharmacy Integration Platform" APP_VERSION: str = "0.1.0" DEBUG: bool = False NODE_ENV: str = "development" DATABASE_URL: str = "postgresql+asyncpg://pip:pip@localhost:5432/pip" DATABASE_POOL_SIZE: int = 20 DATABASE_MAX_OVERFLOW: int = 10 DATABASE_POOL_RECYCLE: int = 3600 REDIS_URL: str = "redis://localhost:6379/0" REDIS_CACHE_TTL: int = 300 RABBITMQ_URL: str = "amqp://pip:pip@localhost:5672/pip" JWT_SECRET_KEY: str = "change-me-in-production" JWT_ALGORITHM: str = "HS256" JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = 7 JWT_ISSUER: str = "pip-platform" OAUTH2_TOKEN_URL: str = "/api/v1/auth/token" RATE_LIMIT_PER_MINUTE: int = 60 RATE_LIMIT_AUTH_PER_MINUTE: int = 10 API_KEY_PREFIX: str = "pip" API_KEY_LENGTH: int = 32 OTEL_EXPORTER_OTLP_ENDPOINT: str = "http://localhost:4317" OTEL_SERVICE_NAME: str = "pip-platform" OTEL_TRACES_ENABLED: bool = True OTEL_METRICS_ENABLED: bool = True LOG_LEVEL: str = "INFO" LOG_JSON_FORMAT: bool = True CORS_ORIGINS: list[str] = ["*"] CORS_ALLOW_CREDENTIALS: bool = True HEALTH_CHECK_CACHE_TTL: int = 10 @model_validator(mode="after") def validate_production_security(self): if self.NODE_ENV.lower() != "production": return self if self.JWT_SECRET_KEY == "change-me-in-production": raise ValueError("JWT_SECRET_KEY must be changed in production") default_credentials = ("pip:pip@", "pip-secret") if any(value in self.DATABASE_URL or value in self.RABBITMQ_URL for value in default_credentials): raise ValueError("default database or broker credentials are not allowed in production") if self.CORS_ALLOW_CREDENTIALS and "*" in self.CORS_ORIGINS: raise ValueError("wildcard CORS_ORIGINS are not allowed with credentials in production") return self @property def DATABASE_URL_SYNC(self) -> str: return self.DATABASE_URL.replace("+asyncpg", "+psycopg2", 1) settings = Settings()