From da8188563fd7ef6fac2418db7db66f529ac51c66 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Sivakumar Date: Thu, 23 Jul 2026 23:44:44 +0530 Subject: [PATCH] Fix job seeker document upload 404ing before profile is saved upload_document and list_documents both required a pre-existing job_seeker_profiles row, but nothing creates that row until the user clicks "Save" on the Basic Information tab. A job seeker who opened the Documents tab first (or never saved Basic Info) got every upload silently rejected with a 404, and the earlier fix in frontend-solid (070c4bd) only addressed a different bug in the dashboard widget - it never touched this upload path. upload_document now lazily creates a blank profile row on first upload instead of 404ing (uploading a verification document doesn't depend on basic profile fields being filled in). list_documents now returns an empty list instead of erroring when no profile exists yet, since that's just the normal empty state for a new job seeker. Co-Authored-By: Claude Sonnet 5 --- apps/job_seekers/src/handlers.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/job_seekers/src/handlers.rs b/apps/job_seekers/src/handlers.rs index 1cb9d24..4690d55 100644 --- a/apps/job_seekers/src/handlers.rs +++ b/apps/job_seekers/src/handlers.rs @@ -678,9 +678,27 @@ async fn upload_document( auth: AuthUser, mut multipart: Multipart, ) -> impl IntoResponse { + // A job seeker who hasn't saved any basic profile info yet won't have a + // job_seeker_profiles row - lazily create a blank one instead of 404ing, + // since uploading a verification document doesn't depend on that data. let seeker = match JobSeekerRepository::get_by_user_id(&state.pool, auth.user_id).await { Ok(Some(s)) => s, - Ok(None) => return (StatusCode::NOT_FOUND, Json(serde_json::json!({ "error": "Job seeker profile not found" }))).into_response(), + Ok(None) => { + let empty_payload = UpsertJobSeekerProfilePayload { + full_name: None, + location: None, + summary: None, + experience_years: None, + skills: None, + resume_url: None, + bio: None, + custom_data: None, + }; + match JobSeekerRepository::upsert(&state.pool, auth.user_id, empty_payload).await { + Ok(s) => s, + Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({ "error": e.to_string() }))).into_response(), + } + } Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({ "error": e.to_string() }))).into_response(), }; @@ -793,9 +811,11 @@ async fn list_documents( State(state): State, auth: AuthUser, ) -> impl IntoResponse { + // No profile row yet means no documents have ever been uploaded either - + // that's a normal empty state, not an error. let seeker = match JobSeekerRepository::get_by_user_id(&state.pool, auth.user_id).await { Ok(Some(s)) => s, - Ok(None) => return (StatusCode::NOT_FOUND, Json(serde_json::json!({ "error": "Job seeker profile not found" }))).into_response(), + Ok(None) => return (StatusCode::OK, Json(serde_json::json!({ "data": [] }))).into_response(), Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({ "error": e.to_string() }))).into_response(), };