""" Configuration Module Handles environment variables and application settings """ import os from typing import List from pydantic import field_validator from pydantic_settings import BaseSettings class Settings(BaseSettings): """Application settings loaded from environment variables""" # Database DATABASE_URL: str = "postgresql://bmc_hub:bmc_hub@localhost:5432/bmc_hub" # API API_HOST: str = "0.0.0.0" API_PORT: int = 8000 API_RELOAD: bool = False ENABLE_RELOAD: bool = False # Added to match docker-compose.yml # Elnet supplier lookup ELNET_API_BASE_URL: str = "https://api.elnet.greenpowerdenmark.dk/api" ELNET_TIMEOUT_SECONDS: int = 12 # Security SECRET_KEY: str = "dev-secret-key-change-in-production" ALLOWED_ORIGINS: List[str] = ["http://localhost:8000", "http://localhost:3000"] CORS_ORIGINS: str = "http://localhost:8000,http://localhost:3000" # Logging LOG_LEVEL: str = "INFO" LOG_FILE: str = "logs/app.log" # e-conomic Integration ECONOMIC_ENABLED: bool = False ECONOMIC_API_URL: str = "https://restapi.e-conomic.com" ECONOMIC_APP_SECRET_TOKEN: str = "" ECONOMIC_AGREEMENT_GRANT_TOKEN: str = "" ECONOMIC_READ_ONLY: bool = True ECONOMIC_DRY_RUN: bool = True # Ollama LLM OLLAMA_ENDPOINT: str = "http://localhost:11434" OLLAMA_MODEL: str = "llama3.2:3b" # Email System Configuration # IMAP Settings IMAP_SERVER: str = "" IMAP_PORT: int = 993 IMAP_USERNAME: str = "" IMAP_PASSWORD: str = "" IMAP_USE_SSL: bool = True IMAP_FOLDER: str = "INBOX" IMAP_READ_ONLY: bool = True # Microsoft Graph API (alternative to IMAP) USE_GRAPH_API: bool = False GRAPH_TENANT_ID: str = "" GRAPH_CLIENT_ID: str = "" GRAPH_CLIENT_SECRET: str = "" GRAPH_USER_EMAIL: str = "" # Email Processing Settings EMAIL_TO_TICKET_ENABLED: bool = False EMAIL_RULES_ENABLED: bool = True EMAIL_RULES_AUTO_PROCESS: bool = False EMAIL_AI_ENABLED: bool = False EMAIL_AUTO_CLASSIFY: bool = True # Enable classification by default (uses keywords if AI disabled) EMAIL_AI_CONFIDENCE_THRESHOLD: float = 0.7 EMAIL_MAX_FETCH_PER_RUN: int = 50 EMAIL_PROCESS_INTERVAL_MINUTES: int = 5 EMAIL_WORKFLOWS_ENABLED: bool = True EMAIL_MAX_UPLOAD_SIZE_MB: int = 50 # Max file size for email uploads ALLOWED_EXTENSIONS: List[str] = ["pdf", "jpg", "jpeg", "png", "gif", "doc", "docx", "xls", "xlsx", "zip"] # Allowed file extensions for uploads # vTiger Cloud Integration VTIGER_ENABLED: bool = False VTIGER_URL: str = "" VTIGER_USERNAME: str = "" VTIGER_API_KEY: str = "" # Data Consistency Settings VTIGER_SYNC_ENABLED: bool = True ECONOMIC_SYNC_ENABLED: bool = True AUTO_CHECK_CONSISTENCY: bool = True # Time Tracking Module Settings TIMETRACKING_DEFAULT_HOURLY_RATE: float = 1200.00 TIMETRACKING_AUTO_ROUND: bool = True TIMETRACKING_ROUND_INCREMENT: float = 0.5 TIMETRACKING_ROUND_METHOD: str = "up" # "up", "down", "nearest" # Time Tracking Module Safety Flags TIMETRACKING_VTIGER_READ_ONLY: bool = True TIMETRACKING_VTIGER_DRY_RUN: bool = True TIMETRACKING_ECONOMIC_READ_ONLY: bool = True TIMETRACKING_ECONOMIC_DRY_RUN: bool = True TIMETRACKING_EXPORT_TYPE: str = "draft" # "draft" or "booked" TIMETRACKING_ECONOMIC_LAYOUT: int = 19 # e-conomic invoice layout number (default: 19 = Danish standard) TIMETRACKING_ECONOMIC_PRODUCT: str = "1000" # e-conomic product number for time entries (default: 1000) # Simply-CRM (Old vTiger On-Premise) OLD_VTIGER_URL: str = "" OLD_VTIGER_USERNAME: str = "" OLD_VTIGER_API_KEY: str = "" # Simply-CRM (Separate System) SIMPLYCRM_URL: str = "" SIMPLYCRM_USERNAME: str = "" SIMPLYCRM_API_KEY: str = "" # Backup System Configuration BACKUP_ENABLED: bool = True BACKUP_STORAGE_PATH: str = "/app/backups" BACKUP_DRY_RUN: bool = False BACKUP_READ_ONLY: bool = False BACKUP_RESTORE_DRY_RUN: bool = True # SAFETY: Test restore uden at overskrive data BACKUP_RETENTION_DAYS: int = 30 BACKUP_RETENTION_MONTHLY: int = 12 BACKUP_MAX_SIZE_GB: int = 100 STORAGE_WARNING_THRESHOLD_PCT: int = 80 DB_DAILY_FORMAT: str = "dump" # Compressed format for daily backups DB_MONTHLY_FORMAT: str = "sql" # Plain SQL for monthly backups BACKUP_INCLUDE_UPLOADS: bool = True # Include uploads/ in file backups BACKUP_INCLUDE_LOGS: bool = True # Include logs/ in file backups BACKUP_INCLUDE_DATA: bool = True # Include data/ in file backups UPLOAD_DIR: str = "uploads" # Upload directory path # Offsite Backup Settings (SFTP) OFFSITE_ENABLED: bool = False OFFSITE_WEEKLY_DAY: str = "sunday" OFFSITE_RETRY_DELAY_HOURS: int = 1 OFFSITE_RETRY_MAX_ATTEMPTS: int = 3 SFTP_HOST: str = "" SFTP_PORT: int = 22 SFTP_USER: str = "" SFTP_PASSWORD: str = "" SFTP_REMOTE_PATH: str = "/backups" SSH_KEY_PATH: str = "" # Mattermost Notifications MATTERMOST_WEBHOOK_URL: str = "" MATTERMOST_ENABLED: bool = False MATTERMOST_CHANNEL: str = "" # Deployment Configuration (used by Docker/Podman) POSTGRES_USER: str = "bmc_hub" POSTGRES_PASSWORD: str = "bmc_hub" POSTGRES_DB: str = "bmc_hub" POSTGRES_PORT: int = 5432 CONTAINER_RUNTIME: str = "docker" RELEASE_VERSION: str = "latest" GITEA_URL: str = "https://g.bmcnetworks.dk" GITHUB_TOKEN: str = "" GITHUB_REPO: str = "ct/bmc_hub" # Whisper Transcription WHISPER_ENABLED: bool = True WHISPER_API_URL: str = "http://172.16.31.115:5000/transcribe" WHISPER_TIMEOUT: int = 300 WHISPER_SUPPORTED_FORMATS: List[str] = [".mp3", ".wav", ".m4a", ".ogg"] @field_validator('*', mode='before') @classmethod def strip_whitespace(cls, v): """Strip leading/trailing whitespace from string values""" if isinstance(v, str): return v.strip() return v class Config: env_file = ".env" case_sensitive = True settings = Settings()