refactor(server): plumb Arc<Settings> through workers and routes

Config sheds its 14 Bucket-B fields (retention, whisper, ollama, llm) and
gains a sibling Arc<Settings> in AppState, loaded from settings.toml at
startup via Settings::load_or_default. Workers (transcribe, analyze,
recovery, auto_trigger) and routes (health, bulk, case_actions,
user_web) take settings as a separate parameter or State<> extractor;
Config::llm_configured moves to Settings::llm_configured.

TestConfig::build_pair() returns (Arc<Config>, Arc<Settings>); the new
create_router_with_settings / create_router_and_session_store_with_settings
helpers wire both into integration tests that exercise LLM/Whisper/Ollama.
The legacy single-Arc create_router falls back to Settings::default()
so the 17 non-LLM tests stay untouched.

Verified: cargo build clean, clippy --all-targets clean, 318 tests pass.
This commit is contained in:
2026-04-27 11:48:41 +02:00
parent 6bbbf10f77
commit a510c20e75
21 changed files with 310 additions and 248 deletions
+34 -14
View File
@@ -11,6 +11,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use doctate_server::config::{Config, User};
use doctate_server::settings::Settings;
/// Unique tempdir path for a given label. `process::id()` + UUID v4
/// keeps parallel `cargo test` runs from colliding; the label lets
@@ -125,10 +126,17 @@ impl TestConfig {
self
}
/// Materialize the config. Panics only if the workspace-defaults in
/// `Config::test_default` themselves are broken (not reachable in
/// practice).
/// Materialize the config alone. Bucket-B overrides (`with_llm`,
/// `with_whisper`, `with_ollama`) are silently dropped — call
/// [`build_pair`] when those need to take effect.
pub fn build(self) -> Arc<Config> {
self.build_pair().0
}
/// Materialize both `Config` and `Settings`. Use when a test exercises
/// LLM, Whisper or Ollama paths and needs the builder-set values to
/// reach the worker.
pub fn build_pair(self) -> (Arc<Config>, Arc<Settings>) {
let data_path = self.data_path.unwrap_or_else(|| unique_tmpdir(self.label));
let api_keys: HashMap<String, String> = self
.users
@@ -136,21 +144,33 @@ impl TestConfig {
.map(|u| (u.api_key.clone(), u.slug.clone()))
.collect();
let defaults = Config::test_default();
Arc::new(Config {
let config = Arc::new(Config {
data_path,
users: self.users,
api_keys,
llm_url: self.llm_url.unwrap_or(defaults.llm_url),
llm_api_key: self.llm_api_key.unwrap_or(defaults.llm_api_key),
llm_model: self.llm_model.unwrap_or(defaults.llm_model),
whisper_url: self.whisper_url.unwrap_or(defaults.whisper_url),
whisper_timeout_seconds: self
.whisper_timeout_seconds
.unwrap_or(defaults.whisper_timeout_seconds),
ollama_url: self.ollama_url.unwrap_or(defaults.ollama_url),
..Config::test_default()
})
});
let mut settings = Settings::default();
if let Some(v) = self.llm_url {
settings.llm.url = v;
}
if let Some(v) = self.llm_api_key {
settings.llm.api_key = v;
}
if let Some(v) = self.llm_model {
settings.llm.model = v;
}
if let Some(v) = self.whisper_url {
settings.whisper.url = v;
}
if let Some(v) = self.whisper_timeout_seconds {
settings.whisper.timeout_seconds = v;
}
if let Some(v) = self.ollama_url {
settings.ollama.url = v;
}
(config, Arc::new(settings))
}
}