WP-00: project skeleton with three-level test harness
Cargo workspace (domain, application, infrastructure, api), axum health endpoint with SPA fallback, Vue 3 + Tailwind frontend, Vitest, Playwright, Makefile, Gitea Actions CI and README. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
35
backend/crates/api/src/config.rs
Normal file
35
backend/crates/api/src/config.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! Runtime configuration read from environment variables (see `.env.example`).
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub database_url: String,
|
||||
pub jwt_secret: String,
|
||||
pub bind: SocketAddr,
|
||||
pub bootstrap_admin: Option<(String, String)>,
|
||||
pub cookie_secure: bool,
|
||||
pub frontend_dir: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_env() -> anyhow::Result<Self> {
|
||||
let env = |k: &str| std::env::var(k).ok().filter(|v| !v.is_empty());
|
||||
let jwt_secret =
|
||||
env("JWT_SECRET").ok_or_else(|| anyhow::anyhow!("JWT_SECRET is required"))?;
|
||||
anyhow::ensure!(
|
||||
jwt_secret.len() >= 32,
|
||||
"JWT_SECRET must be at least 32 characters"
|
||||
);
|
||||
Ok(Self {
|
||||
database_url: env("DATABASE_URL")
|
||||
.unwrap_or_else(|| "sqlite://data/monitoring.db?mode=rwc".into()),
|
||||
jwt_secret,
|
||||
bind: env("BIND")
|
||||
.unwrap_or_else(|| "127.0.0.1:8080".into())
|
||||
.parse()?,
|
||||
bootstrap_admin: env("BOOTSTRAP_ADMIN_EMAIL").zip(env("BOOTSTRAP_ADMIN_PASSWORD")),
|
||||
cookie_secure: env("COOKIE_SECURE").is_some_and(|v| v == "true" || v == "1"),
|
||||
frontend_dir: env("FRONTEND_DIR").unwrap_or_else(|| "../frontend/dist".into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user