Improve base config

This commit is contained in:
Urtzi Alfaro
2025-07-19 21:44:52 +02:00
parent c7fd6135f0
commit 9a67f3d175
11 changed files with 1278 additions and 285 deletions

View File

@@ -1,123 +1,422 @@
# .env.example - Environment Variables Template
# Copy to .env and update values
# ================================================================ # ================================================================
# JWT CONFIGURATION (CRITICAL - CHANGE IN PRODUCTION!) # UPDATED .env.example FILE
# ================================================================ # .env.example
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production-minimum-32-characters-required
# ================================================================
# EXTERNAL API KEYS
# ================================================================ # ================================================================
# AEMET (Spanish Weather Service) API Key
# Get from: https://opendata.aemet.es/centrodedescargas/altaUsuario
AEMET_API_KEY=your-aemet-api-key-here
# Madrid Open Data API Key (Optional)
# Get from: https://datos.madrid.es/portal/site/egob/
MADRID_OPENDATA_API_KEY=your-madrid-opendata-key-here
# ================================================================ # ================================================================
# EMAIL CONFIGURATION (For notifications) # ENVIRONMENT CONFIGURATION
# ================================================================ # ================================================================
# Gmail SMTP Configuration (recommended) # Environment: development, staging, production, testing
SMTP_HOST=smtp.gmail.com ENVIRONMENT=development
SMTP_PORT=587 DEBUG=true
SMTP_USER=your-email@gmail.com LOG_LEVEL=INFO
SMTP_PASSWORD=your-gmail-app-specific-password SERVICE_VERSION=1.0.0
# Alternative: SendGrid
# SMTP_HOST=smtp.sendgrid.net
# SMTP_PORT=587
# SMTP_USER=apikey
# SMTP_PASSWORD=your-sendgrid-api-key
# ================================================================ # ================================================================
# WHATSAPP CONFIGURATION (Twilio) # DATABASE CONFIGURATION
# Each service has its own dedicated database
# ================================================================ # ================================================================
# Twilio WhatsApp Configuration # Auth Service Database
# Get from: https://www.twilio.com/console AUTH_DATABASE_URL=postgresql+asyncpg://auth_user:auth_pass123@auth-db:5432/auth_db
WHATSAPP_ACCOUNT_SID=your-twilio-account-sid
WHATSAPP_AUTH_TOKEN=your-twilio-auth-token # Training Service Database
WHATSAPP_FROM_NUMBER=whatsapp:+14155238886 TRAINING_DATABASE_URL=postgresql+asyncpg://training_user:training_pass123@training-db:5432/training_db
# Forecasting Service Database
FORECASTING_DATABASE_URL=postgresql+asyncpg://forecasting_user:forecasting_pass123@forecasting-db:5432/forecasting_db
# Data Service Database
DATA_DATABASE_URL=postgresql+asyncpg://data_user:data_pass123@data-db:5432/data_db
# Tenant Service Database
TENANT_DATABASE_URL=postgresql+asyncpg://tenant_user:tenant_pass123@tenant-db:5432/tenant_db
# Notification Service Database
NOTIFICATION_DATABASE_URL=postgresql+asyncpg://notification_user:notification_pass123@notification-db:5432/notification_db
# Database Connection Pool Settings
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20
DB_POOL_TIMEOUT=30
DB_POOL_RECYCLE=3600
DB_ECHO=false
# ================================================================ # ================================================================
# DATABASE CONFIGURATION (Auto-configured in Docker) # REDIS CONFIGURATION
# Each service uses a different Redis database
# ================================================================ # ================================================================
# These are set automatically in docker-compose.yml REDIS_URL=redis://redis:6379
# Only change if using external databases REDIS_MAX_CONNECTIONS=50
# AUTH_DATABASE_URL=postgresql+asyncpg://auth_user:auth_pass123@auth-db:5432/auth_db # Redis Database Assignments:
# TENANT_DATABASE_URL=postgresql+asyncpg://tenant_user:tenant_pass123@tenant-db:5432/tenant_db # 0 - Auth Service
# TRAINING_DATABASE_URL=postgresql+asyncpg://training_user:training_pass123@training-db:5432/training_db # 1 - Training Service
# FORECASTING_DATABASE_URL=postgresql+asyncpg://forecasting_user:forecasting_pass123@forecasting-db:5432/forecasting_db # 2 - Forecasting Service
# DATA_DATABASE_URL=postgresql+asyncpg://data_user:data_pass123@data-db:5432/data_db # 3 - Data Service
# NOTIFICATION_DATABASE_URL=postgresql+asyncpg://notification_user:notification_pass123@notification-db:5432/notification_db # 4 - Tenant Service
# 5 - Notification Service
# 6 - Gateway Service
# ================================================================ # ================================================================
# REDIS CONFIGURATION (Auto-configured in Docker) # RABBITMQ CONFIGURATION
# ================================================================ # ================================================================
# REDIS_URL=redis://:redis_pass123@redis:6379 RABBITMQ_URL=amqp://bakery:forecast123@rabbitmq:5672/
RABBITMQ_EXCHANGE=bakery_events
RABBITMQ_QUEUE_PREFIX=bakery
RABBITMQ_RETRY_ATTEMPTS=3
RABBITMQ_RETRY_DELAY=5
# ================================================================ # ================================================================
# RABBITMQ CONFIGURATION (Auto-configured in Docker) # AUTHENTICATION & SECURITY
# ================================================================ # ================================================================
# RABBITMQ_URL=amqp://bakery:forecast123@rabbitmq:5672/ # JWT Configuration (CHANGE IN PRODUCTION!)
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production-very-long-and-secure
# ================================================================ JWT_ALGORITHM=HS256
# CORS CONFIGURATION
# ================================================================
# Allowed origins for CORS (comma-separated)
CORS_ORIGINS=http://localhost:3000,http://localhost:3001,https://yourdomain.com
# ================================================================
# ML/AI CONFIGURATION
# ================================================================
# Model storage configuration
MODEL_STORAGE_PATH=/app/models
MAX_TRAINING_TIME_MINUTES=30
MIN_TRAINING_DATA_DAYS=30
PROPHET_SEASONALITY_MODE=additive
# Prediction caching
PREDICTION_CACHE_TTL_HOURS=6
# ================================================================
# SECURITY CONFIGURATION
# ================================================================
# Password requirements
PASSWORD_MIN_LENGTH=8
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION_MINUTES=30
# Rate limiting
RATE_LIMIT_CALLS_PER_MINUTE=60
RATE_LIMIT_BURST=10
# Session configuration
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30 JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7 JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
# Service-to-Service Authentication
SERVICE_API_KEY=service-api-key-change-in-production
ENABLE_SERVICE_AUTH=false
# Password Requirements
PASSWORD_MIN_LENGTH=8
PASSWORD_REQUIRE_UPPERCASE=true
PASSWORD_REQUIRE_LOWERCASE=true
PASSWORD_REQUIRE_NUMBERS=true
PASSWORD_REQUIRE_SYMBOLS=false
# Security Settings
BCRYPT_ROUNDS=12
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION_MINUTES=30
# ================================================================ # ================================================================
# MONITORING CONFIGURATION # CORS & API CONFIGURATION
# ================================================================ # ================================================================
# Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL CORS_ORIGINS=http://localhost:3000,http://localhost:3001,http://127.0.0.1:3000
LOG_LEVEL=INFO CORS_ALLOW_CREDENTIALS=true
# Service versions # Rate Limiting
SERVICE_VERSION=1.0.0 RATE_LIMIT_ENABLED=true
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=60
RATE_LIMIT_BURST=10
# Data retention # API Documentation
DATA_RETENTION_DAYS=365 API_DOCS_ENABLED=true
# ================================================================
# SERVICE URLS
# ================================================================
GATEWAY_URL=http://gateway:8000
AUTH_SERVICE_URL=http://auth-service:8000
TRAINING_SERVICE_URL=http://training-service:8000
FORECASTING_SERVICE_URL=http://forecasting-service:8000
DATA_SERVICE_URL=http://data-service:8000
TENANT_SERVICE_URL=http://tenant-service:8000
NOTIFICATION_SERVICE_URL=http://notification-service:8000
# HTTP Client Settings
HTTP_TIMEOUT=30
HTTP_RETRIES=3
HTTP_RETRY_DELAY=1.0
# ================================================================
# EXTERNAL APIS & INTEGRATIONS
# ================================================================
# Spanish Weather Service (AEMET)
AEMET_API_KEY=your-aemet-api-key-here
AEMET_TIMEOUT=30
AEMET_RETRY_ATTEMPTS=3
# Madrid Open Data Platform
MADRID_OPENDATA_API_KEY=your-madrid-opendata-key-here
MADRID_OPENDATA_TIMEOUT=30
# Email Configuration (Gmail example)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-email-app-password
SMTP_TLS=true
SMTP_SSL=false
DEFAULT_FROM_EMAIL=noreply@bakeryforecast.es
DEFAULT_FROM_NAME=Bakery Forecast
# WhatsApp API (Twilio example)
WHATSAPP_API_KEY=your-whatsapp-api-key-here
WHATSAPP_BASE_URL=https://api.twilio.com
WHATSAPP_FROM_NUMBER=whatsapp:+14155238886
# ================================================================
# ML & AI CONFIGURATION
# ================================================================
# Model Storage
MODEL_STORAGE_PATH=/app/models
MODEL_STORAGE_BACKEND=local
MODEL_BACKUP_ENABLED=true
MODEL_VERSIONING_ENABLED=true
# Training Configuration
MAX_TRAINING_TIME_MINUTES=30
MAX_CONCURRENT_TRAINING_JOBS=3
MIN_TRAINING_DATA_DAYS=30
TRAINING_BATCH_SIZE=1000
# Prophet Configuration
PROPHET_SEASONALITY_MODE=additive
PROPHET_CHANGEPOINT_PRIOR_SCALE=0.05
PROPHET_SEASONALITY_PRIOR_SCALE=10.0
PROPHET_HOLIDAYS_PRIOR_SCALE=10.0
# Prediction Caching
PREDICTION_CACHE_TTL_HOURS=6
WEATHER_CACHE_TTL_HOURS=1 WEATHER_CACHE_TTL_HOURS=1
TRAFFIC_CACHE_TTL_HOURS=1 TRAFFIC_CACHE_TTL_HOURS=1
# ================================================================
# BUSINESS CONFIGURATION
# ================================================================
# Forecasting Limits
MAX_FORECAST_DAYS=30
MIN_HISTORICAL_DAYS=60
PREDICTION_CONFIDENCE_THRESHOLD=0.8
# Spanish Business Context
TIMEZONE=Europe/Madrid
LOCALE=es_ES.UTF-8
CURRENCY=EUR
BUSINESS_HOUR_START=7
BUSINESS_HOUR_END=20
# Spanish Holidays & Seasonal Adjustments
ENABLE_SPANISH_HOLIDAYS=true
ENABLE_MADRID_HOLIDAYS=true
SCHOOL_CALENDAR_ENABLED=true
# Weather Impact Modeling
WEATHER_IMPACT_ENABLED=true
TEMPERATURE_THRESHOLD_COLD=10.0
TEMPERATURE_THRESHOLD_HOT=30.0
RAIN_IMPACT_FACTOR=0.7
# Business Adjustments
WEEKEND_ADJUSTMENT_FACTOR=0.8
HOLIDAY_ADJUSTMENT_FACTOR=0.5
# ================================================================
# TENANT & SUBSCRIPTION CONFIGURATION
# ================================================================
# Default Settings
DEFAULT_PLAN=basic
TRIAL_PERIOD_DAYS=14
# Plan Limits
BASIC_PLAN_LOCATIONS=1
BASIC_PLAN_PREDICTIONS_PER_DAY=100
BASIC_PLAN_DATA_RETENTION_DAYS=90
PREMIUM_PLAN_LOCATIONS=5
PREMIUM_PLAN_PREDICTIONS_PER_DAY=1000
PREMIUM_PLAN_DATA_RETENTION_DAYS=365
ENTERPRISE_PLAN_LOCATIONS=50
ENTERPRISE_PLAN_PREDICTIONS_PER_DAY=10000
ENTERPRISE_PLAN_DATA_RETENTION_DAYS=1095
# Billing (disabled by default)
BILLING_ENABLED=false
BILLING_CURRENCY=EUR
BILLING_CYCLE_DAYS=30
SPANISH_TAX_RATE=0.21
# Resource Limits
MAX_API_CALLS_PER_MINUTE=100
MAX_STORAGE_MB=1024
MAX_CONCURRENT_REQUESTS=10
# ================================================================
# MONITORING & OBSERVABILITY
# ================================================================
# Logging Configuration
LOG_FORMAT=json
LOG_FILE_ENABLED=false
LOG_FILE_PATH=/app/logs
LOG_ROTATION_SIZE=100MB
LOG_RETENTION_DAYS=30
# Metrics & Monitoring
PROMETHEUS_ENABLED=true
PROMETHEUS_PORT=9090
# Tracing (disabled by default)
JAEGER_ENABLED=false
JAEGER_AGENT_HOST=localhost
JAEGER_AGENT_PORT=6831
# Health Checks
HEALTH_CHECK_TIMEOUT=30
HEALTH_CHECK_INTERVAL=30
# ================================================================
# DATA RETENTION & CLEANUP
# ================================================================
DATA_RETENTION_DAYS=365
LOG_RETENTION_DAYS=90
METRIC_RETENTION_DAYS=90
TEMP_FILE_CLEANUP_HOURS=24
# Service-specific Data Retention
AUTH_DATA_RETENTION_DAYS=365
RAW_DATA_RETENTION_DAYS=90
PROCESSED_DATA_RETENTION_DAYS=365
# ================================================================
# DEVELOPMENT & TESTING
# ================================================================
# Development Features
AUTO_RELOAD=false
PROFILING_ENABLED=false
MOCK_EXTERNAL_APIS=false
# Testing Configuration
TESTING=false
TEST_DATABASE_URL=postgresql+asyncpg://test_user:test_pass@test-db:5432/test_db
# Data Collection Intervals
WEATHER_COLLECTION_INTERVAL_HOURS=1
TRAFFIC_COLLECTION_INTERVAL_HOURS=1
EVENTS_COLLECTION_INTERVAL_HOURS=6
# Data Quality
DATA_VALIDATION_ENABLED=true
OUTLIER_DETECTION_ENABLED=true
DATA_COMPLETENESS_THRESHOLD=0.8
# Geolocation (Madrid, Spain)
DEFAULT_LATITUDE=40.4168
DEFAULT_LONGITUDE=-3.7038
LOCATION_RADIUS_KM=50.0
# ================================================================
# NOTIFICATION CONFIGURATION
# ================================================================
# Notification Types
ENABLE_EMAIL_NOTIFICATIONS=true
ENABLE_WHATSAPP_NOTIFICATIONS=true
ENABLE_PUSH_NOTIFICATIONS=false
# Notification Queuing
MAX_RETRY_ATTEMPTS=3
RETRY_DELAY_SECONDS=60
NOTIFICATION_BATCH_SIZE=100
# Rate Limiting
EMAIL_RATE_LIMIT_PER_HOUR=1000
WHATSAPP_RATE_LIMIT_PER_HOUR=100
# Localization
DEFAULT_LANGUAGE=es
DATE_FORMAT=%d/%m/%Y
TIME_FORMAT=%H:%M
# Templates
EMAIL_TEMPLATES_PATH=/app/templates/email
WHATSAPP_TEMPLATES_PATH=/app/templates/whatsapp
# Delivery & Analytics
IMMEDIATE_DELIVERY=true
SCHEDULED_DELIVERY_ENABLED=true
DELIVERY_TRACKING_ENABLED=true
OPEN_TRACKING_ENABLED=true
CLICK_TRACKING_ENABLED=true
# ================================================================
# COMPLIANCE & GDPR
# ================================================================
# GDPR Compliance
GDPR_COMPLIANCE_ENABLED=true
CONSENT_REQUIRED=true
DATA_EXPORT_ENABLED=true
DATA_DELETION_ENABLED=true
PRIVACY_POLICY_URL=/privacy
# Email Verification
EMAIL_VERIFICATION_REQUIRED=true
EMAIL_VERIFICATION_EXPIRE_HOURS=24
# Account Security
ACCOUNT_LOCKOUT_ENABLED=true
PASSWORD_HISTORY_COUNT=5
SESSION_TIMEOUT_MINUTES=60
CONCURRENT_SESSIONS_LIMIT=3
# ================================================================
# PERFORMANCE & OPTIMIZATION
# ================================================================
# Caching
REALTIME_FORECASTING_ENABLED=true
FORECAST_UPDATE_INTERVAL_HOURS=6
# Batch Processing
BATCH_PROCESSING_ENABLED=true
BATCH_SIZE=1000
PARALLEL_PROCESSING_WORKERS=4
FORECAST_BATCH_SIZE=100
# Circuit Breaker (Gateway)
CIRCUIT_BREAKER_ENABLED=true
CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
CIRCUIT_BREAKER_RECOVERY_TIMEOUT=60
# Load Balancing (Gateway)
ENABLE_LOAD_BALANCING=true
LOAD_BALANCER_ALGORITHM=round_robin
# Request Limits
MAX_REQUEST_SIZE=10485760
REQUEST_TIMEOUT=30
# ================================================================
# BUSINESS INTELLIGENCE & ALERTS
# ================================================================
# Alert Thresholds
HIGH_DEMAND_THRESHOLD=1.5
LOW_DEMAND_THRESHOLD=0.5
STOCKOUT_RISK_THRESHOLD=0.9
# Model Validation
CROSS_VALIDATION_ENABLED=true
VALIDATION_SPLIT_RATIO=0.2
MIN_MODEL_ACCURACY=0.7
# Data Processing
DATA_PREPROCESSING_ENABLED=true
SEASONAL_DECOMPOSITION_ENABLED=true
# Distributed Training (Future scaling)
DISTRIBUTED_TRAINING_ENABLED=false
TRAINING_WORKER_COUNT=1
# Support & Contact
SUPPORT_EMAIL=soporte@bakeryforecast.es
INVOICE_LANGUAGE=es

