Files
kakeibo/backend/src/config.rs
T
suphicakir 3f60efdc33 feat(birikim): otomatik ve manuel kurlar, portföy değerlemesi
- TCMB (döviz alış kuru) ve xaus.com (altın) saatlik arka planda çekilir, gün başına saklanır
- Kaynak erişilemezse son kur geçerli; altın için son USD kuru kullanılır
- Elle kur girişi/silme; aynı gün elle girilen kur önceliklidir
- GET /portfolio: güncel değer, kâr/zarar, toplamlar, son kur çekimi
- RATES_REFRESH_MINUTES ayarı

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 00:59:01 +03:00

104 lines
3.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Ortam değişkenlerinden uygulama ayarlarını okur.
use std::{env, path::PathBuf};
#[derive(Debug, Clone)]
pub struct Config {
pub mongodb_uri: String,
pub jwt_secret: String,
pub app_url: String,
pub port: u16,
pub registration: RegistrationMode,
/// Derlenmiş frontend klasörü (`STATIC_DIR`). Tanımlıysa Axum arayüzü de sunar
/// (canlıda tek servis). Geliştirmede boş: arayüzü Vite sunar.
pub static_dir: Option<PathBuf>,
/// Otomatik kur yenileme aralığı (dakika, `RATES_REFRESH_MINUTES`, varsayılan 60); 0 → kapalı
pub rates_refresh_minutes: u64,
}
/// Yeni hane kaydı politikası (`REGISTRATION` ortam değişkeni).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegistrationMode {
/// Varsayılan. Sistemde hiç hane yokken ilk kayıt yeni hane kurar;
/// sonrasında yalnızca davet koduyla katılınır.
InviteOnly,
/// Herkes yeni hane kurabilir.
Open,
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("{0} ortam değişkeni tanımlı değil (.env dosyasını kontrol edin)")]
Missing(&'static str),
#[error("{0} geçersiz: {1}")]
Invalid(&'static str, &'static str),
}
impl Config {
pub fn from_env() -> Result<Self, ConfigError> {
let mongodb_uri = required("MONGODB_URI")?;
let jwt_secret = required("JWT_SECRET")?;
if jwt_secret.len() < 32 {
return Err(ConfigError::Invalid(
"JWT_SECRET",
"en az 32 karakter olmalı (openssl rand -hex 32)",
));
}
let app_url = env::var("APP_URL").unwrap_or_else(|_| "http://localhost:5173".into());
let registration = match env::var("REGISTRATION").as_deref() {
Err(_) | Ok("") | Ok("invite_only") => RegistrationMode::InviteOnly,
Ok("open") => RegistrationMode::Open,
Ok(_) => {
return Err(ConfigError::Invalid(
"REGISTRATION",
"\"invite_only\" veya \"open\" olmalı",
));
}
};
let static_dir = env::var("STATIC_DIR")
.ok()
.filter(|v| !v.trim().is_empty())
.map(PathBuf::from);
let port = match env::var("PORT") {
Ok(p) => p
.parse()
.map_err(|_| ConfigError::Invalid("PORT", "sayı olmalı"))?,
Err(_) => 8080,
};
let rates_refresh_minutes = match env::var("RATES_REFRESH_MINUTES") {
Ok(m) if !m.trim().is_empty() => m.trim().parse().map_err(|_| {
ConfigError::Invalid("RATES_REFRESH_MINUTES", "dakika (sayı) olmalı")
})?,
_ => 60,
};
Ok(Self {
mongodb_uri,
jwt_secret,
app_url,
port,
registration,
static_dir,
rates_refresh_minutes,
})
}
/// Cookie'lerde `Secure` bayrağı yalnızca HTTPS'te açılır.
pub fn is_https(&self) -> bool {
self.app_url.starts_with("https://")
}
}
fn required(key: &'static str) -> Result<String, ConfigError> {
env::var(key)
.ok()
.filter(|v| !v.trim().is_empty())
.ok_or(ConfigError::Missing(key))
}