Files
manage/backend/src/media_library_viewer_api/config.py
T
Developer b1a66a1ab7 chore(observability): remove remaining observability env vars, docs
Slice 5 (final) of observability-service-registry. Completes the move to
service-registry-only observability config: no observability service env
vars remain.

- config.py: removed alertmanager_url + alertmanager_webhook_url fields.
- docker-compose.yml / docker-compose.dev.yml: removed ALERTMANAGER_URL,
  ALERTMANAGER_WEBHOOK_URL (backend env), and VITE_GRAFANA_URL,
  VITE_PROMETHEUS_URL (frontend build args / dev env).
- frontend/Dockerfile: removed the VITE_GRAFANA_URL / VITE_PROMETHEUS_URL
  ARG, build-stage ENV, and dev-stage ENV lines.
- docs: REQUIREMENTS decision-log entry; CHANGELOG Added/Changed/BREAKING
  for the observability service registry; backend/README monitoring
  section (Observability page, services page config, http_sd_configs,
  new health endpoints, log-only webhook).

The only observability env var remaining is PROMETHEUS_ENABLED (Manage's
own /metrics toggle). Grep-gated: no live references to the removed
vars/fields in backend src, frontend src, compose, or Dockerfile.

ruff clean; 239 backend tests pass; frontend 0 lint errors, build clean,
72 tests pass.

.env.example is assistant-edit-blocked; user follow-up noted in the SDD
tasks: drop the removed vars there too.
2026-06-24 08:49:53 +00:00

107 lines
3.0 KiB
Python

"""Backend configuration using pydantic-settings.
Reads from environment variables and .env file automatically.
Uses a flat settings model so that standard env vars like SSH_HOST,
JELLYFIN_URL etc. are picked up directly without nested-model complications.
"""
from __future__ import annotations
import logging
from functools import lru_cache
from pathlib import Path
from pydantic_settings import BaseSettings
from media_library_viewer_api.logging_utils import describe_settings
logger = logging.getLogger(__name__)
class Settings(BaseSettings):
"""Flat application settings read from env vars / .env file."""
# Logging
log_level: str = "INFO"
log_format: str = "text" # "text" or "json"
# Auth / OIDC (Authentik-compatible JWT validation)
auth_enabled: bool = False
oidc_issuer_url: str = ""
oidc_audience: str = ""
oidc_jwks_url: str = ""
oidc_clock_skew_seconds: int = 30
# SMTP (optional, used for Users -> message popup)
smtp_host: str = ""
smtp_port: int = 587
smtp_username: str = ""
smtp_password: str = ""
smtp_from_address: str = ""
smtp_from_name: str = "Manage"
smtp_use_tls: bool = True
smtp_use_ssl: bool = False
smtp_timeout: int = 30
# Legacy SSH fallback (new preferred path is machine-specific settings)
ssh_host: str = ""
ssh_username: str = ""
ssh_port: int = 22
ssh_key_directory: str = ""
ssh_key_name: str = ""
ssh_password: str = ""
ssh_known_hosts_path: str = ""
# Observability
prometheus_enabled: bool = True
# Remote paths
remote_media_root: str = ""
remote_path_prefix: str = ""
# Derived convenience
@property
def media_root(self) -> str:
return self.remote_media_root or ""
@property
def path_prefix(self) -> str:
return self.remote_path_prefix or ""
@property
def ssh_key_path(self) -> str:
if not self.ssh_key_directory or not self.ssh_key_name:
return ""
return str(Path(self.ssh_key_directory) / self.ssh_key_name)
@property
def ssh_known_hosts_file(self) -> Path:
return Path(self.ssh_known_hosts_path or ".cache/media_library_viewer/known_hosts")
model_config = {"env_file": ".env", "env_file_encoding": "utf-8", "extra": "ignore"} # type: ignore[assignment]
def _find_env_file() -> str | None:
"""Look for .env in CWD, then parent directories up to the repo root."""
current = Path.cwd()
for directory in [current, *current.parents]:
candidate = directory / ".env"
if candidate.is_file():
return str(candidate)
if (directory / ".git").exists():
break
return None
@lru_cache
def get_settings() -> Settings:
"""Return a cached Settings instance."""
env_file = _find_env_file()
settings = Settings(_env_file=env_file) if env_file else Settings()
logger.info(
"Loaded backend settings from %s: %s",
env_file or "environment/defaults",
describe_settings(settings),
)
return settings