View File

@@ -1,65 +1,46 @@
# ================================================================
# GATEWAY SERVICE CONFIGURATION
# gateway/app/core/config.py
# ================================================================
""" """
Gateway configuration Gateway service configuration
Central API Gateway for all microservices
""" """
from shared.config.base import BaseServiceSettings
import os import os
from typing import List, Dict from typing import Dict, List
from pydantic_settings import BaseSettings
class Settings(BaseSettings): class GatewaySettings(BaseServiceSettings):
"""Application settings""" """Gateway-specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "Bakery Forecasting Gateway" APP_NAME: str = "Bakery Forecasting Gateway"
VERSION: str = "1.0.0" SERVICE_NAME: str = "gateway"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "API Gateway for Bakery Forecasting Platform"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Service URLs # Gateway-specific Redis database
AUTH_SERVICE_URL: str = "http://auth-service:8000" REDIS_DB: int = 6
TRAINING_SERVICE_URL: str = "http://training-service:8000"
FORECASTING_SERVICE_URL: str = "http://forecasting-service:8000"
DATA_SERVICE_URL: str = "http://data-service:8000"
TENANT_SERVICE_URL: str = "http://tenant-service:8000"
NOTIFICATION_SERVICE_URL: str = "http://notification-service:8000"
# Service Discovery # Service Discovery
CONSUL_URL: str = os.getenv("CONSUL_URL", "http://consul:8500") CONSUL_URL: str = os.getenv("CONSUL_URL", "http://consul:8500")
ENABLE_SERVICE_DISCOVERY: bool = os.getenv("ENABLE_SERVICE_DISCOVERY", "false").lower() == "true" ENABLE_SERVICE_DISCOVERY: bool = os.getenv("ENABLE_SERVICE_DISCOVERY", "false").lower() == "true"
# CORS
CORS_ORIGINS: str = os.getenv("CORS_ORIGINS", "http://localhost:3000,http://localhost:3001")
@property
def CORS_ORIGINS_LIST(self) -> List[str]:
"""Get CORS origins as list"""
return [origin.strip() for origin in self.CORS_ORIGINS.split(",")]
# Redis settings # Load Balancing
REDIS_URL: str = "redis://redis:6379/6" ENABLE_LOAD_BALANCING: bool = os.getenv("ENABLE_LOAD_BALANCING", "true").lower() == "true"
LOAD_BALANCER_ALGORITHM: str = os.getenv("LOAD_BALANCER_ALGORITHM", "round_robin")
# Rate limiting # Circuit Breaker
RATE_LIMIT_REQUESTS: int = 100 CIRCUIT_BREAKER_ENABLED: bool = os.getenv("CIRCUIT_BREAKER_ENABLED", "true").lower() == "true"
RATE_LIMIT_WINDOW: int = 60 CIRCUIT_BREAKER_FAILURE_THRESHOLD: int = int(os.getenv("CIRCUIT_BREAKER_FAILURE_THRESHOLD", "5"))
CIRCUIT_BREAKER_RECOVERY_TIMEOUT: int = int(os.getenv("CIRCUIT_BREAKER_RECOVERY_TIMEOUT", "60"))
# JWT settings # Request/Response Settings
JWT_SECRET_KEY: str = "your-super-secret-jwt-key-change-in-production" MAX_REQUEST_SIZE: int = int(os.getenv("MAX_REQUEST_SIZE", "10485760")) # 10MB
JWT_ALGORITHM: str = "HS256" REQUEST_TIMEOUT: int = int(os.getenv("REQUEST_TIMEOUT", "30"))
@property # Gateway doesn't need a database
def SERVICES(self) -> Dict[str, str]: DATABASE_URL: str = ""
"""Service registry"""
return {
"auth": self.AUTH_SERVICE_URL,
"training": self.TRAINING_SERVICE_URL,
"forecasting": self.FORECASTING_SERVICE_URL,
"data": self.DATA_SERVICE_URL,
"tenant": self.TENANT_SERVICE_URL,
"notification": self.NOTIFICATION_SERVICE_URL
}
class Config: settings = GatewaySettings()
env_file = ".env"
settings = Settings()

View File

@@ -1,47 +1,56 @@
# ================================================================
# AUTH SERVICE CONFIGURATION
# services/auth/app/core/config.py
# ================================================================
""" """
Authentication service configuration Authentication service configuration
User management and JWT token handling
""" """
from shared.config.base import BaseServiceSettings
import os import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings): class AuthSettings(BaseServiceSettings):
"""Application settings""" """Auth service specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "Authentication Service" APP_NAME: str = "Authentication Service"
VERSION: str = "1.0.0" SERVICE_NAME: str = "auth-service"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "User authentication and authorization service"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Database settings # Database Configuration
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://auth_user:auth_pass123@auth-db:5432/auth_db") DATABASE_URL: str = os.getenv("AUTH_DATABASE_URL",
"postgresql+asyncpg://auth_user:auth_pass123@auth-db:5432/auth_db")
# Redis settings # Redis Database (dedicated for auth)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/0") REDIS_DB: int = 0
# JWT settings # Enhanced Password Requirements for Spain
JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "your-super-secret-jwt-key-change-in-production")
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("JWT_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = int(os.getenv("JWT_REFRESH_TOKEN_EXPIRE_DAYS", "7"))
# Password settings
PASSWORD_MIN_LENGTH: int = 8 PASSWORD_MIN_LENGTH: int = 8
PASSWORD_REQUIRE_UPPERCASE: bool = True PASSWORD_REQUIRE_UPPERCASE: bool = True
PASSWORD_REQUIRE_LOWERCASE: bool = True PASSWORD_REQUIRE_LOWERCASE: bool = True
PASSWORD_REQUIRE_NUMBERS: bool = True PASSWORD_REQUIRE_NUMBERS: bool = True
PASSWORD_REQUIRE_SYMBOLS: bool = False PASSWORD_REQUIRE_SYMBOLS: bool = False
# Security settings # Spanish GDPR Compliance
BCRYPT_ROUNDS: int = 12 GDPR_COMPLIANCE_ENABLED: bool = True
DATA_RETENTION_DAYS: int = int(os.getenv("AUTH_DATA_RETENTION_DAYS", "365"))
CONSENT_REQUIRED: bool = True
PRIVACY_POLICY_URL: str = os.getenv("PRIVACY_POLICY_URL", "/privacy")
# Account Security
ACCOUNT_LOCKOUT_ENABLED: bool = True
MAX_LOGIN_ATTEMPTS: int = 5 MAX_LOGIN_ATTEMPTS: int = 5
LOCKOUT_DURATION_MINUTES: int = 30 LOCKOUT_DURATION_MINUTES: int = 30
PASSWORD_HISTORY_COUNT: int = 5
# RabbitMQ settings # Session Management
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/") SESSION_TIMEOUT_MINUTES: int = int(os.getenv("SESSION_TIMEOUT_MINUTES", "60"))
CONCURRENT_SESSIONS_LIMIT: int = int(os.getenv("CONCURRENT_SESSIONS_LIMIT", "3"))
class Config: # Email Verification
env_file = ".env" EMAIL_VERIFICATION_REQUIRED: bool = os.getenv("EMAIL_VERIFICATION_REQUIRED", "true").lower() == "true"
EMAIL_VERIFICATION_EXPIRE_HOURS: int = int(os.getenv("EMAIL_VERIFICATION_EXPIRE_HOURS", "24"))
settings = Settings() settings = AuthSettings()

View File

@@ -1,37 +1,68 @@
"""Data service configuration""" # ================================================================
# DATA SERVICE CONFIGURATION
# services/data/app/core/config.py
# ================================================================
from pydantic_settings import BaseSettings """
from typing import List Data service configuration
External data integration and management
"""
class Settings(BaseSettings): from shared.config.base import BaseServiceSettings
# Database import os
DATABASE_URL: str = "postgresql+asyncpg://data_user:data_pass123@data-db:5432/data_db"
class DataSettings(BaseServiceSettings):
"""Data service specific settings"""
# Redis # Service Identity
REDIS_URL: str = "redis://redis:6379/3" APP_NAME: str = "Data Service"
# RabbitMQ
RABBITMQ_URL: str = "amqp://bakery:forecast123@rabbitmq:5672/"
# External APIs
AEMET_API_KEY: str = "your-aemet-api-key-here"
MADRID_OPENDATA_API_KEY: str = "your-madrid-opendata-key-here"
# Service settings
SERVICE_NAME: str = "data-service" SERVICE_NAME: str = "data-service"
SERVICE_VERSION: str = "1.0.0" DESCRIPTION: str = "External data integration and management service"
# Auth # Database Configuration
AUTH_SERVICE_URL: str = "http://auth-service:8000" DATABASE_URL: str = os.getenv("DATA_DATABASE_URL",
"postgresql+asyncpg://data_user:data_pass123@data-db:5432/data_db")
# CORS # Redis Database (dedicated for external data cache)
CORS_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:3001"] REDIS_DB: int = 3
# Monitoring # External API Configuration
LOG_LEVEL: str = "INFO" AEMET_API_KEY: str = os.getenv("AEMET_API_KEY", "")
ENABLE_METRICS: bool = True AEMET_BASE_URL: str = "https://opendata.aemet.es/opendata"
AEMET_TIMEOUT: int = int(os.getenv("AEMET_TIMEOUT", "30"))
AEMET_RETRY_ATTEMPTS: int = int(os.getenv("AEMET_RETRY_ATTEMPTS", "3"))
class Config: MADRID_OPENDATA_API_KEY: str = os.getenv("MADRID_OPENDATA_API_KEY", "")
env_file = ".env" MADRID_OPENDATA_BASE_URL: str = "https://datos.madrid.es"
MADRID_OPENDATA_TIMEOUT: int = int(os.getenv("MADRID_OPENDATA_TIMEOUT", "30"))
# Data Collection Configuration
WEATHER_COLLECTION_INTERVAL_HOURS: int = int(os.getenv("WEATHER_COLLECTION_INTERVAL_HOURS", "1"))
TRAFFIC_COLLECTION_INTERVAL_HOURS: int = int(os.getenv("TRAFFIC_COLLECTION_INTERVAL_HOURS", "1"))
EVENTS_COLLECTION_INTERVAL_HOURS: int = int(os.getenv("EVENTS_COLLECTION_INTERVAL_HOURS", "6"))
# Cache TTL Configuration
WEATHER_CACHE_TTL_HOURS: int = int(os.getenv("WEATHER_CACHE_TTL_HOURS", "1"))
TRAFFIC_CACHE_TTL_HOURS: int = int(os.getenv("TRAFFIC_CACHE_TTL_HOURS", "1"))
EVENTS_CACHE_TTL_HOURS: int = int(os.getenv("EVENTS_CACHE_TTL_HOURS", "6"))
# Data Quality Configuration
DATA_VALIDATION_ENABLED: bool = os.getenv("DATA_VALIDATION_ENABLED", "true").lower() == "true"
OUTLIER_DETECTION_ENABLED: bool = os.getenv("OUTLIER_DETECTION_ENABLED", "true").lower() == "true"
DATA_COMPLETENESS_THRESHOLD: float = float(os.getenv("DATA_COMPLETENESS_THRESHOLD", "0.8"))
# Geolocation Settings (Madrid focus)
DEFAULT_LATITUDE: float = float(os.getenv("DEFAULT_LATITUDE", "40.4168")) # Madrid
DEFAULT_LONGITUDE: float = float(os.getenv("DEFAULT_LONGITUDE", "-3.7038")) # Madrid
LOCATION_RADIUS_KM: float = float(os.getenv("LOCATION_RADIUS_KM", "50.0"))
# Data Retention
RAW_DATA_RETENTION_DAYS: int = int(os.getenv("RAW_DATA_RETENTION_DAYS", "90"))
PROCESSED_DATA_RETENTION_DAYS: int = int(os.getenv("PROCESSED_DATA_RETENTION_DAYS", "365"))
# Batch Processing
BATCH_PROCESSING_ENABLED: bool = os.getenv("BATCH_PROCESSING_ENABLED", "true").lower() == "true"
BATCH_SIZE: int = int(os.getenv("BATCH_SIZE", "1000"))
PARALLEL_PROCESSING_WORKERS: int = int(os.getenv("PARALLEL_PROCESSING_WORKERS", "4"))
settings = Settings() settings = DataSettings()

View File

@@ -1,32 +1,59 @@
# ================================================================
# FORECASTING SERVICE CONFIGURATION
# services/forecasting/app/core/config.py
# ================================================================
""" """
uLuforecasting service configuration Forecasting service configuration
Demand prediction and forecasting
""" """
from shared.config.base import BaseServiceSettings
import os import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings): class ForecastingSettings(BaseServiceSettings):
"""Application settings""" """Forecasting service specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "uLuforecasting Service" APP_NAME: str = "Forecasting Service"
VERSION: str = "1.0.0" SERVICE_NAME: str = "forecasting-service"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "Demand prediction and forecasting service"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Database settings # Database Configuration
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://forecasting_user:forecasting_pass123@forecasting-db:5432/forecasting_db") DATABASE_URL: str = os.getenv("FORECASTING_DATABASE_URL",
"postgresql+asyncpg://forecasting_user:forecasting_pass123@forecasting-db:5432/forecasting_db")
# Redis settings # Redis Database (dedicated for prediction cache)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/0") REDIS_DB: int = 2
# RabbitMQ settings # Prediction Configuration
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/") MAX_FORECAST_DAYS: int = int(os.getenv("MAX_FORECAST_DAYS", "30"))
MIN_HISTORICAL_DAYS: int = int(os.getenv("MIN_HISTORICAL_DAYS", "60"))
PREDICTION_CONFIDENCE_THRESHOLD: float = float(os.getenv("PREDICTION_CONFIDENCE_THRESHOLD", "0.8"))
# Service URLs # Caching Configuration
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000") PREDICTION_CACHE_TTL_HOURS: int = int(os.getenv("PREDICTION_CACHE_TTL_HOURS", "6"))
FORECAST_BATCH_SIZE: int = int(os.getenv("FORECAST_BATCH_SIZE", "100"))
class Config: # Real-time Forecasting
env_file = ".env" REALTIME_FORECASTING_ENABLED: bool = os.getenv("REALTIME_FORECASTING_ENABLED", "true").lower() == "true"
FORECAST_UPDATE_INTERVAL_HOURS: int = int(os.getenv("FORECAST_UPDATE_INTERVAL_HOURS", "6"))
# Business Rules for Spanish Bakeries
BUSINESS_HOUR_START: int = 7 # 7 AM
BUSINESS_HOUR_END: int = 20 # 8 PM
WEEKEND_ADJUSTMENT_FACTOR: float = float(os.getenv("WEEKEND_ADJUSTMENT_FACTOR", "0.8"))
HOLIDAY_ADJUSTMENT_FACTOR: float = float(os.getenv("HOLIDAY_ADJUSTMENT_FACTOR", "0.5"))
# Weather Impact Modeling
WEATHER_IMPACT_ENABLED: bool = os.getenv("WEATHER_IMPACT_ENABLED", "true").lower() == "true"
TEMPERATURE_THRESHOLD_COLD: float = float(os.getenv("TEMPERATURE_THRESHOLD_COLD", "10.0"))
TEMPERATURE_THRESHOLD_HOT: float = float(os.getenv("TEMPERATURE_THRESHOLD_HOT", "30.0"))
RAIN_IMPACT_FACTOR: float = float(os.getenv("RAIN_IMPACT_FACTOR", "0.7"))
# Alert Thresholds
HIGH_DEMAND_THRESHOLD: float = float(os.getenv("HIGH_DEMAND_THRESHOLD", "1.5"))
LOW_DEMAND_THRESHOLD: float = float(os.getenv("LOW_DEMAND_THRESHOLD", "0.5"))
STOCKOUT_RISK_THRESHOLD: float = float(os.getenv("STOCKOUT_RISK_THRESHOLD", "0.9"))
settings = Settings() settings = ForecastingSettings()

View File

@@ -1,32 +1,83 @@
# ================================================================
# NOTIFICATION SERVICE CONFIGURATION
# services/notification/app/core/config.py
# ================================================================
""" """
uLunotification service configuration Notification service configuration
Email and WhatsApp notification handling
""" """
from shared.config.base import BaseServiceSettings
import os import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings): class NotificationSettings(BaseServiceSettings):
"""Application settings""" """Notification service specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "uLunotification Service" APP_NAME: str = "Notification Service"
VERSION: str = "1.0.0" SERVICE_NAME: str = "notification-service"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "Email and WhatsApp notification service"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Database settings # Database Configuration
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://notification_user:notification_pass123@notification-db:5432/notification_db") DATABASE_URL: str = os.getenv("NOTIFICATION_DATABASE_URL",
"postgresql+asyncpg://notification_user:notification_pass123@notification-db:5432/notification_db")
# Redis settings # Redis Database (dedicated for notification queue)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/0") REDIS_DB: int = 5
# RabbitMQ settings # Email Configuration
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/") SMTP_HOST: str = os.getenv("SMTP_HOST", "smtp.gmail.com")
SMTP_PORT: int = int(os.getenv("SMTP_PORT", "587"))
SMTP_USER: str = os.getenv("SMTP_USER", "")
SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD", "")
SMTP_TLS: bool = os.getenv("SMTP_TLS", "true").lower() == "true"
SMTP_SSL: bool = os.getenv("SMTP_SSL", "false").lower() == "true"
# Service URLs # Email Settings
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000") DEFAULT_FROM_EMAIL: str = os.getenv("DEFAULT_FROM_EMAIL", "noreply@bakeryforecast.es")
DEFAULT_FROM_NAME: str = os.getenv("DEFAULT_FROM_NAME", "Bakery Forecast")
EMAIL_TEMPLATES_PATH: str = os.getenv("EMAIL_TEMPLATES_PATH", "/app/templates/email")
class Config: # WhatsApp Configuration
env_file = ".env" WHATSAPP_API_KEY: str = os.getenv("WHATSAPP_API_KEY", "")
WHATSAPP_BASE_URL: str = os.getenv("WHATSAPP_BASE_URL", "https://api.twilio.com")
WHATSAPP_FROM_NUMBER: str = os.getenv("WHATSAPP_FROM_NUMBER", "")
WHATSAPP_TEMPLATES_PATH: str = os.getenv("WHATSAPP_TEMPLATES_PATH", "/app/templates/whatsapp")
# Notification Queuing
MAX_RETRY_ATTEMPTS: int = int(os.getenv("MAX_RETRY_ATTEMPTS", "3"))
RETRY_DELAY_SECONDS: int = int(os.getenv("RETRY_DELAY_SECONDS", "60"))
BATCH_SIZE: int = int(os.getenv("NOTIFICATION_BATCH_SIZE", "100"))
# Rate Limiting
EMAIL_RATE_LIMIT_PER_HOUR: int = int(os.getenv("EMAIL_RATE_LIMIT_PER_HOUR", "1000"))
WHATSAPP_RATE_LIMIT_PER_HOUR: int = int(os.getenv("WHATSAPP_RATE_LIMIT_PER_HOUR", "100"))
# Spanish Localization
DEFAULT_LANGUAGE: str = os.getenv("DEFAULT_LANGUAGE", "es")
TIMEZONE: str = "Europe/Madrid"
DATE_FORMAT: str = "%d/%m/%Y"
TIME_FORMAT: str = "%H:%M"
# Notification Types
ENABLE_EMAIL_NOTIFICATIONS: bool = os.getenv("ENABLE_EMAIL_NOTIFICATIONS", "true").lower() == "true"
ENABLE_WHATSAPP_NOTIFICATIONS: bool = os.getenv("ENABLE_WHATSAPP_NOTIFICATIONS", "true").lower() == "true"
ENABLE_PUSH_NOTIFICATIONS: bool = os.getenv("ENABLE_PUSH_NOTIFICATIONS", "false").lower() == "true"
# Template Categories
ALERT_TEMPLATES_ENABLED: bool = True
MARKETING_TEMPLATES_ENABLED: bool = os.getenv("MARKETING_TEMPLATES_ENABLED", "false").lower() == "true"
TRANSACTIONAL_TEMPLATES_ENABLED: bool = True
# Delivery Configuration
IMMEDIATE_DELIVERY: bool = os.getenv("IMMEDIATE_DELIVERY", "true").lower() == "true"
SCHEDULED_DELIVERY_ENABLED: bool = os.getenv("SCHEDULED_DELIVERY_ENABLED", "true").lower() == "true"
BULK_DELIVERY_ENABLED: bool = os.getenv("BULK_DELIVERY_ENABLED", "true").lower() == "true"
# Analytics
DELIVERY_TRACKING_ENABLED: bool = os.getenv("DELIVERY_TRACKING_ENABLED", "true").lower() == "true"
OPEN_TRACKING_ENABLED: bool = os.getenv("OPEN_TRACKING_ENABLED", "true").lower() == "true"
CLICK_TRACKING_ENABLED: bool = os.getenv("CLICK_TRACKING_ENABLED", "true").lower() == "true"
settings = Settings() settings = NotificationSettings()

