fix(verification): align document keys and dedupe role maps across handlers
All checks were successful
build-and-release / build (cron) (push) Successful in 16s
build-and-release / build (social-media-managers) (push) Successful in 3s
build-and-release / build (developers) (push) Successful in 15s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (video-editors) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (customers) (push) Successful in 7s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (catering-services) (push) Successful in 10s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 6s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 3s
build-and-release / build (users) (push) Successful in 8m30s
build-and-release / build (employees) (push) Successful in 13s
build-and-release / build (companies) (push) Successful in 16s
build-and-release / build (graphic-designers) (push) Successful in 3s

extract_documents() recognized a stale set of document keys that no longer
matched what the frontend actually uploads (portfolio_ownership_proof,
professional_certifications, qualification_proof, tax_document), so every
non-COMPANY role's verification case was created with an empty documents
array. Also extracts role_key_to_display/role_to_table into a shared
role_meta module — verifications.rs and approvals.rs were each missing
UGC_CONTENT_CREATOR from their inline copies, so that role's rejections
and final approvals were silently no-ops.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Ashwin Kumar Sivakumar 2026-07-14 21:23:30 +05:30
parent b9133018a5
commit 308daf4959
5 changed files with 66 additions and 101 deletions

View file

@ -17,6 +17,8 @@ use db::models::verification::VerificationRepository;
use serde::Deserialize;
use uuid::Uuid;
use super::role_meta::{role_key_to_display, role_to_table};
pub fn router() -> Router<AppState> {
Router::new()
.route("/", get(list_pending))
@ -165,44 +167,15 @@ async fn list_pending(
.into_response()
}
fn role_key_to_display(role_key: &str) -> String {
match role_key.to_uppercase().as_str() {
"COMPANY" => "Company".to_string(),
"CUSTOMER" => "Customer".to_string(),
"JOB_SEEKER" | "JOBSEEKER" => "Job Seeker".to_string(),
"PHOTOGRAPHER" => "Photographer".to_string(),
"MAKEUP_ARTIST" => "Makeup Artist".to_string(),
"TUTOR" => "Tutor".to_string(),
"DEVELOPER" => "Developer".to_string(),
"VIDEO_EDITOR" => "Video Editor".to_string(),
"GRAPHIC_DESIGNER" => "Graphic Designer".to_string(),
"SOCIAL_MEDIA_MANAGER" => "Social Media Manager".to_string(),
"FITNESS_TRAINER" => "Fitness Trainer".to_string(),
"CATERING_SERVICES" => "Catering Services".to_string(),
_ => role_key.to_string(),
}
}
async fn activate_profile_after_final_approval(
state: &AppState,
user_id: Uuid,
role_key: &str,
) -> Result<(), sqlx::Error> {
let role_key = role_key.to_uppercase();
let table = match role_key.as_str() {
"COMPANY" => "company_profiles",
"CUSTOMER" => "customer_profiles",
"JOB_SEEKER" | "JOBSEEKER" => "job_seeker_profiles",
"PHOTOGRAPHER" => "photographer_profiles",
"MAKEUP_ARTIST" => "makeup_artist_profiles",
"TUTOR" => "tutor_profiles",
"DEVELOPER" => "developer_profiles",
"VIDEO_EDITOR" => "video_editor_profiles",
"GRAPHIC_DESIGNER" => "graphic_designer_profiles",
"SOCIAL_MEDIA_MANAGER" => "social_media_manager_profiles",
"FITNESS_TRAINER" => "fitness_trainer_profiles",
"CATERING_SERVICES" => "catering_service_profiles",
_ => return Ok(()),
let table = match role_to_table(&role_key) {
Some(t) => t,
None => return Ok(()),
};
let user_role_profile_id = match sqlx::query_scalar::<_, Uuid>(
@ -276,20 +249,9 @@ async fn reject_profile_after_final_approval(
reason: Option<&str>,
) -> Result<(), sqlx::Error> {
let role_key = role_key.to_uppercase();
let table = match role_key.as_str() {
"COMPANY" => "company_profiles",
"CUSTOMER" => "customer_profiles",
"JOB_SEEKER" | "JOBSEEKER" => "job_seeker_profiles",
"PHOTOGRAPHER" => "photographer_profiles",
"MAKEUP_ARTIST" => "makeup_artist_profiles",
"TUTOR" => "tutor_profiles",
"DEVELOPER" => "developer_profiles",
"VIDEO_EDITOR" => "video_editor_profiles",
"GRAPHIC_DESIGNER" => "graphic_designer_profiles",
"SOCIAL_MEDIA_MANAGER" => "social_media_manager_profiles",
"FITNESS_TRAINER" => "fitness_trainer_profiles",
"CATERING_SERVICES" => "catering_service_profiles",
_ => return Ok(()),
let table = match role_to_table(&role_key) {
Some(t) => t,
None => return Ok(()),
};
let user_role_profile_id = match sqlx::query_scalar::<_, Uuid>(

View file

@ -26,4 +26,5 @@ pub mod user_roles;
pub mod external_roles;
pub mod verifications;
pub mod profile;
pub mod role_meta;
pub mod settings;

View file

@ -11,6 +11,8 @@ use db::models::{role::RoleRepository, user::UserRepository, verification::Verif
use serde::Deserialize;
use uuid::Uuid;
use super::role_meta::role_to_table;
// ── Routers ───────────────────────────────────────────────────────────────────
pub fn router() -> Router<AppState> {
@ -52,24 +54,6 @@ pub struct SubmitInput {
// ── Helpers ───────────────────────────────────────────────────────────────────
fn role_to_table(role_key: &str) -> Option<&'static str> {
match role_key.to_uppercase().as_str() {
"PHOTOGRAPHER" => Some("photographer_profiles"),
"MAKEUP_ARTIST" => Some("makeup_artist_profiles"),
"TUTOR" => Some("tutor_profiles"),
"DEVELOPER" => Some("developer_profiles"),
"VIDEO_EDITOR" => Some("video_editor_profiles"),
"GRAPHIC_DESIGNER" => Some("graphic_designer_profiles"),
"SOCIAL_MEDIA_MANAGER" => Some("social_media_manager_profiles"),
"FITNESS_TRAINER" => Some("fitness_trainer_profiles"),
"CATERING_SERVICES" => Some("catering_service_profiles"),
"UGC_CONTENT_CREATOR" => Some("ugc_content_creator_profiles"),
"JOB_SEEKER" | "JOBSEEKER" => Some("job_seeker_profiles"),
"CUSTOMER" => Some("customer_profiles"),
_ => None,
}
}
fn is_dummy_account_email(email: &str) -> bool {
email.ends_with("@demo.com")
|| email == "paymentgateway@demo.com"
@ -78,17 +62,19 @@ fn is_dummy_account_email(email: &str) -> bool {
}
fn extract_documents(profile_data: &serde_json::Value) -> serde_json::Value {
// Keep in sync with DOC_FIELDS in nxtgauge-frontend-solid/src/lib/profile-fields-config.ts —
// each entry there is the source of truth for the document key a role's upload writes.
let doc_keys = [
"aadhar_doc",
"registration_doc",
"gst_doc",
"sample_work",
"degree_certificate",
"address_proof",
"portfolio_ownership_proof",
"professional_certifications",
"qualification_proof",
"certification_doc",
"fssai_license",
"identity_proof",
"address_proof",
"portfolio_proof",
"tax_document",
];
let mut docs = vec![];
for key in &doc_keys {

View file

@ -0,0 +1,43 @@
//! Single source of truth for role_key <-> display name / profile table mappings,
//! shared by profile.rs, verifications.rs and approvals.rs so a role added to one
//! consumer can't silently be missing from another.
pub fn role_key_to_display(role_key: &str) -> String {
match role_key.to_uppercase().as_str() {
"COMPANY" => "Company".to_string(),
"CUSTOMER" => "Customer".to_string(),
"JOB_SEEKER" | "JOBSEEKER" => "Job Seeker".to_string(),
"PHOTOGRAPHER" => "Photographer".to_string(),
"MAKEUP_ARTIST" => "Makeup Artist".to_string(),
"TUTOR" => "Tutor".to_string(),
"DEVELOPER" => "Developer".to_string(),
"VIDEO_EDITOR" => "Video Editor".to_string(),
"GRAPHIC_DESIGNER" => "Graphic Designer".to_string(),
"SOCIAL_MEDIA_MANAGER" => "Social Media Manager".to_string(),
"FITNESS_TRAINER" => "Fitness Trainer".to_string(),
"CATERING_SERVICES" => "Catering Services".to_string(),
"UGC_CONTENT_CREATOR" => "UGC Content Creator".to_string(),
_ => role_key.to_string(),
}
}
/// Returns the profile table for a role, or None for roles with no dedicated
/// profile table under this pipeline (e.g. COMPANY, which is handled separately).
pub fn role_to_table(role_key: &str) -> Option<&'static str> {
match role_key.to_uppercase().as_str() {
"PHOTOGRAPHER" => Some("photographer_profiles"),
"MAKEUP_ARTIST" => Some("makeup_artist_profiles"),
"TUTOR" => Some("tutor_profiles"),
"DEVELOPER" => Some("developer_profiles"),
"VIDEO_EDITOR" => Some("video_editor_profiles"),
"GRAPHIC_DESIGNER" => Some("graphic_designer_profiles"),
"SOCIAL_MEDIA_MANAGER" => Some("social_media_manager_profiles"),
"FITNESS_TRAINER" => Some("fitness_trainer_profiles"),
"CATERING_SERVICES" => Some("catering_service_profiles"),
"UGC_CONTENT_CREATOR" => Some("ugc_content_creator_profiles"),
"JOB_SEEKER" | "JOBSEEKER" => Some("job_seeker_profiles"),
"CUSTOMER" => Some("customer_profiles"),
"COMPANY" => Some("company_profiles"),
_ => None,
}
}

View file

@ -11,6 +11,8 @@ use db::models::verification::{VerificationRepository};
use serde::Deserialize;
use uuid::Uuid;
use super::role_meta::{role_key_to_display, role_to_table};
/// Creates an entry in approval_requests after verification is approved.
/// This is the bridge between Verification Management and Approval Management.
async fn create_approval_request_from_verification(
@ -128,24 +130,6 @@ pub struct ActionPayload {
pub reason: Option<String>,
}
fn role_key_to_display(role_key: &str) -> String {
match role_key.to_uppercase().as_str() {
"COMPANY" => "Company".to_string(),
"CUSTOMER" => "Customer".to_string(),
"JOB_SEEKER" | "JOBSEEKER" => "Job Seeker".to_string(),
"PHOTOGRAPHER" => "Photographer".to_string(),
"MAKEUP_ARTIST" => "Makeup Artist".to_string(),
"TUTOR" => "Tutor".to_string(),
"DEVELOPER" => "Developer".to_string(),
"VIDEO_EDITOR" => "Video Editor".to_string(),
"GRAPHIC_DESIGNER" => "Graphic Designer".to_string(),
"SOCIAL_MEDIA_MANAGER" => "Social Media Manager".to_string(),
"FITNESS_TRAINER" => "Fitness Trainer".to_string(),
"CATERING_SERVICES" => "Catering Services".to_string(),
_ => role_key.to_string(),
}
}
async fn trigger_rejection(
state: &AppState,
user_id: Uuid,
@ -157,20 +141,9 @@ async fn trigger_rejection(
let reason_str = reason.unwrap_or("Verification rejected");
if case_type == "PROFILE_VERIFICATION" {
let table = match role_key.as_str() {
"COMPANY" => "company_profiles",
"CUSTOMER" => "customer_profiles",
"JOB_SEEKER" | "JOBSEEKER" => "job_seeker_profiles",
"PHOTOGRAPHER" => "photographer_profiles",
"MAKEUP_ARTIST" => "makeup_artist_profiles",
"TUTOR" => "tutor_profiles",
"DEVELOPER" => "developer_profiles",
"VIDEO_EDITOR" => "video_editor_profiles",
"GRAPHIC_DESIGNER" => "graphic_designer_profiles",
"SOCIAL_MEDIA_MANAGER" => "social_media_manager_profiles",
"FITNESS_TRAINER" => "fitness_trainer_profiles",
"CATERING_SERVICES" => "catering_service_profiles",
_ => return Ok(()),
let table = match role_to_table(&role_key) {
Some(t) => t,
None => return Ok(()),
};
let user_role_profile_id = match sqlx::query_scalar::<_, Uuid>(