Open public jobs
Current starter jobs include website QA, lead research, and AI-output review.
Browse open jobsdiff --git a/backend/api_core.py b/backend/api_core.py index 2c766fb..f515d27 100644 --- a/backend/api_core.py +++ b/backend/api_core.py @@ -7871,6 +7871,10 @@ def _handle_routes(db): f"SELECT COUNT(*) as c FROM jobs WHERE status='open' AND employer_id NOT IN ({seeded_user_subquery})", seeded_values ).fetchone()['c'] + accepting_jobs_count = db.execute( + f"SELECT COUNT(*) as c FROM jobs WHERE status IN ('open','reviewing') AND employer_id NOT IN ({seeded_user_subquery})", + seeded_values + ).fetchone()['c'] completed_orders = db.execute( f"""SELECT COUNT(*) as c FROM orders WHERE status='completed' @@ -7891,6 +7895,7 @@ def _handle_routes(db): "workers_registered": workers_count, "employers_registered": employers_count, "open_jobs": jobs_count, + "accepting_jobs": accepting_jobs_count, "completed_orders": completed_orders, "total_users": total_users, "categories": categories_count @@ -11594,7 +11599,7 @@ def build_link_result(value): j.title as job_title, j.category as job_category, j.status as job_status, j.budget_amount, j.budget_type, j.employer_id, wu.name as worker_name, wu.email as worker_email, - eu.name as employer_name + eu.name as employer_name, eu.email as employer_email FROM applications a JOIN jobs j ON j.id = a.job_id JOIN users wu ON wu.id = a.worker_id @@ -11623,13 +11628,31 @@ def build_link_result(value): "needs_manual_review" if quality_flags else "weak_or_incomplete" ) + employer_email = item.pop("employer_email", "") + if is_seeded_sample_email(employer_email): + item["operational_class"] = "sample" + item["actionability_reason"] = "seed_or_sample_employer" + elif item.get("status") == "pending" and item.get("job_status") in ("open", "reviewing"): + item["operational_class"] = "actionable" + item["actionability_reason"] = "pending_on_accepting_job" + else: + item["operational_class"] = "historical" + item["actionability_reason"] = ( + "application_not_pending" + if item.get("status") != "pending" + else "job_not_accepting_applications" + ) applications.append(item) + actionable = [a for a in applications if a["operational_class"] == "actionable"] summary = { "total_recent_applications": len(applications), - "strong_candidates": sum(1 for a in applications if a["triage_status"] == "strong_candidate"), - "needs_manual_review": sum(1 for a in applications if a["triage_status"] == "needs_manual_review"), - "weak_or_incomplete": sum(1 for a in applications if a["triage_status"] == "weak_or_incomplete"), + "strong_candidates": sum(1 for a in actionable if a["triage_status"] == "strong_candidate"), + "needs_manual_review": sum(1 for a in actionable if a["triage_status"] == "needs_manual_review"), + "weak_or_incomplete": sum(1 for a in actionable if a["triage_status"] == "weak_or_incomplete"), "pending_applications": sum(1 for a in applications if a.get("status") == "pending"), + "actionable_applications": len(actionable), + "sample_applications": sum(1 for a in applications if a["operational_class"] == "sample"), + "historical_applications": sum(1 for a in applications if a["operational_class"] == "historical"), } return json_response({"summary": summary, "applications": applications, "limit": limit}) diff --git a/backend/test_deep_audit_regressions.py b/backend/test_deep_audit_regressions.py index c4ed745..9af1148 100644 --- a/backend/test_deep_audit_regressions.py +++ b/backend/test_deep_audit_regressions.py @@ -1732,10 +1732,17 @@ def test_admin_application_pipeline_surfaces_quality_triage(self): db.execute("INSERT INTO users (id,email,password_hash,name,is_admin) VALUES (1,'admin@example.com','x','Admin',1)") db.execute("INSERT INTO users (id,email,password_hash,name) VALUES (2,'worker@example.com','x','Worker')") db.execute("INSERT INTO users (id,email,password_hash,name) VALUES (3,'employer@example.com','x','Employer')") + db.execute("INSERT INTO users (id,email,password_hash,name) VALUES (4,'hiring@cloudnative.dev','x','Sample Employer')") db.execute("INSERT INTO sessions (user_id,token,expires_at) VALUES (1,?,datetime('now','+1 day'))", [token]) db.execute("INSERT INTO jobs (id,employer_id,title,description,category,budget_type,budget_amount,status) VALUES (7,3,'QA Job','Desc','testing','fixed',25,'open')") + db.execute("INSERT INTO jobs (id,employer_id,title,description,category,budget_type,budget_amount,status) VALUES (8,3,'Closed QA Job','Desc','testing','fixed',25,'hired')") + db.execute("INSERT INTO jobs (id,employer_id,title,description,category,budget_type,budget_amount,status) VALUES (9,4,'Sample QA Job','Desc','testing','fixed',25,'reviewing')") + db.execute("INSERT INTO jobs (id,employer_id,title,description,category,budget_type,budget_amount,status) VALUES (10,3,'Reviewed QA Job','Desc','testing','fixed',25,'reviewing')") cover = "I can deliver this today with screenshots, a short issue list, and prioritized notes based on testing the signup flow on desktop and mobile." db.execute("INSERT INTO applications (job_id,worker_id,cover_message,portfolio_url,status) VALUES (7,2,?,'https://example.com/proof','pending')", [cover]) + db.execute("INSERT INTO applications (job_id,worker_id,cover_message,status) VALUES (8,2,'Historical pending application','pending')") + db.execute("INSERT INTO applications (job_id,worker_id,cover_message,status) VALUES (9,2,'Sample application','pending')") + db.execute("INSERT INTO applications (job_id,worker_id,cover_message,status) VALUES (10,2,'Accepted application','accepted')") db.commit() finally: db.close() @@ -1753,13 +1760,28 @@ def test_admin_application_pipeline_surfaces_quality_triage(self): self.module.handle_request() status, body = parse_cgi_output(out.getvalue()) self.assertEqual(status, 200, body) - self.assertEqual(body["summary"]["total_recent_applications"], 1) + self.assertEqual(body["summary"]["total_recent_applications"], 4) self.assertEqual(body["summary"]["strong_candidates"], 1) - app = body["applications"][0] + self.assertEqual(body["summary"]["pending_applications"], 3) + self.assertEqual(body["summary"]["actionable_applications"], 1) + self.assertEqual(body["summary"]["sample_applications"], 1) + self.assertEqual(body["summary"]["historical_applications"], 2) + apps_by_job = {app["job_id"]: app for app in body["applications"]} + app = apps_by_job[7] self.assertEqual(app["triage_status"], "strong_candidate") + self.assertEqual(app["operational_class"], "actionable") + self.assertEqual(app["actionability_reason"], "pending_on_accepting_job") self.assertIn("specific_cover_message", app["quality_flags"]) self.assertIn("portfolio_or_proof_url", app["quality_flags"]) self.assertIn("deliverable_or_timing_signal", app["quality_flags"]) + self.assertEqual(apps_by_job[8]["operational_class"], "historical") + self.assertEqual(apps_by_job[8]["actionability_reason"], "job_not_accepting_applications") + self.assertEqual(apps_by_job[9]["operational_class"], "sample") + self.assertEqual(apps_by_job[9]["actionability_reason"], "seed_or_sample_employer") + for returned_app in apps_by_job.values(): + self.assertNotIn("employer_email", returned_app) + self.assertEqual(apps_by_job[10]["operational_class"], "historical") + self.assertEqual(apps_by_job[10]["actionability_reason"], "application_not_pending") def test_admin_worker_activation_notifications_requires_admin(self): self.module._request_ctx.request_method = "POST" @@ -1892,6 +1914,51 @@ def test_public_jobs_default_includes_every_application_accepting_status(self): {1: "open", 2: "reviewing"}, ) + def test_public_platform_stats_distinguish_open_from_application_accepting_jobs(self): + db = self.module.get_db() + try: + db.execute( + "INSERT INTO users (id,email,password_hash,name) VALUES (1,'buyer@real-company.example','x','Real Buyer')" + ) + db.execute( + "INSERT INTO users (id,email,password_hash,name) VALUES (2,'hiring@cloudnative.dev','x','Sample Employer')" + ) + for job_id, employer_id, title, status in [ + (1, 1, "Fresh public job", "open"), + (2, 1, "Public job under review", "reviewing"), + (3, 1, "Already hired job", "hired"), + (4, 2, "Sample reviewing job", "reviewing"), + ]: + db.execute( + """INSERT INTO jobs + (id,employer_id,title,description,category,budget_type,budget_amount,status) + VALUES (?,?,?,?,?,'fixed',25,?)""", + [job_id, employer_id, title, "Bounded work", "testing", status], + ) + db.commit() + finally: + db.close() + + status, response = self._request_api("GET", "/platform/stats") + self.assertEqual(status, 200, response) + self.assertEqual(response["open_jobs"], 1) + self.assertEqual(response["accepting_jobs"], 2) + + generator = (REPO_ROOT / "scripts/generate-marketplace-pulse.py").read_text(encoding="utf-8") + self.assertIn("stats.get('accepting_jobs', len(jobs))", generator) + self.assertIn("Jobs Accepting Applications", generator) + self.assertNotIn("stats.get('open_jobs', len(jobs))", generator) + + stats_page = (REPO_ROOT / "frontend/stats.html").read_text(encoding="utf-8") + self.assertIn("jobs accepting applications, registered users", stats_page) + self.assertNotIn("services listed, jobs open, registered users", stats_page) + + homepage = (REPO_ROOT / "frontend/index.html").read_text(encoding="utf-8") + self.assertIn("Browse jobs accepting applications", homepage) + self.assertIn("Discover public services, jobs accepting applications", homepage) + self.assertNotIn("Loading open jobs", homepage) + self.assertNotIn("Discover public services, open jobs", homepage) + def test_public_homepage_visual_cleanup_invariants(self): text = (REPO_ROOT / "frontend/index.html").read_text(encoding="utf-8", errors="ignore") @@ -2137,7 +2204,8 @@ def test_growth_activation_pages_and_homepage_proof_are_discoverable(self): "href=\"/#/post-job?template=lead_qualification\"", ], "frontend/earn/open-paid-tasks.html": [ - "Find open paid tasks you can apply to today", + "Find paid tasks you can apply to today", + "Jobs accepting applications", "worker_open_tasks_click", "What a strong application says", ], diff --git a/frontend/earn/open-paid-tasks.html b/frontend/earn/open-paid-tasks.html index 518cfa7..be6af9d 100644 --- a/frontend/earn/open-paid-tasks.html +++ b/frontend/earn/open-paid-tasks.html @@ -28,4 +28,15 @@ if (event.target.closest('.lp-mobile-link')) toggleMobileMenu(false); }); } -
Browse current jobs, apply with a short specific message, and keep work/payment on-platform.
Current starter jobs include website QA, lead research, and AI-output review.
Browse open jobsState the job you want, relevant experience, timing, and one example or link if available.
Do not send private payment details or move work off-platform. Apply directly through GoHireHumans.
website testinglead researchAI fact-checkingdata cleanuplocal verification