feat: add job maintenance dashboard and automated stale job expiration system

This commit is contained in:
2026-08-22 01:51:43 -07:00
parent 367929e7d0
commit 7ec91f384f
12 changed files with 633 additions and 56 deletions
+39 -16
View File
@@ -18,6 +18,7 @@ const jobsTabHTML = `{{ define "jobsTab" }}
<option value="not-qualified">❌ Not Qualified</option>
<option value="saved">💾 Saved / In Pipeline</option>
<option value="all">🌐 All Jobs</option>
<option value="expired">⚠️ Expired / Closed</option>
<option value="opted-out">🚫 Opted-out</option>
</select>
<button hx-get="/jobs" hx-target="#jobs-container" hx-swap="innerHTML"
@@ -45,7 +46,7 @@ const jobListHTML = `{{ define "jobs" }}
<th class="px-4 py-3" data-sort="status">Analysis</th>
<th class="px-4 py-3" data-sort="score">Score &amp; Qualification</th>
<th class="px-4 py-3">Reason / Tags</th>
<th class="px-4 py-3" data-sort="date">Crawled</th>
<th class="px-4 py-3" data-sort="date">Last Updated</th>
<th class="px-4 py-3 text-right">Actions</th>
</tr>
</thead>
@@ -54,7 +55,7 @@ const jobListHTML = `{{ define "jobs" }}
{{- $qual := "pending" -}}
{{- if .Analysis }}{{ if .Analysis.IsQualified }}{{ $qual = "qualified" }}{{ else }}{{ $qual = "not-qualified" }}{{ end }}{{ end -}}
{{- $appClass := "none" -}}
{{- if .App }}{{ if eq .App.Status "OPTED_OUT" }}{{ $appClass = "opted-out" }}{{ else }}{{ $appClass = "pipeline" }}{{ end }}{{ end -}}
{{- if .App }}{{ if eq .App.Status "OPTED_OUT" }}{{ $appClass = "opted-out" }}{{ else if eq .App.Status "EXPIRED" }}{{ $appClass = "expired" }}{{ else }}{{ $appClass = "pipeline" }}{{ end }}{{ end -}}
<tr class="hover:bg-slate-800/40 transition-colors group" data-row data-qual="{{ $qual }}" data-app="{{ $appClass }}">
<!-- Title & Company -->
@@ -117,9 +118,13 @@ const jobListHTML = `{{ define "jobs" }}
<!-- Reason / Matched Tags -->
<td class="px-4 py-3 max-w-[180px]">
{{ if .App }}{{ if eq .App.Status "OPTED_OUT" }}
<span class="text-[10px] text-slate-500 italic">Opted out</span>
{{ end }}{{ end }}
{{ if .App }}
{{ if eq .App.Status "OPTED_OUT" }}
<span class="text-[10px] text-slate-500 italic block">Opted out</span>
{{ else if eq .App.Status "EXPIRED" }}
<span class="text-[10px] text-amber-400/80 italic block">⚠️ No longer active</span>
{{ end }}
{{ end }}
{{ if .Analysis }}
{{ if .Analysis.IsQualified }}
<div class="flex flex-wrap gap-1">
@@ -139,8 +144,8 @@ const jobListHTML = `{{ define "jobs" }}
</td>
<!-- Date -->
<td class="px-4 py-3 text-slate-400 text-[11px]" data-sort-val="{{ .CrawledAt.Unix }}">
{{ formatDate .CrawledAt }}
<td class="px-4 py-3 text-slate-400 text-[11px]" data-sort-val="{{ .LastSeenAt.Unix }}">
{{ formatDate .LastSeenAt }}
</td>
<!-- Actions: Save + Opt-out OR status badge -->
@@ -148,14 +153,32 @@ const jobListHTML = `{{ define "jobs" }}
{{ if .App }}
{{ if eq .App.Status "OPTED_OUT" }}
<!-- Opted out: show undo button -->
<button hx-post="/applications"
hx-vals='{"raw_job_id": {{ .ID }}, "status": "SAVED"}'
hx-target="#jobs-container"
hx-swap="innerHTML"
title="Undo opt-out"
class="px-2.5 py-1 rounded bg-slate-800 hover:bg-slate-700 text-slate-400 border border-slate-700 text-[10px] transition-colors">
↩ Undo
</button>
<div class="flex items-center justify-end gap-1.5">
<span class="text-[10px] text-slate-500">Opted-out</span>
<button hx-post="/applications"
hx-vals='{"raw_job_id": {{ .ID }}, "status": "SAVED"}'
hx-target="#jobs-container"
hx-swap="innerHTML"
title="Undo opt-out"
class="px-2 py-0.5 rounded bg-slate-800 hover:bg-slate-700 text-slate-300 border border-slate-700 text-[10px] transition-colors">
↩
</button>
</div>
{{ else if eq .App.Status "EXPIRED" }}
<!-- Expired -->
<div class="flex items-center justify-end gap-1.5">
<span class="px-2 py-0.5 rounded bg-slate-800 text-slate-400 text-[10px] font-bold border border-slate-700">
⚠️ EXPIRED
</span>
<button hx-post="/applications"
hx-vals='{"raw_job_id": {{ .ID }}, "status": "SAVED"}'
hx-target="#jobs-container"
hx-swap="innerHTML"
title="Re-open / Save"
class="px-2 py-0.5 rounded bg-slate-800 hover:bg-slate-700 text-slate-300 border border-slate-700 text-[10px] transition-colors">
↩
</button>
</div>
{{ else }}
<!-- In pipeline -->
<span class="px-2 py-1 rounded bg-violet-500/20 text-violet-300 text-[10px] font-bold border border-violet-500/30">
@@ -203,7 +226,7 @@ const jobDetailHTML = `{{ define "jobDetail" }}
<div class="flex-1 min-w-0 pr-4">
<span class="text-xs font-bold text-indigo-400 uppercase tracking-wide">{{ .Company }}</span>
<h2 class="text-xl font-extrabold text-white mt-0.5 leading-tight">{{ .Title }}</h2>
<p class="text-xs text-slate-400 mt-1">📍 {{ .Location }} &bull; Ingested {{ formatDate .CrawledAt }}</p>
<p class="text-xs text-slate-400 mt-1">📍 {{ .Location }} &bull; Last Updated {{ formatDate .LastSeenAt }}</p>
</div>
<button onclick="closeDetailModal()" class="flex-shrink-0 text-slate-400 hover:text-white text-lg p-1 rounded hover:bg-slate-800 transition-colors">✕</button>
</div>