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
+22 -5
View File
@@ -5,16 +5,19 @@ import { fetchDataCareer, fetchStellenBasel, fetchItJobsCh, fetchJobRoom, fetchB
const CSV = "./results/jobs.csv";
const OLD_HEADER = "date_found,posted_at,search,title,company,link";
const HEADER = "date_found,posted_at,search,title,company,link,source";
const HEADER_NO_LOCATION = "date_found,posted_at,search,title,company,link,source";
const HEADER = "date_found,posted_at,search,title,company,link,source,location";
// Migrate CSV: add source column if the old header is present
// Migrate CSV: add source column if the old header is present, then location
// (the posting's real location, as parsed off its own card — distinct from
// `search`, which is just the query that found it. See CLAUDE.md.)
const csvExists = await Bun.file(CSV).exists();
if (csvExists) {
const raw = await Bun.file(CSV).text();
if (raw.startsWith(OLD_HEADER + "\n") || raw === OLD_HEADER) {
const lines = raw.split("\n");
const migrated = [
HEADER,
HEADER_NO_LOCATION,
...lines.slice(1).map((l) => (l.trim() ? l + ',"linkedin.com"' : "")),
]
.join("\n")
@@ -22,6 +25,20 @@ if (csvExists) {
await Bun.write(CSV, migrated);
}
}
{
const raw = await Bun.file(CSV).text().catch(() => "");
if (raw.startsWith(HEADER_NO_LOCATION + "\n") || raw === HEADER_NO_LOCATION) {
const lines = raw.split("\n");
const migrated = [
HEADER,
// Unknown for pre-existing rows — daily.ts falls back to `search` when empty.
...lines.slice(1).map((l) => (l.trim() ? l + ',""' : "")),
]
.join("\n")
.replace(/\n+$/, "") + "\n";
await Bun.write(CSV, migrated);
}
}
// Load existing links for deduplication
const existingLinks = new Set<string>();
@@ -68,7 +85,7 @@ for (const config of searches) {
console.log("ok");
existingLinks.add(job.link);
newRows.push(
[date, job.postedAt, config.label, job.title, job.company, job.link, "linkedin.com"]
[date, job.postedAt, config.label, job.title, job.company, job.link, "linkedin.com", job.location]
.map(csvCell)
.join(",")
);
@@ -117,7 +134,7 @@ for (const { label, fetch: fetchFn } of extraSources) {
}
existingLinks.add(job.link);
newRows.push(
[date, job.postedAt, job.search, job.title, job.company, job.link, job.source]
[date, job.postedAt, job.search, job.title, job.company, job.link, job.source, job.location]
.map(csvCell)
.join(",")
);