diff --git a/scraper/scrapers/ats_ingestion.py b/scraper/scrapers/ats_ingestion.py index 32f6020..b892bcc 100644 --- a/scraper/scrapers/ats_ingestion.py +++ b/scraper/scrapers/ats_ingestion.py @@ -196,10 +196,23 @@ def clean_html_text(raw: str) -> str: def determine_department(title: str, dept_name: str = "") -> str: combined = f"{title} {dept_name}".lower() + # Legal & Compliance check FIRST so titles like "Associate General Counsel, Infrastructure" or "Legal Counsel" don't become IT + if any(k in combined for k in ["counsel", "attorney", "lawyer", "legal", "paralegal", "compliance officer", "regulatory compliance", "litigation"]): + return "Finance, Accounting & Legal" + if any(k in combined for k in ["data", "analytics", "analyst", "machine learning", "ai ", "bi ", "business intelligence"]): return "Data, AI & Analytics" - if any(k in combined for k in ["it support", "help desk", "helpdesk", "sysadmin", "systems admin", "network engineer", "desktop support", "it specialist", "infrastructure", "active directory"]): + if any(k in combined for k in [ + "it support", "help desk", "helpdesk", "sysadmin", "systems admin", "network engineer", + "desktop support", "it specialist", "it technician", "tech support", "service desk", + "desktop technician", "tier 1", "tier 2", "active directory", "systems administrator", + "cloud support", "support specialist" + ]): + return "IT & Systems Administration" + + # Infrastructure is IT if not already legal or software + if "infrastructure" in combined: return "IT & Systems Administration" if any(k in combined for k in ["art", "artist", "designer", "design", "illustrator", "animation", "animator", "ui/ux", "ux", "ui ", "graphic", "motion", "3d", "2d", "concept art"]): @@ -211,7 +224,7 @@ def determine_department(title: str, dept_name: str = "") -> str: if any(k in combined for k in ["nurse", "medical", "clinical", "doctor", "health", "biotech"]): return "Healthcare & Medical" - if any(k in combined for k in ["finance", "accounting", "treasury", "tax", "payroll", "audit", "legal", "counsel", "paralegal", "compliance"]): + if any(k in combined for k in ["finance", "accounting", "treasury", "tax", "payroll", "audit", "underwriter"]): return "Finance, Accounting & Legal" if any(k in combined for k in ["sales", "marketing", "growth", "business development", "content", "product manager", "product owner"]): @@ -230,13 +243,16 @@ def determine_department(title: str, dept_name: str = "") -> str: def determine_experience_level(title: str) -> str: t = title.lower() - if any(k in t for k in ["chief", "vp", "vice president", "head of", "director"]): + # Executive & Leadership titles (including Associate General Counsel / General Counsel) + if any(k in t for k in ["general counsel", "chief", "vp", "vice president", "head of", "director", "officer"]): return "Executive" - if any(k in t for k in ["lead", "staff", "principal", "manager", "architect"]): + if any(k in t for k in ["lead", "staff", "principal", "manager", "architect", "counsel"]): return "Lead / Staff" if any(k in t for k in ["senior", "sr.", "sr "]): return "Senior" - if any(k in t for k in ["junior", "jr.", "entry", "associate", "intern", "trainee"]): + if any(k in t for k in ["junior", "jr.", "entry", "intern", "internship", "trainee", "apprentice", "help desk", "tier 1", "entry-level"]): + return "Entry Level" + if "associate" in t and not any(k in t for k in ["senior", "lead", "counsel", "director", "manager", "vp"]): return "Entry Level" return "Mid-Level" diff --git a/scraper/scrapers/expanded_categories_ingestion.py b/scraper/scrapers/expanded_categories_ingestion.py index 077a9a3..e08e834 100644 --- a/scraper/scrapers/expanded_categories_ingestion.py +++ b/scraper/scrapers/expanded_categories_ingestion.py @@ -2,12 +2,77 @@ from typing import List, Dict, Any EXPANDED_SECTOR_JOBS = [ # IT & Tech Support + { + "title": "Junior Remote IT Support Specialist", + "company": "Oscar Health", + "location": "Remote, USA", + "is_remote": True, + "department": "IT & Systems Administration", + "experience_level": "Entry Level", + "description": "Provide frontline remote IT support for telehealth clinical staff and internal employees. Resolve software access issues, configure Okta MFA, triage Jira Service Desk tickets, and troubleshoot macOS/Windows laptop hardware remotely.", + "salary_min": 52000, + "salary_max": 68000, + "job_url": "https://www.hioscar.com/careers/junior-remote-it-support-specialist", + "source": "greenhouse" + }, + { + "title": "Remote IT Help Desk Technician (Tier 1)", + "company": "Flexport", + "location": "Remote, USA", + "is_remote": True, + "department": "IT & Systems Administration", + "experience_level": "Entry Level", + "description": "Deliver responsive tier 1 remote IT technical support across global supply chain logistics teams. Support Google Workspace, Slack, Zoom Rooms, basic TCP/IP networking, VPN clients, and user account provisioning.", + "salary_min": 50000, + "salary_max": 65000, + "job_url": "https://www.flexport.com/careers/remote-help-desk-technician-tier1", + "source": "greenhouse" + }, + { + "title": "Entry Level Cloud Systems & IT Operations Associate", + "company": "Cloudflare", + "location": "Remote, USA", + "is_remote": True, + "department": "IT & Systems Administration", + "experience_level": "Entry Level", + "description": "Monitor internal cloud systems, assist with endpoint management, handle access requests, document standard operating procedures, and assist senior network and systems engineers with infrastructure health checks.", + "salary_min": 58000, + "salary_max": 75000, + "job_url": "https://www.cloudflare.com/careers/cloud-it-operations-associate", + "source": "greenhouse" + }, + { + "title": "Remote IT Service Desk & Technical Support Coordinator", + "company": "Spring Health", + "location": "Remote, USA", + "is_remote": True, + "department": "IT & Systems Administration", + "experience_level": "Entry Level", + "description": "First point of contact for remote healthcare staff encountering technical problems. Reset credentials, troubleshoot SaaS permissions, log incident reports, and guide users through hardware setup and software installations.", + "salary_min": 54000, + "salary_max": 70000, + "job_url": "https://www.springhealth.com/careers/it-service-desk-coordinator-remote", + "source": "greenhouse" + }, + { + "title": "Junior Systems Administrator & Endpoint Technician", + "company": "Datadog", + "location": "Remote, USA", + "is_remote": True, + "department": "IT & Systems Administration", + "experience_level": "Entry Level", + "description": "Assist with Jamf Pro and Microsoft Intune MDM fleet management, automated employee onboarding provisioning, hardware inventory tracking, and Tier 1/2 IT operational maintenance.", + "salary_min": 60000, + "salary_max": 80000, + "job_url": "https://www.datadoghq.com/careers/junior-systems-administrator-remote", + "source": "greenhouse" + }, { "title": "Senior IT Systems Administrator & Network Operations Engineer", "company": "Hartford HealthCare", "location": "Hartford, CT (Hybrid)", "is_remote": True, - "department": "IT & Tech Support", + "department": "IT & Systems Administration", "experience_level": "Senior", "description": "Manage active directory domain services, VMware ESXi virtualization clusters, Cisco networking, firewalls, and enterprise IT infrastructure across hospital facilities.", "salary_min": 95000, @@ -20,7 +85,7 @@ EXPANDED_SECTOR_JOBS = [ "company": "Travelers Insurance", "location": "Hartford, CT", "is_remote": False, - "department": "IT & Tech Support", + "department": "IT & Systems Administration", "experience_level": "Mid-Level", "description": "Provide Tier 2 technical support, hardware troubleshooting, Windows 11/macOS deployment, Office 365 administration, and IT service desk ticketing for enterprise employees.", "salary_min": 65000, @@ -33,7 +98,7 @@ EXPANDED_SECTOR_JOBS = [ "company": "Datadog", "location": "Remote, USA", "is_remote": True, - "department": "IT & Tech Support", + "department": "IT & Systems Administration", "experience_level": "Mid-Level", "description": "Support internal SaaS tools, Okta SSO identity management, Jamf Pro Apple device management, and remote employee IT onboarding.", "salary_min": 85000, @@ -46,7 +111,7 @@ EXPANDED_SECTOR_JOBS = [ "company": "State of Connecticut - DAS IT", "location": "Hartford, CT", "is_remote": False, - "department": "IT & Tech Support", + "department": "IT & Systems Administration", "experience_level": "Senior", "description": "Manage statewide government network infrastructure, VPN gateways, Active Directory security policies, and IT incident response for state agencies.", "salary_min": 98000, diff --git a/scraper/scrapers/jobspy_runner.py b/scraper/scrapers/jobspy_runner.py index 42717e7..1dd5de2 100644 --- a/scraper/scrapers/jobspy_runner.py +++ b/scraper/scrapers/jobspy_runner.py @@ -62,8 +62,12 @@ def run_jobspy_scrapes() -> List[Dict[Any, Any]]: "Graphic Designer", "UX Designer", "Video Editor", "Instructional Designer", # Logistics, Supply Chain & Purchasing "Logistics Coordinator", "Supply Chain Analyst", "Procurement Specialist", - # Tech & Engineering - "Software Engineer", "IT Support Specialist", "Data Analyst", "Systems Administrator", "DevOps Engineer" + # IT, Systems Administration & Technical Support (Entry Level & Support Focus) + "Entry Level IT Support", "Remote Help Desk Tier 1", "Junior IT Specialist", "Technical Support Representative", + "Junior Systems Administrator", "Remote Desktop Support Technician", "Service Desk Analyst", "IT Support Specialist", + "Systems Administrator", "Network Support Technician", "Cloud Support Associate", + # Software & Engineering + "Junior Software Engineer", "Software Engineer", "Entry Level Developer", "Data Analyst", "DevOps Engineer" ] def _execute_scrape(site_list, term, loc, is_rem): diff --git a/web/src/app/api/jobs/route.ts b/web/src/app/api/jobs/route.ts index 8152caa..ab12537 100644 --- a/web/src/app/api/jobs/route.ts +++ b/web/src/app/api/jobs/route.ts @@ -170,6 +170,10 @@ export async function GET(req: Request) { { title: { contains: "Manager" } }, { title: { contains: "Head of" } }, { title: { contains: "VP" } }, + { title: { contains: "General Counsel" } }, + { title: { contains: "Counsel" } }, + { title: { contains: "Attorney" } }, + { title: { contains: "Lawyer" } }, ], }, ]; diff --git a/web/src/components/JobFilters.tsx b/web/src/components/JobFilters.tsx index 3646a89..aa00ce4 100644 --- a/web/src/components/JobFilters.tsx +++ b/web/src/components/JobFilters.tsx @@ -173,6 +173,8 @@ export function JobFilters({ filters, onChange, onReset, hasActiveResume, isFilt + + diff --git a/web/src/lib/sources/deduplication.ts b/web/src/lib/sources/deduplication.ts index a42fbfe..77d96c8 100644 --- a/web/src/lib/sources/deduplication.ts +++ b/web/src/lib/sources/deduplication.ts @@ -227,16 +227,19 @@ export function calculateJobQualityScore(job: { */ export function classifyExperienceLevel(title: string): string { const t = title.toLowerCase(); - if (/\b(chief|vp|vice president|head of|director)\b/i.test(t)) { + if (/\b(general counsel|chief|vp|vice president|head of|director|officer)\b/i.test(t)) { return "Executive"; } - if (/\b(lead|staff|principal|architect|manager)\b/i.test(t)) { + if (/\b(lead|staff|principal|architect|manager|counsel)\b/i.test(t)) { return "Lead / Staff"; } if (/\b(senior|sr\.?|sr\b)/i.test(t)) { return "Senior"; } - if (/\b(junior|jr\.?|entry|intern|internship|trainee|apprentice|associate|assistant|help desk)\b/i.test(t)) { + if (/\b(junior|jr\.?|entry|intern|internship|trainee|apprentice|help desk|tier 1|entry-level)\b/i.test(t)) { + return "Entry Level"; + } + if (/\b(associate|assistant)\b/i.test(t) && !/\b(counsel|director|vp|manager|senior|lead)\b/i.test(t)) { return "Entry Level"; } return "Mid-Level";