{"id":40,"date":"2026-08-06T20:37:34","date_gmt":"2026-08-06T20:37:34","guid":{"rendered":"https:\/\/helpnetai.com\/jobs\/?page_id=40"},"modified":"2026-08-07T01:49:25","modified_gmt":"2026-08-07T01:49:25","slug":"job-analytics-v1-html","status":"publish","type":"page","link":"https:\/\/helpnetai.com\/jobs\/job-analytics-v1-html\/","title":{"rendered":"Analytics"},"content":{"rendered":"\n<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>Job Intelligence Analytics<\/title>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"><\/script>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.7\"><\/script>\n<style>\n:root{--bg:#f8fafc;--card:#fff;--text:#0f172a;--muted:#64748b;--line:#e2e8f0;--accent:#2563eb;--warn:#92400e}\n*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif}\n.shell{width:min(1500px,100%);margin:auto;padding:24px clamp(14px,3vw,42px)}.top{display:flex;gap:18px;justify-content:space-between;align-items:center;flex-wrap:wrap}\nh1{margin:0}.muted{color:var(--muted)}.controls{display:flex;gap:8px}select,button{padding:9px 14px;border:1px solid var(--line);border-radius:8px;background:#fff}\nbutton{background:var(--accent);color:white;border-color:var(--accent);cursor:pointer}.tabs{display:flex;gap:8px;flex-wrap:wrap;margin:22px 0}\n.tab{background:#fff;color:var(--text)}.tab.active{background:var(--accent);color:#fff}.view{display:none!important}.view.active{display:block!important}\n.grid{display:grid;grid-template-columns:repeat(6,1fr);gap:12px}.kpi,.panel{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:16px}\n.kpi span{display:block;color:var(--muted);font-size:.85rem}.kpi b{font-size:1.55rem}.charts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-top:14px}\n.panel h3{margin-top:0}.chartbox{height:330px}table{width:100%;border-collapse:collapse}th,td{padding:9px;border-bottom:1px solid var(--line);text-align:left;font-size:.9rem}\n.notice{padding:14px;border:1px solid #fde68a;background:#fffbeb;color:var(--warn);border-radius:10px}#error{color:#b91c1c;font-weight:600}\n@media(max-width:1100px){.grid{grid-template-columns:repeat(3,1fr)}.charts{grid-template-columns:1fr}}\n@media(max-width:600px){.grid{grid-template-columns:repeat(2,1fr)}.shell{padding:14px}}\n<\/style><\/head><body><main class=\"shell\">\n<div class=\"top\"><div><h1>Job Intelligence Analytics<\/h1><div class=\"muted\">Admin BI \u00b7 deterministic market evidence and enrichment intelligence<\/div><\/div>\n<div class=\"controls\"><select id=\"days\"><option value=\"7\">7 days<\/option><option value=\"30\" selected>30 days<\/option><option value=\"90\">90 days<\/option><option value=\"180\">180 days<\/option><\/select><button id=\"refresh\">Refresh<\/button><\/div><\/div>\n<p id=\"status\" class=\"muted\">Authenticating\u2026<\/p><p id=\"error\"><\/p>\n<div class=\"tabs\">\n<button class=\"tab active\" data-view=\"overview\">Overview<\/button><button class=\"tab\" data-view=\"skills\">Skills<\/button>\n<button class=\"tab\" data-view=\"roles\">Roles<\/button><button class=\"tab\" data-view=\"salary\">Salary<\/button>\n<button class=\"tab\" data-view=\"trends\">Trends<\/button><button class=\"tab\" data-view=\"semantic\">Semantic<\/button>\n<\/div>\n<section id=\"dashboard\" class=\"hidden\">\n<div id=\"overview\" class=\"view active\"><div class=\"grid\">\n<div class=\"kpi\"><span>Active Jobs<\/span><b id=\"active\">\u2014<\/b><\/div><div class=\"kpi\"><span>New Jobs<\/span><b id=\"newJobs\">\u2014<\/b><\/div>\n<div class=\"kpi\"><span>Companies Hiring<\/span><b id=\"companies\">\u2014<\/b><\/div><div class=\"kpi\"><span>Enriched Jobs<\/span><b id=\"enriched\">\u2014<\/b><\/div>\n<div class=\"kpi\"><span>Avg AI Confidence<\/span><b id=\"confidence\">\u2014<\/b><\/div><div class=\"kpi\"><span>Salary Coverage<\/span><b id=\"salaryCoverage\">\u2014<\/b><\/div>\n<\/div><div class=\"charts\"><div class=\"panel\"><h3>New jobs over time<\/h3><div class=\"chartbox\"><canvas id=\"dailyChart\"><\/canvas><\/div><\/div>\n<div class=\"panel\"><h3>Top hiring companies<\/h3><div class=\"chartbox\"><canvas id=\"companyChart\"><\/canvas><\/div><\/div>\n<div class=\"panel\"><h3>Top locations<\/h3><div class=\"chartbox\"><canvas id=\"locationChart\"><\/canvas><\/div><\/div>\n<div class=\"panel\"><h3>Enrichment quality<\/h3><table id=\"qualityTable\"><\/table><\/div><\/div><\/div>\n<div id=\"skills\" class=\"view\"><p id=\"skillsSummary\" class=\"muted\"><\/p><div class=\"charts\"><div class=\"panel\"><h3>Skill demand<\/h3><div class=\"chartbox\"><canvas id=\"skillChart\"><\/canvas><\/div><\/div>\n<div class=\"panel\"><h3>Top skill combinations<\/h3><table id=\"pairTable\"><\/table><\/div><\/div><\/div>\n<div id=\"roles\" class=\"view\"><p id=\"rolesSummary\" class=\"muted\"><\/p><div class=\"charts\"><div class=\"panel\"><h3>Role families<\/h3><div class=\"chartbox\"><canvas id=\"roleFamilyChart\"><\/canvas><\/div><\/div>\n<div class=\"panel\"><h3>Seniority<\/h3><div class=\"chartbox\"><canvas id=\"seniorityChart\"><\/canvas><\/div><\/div><\/div><\/div>\n<div id=\"salary\" class=\"view\"><div class=\"panel\"><h3>Salary evidence<\/h3><p id=\"salaryNote\" class=\"muted\"><\/p><table id=\"salaryTable\"><\/table><\/div><\/div>\n<div id=\"trends\" class=\"view\"><p id=\"trendsSummary\" class=\"muted\"><\/p><div class=\"panel\"><h3>Skill movement<\/h3><p class=\"muted\">Current window compared with the immediately preceding window. Early percentages should be treated as immature.<\/p><table id=\"trendTable\"><\/table><\/div><\/div>\n<div id=\"semantic\" class=\"view\"><div class=\"notice\"><strong>Semantic Intelligence is accumulating data.<\/strong><p id=\"semanticMessage\"><\/p><\/div><\/div>\n<\/section><\/main><script>\nconst SUPABASE_URL=\"https:\/\/vubuujwrsowpnfcengfq.supabase.co\",SUPABASE_ANON_KEY=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZ1YnV1andyc293cG5mY2VuZ2ZxIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODYwMDU0NDQsImV4cCI6MjEwMTU4MTQ0NH0.TSg9vXaNkPFWeL6A162O1vENoFmCRnlesdhXMoEVSW4\",ANALYTICS_WEBHOOK=\"https:\/\/auto.helpnetai.com\/webhook\/job-analytics-admin-v1\";\nconst sb=window.supabase.createClient(SUPABASE_URL,SUPABASE_ANON_KEY), charts={}, $=id=>document.getElementById(id);\nconst esc=v=>String(v??'').replace(\/[&<>\"']\/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#039;'}[c]));\nfunction chart(id,type,labels,data,label='Jobs'){if(charts[id])charts[id].destroy();charts[id]=new Chart($(id),{type,data:{labels,datasets:[{label,data}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true}}}})}\nfunction table(id,heads,rows){$(id).innerHTML='<thead><tr>'+heads.map(x=>`<th>${esc(x)}<\/th>`).join('')+'<\/tr><\/thead><tbody>'+rows.map(r=>'<tr>'+r.map(x=>`<td>${esc(x)}<\/td>`).join('')+'<\/tr>').join('')+'<\/tbody>'}\nfunction openTab(name){\n document.querySelectorAll('.tab').forEach(x=>x.classList.toggle('active',x.dataset.view===name));\n document.querySelectorAll('.view').forEach(x=>x.classList.toggle('active',x.id===name));\n requestAnimationFrame(()=>Object.values(charts).forEach(c=>{try{c.resize()}catch(e){}}));\n}\ndocument.querySelectorAll('.tab').forEach(b=>b.addEventListener('click',()=>openTab(b.dataset.view)));\nasync function load(){\n $('error').textContent='';$('status').textContent='Loading intelligence\u2026';\n try {\n   const {data:{session}}=await sb.auth.getSession();\n   if(!session){$('status').textContent='Please sign in as an admin from the Job Search page first.';return}\n\n   const r=await fetch(ANALYTICS_WEBHOOK,{\n     method:'POST',\n     headers:{'Content-Type':'application\/json','Authorization':`Bearer ${session.access_token}`},\n     body:JSON.stringify({days:Number($('days').value)})\n   });\n   if(!r.ok) throw new Error(`Analytics request failed (${r.status}): ${await r.text()}`);\n\n   let d=await r.json();\n\n   \/\/ n8n may return the response as a one-item array. Only unwrap that outer array.\n   if(Array.isArray(d) && d.length===1) d=d[0];\n\n   console.log('Job Intelligence payload:',d);\n\n   if(!d || !d.market || !d.market.kpi){\n     throw new Error('Dashboard response is missing market.kpi');\n   }\n\n   const m=d.market;\n   const k=m.kpi;\n   const q=d.quality || {};\n   const qe=q.enrichment || {};\n   const sal=d.salary || {};\n   const cov=sal.coverage || {};\n\n   $('active').textContent=String(k.active_jobs ?? '\u2014');\n   $('newJobs').textContent=String(k.new_jobs ?? '\u2014');\n   $('companies').textContent=String(k.companies_hiring ?? '\u2014');\n   $('enriched').textContent=String(qe.enriched_jobs ?? '\u2014');\n   $('confidence').textContent=qe.avg_confidence == null ? '\u2014' : Number(qe.avg_confidence).toFixed(3);\n   $('salaryCoverage').textContent=String(cov.coverage_pct ?? k.salary_coverage_pct ?? 0)+'%';\n\n   const daily=Array.isArray(m.daily_jobs)?m.daily_jobs:[];\n   chart('dailyChart','line',daily.map(x=>x.date),daily.map(x=>Number(x.count||0)));\n\n   for(const [id,key] of [['companyChart','top_companies'],['locationChart','top_locations']]){\n     const a=Array.isArray(m[key])?m[key]:[];\n     chart(id,'bar',a.map(x=>x.label),a.map(x=>Number(x.count||0)));\n   }\n\n   table('qualityTable',['Metric','Value'],[\n     ['Pending',qe.pending??0],['Processing',qe.processing??0],['Failed',qe.failed??0],\n     ['Missing role family',qe.missing_role_family??0],['Missing skills',qe.missing_skills??0],\n     ['Canonical skills',q.skills?.canonical_skills??0],['Job-skill links',q.job_skills?.job_skill_links??0]\n   ]);\n\n   const sk=d.skills||{};\n   const top=Array.isArray(sk.top_skills)?sk.top_skills:[];\n   $('skillsSummary').textContent=`${sk.enriched_active_jobs??0} enriched active jobs \u00b7 ${top.length} ranked skills \u00b7 ${(Array.isArray(sk.cooccurrence)?sk.cooccurrence:[]).length} skill pairs`;\n   chart('skillChart','bar',top.slice(0,20).map(x=>x.skill),top.slice(0,20).map(x=>Number(x.penetration_pct||0)),'Penetration %');\n   table('pairTable',['Skill A','Skill B','Jobs'],\n     (Array.isArray(sk.cooccurrence)?sk.cooccurrence:[]).slice(0,25).map(x=>[x.skill_a,x.skill_b,x.jobs]));\n\n   const ro=d.roles||{};\n   const fam=Array.isArray(ro.families)?ro.families:[];\n   const sen=Array.isArray(ro.seniority)?ro.seniority:[];\n   $('rolesSummary').textContent=`${ro.distinct_role_families??fam.length} role families \u00b7 ${ro.distinct_normalized_roles??0} normalized roles`;\n   chart('roleFamilyChart','bar',fam.map(x=>x.role_family),fam.map(x=>Number(x.jobs||0)));\n   chart('seniorityChart','bar',sen.map(x=>x.seniority),sen.map(x=>Number(x.jobs||0)));\n\n   $('salaryNote').textContent=`Salary coverage: ${cov.jobs_with_salary??0} of ${cov.enriched_jobs??0} enriched jobs (${cov.coverage_pct??0}%). Values are not converted across currencies.`;\n   table('salaryTable',['Role family','Currency','Sample','Median midpoint'],\n     (Array.isArray(sal.by_role_family)?sal.by_role_family:[]).map(x=>[x.role_family,x.currency,x.sample_size,x.median_midpoint??'\u2014']));\n\n   const tr=d.trends||{};\n   $('trendsSummary').textContent=`${Array.isArray(tr.skills)?tr.skills.length:0} skills in the ${tr.window_days??d.period_days??30}-day comparison window`;\n   table('trendTable',['Skill','Current jobs','Previous jobs','Change %'],\n     (Array.isArray(tr.skills)?tr.skills:[]).map(x=>[x.skill,x.current_jobs,x.previous_jobs,x.change_pct==null?'\u2014':x.change_pct+'%']));\n\n   $('semanticMessage').textContent=d.semantic?.message||'Awaiting clustering.';\n   $('dashboard').classList.remove('hidden');\n   openTab(document.querySelector('.tab.active')?.dataset.view || 'overview');\n   $('status').textContent=`Updated ${new Date(d.generated_at).toLocaleString()} \u00b7 ${d.period_days} day view`;\n } catch(err) {\n   console.error('Job Intelligence dashboard error:',err);\n   $('error').textContent=err.message || String(err);\n   $('status').textContent='';\n }\n}\n$('refresh').onclick=load;$('days').onchange=load;load();\n<\/script><\/body><\/html>\n","protected":false},"excerpt":{"rendered":"<p>Job Intelligence Analytics Job Intelligence Analytics Admin BI \u00b7 deterministic market evidence and enrichment intelligence 7 days30 days90 days180 daysRefresh Authenticating\u2026 OverviewSkills RolesSalary TrendsSemantic Active Jobs\u2014 New Jobs\u2014 Companies Hiring\u2014 Enriched Jobs\u2014 Avg AI Confidence\u2014 Salary Coverage\u2014 New jobs over time Top hiring companies Top locations Enrichment quality Skill demand Top skill combinations Role families&hellip;&nbsp;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"class_list":["post-40","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/pages\/40","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/comments?post=40"}],"version-history":[{"count":6,"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/pages\/40\/revisions"}],"predecessor-version":[{"id":55,"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/pages\/40\/revisions\/55"}],"wp:attachment":[{"href":"https:\/\/helpnetai.com\/jobs\/wp-json\/wp\/v2\/media?parent=40"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}