Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart with Orion/orion/ORION across 184 files. This includes database identifiers, email addresses, domain references, R2 bucket names, DNS prefixes, encryption salt, Celery app name, config defaults, Docker configs, CI configs, documentation, seed data, and templates. Renames homepage-wizamart.html template to homepage-orion.html. Fixes duplicate file_pattern key in api.yaml architecture rule. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
367 lines
13 KiB
Python
367 lines
13 KiB
Python
# app/core/config.py
|
|
"""
|
|
Application configuration using Pydantic Settings.
|
|
|
|
This module provides classes and functions for:
|
|
- Configuration management via environment variables
|
|
- Database settings
|
|
- JWT and authentication configuration
|
|
- Platform domain and multi-tenancy settings
|
|
- Admin initialization settings
|
|
|
|
Note: Environment detection is handled by app.core.environment module.
|
|
This module focuses purely on configuration storage and validation.
|
|
"""
|
|
|
|
from pydantic_settings import BaseSettings
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""
|
|
Settings class for application configuration.
|
|
|
|
Environment detection is delegated to app.core.environment.
|
|
This class focuses on configuration values only.
|
|
"""
|
|
|
|
# =============================================================================
|
|
# PROJECT INFORMATION
|
|
# =============================================================================
|
|
project_name: str = "Orion - Multi-Store Marketplace Platform"
|
|
version: str = "2.2.0"
|
|
|
|
# Clean description without HTML
|
|
description: str = """
|
|
Marketplace product import and management system with multi-store support.
|
|
|
|
**Features:**
|
|
- JWT Authentication with role-based access
|
|
- Multi-marketplace product import (CSV processing)
|
|
- Inventory management across multiple locations
|
|
- Store management with individual configurations
|
|
|
|
**Documentation:** Visit /documentation for complete guides
|
|
**API Testing:** Use /docs for interactive API exploration
|
|
"""
|
|
|
|
# =============================================================================
|
|
# DATABASE (PostgreSQL only)
|
|
# =============================================================================
|
|
database_url: str = "postgresql://orion_user:secure_password@localhost:5432/orion_db"
|
|
|
|
# =============================================================================
|
|
# ADMIN INITIALIZATION (for init_production.py)
|
|
# =============================================================================
|
|
admin_email: str = "admin@orion.lu"
|
|
admin_username: str = "admin"
|
|
admin_password: str = "admin123" # CHANGE IN PRODUCTION!
|
|
admin_first_name: str = "Platform"
|
|
admin_last_name: str = "Administrator"
|
|
|
|
# =============================================================================
|
|
# JWT AUTHENTICATION
|
|
# =============================================================================
|
|
jwt_secret_key: str = "change-this-in-production"
|
|
jwt_expire_hours: int = 24
|
|
jwt_expire_minutes: int = 30
|
|
|
|
# =============================================================================
|
|
# API SERVER
|
|
# =============================================================================
|
|
api_host: str = "0.0.0.0"
|
|
api_port: int = 8000
|
|
debug: bool = True
|
|
|
|
# =============================================================================
|
|
# DOCUMENTATION
|
|
# =============================================================================
|
|
documentation_url: str = "http://localhost:8001"
|
|
|
|
# =============================================================================
|
|
# MIDDLEWARE & SECURITY
|
|
# =============================================================================
|
|
allowed_hosts: list[str] = ["*"] # Configure for production
|
|
|
|
# Rate Limiting
|
|
rate_limit_enabled: bool = True
|
|
rate_limit_requests: int = 100
|
|
rate_limit_window: int = 3600
|
|
|
|
# =============================================================================
|
|
# LOGGING
|
|
# =============================================================================
|
|
log_level: str = "INFO"
|
|
log_file: str | None = None
|
|
|
|
# =============================================================================
|
|
# PLATFORM DOMAIN CONFIGURATION
|
|
# =============================================================================
|
|
platform_domain: str = "orion.lu"
|
|
|
|
# Custom domain features
|
|
allow_custom_domains: bool = True
|
|
require_domain_verification: bool = True
|
|
|
|
# SSL/TLS configuration for custom domains
|
|
ssl_provider: str = "letsencrypt" # or "cloudflare", "manual"
|
|
auto_provision_ssl: bool = False
|
|
|
|
# DNS verification
|
|
dns_verification_prefix: str = "_orion-verify"
|
|
dns_verification_ttl: int = 3600
|
|
|
|
# =============================================================================
|
|
# PLATFORM LIMITS
|
|
# =============================================================================
|
|
max_stores_per_user: int = 5
|
|
max_team_members_per_store: int = 50
|
|
invitation_expiry_days: int = 7
|
|
|
|
# =============================================================================
|
|
# STRIPE BILLING
|
|
# =============================================================================
|
|
stripe_secret_key: str = ""
|
|
stripe_publishable_key: str = ""
|
|
stripe_webhook_secret: str = ""
|
|
stripe_trial_days: int = 30 # 1-month free trial (card collected upfront but not charged)
|
|
|
|
# =============================================================================
|
|
# EMAIL CONFIGURATION
|
|
# =============================================================================
|
|
# Provider: smtp, sendgrid, mailgun, ses
|
|
email_provider: str = "smtp"
|
|
email_from_address: str = "noreply@orion.lu"
|
|
email_from_name: str = "Orion"
|
|
email_reply_to: str = "" # Optional reply-to address
|
|
|
|
# SMTP Settings (used when email_provider=smtp)
|
|
smtp_host: str = "localhost"
|
|
smtp_port: int = 587
|
|
smtp_user: str = ""
|
|
smtp_password: str = ""
|
|
smtp_use_tls: bool = True
|
|
smtp_use_ssl: bool = False # For port 465
|
|
|
|
# SendGrid (used when email_provider=sendgrid)
|
|
sendgrid_api_key: str = ""
|
|
|
|
# Mailgun (used when email_provider=mailgun)
|
|
mailgun_api_key: str = ""
|
|
mailgun_domain: str = ""
|
|
|
|
# Amazon SES (used when email_provider=ses)
|
|
aws_access_key_id: str = ""
|
|
aws_secret_access_key: str = ""
|
|
aws_region: str = "eu-west-1"
|
|
|
|
# Email behavior
|
|
email_enabled: bool = True # Set to False to disable all emails
|
|
email_debug: bool = False # Log emails instead of sending (for development)
|
|
|
|
# =============================================================================
|
|
# STOREFRONT DEFAULTS
|
|
# =============================================================================
|
|
# These can be overridden by AdminSetting in the database
|
|
default_storefront_locale: str = "fr-LU" # Currency/number formatting locale
|
|
default_currency: str = "EUR" # Default currency code
|
|
|
|
# =============================================================================
|
|
# DEMO/SEED DATA CONFIGURATION
|
|
# =============================================================================
|
|
# Controls for demo data seeding
|
|
seed_demo_stores: int = 3 # Number of demo stores to create
|
|
seed_customers_per_store: int = 15 # Customers per store
|
|
seed_products_per_store: int = 20 # Products per store
|
|
seed_orders_per_store: int = 10 # Orders per store
|
|
|
|
# =============================================================================
|
|
# CELERY / REDIS TASK QUEUE
|
|
# =============================================================================
|
|
# Redis URL for Celery broker and result backend
|
|
redis_url: str = "redis://localhost:6379/0"
|
|
|
|
# Feature flag: enable Celery for background tasks (False = use FastAPI BackgroundTasks)
|
|
use_celery: bool = False
|
|
|
|
# Flower monitoring dashboard
|
|
flower_url: str = "http://localhost:5555"
|
|
flower_password: str = "changeme" # CHANGE IN PRODUCTION!
|
|
|
|
# =============================================================================
|
|
# SENTRY ERROR TRACKING
|
|
# =============================================================================
|
|
sentry_dsn: str | None = None # Set to enable Sentry
|
|
sentry_environment: str = "development" # development, staging, production
|
|
sentry_traces_sample_rate: float = 0.1 # 10% of transactions for performance monitoring
|
|
|
|
# =============================================================================
|
|
# CLOUDFLARE R2 STORAGE
|
|
# =============================================================================
|
|
storage_backend: str = "local" # "local" or "r2"
|
|
r2_account_id: str | None = None
|
|
r2_access_key_id: str | None = None
|
|
r2_secret_access_key: str | None = None
|
|
r2_bucket_name: str = "orion-media"
|
|
r2_public_url: str | None = None # Custom domain for public access (e.g., https://media.yoursite.com)
|
|
|
|
# =============================================================================
|
|
# CLOUDFLARE CDN / PROXY
|
|
# =============================================================================
|
|
cloudflare_enabled: bool = False # Set to True when using CloudFlare proxy
|
|
|
|
model_config = {"env_file": ".env"}
|
|
|
|
|
|
# Singleton settings instance
|
|
settings = Settings()
|
|
|
|
# =============================================================================
|
|
# ENVIRONMENT UTILITIES - Module-level functions
|
|
# =============================================================================
|
|
# Import environment detection utilities
|
|
from app.core.environment import (
|
|
get_environment,
|
|
is_development,
|
|
is_production,
|
|
is_staging,
|
|
should_use_secure_cookies,
|
|
)
|
|
|
|
|
|
def get_current_environment() -> str:
|
|
"""
|
|
Get current environment.
|
|
|
|
Convenience function that delegates to app.core.environment.
|
|
Use this when you need just the environment string.
|
|
"""
|
|
return get_environment()
|
|
|
|
|
|
def is_production_environment() -> bool:
|
|
"""
|
|
Check if running in production.
|
|
|
|
Convenience function that delegates to app.core.environment.
|
|
Use this for production-specific logic.
|
|
"""
|
|
return is_production()
|
|
|
|
|
|
def is_development_environment() -> bool:
|
|
"""
|
|
Check if running in development.
|
|
|
|
Convenience function that delegates to app.core.environment.
|
|
Use this for development-specific logic.
|
|
"""
|
|
return is_development()
|
|
|
|
|
|
def is_staging_environment() -> bool:
|
|
"""
|
|
Check if running in staging.
|
|
|
|
Convenience function that delegates to app.core.environment.
|
|
Use this for staging-specific logic.
|
|
"""
|
|
return is_staging()
|
|
|
|
|
|
# =============================================================================
|
|
# VALIDATION FUNCTIONS
|
|
# =============================================================================
|
|
|
|
|
|
def validate_database_url() -> None:
|
|
"""
|
|
Validate that database URL is PostgreSQL.
|
|
|
|
Raises:
|
|
ValueError: If database URL is not PostgreSQL
|
|
"""
|
|
if settings.database_url.startswith("sqlite"):
|
|
raise ValueError(
|
|
"SQLite is not supported. Please use PostgreSQL.\n"
|
|
"Set DATABASE_URL environment variable to a PostgreSQL connection string.\n"
|
|
"Example: postgresql://user:password@localhost:5432/dbname\n"
|
|
"For local development, run: docker-compose up -d db"
|
|
)
|
|
if not settings.database_url.startswith("postgresql"):
|
|
raise ValueError(
|
|
f"Unsupported database: {settings.database_url.split(':')[0]}\n"
|
|
"Only PostgreSQL is supported."
|
|
)
|
|
|
|
|
|
def validate_production_settings() -> list[str]:
|
|
"""
|
|
Validate settings for production environment.
|
|
|
|
Returns:
|
|
List of warning messages if configuration is insecure
|
|
"""
|
|
warnings = []
|
|
|
|
if is_production():
|
|
# Check for default/insecure values
|
|
if settings.admin_password == "admin123":
|
|
warnings.append("⚠️ Using default admin password in production!")
|
|
|
|
if settings.jwt_secret_key == "change-this-in-production":
|
|
warnings.append("⚠️ Using default JWT secret key in production!")
|
|
|
|
if settings.debug:
|
|
warnings.append("⚠️ Debug mode enabled in production!")
|
|
|
|
if "*" in settings.allowed_hosts:
|
|
warnings.append("⚠️ ALLOWED_HOSTS is set to wildcard (*) in production!")
|
|
|
|
return warnings
|
|
|
|
|
|
def print_environment_info():
|
|
"""Print current environment configuration."""
|
|
print("\n" + "=" * 70)
|
|
print(f" ENVIRONMENT: {get_environment().upper()}")
|
|
print("=" * 70)
|
|
print(f" Database: {settings.database_url}")
|
|
print(f" Debug mode: {settings.debug}")
|
|
print(f" API port: {settings.api_port}")
|
|
print(f" Platform: {settings.platform_domain}")
|
|
print(f" Secure cookies: {should_use_secure_cookies()}")
|
|
print("=" * 70 + "\n")
|
|
|
|
# Show warnings if in production
|
|
if is_production():
|
|
warnings = validate_production_settings()
|
|
if warnings:
|
|
print("\n⚠️ PRODUCTION WARNINGS:")
|
|
for warning in warnings:
|
|
print(f" {warning}")
|
|
print()
|
|
|
|
|
|
# =============================================================================
|
|
# PUBLIC API
|
|
# =============================================================================
|
|
__all__ = [
|
|
# Settings singleton
|
|
"settings",
|
|
# Environment detection (re-exported from app.core.environment)
|
|
"get_environment",
|
|
"is_development",
|
|
"is_production",
|
|
"is_staging",
|
|
"should_use_secure_cookies",
|
|
# Convenience functions
|
|
"get_current_environment",
|
|
"is_production_environment",
|
|
"is_development_environment",
|
|
"is_staging_environment",
|
|
# Validation
|
|
"validate_database_url",
|
|
"validate_production_settings",
|
|
"print_environment_info",
|
|
]
|