2026-01-17 14:18:00 +05:30
|
|
|
from pydantic_settings import BaseSettings
|
|
|
|
|
from typing import Optional
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
app_env = os.getenv("APP_ENV", "local")
|
|
|
|
|
env_filename = f".env.{app_env}"
|
|
|
|
|
|
|
|
|
|
base_path = Path(__file__).resolve().parent.parent.parent
|
|
|
|
|
backend_path = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
2026-08-31 20:04:12 -04:00
|
|
|
_explicit = dict(os.environ)
|
|
|
|
|
|
2026-02-02 17:33:35 +05:30
|
|
|
load_dotenv(dotenv_path=base_path / '.env')
|
2026-08-31 20:04:12 -04:00
|
|
|
load_dotenv(dotenv_path=backend_path / '.env')
|
2026-01-17 14:18:00 +05:30
|
|
|
|
|
|
|
|
if (base_path / env_filename).exists():
|
|
|
|
|
load_dotenv(dotenv_path=base_path / env_filename, override=True)
|
|
|
|
|
if (backend_path / env_filename).exists():
|
|
|
|
|
load_dotenv(dotenv_path=backend_path / env_filename, override=True)
|
|
|
|
|
|
2026-08-31 20:04:12 -04:00
|
|
|
os.environ.update(_explicit)
|
|
|
|
|
|
2026-01-17 14:18:00 +05:30
|
|
|
class Settings(BaseSettings):
|
2026-02-02 17:33:35 +05:30
|
|
|
PROJECT_NAME: str
|
|
|
|
|
VERSION: str
|
2026-01-17 14:18:00 +05:30
|
|
|
|
|
|
|
|
PORT: int
|
|
|
|
|
HOST: str
|
|
|
|
|
APP_ENV: str
|
|
|
|
|
SECRET_KEY: str
|
|
|
|
|
ALLOWED_HOSTS: str = "*"
|
|
|
|
|
|
|
|
|
|
FRONTEND_URL: str
|
|
|
|
|
CORS_ALLOWED_ORIGINS: Optional[str] = None
|
|
|
|
|
CORS_ALLOW_ORIGIN_REGEX: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
ENCRYPTION_KEY: Optional[str] = None
|
|
|
|
|
BCRYPT_ROUNDS: int = 12
|
|
|
|
|
|
2026-08-31 20:04:12 -04:00
|
|
|
ALLOW_PUBLIC_SIGNUP: bool = False
|
|
|
|
|
|
|
|
|
|
MODULE_TRUST_REQUIRE_REPLAY_CONTROLS: bool = False
|
|
|
|
|
|
|
|
|
|
ALERT_WEBHOOK_URL: Optional[str] = None
|
|
|
|
|
ALERT_EMAIL: Optional[str] = None
|
|
|
|
|
ALERT_RENOTIFY_MINUTES: int = 60
|
|
|
|
|
ALERT_STUCK_EVENTS_THRESHOLD: int = 5
|
|
|
|
|
ALERT_STUCK_EVENTS_CRITICAL: int = 50
|
|
|
|
|
ALERT_TOKEN_REUSE_WINDOW_HOURS: int = 24
|
|
|
|
|
MODULE_TRUST_MAX_SKEW_SECONDS: int = 120
|
|
|
|
|
|
2026-01-17 14:18:00 +05:30
|
|
|
DATABASE_URL: str
|
|
|
|
|
DB_SSL: bool = False
|
|
|
|
|
|
2026-02-02 17:33:35 +05:30
|
|
|
REDIS_HOST: str
|
|
|
|
|
REDIS_PORT: int
|
|
|
|
|
REDIS_PASSWORD: Optional[str]
|
|
|
|
|
REDIS_DB: int = 0
|
|
|
|
|
|
|
|
|
|
REDIS_ENABLED: bool = True
|
|
|
|
|
REDIS_TIMEOUT: int = 10
|
|
|
|
|
REDIS_MAX_CONNECTIONS: int = 10
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def REDIS_URL(self) -> str:
|
|
|
|
|
if self.REDIS_PASSWORD:
|
|
|
|
|
return f"redis://:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
|
|
|
|
return f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
2026-01-17 14:18:00 +05:30
|
|
|
|
|
|
|
|
SMTP_HOST: str
|
2026-02-02 17:33:35 +05:30
|
|
|
SMTP_PORT: int
|
2026-01-17 14:18:00 +05:30
|
|
|
SMTP_SECURE: bool = True
|
|
|
|
|
SMTP_USER: str
|
|
|
|
|
SMTP_PASSWORD: str
|
|
|
|
|
EMAIL_FROM: str
|
|
|
|
|
|
|
|
|
|
ACCESS_TOKEN_SECRET: str
|
2026-02-16 15:32:05 +05:30
|
|
|
ACCESS_TOKEN_EXPIRES: int = 900
|
2026-01-17 14:18:00 +05:30
|
|
|
REFRESH_TOKEN_SECRET: str
|
|
|
|
|
REFRESH_TOKEN_EXPIRES: int = 864000
|
|
|
|
|
JWT_ALGORITHM: str = "HS256"
|
2026-02-17 11:57:24 +05:30
|
|
|
|
|
|
|
|
COOKIE_SECURE: bool = False
|
|
|
|
|
COOKIE_DOMAIN: Optional[str] = None
|
|
|
|
|
|
2026-08-31 20:04:12 -04:00
|
|
|
AUDIT_RETENTION_DATABASE_URL: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
DOCUMENT_STORAGE_PATH: str = "./storage/documents"
|
|
|
|
|
DOCUMENT_MAX_BYTES: int = 25 * 1024 * 1024
|
|
|
|
|
DOCUMENT_QUOTA_BYTES: int = 2 * 1024 * 1024 * 1024
|
|
|
|
|
|
2026-01-17 14:18:00 +05:30
|
|
|
SUPER_ADMIN_EMAIL: str
|
|
|
|
|
SUPER_ADMIN_PASSWORD: str
|
|
|
|
|
SUPER_ADMIN_FIRST_NAME: str = "Super"
|
|
|
|
|
SUPER_ADMIN_LAST_NAME: str = "Admin"
|
|
|
|
|
|
2026-01-20 17:38:01 +05:30
|
|
|
SAAS_PRIVATE_KEY: Optional[str] = None
|
|
|
|
|
SAAS_KEY_ID: str = "saas-key-v1"
|
2026-01-17 14:18:00 +05:30
|
|
|
|
|
|
|
|
PAYPAL_CLIENT_ID: str
|
|
|
|
|
PAYPAL_CLIENT_SECRET: str
|
|
|
|
|
PAYPAL_MODE: str = "sandbox"
|
|
|
|
|
PAYPAL_API_URL: str = "https://api-m.sandbox.paypal.com"
|
2026-02-02 17:33:35 +05:30
|
|
|
|
|
|
|
|
REDIS_CHAT_TTL: int = 86400
|
2026-01-17 14:18:00 +05:30
|
|
|
|
|
|
|
|
LOG_LEVEL: str = "info"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def MAIL_USERNAME(self) -> str:
|
|
|
|
|
return self.SMTP_USER
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def MAIL_PASSWORD(self) -> str:
|
|
|
|
|
return self.SMTP_PASSWORD
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def MAIL_PORT(self) -> int:
|
|
|
|
|
return self.SMTP_PORT
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def MAIL_SERVER(self) -> str:
|
|
|
|
|
return self.SMTP_HOST
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def MAIL_FROM(self) -> str:
|
|
|
|
|
return self.EMAIL_FROM
|
|
|
|
|
|
|
|
|
|
model_config = {
|
|
|
|
|
"case_sensitive": True,
|
|
|
|
|
"extra": "ignore",
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 20:39:41 -04:00
|
|
|
settings = Settings()
|