//! Shared application state passed to all handlers via Axum's `State` extractor. use sqlx::PgPool; use crate::config::AppConfig; use crate::services::rate_limiter::{ProviderRateLimiter, RateLimiter}; use crate::services::synthesis::JobStore; /// Application state shared across all request handlers. /// /// Cloned cheaply (all inner types are `Arc`-based or `Clone`-cheap). #[derive(Clone)] pub struct AppState { pub config: AppConfig, pub pool: PgPool, pub http_client: reqwest::Client, /// Rate limiter for auth endpoints (magic link requests). pub auth_rate_limiter: RateLimiter, /// Per-provider rate limiter for LLM API calls. /// Loaded from DB at startup, hot-reloaded when admin updates config. pub provider_rate_limiter: ProviderRateLimiter, /// In-memory store for active generation jobs. /// Maps job_id -> progress watch channel. pub job_store: JobStore, } impl AppState { /// Create a new `AppState` instance. pub fn new(config: AppConfig, pool: PgPool, http_client: reqwest::Client) -> Self { // Auth rate limiter: 10 requests per 60 seconds per key (email or IP) let auth_rate_limiter = RateLimiter::new(10, std::time::Duration::from_secs(60)); // Provider rate limiter: loaded from DB after creation via `reload_from_db` let provider_rate_limiter = ProviderRateLimiter::new(); // In-memory job store for generation progress tracking let job_store = JobStore::new(); Self { config, pool, http_client, auth_rate_limiter, provider_rate_limiter, job_store, } } }