fix: group telegram digest by posting's real location, not search label

fetch.ts already parses each job card's own location, but index.ts
discarded it and stored only the search-area label in the CSV, so
daily.ts's telegram grouping used the query that found a job instead
of where it actually is (e.g. a Bern search surfacing a Lausanne job).
Now the location is written to a new CSV column and used for grouping,
with a one-time migration for existing rows.
This commit is contained in:
2026-08-28 19:56:40 +02:00
parent 7276aded92
commit 2de9809ea9
3 changed files with 40 additions and 13 deletions
+14 -7
View File
@@ -11,7 +11,7 @@ const SENT = "./results/sent.txt"; // links already pushed — never resend
const dry = process.argv.includes("--dry-run");
const resend = process.argv.includes("--resend");
type Row = { fetched: string; posted: string; search: string; title: string; company: string; link: string; source: string };
type Row = { fetched: string; posted: string; search: string; title: string; company: string; link: string; source: string; location: string };
function parse(text: string): Row[] {
return text
@@ -20,7 +20,7 @@ function parse(text: string): Row[] {
.filter(Boolean)
.map((l) => {
const c = l.replace(/^"|"$/g, "").split('","');
return { fetched: c[0], posted: c[1], search: c[2], title: c[3], company: c[4], link: c[5], source: c[6] };
return { fetched: c[0], posted: c[1], search: c[2], title: c[3], company: c[4], link: c[5], source: c[6], location: c[7] ?? "" };
});
}
@@ -60,13 +60,20 @@ if (!matched.length) {
process.exit(0);
}
// Group by area so the message scans quickly on a phone.
// Group by area so the message scans quickly on a phone. Match against the
// posting's own location first — `search` is just the query that found it,
// and recruiters/multi-site companies often post under a different area than
// the job actually sits in (e.g. a "Bern" LinkedIn sweep surfacing a Lausanne
// posting). Fall back to `search` only when no location was captured (rows
// written before the location column existed).
const area = (r: Row) => {
const loc = r.location.toLowerCase();
const s = r.search.toLowerCase();
if (s.includes("remote")) return "🌍 Remote";
if (s.includes("basel")) return "🟢 Basel";
if (s.includes("zürich") || s.includes("zurich")) return "🔵 Zürich";
if (s.includes("bern")) return "🟣 Bern";
const text = loc || s;
if (s.includes("remote") || loc.includes("remote")) return "🌍 Remote";
if (text.includes("basel")) return "🟢 Basel";
if (text.includes("zürich") || text.includes("zurich")) return "🔵 Zürich";
if (text.includes("bern")) return "🟣 Bern";
return "⚪️ Other";
};
const order = ["🟢 Basel", "🌍 Remote", "🔵 Zürich", "🟣 Bern", "⚪️ Other"];