Carry firma_slug on job offers, supplied by the ingesting client

The blacklist company slug now lives on the offers themselves. POST /joboffers
accepts firma_slug and stores it as supplied (deriving it from firma only when
omitted); it is persisted on jobangebote (schema + ALTER/backfill + index) and
returned in the Joboffer response. Blacklist matching prefers the client-supplied
slug over one derived from firma, so the indexing client controls the identity
used to block an offer. OpenAPI request/response schemas updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 22:42:41 +02:00
co-authored by Claude Opus 4.8
parent f935e00b53
commit 22f967c753
4 changed files with 28 additions and 5 deletions
+13
View File
@@ -803,6 +803,19 @@ function initializeDatabase() {
});
});
db.run('CREATE INDEX IF NOT EXISTS idx_jobangebote_url_norm ON jobangebote(url_norm)', () => {});
// Company slug carried on the offer itself (supplied by the indexing
// client, else derived from firma). Used for blacklist matching and
// "same company" grouping. Backfill derives it from firma.
db.run('ALTER TABLE jobangebote ADD COLUMN firma_slug TEXT', () => {
db.all('SELECT id, firma FROM jobangebote WHERE firma_slug IS NULL AND firma IS NOT NULL AND firma != ""', (err, rows) => {
if (err || !rows) return;
rows.forEach((r) => {
const slug = blacklist.firmaSlug(r.firma);
if (slug) db.run('UPDATE jobangebote SET firma_slug = ? WHERE id = ?', [slug, r.id], () => {});
});
});
});
db.run('CREATE INDEX IF NOT EXISTS idx_jobangebote_firma_slug ON jobangebote(firma_slug)', () => {});
// Blacklist of job offers that must never (re)appear in the list. A
// deleted offer is auto-blacklisted; manual entries can block a URL,
// a whole domain, a company, or a specific company+title posting.