Koovira Dev Docs
20-modules/jobs/overview.md

Module: Jobs / Employer (jobs / jobs+jobseeker)

Status: ๐ŸŸข Production (jobs + applications live) / ๐ŸŸก monetization off ยท Last validated: 2026-09-06 ยท Priority: P0

Job board + applicant tracking: employers post jobs and manage a hiring pipeline; job seekers build resumes and apply. Validated against classs/JobModule.php (+ JobEmployerOpsModule.php) + schema.

A. Purpose

Employers hire; seekers find work. Revenue = employer plans + pay-per-application โ€” but application fees default to โ‚น0 (empty kv_commission_rules).

B. Actors

Job seeker (jobseeker); employer/recruiter (jobs) + staff; admin.

C. Entry points

Consumer/seeker: /jobs_hub.php (search), /job_detail.php (detail + apply form โ€” calls JobModule::getJob at job_detail.php:23), /my_resume.php. Employer: /merchant/jobs_dashboard.php + 14 routes (verified: merchant/page_sidebar/jobs_pagegroup.php โ€” 9 top-level pages + a 6-item "AI Hiring" submenu = 15 nav entries incl. the dashboard); careerlab_dashboard.php (CareerLab).

Correction (2026-09-06): the previous text named apply-job.php as the seeker-facing apply entry point. That file exists at api/apply-job.php, but it is an unrelated legacy endpoint (requires APP_PATH . '/models/User.php', never calls JobModule) โ€” not part of this flow. The real apply path is the form on job_detail.php, POSTed to forms/doaction_jobs.php:406 ($jobModule->applyToJob(...)).

D. Onboarding

Seeker: uploadResume (:564) / createDigitalResume (:634), setJobPreferences (:2140), setOpenToWork (:2093). Employer: enroll jobs, createJob (:721).

E. Feature registry (prefix JOB-)

IDFeatureActorMethodTablesStatus
JOB-001Upload / build resumeseekeruploadResume :564, createDigitalResume :634user_resumes (17 rows, 2026-09-06)๐ŸŸข
JOB-002Profile strength / open-to-workseekergetProfileStrength :2012, setOpenToWork :2093customer_master.profile_data (JSON)๐ŸŸข
JOB-003Create / edit jobemployercreateJob :721, updateJob :1438job_posts๐ŸŸข
JOB-004Search jobsanon+seekersearchJobs :1666job_posts๐ŸŸข
JOB-005Job detailanon+seekergetJob(publicOnly) :1939job_posts๐ŸŸข
JOB-006Apply to jobseekerapplyToJob :2216job_applications๐ŸŸข (fee=0, see gap)
JOB-007Employer pipelineemployerlistJobsForOwner :2509, ownerUpdateJobStatus :2541job_posts, job_pipeline_stages๐ŸŸข
JOB-008Report jobuserreportJob :1980job_reports๐ŸŸข

F. Apply flow (JOB-006)

jobs_hub.php โ†’ job_detail.php (getJob(publicOnly) :1939) โ†’ forms/doaction_jobs.php:406
  โ†’ applyToJob(userId, data)  :2216
  INSERT job_applications (candidate โ†’ job, resume ref)
  pay-per-application fee resolved via kv_commission_rules โ†’ 0 (empty) โ†’ free today
  notify employer; candidate enters job_pipeline_stages
Correction (2026-09-06): replaced the previous apply-job.php hop โ€” see the note under section C; the actual dispatcher is forms/doaction_jobs.php.

G. Data model (2026-09-06)

TableRowsRole
job_posts1,049job listings
job_applications8applications
job_pipeline_stages30ATS pipeline stages
Correction (2026-09-06): the previous note said resume/seeker-profile tables existed "under different names than guessed" and left them unnamed. Re-derived from code: resumes live in user_resumes (JobModule::createDigitalResume :643 inserts here; 17 rows, 2026-09-06), and open-to-work/preferences flags live in the profile_data JSON column of customer_master (JobModule::setOpenToWork :2100), not a dedicated job_seeker_profiles table (confirmed absent). resume_master and job_seeker_profiles remain not-live names.

H. Financial impact โ€” the gap (validated)

3 employer plans exist (kv_membership_plans module_key='jobs': free, silver, gold). Correction (2026-09-06): live kv_memberships shows 17 free/active + 1 free/paused + 1 gold/active (no silver subscribers) โ€” the prior "13 free + 1 gold active" is stale. Pay-per-application is blocked: the fee is resolved via kv_commission_rules which is empty, so applications are free (LeadUnlockService-style fee โ†’ 0). See ../../40-financial/commission.md.

K. State machine

Job: draft โ†’ published โ†’ paused โ†’ closed. Application (pipeline): applied โ†’ screening โ†’ shortlisted โ†’ interview โ†’ offer โ†’ hired / rejected (job_pipeline_stages, ownerUpdateJobStatus).

L. Errors (prefix JOB-E)

  • JOB-E001 application charged โ‚น0 unexpectedly โ€” kv_commission_rules empty.
  • JOB-E002 cannot apply โ€” seeker profile/resume missing (getProfileStrength low) or job closed.

M / N. Dependencies & change-impact

Wallet (fees), membership (employer plans), CareerLab/YEP, notifications. Seeding kv_commission_rules turns on per-application monetization โ€” re-test apply + employer wallet debit.