Skip to main content

Core Settings Architecture

The application's configuration is managed by a centralized system built on Pydantic's BaseSettings. This architecture ensures that environment variables are validated, typed, and easily accessible throughout the codebase via a single source of truth.

The core of this system resides in backend/app/core/config.py, where the Settings class defines the application's schema and the settings singleton provides the runtime instance used by other modules.

Environment Variable Management​

The Settings class uses Pydantic's SettingsConfigDict to automatically load variables from an environment file. By default, it is configured to look for a .env file located one level above the backend directory:

class Settings(BaseSettings):
model_config = SettingsConfigDict(
# Use top level .env file (one level above ./backend/)
env_file="../.env",
env_ignore_empty=True,
extra="ignore",
)

This setup allows the project to maintain a single environment configuration at the root level that serves both the backend and other services (like the database or frontend) in a containerized environment.

Core Configuration Components​

The Settings class organizes configuration into several logical groups, often using computed properties to derive complex values from simple environment variables.

Database Connection​

Instead of requiring a full connection string in the environment, the application builds the SQLALCHEMY_DATABASE_URI dynamically. This ensures consistency and allows the application to use the postgresql+psycopg driver specifically.

@computed_field
@property
def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn:
return PostgresDsn.build(
scheme="postgresql+psycopg",
username=self.POSTGRES_USER,
password=self.POSTGRES_PASSWORD,
host=self.POSTGRES_SERVER,
port=self.POSTGRES_PORT,
path=self.POSTGRES_DB,
)

This URI is then consumed by backend/app/core/db.py to initialize the SQLModel engine:

engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))

CORS Configuration​

The application handles Cross-Origin Resource Sharing (CORS) by combining a list of origins from the environment with the frontend host. The BACKEND_CORS_ORIGINS variable is processed by a BeforeValidator called parse_cors, which allows it to be provided as either a JSON list or a comma-separated string.

@computed_field
@property
def all_cors_origins(self) -> list[str]:
return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [
self.FRONTEND_HOST
]

Security and Validation​

A critical feature of the Settings architecture is its enforcement of security standards. The class includes a _check_default_secret method that prevents the application from running in non-local environments if sensitive keys are left as the default value "changethis".

def _check_default_secret(self, var_name: str, value: str | None) -> None:
if value == "changethis":
message = (
f'The value of {var_name} is "changethis", '
"for security, please change it, at least for deployments."
)
if self.ENVIRONMENT == "local":
warnings.warn(message, stacklevel=1)
else:
raise ValueError(message)

This check is triggered automatically during class instantiation via a model_validator for the SECRET_KEY, POSTGRES_PASSWORD, and FIRST_SUPERUSER_PASSWORD.

Application Integration​

The settings singleton is imported across the application to configure various services.

FastAPI Initialization​

In backend/app/main.py, the settings instance defines the API metadata, documentation URLs, and middleware:

from app.core.config import settings

app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json",
generate_unique_id_function=custom_generate_unique_id,
)

if settings.all_cors_origins:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.all_cors_origins,
# ... other CORS settings
)

External Services​

Settings also control the integration of external tools like Sentry. The application conditionally initializes the Sentry SDK based on the ENVIRONMENT and the presence of a SENTRY_DSN:

if settings.SENTRY_DSN and settings.ENVIRONMENT != "local":
sentry_sdk.init(dsn=str(settings.SENTRY_DSN), enable_tracing=True)

Similarly, email functionality is toggled via the emails_enabled computed property, which checks if the necessary SMTP settings (like SMTP_HOST and EMAILS_FROM_EMAIL) are provided.