""" Settings configuration that works in both local development and Docker environments. In local development: - Loads from .env file if it exists - Environment variables override .env file values In Docker: - Reads directly from environment variables (no .env file needed) - Use docker-compose.yml or docker run -e to set environment variables """ import os from os import environ from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict( # Try to load .env file for local development, but don't fail if it doesn't exist env_file=".env" if os.path.exists(".env") else None, env_file_encoding="utf-8", extra="ignore", # Environment variables take precedence over .env file env_ignore_empty=True, ) airtable_pat: str airtable_base: str slack_signing_secret: str slack_client_id: str slack_bolt_is_broken_so_this_cant_be_called_client_secret: str slack_bot_token: str app_base_url: str game_id_salt: str airtable_submissions_table: str airtable_users_table: str airtable_items_table: str airtable_sessions_table: str airtable_item_instances_table: str # Security settings environment: str = "development" # development, staging, production max_request_size: int = 1048576 # 1MB default rate_limit_requests: int = 20 # requests per minute per IP allowed_origins: str = "*" # Comma-separated list or "*" for development trust_proxy_headers: bool = False # Whether to trust X-Forwarded-For headers # Session security session_ttl_hours: int = 24 # Session expires after 24 hours # Logging settings log_level: str = "INFO" # DEBUG, INFO, WARNING, ERROR, CRITICAL log_format: str = "standard" # standard, json, verbose log_file: str = "" # Empty string means no file logging, only console log_max_size: int = 10485760 # 10MB default for log rotation log_backup_count: int = 5 # Number of backup log files to keep verbose_logging: bool = False # Enable verbose debug logging # Redis/Valkey settings - prioritize explicit env vars, fall back to container detection redis_host: str = environ.get("REDIS_HOST") or ( "valkey" if environ.get("DOCKER_CONTAINER") else "localhost" ) redis_port: int = int(environ.get("REDIS_PORT", "6379")) @property def is_production(self) -> bool: return self.environment == "production" @property def is_container(self) -> bool: """Detect if running in a container environment.""" return bool(environ.get("DOCKER_CONTAINER") or environ.get("REDIS_HOST")) @property def origins_list(self) -> list[str]: if self.allowed_origins == "*": return ["*"] return [origin.strip() for origin in self.allowed_origins.split(",")] settings = Settings() # type: ignore