View File

@@ -1,32 +1,70 @@
# ================================================================
# TENANT SERVICE CONFIGURATION
# services/tenant/app/core/config.py
# ================================================================
""" """
uLutenant service configuration Tenant service configuration
Multi-tenant management and subscription handling
""" """
from shared.config.base import BaseServiceSettings
import os import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings): class TenantSettings(BaseServiceSettings):
"""Application settings""" """Tenant service specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "uLutenant Service" APP_NAME: str = "Tenant Service"
VERSION: str = "1.0.0" SERVICE_NAME: str = "tenant-service"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "Multi-tenant management and subscription service"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Database settings # Database Configuration
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://tenant_user:tenant_pass123@tenant-db:5432/tenant_db") DATABASE_URL: str = os.getenv("TENANT_DATABASE_URL",
"postgresql+asyncpg://tenant_user:tenant_pass123@tenant-db:5432/tenant_db")
# Redis settings # Redis Database (dedicated for tenant data)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/0") REDIS_DB: int = 4
# RabbitMQ settings # Subscription Plans
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/") DEFAULT_PLAN: str = os.getenv("DEFAULT_PLAN", "basic")
TRIAL_PERIOD_DAYS: int = int(os.getenv("TRIAL_PERIOD_DAYS", "14"))
# Service URLs # Plan Limits
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000") BASIC_PLAN_LOCATIONS: int = int(os.getenv("BASIC_PLAN_LOCATIONS", "1"))
BASIC_PLAN_PREDICTIONS_PER_DAY: int = int(os.getenv("BASIC_PLAN_PREDICTIONS_PER_DAY", "100"))
BASIC_PLAN_DATA_RETENTION_DAYS: int = int(os.getenv("BASIC_PLAN_DATA_RETENTION_DAYS", "90"))
class Config: PREMIUM_PLAN_LOCATIONS: int = int(os.getenv("PREMIUM_PLAN_LOCATIONS", "5"))
env_file = ".env" PREMIUM_PLAN_PREDICTIONS_PER_DAY: int = int(os.getenv("PREMIUM_PLAN_PREDICTIONS_PER_DAY", "1000"))
PREMIUM_PLAN_DATA_RETENTION_DAYS: int = int(os.getenv("PREMIUM_PLAN_DATA_RETENTION_DAYS", "365"))
ENTERPRISE_PLAN_LOCATIONS: int = int(os.getenv("ENTERPRISE_PLAN_LOCATIONS", "50"))
ENTERPRISE_PLAN_PREDICTIONS_PER_DAY: int = int(os.getenv("ENTERPRISE_PLAN_PREDICTIONS_PER_DAY", "10000"))
ENTERPRISE_PLAN_DATA_RETENTION_DAYS: int = int(os.getenv("ENTERPRISE_PLAN_DATA_RETENTION_DAYS", "1095"))
# Billing Configuration
BILLING_ENABLED: bool = os.getenv("BILLING_ENABLED", "false").lower() == "true"
BILLING_CURRENCY: str = os.getenv("BILLING_CURRENCY", "EUR")
BILLING_CYCLE_DAYS: int = int(os.getenv("BILLING_CYCLE_DAYS", "30"))
# Resource Limits
MAX_API_CALLS_PER_MINUTE: int = int(os.getenv("MAX_API_CALLS_PER_MINUTE", "100"))
MAX_STORAGE_MB: int = int(os.getenv("MAX_STORAGE_MB", "1024"))
MAX_CONCURRENT_REQUESTS: int = int(os.getenv("MAX_CONCURRENT_REQUESTS", "10"))
# Spanish Business Configuration
SPANISH_TAX_RATE: float = float(os.getenv("SPANISH_TAX_RATE", "0.21")) # IVA 21%
INVOICE_LANGUAGE: str = os.getenv("INVOICE_LANGUAGE", "es")
SUPPORT_EMAIL: str = os.getenv("SUPPORT_EMAIL", "soporte@bakeryforecast.es")
# Onboarding
ONBOARDING_ENABLED: bool = os.getenv("ONBOARDING_ENABLED", "true").lower() == "true"
DEMO_DATA_ENABLED: bool = os.getenv("DEMO_DATA_ENABLED", "true").lower() == "true"
# Compliance
GDPR_COMPLIANCE_ENABLED: bool = True
DATA_EXPORT_ENABLED: bool = True
DATA_DELETION_ENABLED: bool = True
settings = Settings() settings = TenantSettings()

View File

@@ -1,53 +1,65 @@
# ================================================================
# TRAINING SERVICE CONFIGURATION
# services/training/app/core/config.py
# ================================================================
""" """
Training service configuration Training service configuration
ML model training and management
""" """
from shared.config.base import BaseServiceSettings
import os import os
from pydantic_settings import BaseSettings
from typing import List
class Settings(BaseSettings): class TrainingSettings(BaseServiceSettings):
"""Application settings""" """Training service specific settings"""
# Basic settings # Service Identity
APP_NAME: str = "Training Service" APP_NAME: str = "Training Service"
VERSION: str = "1.0.0" SERVICE_NAME: str = "training-service"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" DESCRIPTION: str = "Machine learning model training service"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Database settings # Database Configuration
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://training_user:training_pass123@training-db:5432/training_db") DATABASE_URL: str = os.getenv("TRAINING_DATABASE_URL",
"postgresql+asyncpg://training_user:training_pass123@training-db:5432/training_db")
# Redis settings # Redis Database (dedicated for training cache)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/1") REDIS_DB: int = 1
# RabbitMQ settings # ML Model Storage
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/")
# Service URLs
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000")
DATA_SERVICE_URL: str = os.getenv("DATA_SERVICE_URL", "http://data-service:8000")
# ML Settings
MODEL_STORAGE_PATH: str = os.getenv("MODEL_STORAGE_PATH", "/app/models") MODEL_STORAGE_PATH: str = os.getenv("MODEL_STORAGE_PATH", "/app/models")
MODEL_BACKUP_ENABLED: bool = os.getenv("MODEL_BACKUP_ENABLED", "true").lower() == "true"
MODEL_VERSIONING_ENABLED: bool = os.getenv("MODEL_VERSIONING_ENABLED", "true").lower() == "true"
# Training Configuration
MAX_TRAINING_TIME_MINUTES: int = int(os.getenv("MAX_TRAINING_TIME_MINUTES", "30")) MAX_TRAINING_TIME_MINUTES: int = int(os.getenv("MAX_TRAINING_TIME_MINUTES", "30"))
MAX_CONCURRENT_TRAINING_JOBS: int = int(os.getenv("MAX_CONCURRENT_TRAINING_JOBS", "3"))
MIN_TRAINING_DATA_DAYS: int = int(os.getenv("MIN_TRAINING_DATA_DAYS", "30")) MIN_TRAINING_DATA_DAYS: int = int(os.getenv("MIN_TRAINING_DATA_DAYS", "30"))
TRAINING_BATCH_SIZE: int = int(os.getenv("TRAINING_BATCH_SIZE", "1000"))
# Prophet Settings # Prophet Specific Configuration
PROPHET_SEASONALITY_MODE: str = os.getenv("PROPHET_SEASONALITY_MODE", "additive") PROPHET_SEASONALITY_MODE: str = os.getenv("PROPHET_SEASONALITY_MODE", "additive")
PROPHET_DAILY_SEASONALITY: bool = os.getenv("PROPHET_DAILY_SEASONALITY", "true").lower() == "true" PROPHET_CHANGEPOINT_PRIOR_SCALE: float = float(os.getenv("PROPHET_CHANGEPOINT_PRIOR_SCALE", "0.05"))
PROPHET_WEEKLY_SEASONALITY: bool = os.getenv("PROPHET_WEEKLY_SEASONALITY", "true").lower() == "true" PROPHET_SEASONALITY_PRIOR_SCALE: float = float(os.getenv("PROPHET_SEASONALITY_PRIOR_SCALE", "10.0"))
PROPHET_YEARLY_SEASONALITY: bool = os.getenv("PROPHET_YEARLY_SEASONALITY", "true").lower() == "true" PROPHET_HOLIDAYS_PRIOR_SCALE: float = float(os.getenv("PROPHET_HOLIDAYS_PRIOR_SCALE", "10.0"))
# CORS # Spanish Holiday Integration
CORS_ORIGINS: str = os.getenv("CORS_ORIGINS", "http://localhost:3000,http://localhost:3001") ENABLE_SPANISH_HOLIDAYS: bool = True
ENABLE_MADRID_HOLIDAYS: bool = True
ENABLE_CUSTOM_HOLIDAYS: bool = os.getenv("ENABLE_CUSTOM_HOLIDAYS", "true").lower() == "true"
@property # Data Processing
def CORS_ORIGINS_LIST(self) -> List[str]: DATA_PREPROCESSING_ENABLED: bool = True
"""Get CORS origins as list""" OUTLIER_DETECTION_ENABLED: bool = os.getenv("OUTLIER_DETECTION_ENABLED", "true").lower() == "true"
return [origin.strip() for origin in self.CORS_ORIGINS.split(",")] SEASONAL_DECOMPOSITION_ENABLED: bool = os.getenv("SEASONAL_DECOMPOSITION_ENABLED", "true").lower() == "true"
class Config: # Model Validation
env_file = ".env" CROSS_VALIDATION_ENABLED: bool = os.getenv("CROSS_VALIDATION_ENABLED", "true").lower() == "true"
VALIDATION_SPLIT_RATIO: float = float(os.getenv("VALIDATION_SPLIT_RATIO", "0.2"))
MIN_MODEL_ACCURACY: float = float(os.getenv("MIN_MODEL_ACCURACY", "0.7"))
# Distributed Training (for future scaling)
DISTRIBUTED_TRAINING_ENABLED: bool = os.getenv("DISTRIBUTED_TRAINING_ENABLED", "false").lower() == "true"
TRAINING_WORKER_COUNT: int = int(os.getenv("TRAINING_WORKER_COUNT", "1"))
settings = Settings() settings = TrainingSettings()

392
shared/config/base.py Normal file
View File

@@ -0,0 +1,392 @@
# shared/config/base.py
"""
Base configuration for all microservices
Provides common settings and patterns
"""
import os
from typing import List, Dict, Optional, Any
from pydantic_settings import BaseSettings
from pydantic import validator
class BaseServiceSettings(BaseSettings):
"""
Base configuration class for all microservices
Provides common settings and validation patterns
"""
# ================================================================
# CORE SERVICE SETTINGS
# ================================================================
# Application Identity
APP_NAME: str = "Bakery Service"
SERVICE_NAME: str = "base-service"
VERSION: str = "1.0.0"
DESCRIPTION: str = "Base microservice for bakery platform"
# Environment & Debugging
ENVIRONMENT: str = os.getenv("ENVIRONMENT", "development")
DEBUG: bool = os.getenv("DEBUG", "false").lower() == "true"
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# Service Discovery & Health
SERVICE_HOST: str = os.getenv("SERVICE_HOST", "0.0.0.0")
SERVICE_PORT: int = int(os.getenv("SERVICE_PORT", "8000"))
HEALTH_CHECK_ENABLED: bool = True
METRICS_ENABLED: bool = True
# ================================================================
# DATABASE CONFIGURATION
# ================================================================
# Primary database URL (should be overridden by each service)
DATABASE_URL: str = os.getenv("DATABASE_URL", "")
# Database connection settings
DB_POOL_SIZE: int = int(os.getenv("DB_POOL_SIZE", "10"))
DB_MAX_OVERFLOW: int = int(os.getenv("DB_MAX_OVERFLOW", "20"))
DB_POOL_TIMEOUT: int = int(os.getenv("DB_POOL_TIMEOUT", "30"))
DB_POOL_RECYCLE: int = int(os.getenv("DB_POOL_RECYCLE", "3600"))
DB_ECHO: bool = os.getenv("DB_ECHO", "false").lower() == "true"
# ================================================================
# REDIS CONFIGURATION
# ================================================================
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379")
REDIS_DB: int = int(os.getenv("REDIS_DB", "0"))
REDIS_MAX_CONNECTIONS: int = int(os.getenv("REDIS_MAX_CONNECTIONS", "50"))
REDIS_RETRY_ON_TIMEOUT: bool = True
REDIS_SOCKET_KEEPALIVE: bool = True
REDIS_SOCKET_KEEPALIVE_OPTIONS: Dict[str, int] = {
"TCP_KEEPIDLE": 1,
"TCP_KEEPINTVL": 3,
"TCP_KEEPCNT": 5,
}
@property
def REDIS_URL_WITH_DB(self) -> str:
"""Get Redis URL with database number"""
base_url = self.REDIS_URL.rstrip('/')
return f"{base_url}/{self.REDIS_DB}"
# ================================================================
# RABBITMQ CONFIGURATION
# ================================================================
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/")
RABBITMQ_EXCHANGE: str = os.getenv("RABBITMQ_EXCHANGE", "bakery_events")
RABBITMQ_QUEUE_PREFIX: str = os.getenv("RABBITMQ_QUEUE_PREFIX", "bakery")
RABBITMQ_RETRY_ATTEMPTS: int = int(os.getenv("RABBITMQ_RETRY_ATTEMPTS", "3"))
RABBITMQ_RETRY_DELAY: int = int(os.getenv("RABBITMQ_RETRY_DELAY", "5"))
# ================================================================
# AUTHENTICATION & SECURITY
# ================================================================
# JWT Configuration
JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "change-this-in-production")
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("JWT_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = int(os.getenv("JWT_REFRESH_TOKEN_EXPIRE_DAYS", "7"))
# Service-to-Service Authentication
SERVICE_API_KEY: str = os.getenv("SERVICE_API_KEY", "service-api-key-change-in-production")
ENABLE_SERVICE_AUTH: bool = os.getenv("ENABLE_SERVICE_AUTH", "false").lower() == "true"
# Password Requirements
PASSWORD_MIN_LENGTH: int = int(os.getenv("PASSWORD_MIN_LENGTH", "8"))
PASSWORD_REQUIRE_UPPERCASE: bool = os.getenv("PASSWORD_REQUIRE_UPPERCASE", "true").lower() == "true"
PASSWORD_REQUIRE_LOWERCASE: bool = os.getenv("PASSWORD_REQUIRE_LOWERCASE", "true").lower() == "true"
PASSWORD_REQUIRE_NUMBERS: bool = os.getenv("PASSWORD_REQUIRE_NUMBERS", "true").lower() == "true"
PASSWORD_REQUIRE_SYMBOLS: bool = os.getenv("PASSWORD_REQUIRE_SYMBOLS", "false").lower() == "true"
# Security Settings
BCRYPT_ROUNDS: int = int(os.getenv("BCRYPT_ROUNDS", "12"))
MAX_LOGIN_ATTEMPTS: int = int(os.getenv("MAX_LOGIN_ATTEMPTS", "5"))
LOCKOUT_DURATION_MINUTES: int = int(os.getenv("LOCKOUT_DURATION_MINUTES", "30"))
# ================================================================
# INTER-SERVICE COMMUNICATION
# ================================================================
# Service URLs (can be overridden by environment variables)
GATEWAY_URL: str = os.getenv("GATEWAY_URL", "http://gateway:8000")
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000")
TRAINING_SERVICE_URL: str = os.getenv("TRAINING_SERVICE_URL", "http://training-service:8000")
FORECASTING_SERVICE_URL: str = os.getenv("FORECASTING_SERVICE_URL", "http://forecasting-service:8000")
DATA_SERVICE_URL: str = os.getenv("DATA_SERVICE_URL", "http://data-service:8000")
TENANT_SERVICE_URL: str = os.getenv("TENANT_SERVICE_URL", "http://tenant-service:8000")
NOTIFICATION_SERVICE_URL: str = os.getenv("NOTIFICATION_SERVICE_URL", "http://notification-service:8000")
# HTTP Client Settings
HTTP_TIMEOUT: int = int(os.getenv("HTTP_TIMEOUT", "30"))
HTTP_RETRIES: int = int(os.getenv("HTTP_RETRIES", "3"))
HTTP_RETRY_DELAY: float = float(os.getenv("HTTP_RETRY_DELAY", "1.0"))
# ================================================================
# CORS & API CONFIGURATION
# ================================================================
CORS_ORIGINS: str = os.getenv("CORS_ORIGINS", "http://localhost:3000,http://localhost:3001")
CORS_ALLOW_CREDENTIALS: bool = os.getenv("CORS_ALLOW_CREDENTIALS", "true").lower() == "true"
CORS_ALLOW_METHODS: List[str] = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
CORS_ALLOW_HEADERS: List[str] = ["*"]
@property
def CORS_ORIGINS_LIST(self) -> List[str]:
"""Get CORS origins as list"""
return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()]
# Rate Limiting
RATE_LIMIT_ENABLED: bool = os.getenv("RATE_LIMIT_ENABLED", "true").lower() == "true"
RATE_LIMIT_REQUESTS: int = int(os.getenv("RATE_LIMIT_REQUESTS", "100"))
RATE_LIMIT_WINDOW: int = int(os.getenv("RATE_LIMIT_WINDOW", "60"))
RATE_LIMIT_BURST: int = int(os.getenv("RATE_LIMIT_BURST", "10"))
# API Documentation
API_DOCS_ENABLED: bool = os.getenv("API_DOCS_ENABLED", "true").lower() == "true"
API_DOCS_URL: str = "/docs"
API_REDOC_URL: str = "/redoc"
API_OPENAPI_URL: str = "/openapi.json"
# ================================================================
# EXTERNAL APIS & INTEGRATIONS
# ================================================================
# Weather API (AEMET - Spanish Weather Service)
AEMET_API_KEY: str = os.getenv("AEMET_API_KEY", "")
AEMET_BASE_URL: str = "https://opendata.aemet.es/opendata"
AEMET_TIMEOUT: int = int(os.getenv("AEMET_TIMEOUT", "30"))
# Madrid Open Data
MADRID_OPENDATA_API_KEY: str = os.getenv("MADRID_OPENDATA_API_KEY", "")
MADRID_OPENDATA_BASE_URL: str = "https://datos.madrid.es"
MADRID_OPENDATA_TIMEOUT: int = int(os.getenv("MADRID_OPENDATA_TIMEOUT", "30"))
# Email Configuration
SMTP_HOST: str = os.getenv("SMTP_HOST", "smtp.gmail.com")
SMTP_PORT: int = int(os.getenv("SMTP_PORT", "587"))
SMTP_USER: str = os.getenv("SMTP_USER", "")
SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD", "")
SMTP_TLS: bool = os.getenv("SMTP_TLS", "true").lower() == "true"
SMTP_SSL: bool = os.getenv("SMTP_SSL", "false").lower() == "true"
# WhatsApp API
WHATSAPP_API_KEY: str = os.getenv("WHATSAPP_API_KEY", "")
WHATSAPP_BASE_URL: str = os.getenv("WHATSAPP_BASE_URL", "https://api.twilio.com")
WHATSAPP_FROM_NUMBER: str = os.getenv("WHATSAPP_FROM_NUMBER", "")
# ================================================================
# ML & AI CONFIGURATION
# ================================================================
# Model Storage
MODEL_STORAGE_PATH: str = os.getenv("MODEL_STORAGE_PATH", "/app/models")
MODEL_STORAGE_BACKEND: str = os.getenv("MODEL_STORAGE_BACKEND", "local") # local, s3, gcs
# Training Configuration
MAX_TRAINING_TIME_MINUTES: int = int(os.getenv("MAX_TRAINING_TIME_MINUTES", "30"))
MIN_TRAINING_DATA_DAYS: int = int(os.getenv("MIN_TRAINING_DATA_DAYS", "30"))
TRAINING_BATCH_SIZE: int = int(os.getenv("TRAINING_BATCH_SIZE", "1000"))
# Prophet Configuration
PROPHET_SEASONALITY_MODE: str = os.getenv("PROPHET_SEASONALITY_MODE", "additive")
PROPHET_CHANGEPOINT_PRIOR_SCALE: float = float(os.getenv("PROPHET_CHANGEPOINT_PRIOR_SCALE", "0.05"))
PROPHET_SEASONALITY_PRIOR_SCALE: float = float(os.getenv("PROPHET_SEASONALITY_PRIOR_SCALE", "10.0"))
# Prediction Caching
PREDICTION_CACHE_TTL_HOURS: int = int(os.getenv("PREDICTION_CACHE_TTL_HOURS", "6"))
WEATHER_CACHE_TTL_HOURS: int = int(os.getenv("WEATHER_CACHE_TTL_HOURS", "1"))
TRAFFIC_CACHE_TTL_HOURS: int = int(os.getenv("TRAFFIC_CACHE_TTL_HOURS", "1"))
# ================================================================
# MONITORING & OBSERVABILITY
# ================================================================
# Logging Configuration
LOG_FORMAT: str = os.getenv("LOG_FORMAT", "json") # json, text
LOG_FILE_ENABLED: bool = os.getenv("LOG_FILE_ENABLED", "false").lower() == "true"
LOG_FILE_PATH: str = os.getenv("LOG_FILE_PATH", "/app/logs")
LOG_ROTATION_SIZE: str = os.getenv("LOG_ROTATION_SIZE", "100MB")
LOG_RETENTION_DAYS: int = int(os.getenv("LOG_RETENTION_DAYS", "30"))
# Metrics & Monitoring
PROMETHEUS_ENABLED: bool = os.getenv("PROMETHEUS_ENABLED", "true").lower() == "true"
PROMETHEUS_PORT: int = int(os.getenv("PROMETHEUS_PORT", "9090"))
PROMETHEUS_PATH: str = "/metrics"
# Tracing
JAEGER_ENABLED: bool = os.getenv("JAEGER_ENABLED", "false").lower() == "true"
JAEGER_AGENT_HOST: str = os.getenv("JAEGER_AGENT_HOST", "localhost")
JAEGER_AGENT_PORT: int = int(os.getenv("JAEGER_AGENT_PORT", "6831"))
# Health Checks
HEALTH_CHECK_TIMEOUT: int = int(os.getenv("HEALTH_CHECK_TIMEOUT", "30"))
HEALTH_CHECK_INTERVAL: int = int(os.getenv("HEALTH_CHECK_INTERVAL", "30"))
# ================================================================
# DATA RETENTION & CLEANUP
# ================================================================
DATA_RETENTION_DAYS: int = int(os.getenv("DATA_RETENTION_DAYS", "365"))
LOG_RETENTION_DAYS: int = int(os.getenv("LOG_RETENTION_DAYS", "90"))
METRIC_RETENTION_DAYS: int = int(os.getenv("METRIC_RETENTION_DAYS", "90"))
TEMP_FILE_CLEANUP_HOURS: int = int(os.getenv("TEMP_FILE_CLEANUP_HOURS", "24"))
# ================================================================
# BUSINESS RULES & CONSTRAINTS
# ================================================================
# Forecasting Business Rules
MAX_FORECAST_DAYS: int = int(os.getenv("MAX_FORECAST_DAYS", "30"))
MIN_HISTORICAL_DAYS: int = int(os.getenv("MIN_HISTORICAL_DAYS", "60"))
CONFIDENCE_THRESHOLD: float = float(os.getenv("CONFIDENCE_THRESHOLD", "0.8"))
# Spanish Business Context
TIMEZONE: str = os.getenv("TIMEZONE", "Europe/Madrid")
LOCALE: str = os.getenv("LOCALE", "es_ES.UTF-8")
CURRENCY: str = os.getenv("CURRENCY", "EUR")
# Business Hours (24-hour format)
BUSINESS_HOUR_START: int = int(os.getenv("BUSINESS_HOUR_START", "7"))
BUSINESS_HOUR_END: int = int(os.getenv("BUSINESS_HOUR_END", "20"))
# Spanish Holidays & Seasonal Adjustments
ENABLE_SPANISH_HOLIDAYS: bool = os.getenv("ENABLE_SPANISH_HOLIDAYS", "true").lower() == "true"
ENABLE_MADRID_HOLIDAYS: bool = os.getenv("ENABLE_MADRID_HOLIDAYS", "true").lower() == "true"
SCHOOL_CALENDAR_ENABLED: bool = os.getenv("SCHOOL_CALENDAR_ENABLED", "true").lower() == "true"
# ================================================================
# DEVELOPMENT & TESTING
# ================================================================
# Testing Configuration
TESTING: bool = os.getenv("TESTING", "false").lower() == "true"
TEST_DATABASE_URL: str = os.getenv("TEST_DATABASE_URL", "")
MOCK_EXTERNAL_APIS: bool = os.getenv("MOCK_EXTERNAL_APIS", "false").lower() == "true"
# Development Features
AUTO_RELOAD: bool = os.getenv("AUTO_RELOAD", "false").lower() == "true"
PROFILING_ENABLED: bool = os.getenv("PROFILING_ENABLED", "false").lower() == "true"
# ================================================================
# VALIDATORS
# ================================================================
@validator('JWT_SECRET_KEY')
def validate_jwt_secret(cls, v):
if v == "change-this-in-production" and os.getenv("ENVIRONMENT") == "production":
raise ValueError("JWT_SECRET_KEY must be changed in production")
if len(v) < 32:
raise ValueError("JWT_SECRET_KEY must be at least 32 characters long")
return v
@validator('DATABASE_URL')
def validate_database_url(cls, v):
if not v:
raise ValueError("DATABASE_URL is required")
if not v.startswith(('postgresql://', 'postgresql+asyncpg://')):
raise ValueError("DATABASE_URL must be a PostgreSQL URL")
return v
@validator('LOG_LEVEL')
def validate_log_level(cls, v):
valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
if v.upper() not in valid_levels:
raise ValueError(f"LOG_LEVEL must be one of: {valid_levels}")
return v.upper()
@validator('ENVIRONMENT')
def validate_environment(cls, v):
valid_envs = ['development', 'staging', 'production', 'testing']
if v.lower() not in valid_envs:
raise ValueError(f"ENVIRONMENT must be one of: {valid_envs}")
return v.lower()
# ================================================================
# COMPUTED PROPERTIES
# ================================================================
@property
def IS_PRODUCTION(self) -> bool:
"""Check if running in production"""
return self.ENVIRONMENT == "production"
@property
def IS_DEVELOPMENT(self) -> bool:
"""Check if running in development"""
return self.ENVIRONMENT == "development"
@property
def IS_TESTING(self) -> bool:
"""Check if running tests"""
return self.TESTING or self.ENVIRONMENT == "testing"
@property
def SERVICE_REGISTRY(self) -> Dict[str, str]:
"""Get all service URLs"""
return {
"gateway": self.GATEWAY_URL,
"auth": self.AUTH_SERVICE_URL,
"training": self.TRAINING_SERVICE_URL,
"forecasting": self.FORECASTING_SERVICE_URL,
"data": self.DATA_SERVICE_URL,
"tenant": self.TENANT_SERVICE_URL,
"notification": self.NOTIFICATION_SERVICE_URL,
}
@property
def DATABASE_CONFIG(self) -> Dict[str, Any]:
"""Get database configuration for SQLAlchemy"""
return {
"url": self.DATABASE_URL,
"pool_size": self.DB_POOL_SIZE,
"max_overflow": self.DB_MAX_OVERFLOW,
"pool_timeout": self.DB_POOL_TIMEOUT,
"pool_recycle": self.DB_POOL_RECYCLE,
"echo": self.DB_ECHO,
}
@property
def REDIS_CONFIG(self) -> Dict[str, Any]:
"""Get Redis configuration"""
return {
"url": self.REDIS_URL_WITH_DB,
"max_connections": self.REDIS_MAX_CONNECTIONS,
"retry_on_timeout": self.REDIS_RETRY_ON_TIMEOUT,
"socket_keepalive": self.REDIS_SOCKET_KEEPALIVE,
"socket_keepalive_options": self.REDIS_SOCKET_KEEPALIVE_OPTIONS,
}
# ================================================================
# CONFIGURATION LOADING
# ================================================================
class Config:
env_file = ".env"
env_file_encoding = 'utf-8'
case_sensitive = True
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Validate critical settings in production
if self.IS_PRODUCTION:
self._validate_production_settings()
def _validate_production_settings(self):
"""Validate production-specific settings"""
critical_settings = [
'JWT_SECRET_KEY',
'DATABASE_URL',
'REDIS_URL',
'RABBITMQ_URL'
]
for setting in critical_settings:
value = getattr(self, setting)
if not value or 'change' in value.lower() or 'default' in value.lower():
raise ValueError(f"{setting} must be properly configured for production")

View File

@@ -0,0 +1,70 @@
# ================================================================
# ENVIRONMENT-SPECIFIC CONFIGURATIONS
# shared/config/environments.py
# ================================================================
"""
Environment-specific configuration overrides
"""
from typing import Dict, Any
DEVELOPMENT_OVERRIDES: Dict[str, Any] = {
"DEBUG": True,
"LOG_LEVEL": "DEBUG",
"DB_ECHO": True,
"API_DOCS_ENABLED": True,
"CORS_ORIGINS": "http://localhost:3000,http://localhost:3001,http://127.0.0.1:3000",
"MOCK_EXTERNAL_APIS": True,
"AUTO_RELOAD": True,
}
STAGING_OVERRIDES: Dict[str, Any] = {
"DEBUG": False,
"LOG_LEVEL": "INFO",
"DB_ECHO": False,
"API_DOCS_ENABLED": True,
"MOCK_EXTERNAL_APIS": False,
"AUTO_RELOAD": False,
}
PRODUCTION_OVERRIDES: Dict[str, Any] = {
"DEBUG": False,
"LOG_LEVEL": "WARNING",
"DB_ECHO": False,
"API_DOCS_ENABLED": False,
"MOCK_EXTERNAL_APIS": False,
"AUTO_RELOAD": False,
"PROFILING_ENABLED": False,
"RATE_LIMIT_ENABLED": True,
}
TESTING_OVERRIDES: Dict[str, Any] = {
"TESTING": True,
"DEBUG": True,
"LOG_LEVEL": "DEBUG",
"DATABASE_URL": "postgresql+asyncpg://test_user:test_pass@test-db:5432/test_db",
"REDIS_URL": "redis://test-redis:6379",
"MOCK_EXTERNAL_APIS": True,
"EMAIL_VERIFICATION_REQUIRED": False,
"RATE_LIMIT_ENABLED": False,
}
def get_environment_overrides(environment: str) -> Dict[str, Any]:
"""
Get configuration overrides for specific environment
Args:
environment: Environment name (development, staging, production, testing)
Returns:
Dict: Configuration overrides
"""
overrides = {
"development": DEVELOPMENT_OVERRIDES,
"staging": STAGING_OVERRIDES,
"production": PRODUCTION_OVERRIDES,
"testing": TESTING_OVERRIDES,
}
return overrides.get(environment.lower(), {})

83
shared/config/utils.py Normal file
View File

@@ -0,0 +1,83 @@
# ================================================================
# SHARED CONFIGURATION UTILITIES
# shared/config/utils.py
# ================================================================
"""
Configuration utilities and helpers
"""
from typing import Dict, Any, Type
from shared.config.base import BaseServiceSettings
# Service settings registry
SERVICE_SETTINGS: Dict[str, Type[BaseServiceSettings]] = {
"gateway": GatewaySettings,
"auth-service": AuthSettings,
"training-service": TrainingSettings,
"forecasting-service": ForecastingSettings,
"data-service": DataSettings,
"tenant-service": TenantSettings,
"notification-service": NotificationSettings,
}
def get_settings_for_service(service_name: str) -> BaseServiceSettings:
"""
Get settings instance for a specific service
Args:
service_name: Name of the service
Returns:
BaseServiceSettings: Configured settings instance
Raises:
ValueError: If service name is not recognized
"""
if service_name not in SERVICE_SETTINGS:
raise ValueError(f"Unknown service: {service_name}. Available: {list(SERVICE_SETTINGS.keys())}")
settings_class = SERVICE_SETTINGS[service_name]
return settings_class()
def validate_all_service_configs() -> Dict[str, Any]:
"""
Validate configuration for all services
Returns:
Dict: Validation results for each service
"""
results = {}
for service_name, settings_class in SERVICE_SETTINGS.items():
try:
settings = settings_class()
results[service_name] = {
"status": "valid",
"config": {
"app_name": settings.APP_NAME,
"version": settings.VERSION,
"environment": settings.ENVIRONMENT,
"database_configured": bool(settings.DATABASE_URL),
"redis_configured": bool(settings.REDIS_URL),
"debug_mode": settings.DEBUG,
}
}
except Exception as e:
results[service_name] = {
"status": "error",
"error": str(e)
}
return results
def get_service_urls() -> Dict[str, str]:
"""
Get all service URLs from any service configuration
Returns:
Dict: Service name to URL mapping
"""
# Use auth service settings as reference (all services have same URLs)
settings = AuthSettings()
return settings.SERVICE_REGISTRY