849763896d
Run Tests on Branches / Detect Changes (push) Successful in 12s
Run Tests on Branches / Frontend Tests (push) Successful in 2m12s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Successful in 2m2s
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
Run Tests on Branches / Backend Tests (push) Successful in 2m8s
78 lines
2.4 KiB
Python
78 lines
2.4 KiB
Python
from pydantic import model_validator
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
env_nested_delimiter="__",
|
|
extra="ignore",
|
|
)
|
|
|
|
APP_NAME: str = "PIP - Pharmacy Integration Platform"
|
|
APP_VERSION: str = "0.1.0"
|
|
DEBUG: bool = False
|
|
NODE_ENV: str = "development"
|
|
|
|
DATABASE_URL: str = "postgresql+asyncpg://pip:pip@localhost:5432/pip"
|
|
DATABASE_POOL_SIZE: int = 20
|
|
DATABASE_MAX_OVERFLOW: int = 10
|
|
DATABASE_POOL_RECYCLE: int = 3600
|
|
|
|
REDIS_URL: str = "redis://localhost:6379/0"
|
|
REDIS_CACHE_TTL: int = 300
|
|
|
|
RABBITMQ_URL: str = "amqp://pip:pip@localhost:5672/pip"
|
|
|
|
JWT_SECRET_KEY: str = "change-me-in-production"
|
|
JWT_ALGORITHM: str = "HS256"
|
|
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
|
JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
|
JWT_ISSUER: str = "pip-platform"
|
|
|
|
OAUTH2_TOKEN_URL: str = "/api/v1/auth/token"
|
|
|
|
RATE_LIMIT_PER_MINUTE: int = 60
|
|
RATE_LIMIT_AUTH_PER_MINUTE: int = 10
|
|
|
|
API_KEY_PREFIX: str = "pip"
|
|
API_KEY_LENGTH: int = 32
|
|
|
|
OTEL_EXPORTER_OTLP_ENDPOINT: str = "http://localhost:4317"
|
|
OTEL_SERVICE_NAME: str = "pip-platform"
|
|
OTEL_TRACES_ENABLED: bool = True
|
|
OTEL_METRICS_ENABLED: bool = True
|
|
|
|
LOG_LEVEL: str = "INFO"
|
|
LOG_JSON_FORMAT: bool = True
|
|
|
|
CORS_ORIGINS: list[str] = ["*"]
|
|
CORS_ALLOW_CREDENTIALS: bool = True
|
|
|
|
HEALTH_CHECK_CACHE_TTL: int = 10
|
|
|
|
@model_validator(mode="after")
|
|
def validate_production_security(self):
|
|
if self.NODE_ENV.lower() != "production":
|
|
return self
|
|
|
|
if self.JWT_SECRET_KEY == "change-me-in-production":
|
|
raise ValueError("JWT_SECRET_KEY must be changed in production")
|
|
|
|
default_credentials = ("pip:pip@", "pip-secret")
|
|
if any(value in self.DATABASE_URL or value in self.RABBITMQ_URL for value in default_credentials):
|
|
raise ValueError("default database or broker credentials are not allowed in production")
|
|
|
|
if self.CORS_ALLOW_CREDENTIALS and "*" in self.CORS_ORIGINS:
|
|
raise ValueError("wildcard CORS_ORIGINS are not allowed with credentials in production")
|
|
|
|
return self
|
|
|
|
@property
|
|
def DATABASE_URL_SYNC(self) -> str:
|
|
return self.DATABASE_URL.replace("+asyncpg", "+psycopg2", 1)
|
|
|
|
|
|
settings = Settings()
|