//! Derlenmiş arayüzün (frontend/dist) sunulması — tek sayfa uygulama (SPA). //! //! - `/assets/*` : adları içerik özetli (hash) → 1 yıl önbellek, `immutable` //! - diğer dosyalar (favicon, ikonlar): 1 saat önbellek //! - olmayan yol (`/defter`, `/plan` ...) → `index.html` (yönlendirmeyi React Router yapar) //! - HTML hiç önbelleğe alınmaz → yeni sürüm yayınlanınca hemen yüklenir use std::path::Path; use axum::{ Router, extract::Request, http::{HeaderValue, header}, middleware::{self, Next}, response::Response, }; use tower_http::services::{ServeDir, ServeFile}; pub fn router(dir: &Path) -> Router { let files = ServeDir::new(dir).fallback(ServeFile::new(dir.join("index.html"))); Router::new() .fallback_service(files) .layer(middleware::from_fn(cache_headers)) } async fn cache_headers(req: Request, next: Next) -> Response { let is_asset = req.uri().path().starts_with("/assets/"); let mut res = next.run(req).await; let is_html = res .headers() .get(header::CONTENT_TYPE) .is_some_and(|v| v.as_bytes().starts_with(b"text/html")); let policy = match (is_html, is_asset) { (true, _) => "no-cache", (false, true) => "public, max-age=31536000, immutable", (false, false) => "public, max-age=3600", }; res.headers_mut() .insert(header::CACHE_CONTROL, HeaderValue::from_static(policy)); res }