From a0a9a1024d67a1b86151c73b9c51db0d678bc6a1 Mon Sep 17 00:00:00 2001 From: pi-bot-01 Date: Sat, 21 Mar 2026 14:04:22 -0700 Subject: [PATCH] feat: add /health endpoint for monitoring and reverse proxy checks Returns {"ok":true,"status":"live"} with HTTP 200 when the service is running and the database is accessible. Returns HTTP 503 if the database check fails. No authentication required. --- src/routes.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/routes.rs b/src/routes.rs index 6d5c4ce..abca695 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -16,6 +16,8 @@ use crate::{models::*, AppState}; pub fn router(state: AppState) -> Router { Router::new() + // Health check (no auth) + .route("/health", get(health_check)) // Web UI .route("/", get(dashboard)) .route("/login", get(login_page).post(login_post)) @@ -29,6 +31,30 @@ pub fn router(state: AppState) -> Router { .with_state(state) } +// ── Health Check ───────────────────────────────────────────────── + +async fn health_check(State(state): State) -> impl IntoResponse { + // Verify the database is accessible with a simple query + let db_ok = { + let db = state.db.lock().unwrap(); + db.query_row("SELECT 1", [], |_| Ok(())).is_ok() + }; + + if db_ok { + ( + StatusCode::OK, + Json(serde_json::json!({"ok": true, "status": "live"})), + ) + .into_response() + } else { + ( + StatusCode::SERVICE_UNAVAILABLE, + Json(serde_json::json!({"ok": false, "status": "database unreachable"})), + ) + .into_response() + } +} + // ── Helpers ────────────────────────────────────────────────────── fn session_user(jar: &CookieJar, state: &AppState) -> Option { -- 2.54.0