Scanner: Stellenanzeigen aus Jobbörsen (DACH, max. 21 Tage)

Neuer Menüpunkt Scanner mit Dashboard und Suchagenten, Zeitplan und
API-Schlüssel unter Einstellungen -> Scanner.

- Quellen: Agentur für Arbeit (API), StepStone, karriere.at,
  freelancermap (HTML) sowie Adzuna und Jooble (kostenlose Schlüssel)
- Quote = gefundene Schlagwörter, Titel zählt doppelt; keine KI
- Abgleich mit icon_companies, bekannte Firmen oben mit Abzeichen
- Zeitplan Vorgabe stündlich Mo-Fr 06-20 Uhr, einstellbar
- Sperre gegen parallele Läufe wie im perinco-Scanner

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
schakal00783
2026-09-29 10:49:44 +02:00
co-authored by Claude Opus 5.5
parent 6fe5b18c11
commit 1b82f580db
23 changed files with 2894 additions and 2 deletions
+80
View File
@@ -419,3 +419,83 @@ CREATE TABLE IF NOT EXISTS icon_settings (
value MEDIUMTEXT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------------------
-- Scanner: Stellenanzeigen aus Jobbörsen (DACH, höchstens 21 Tage alt)
--
-- Ein Suchagent ist eine Liste von Schlagwörtern plus der Börsen, in denen
-- gesucht wird, plus Ausschlussbegriffen. Jede Anzeige liegt genau einmal in
-- icon_scanner_jobs (eindeutig je Börse und deren Kennung); welcher Agent sie
-- mit welcher Güte gefunden hat, steht in icon_scanner_matches.
--
-- Bewertet wird nicht per KI, sondern per Zählung: je mehr Schlagwörter eines
-- Agenten in Titel und Text vorkommen, desto höher der Treffer.
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS icon_scanner_agents (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(190) NOT NULL,
-- JSON-Arrays: ["SAP FI", "Interim CFO"], ["ba", "stepstone"], ["Praktikum"]
keywords TEXT NOT NULL,
sources TEXT NOT NULL,
excludes TEXT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_by INT UNSIGNED NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_icon_scanner_agents_creator FOREIGN KEY (created_by)
REFERENCES icon_users (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS icon_scanner_jobs (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
source VARCHAR(30) NOT NULL,
external_id VARCHAR(190) NOT NULL,
title VARCHAR(500) NOT NULL,
company VARCHAR(300) NULL,
-- Treffer im CRM: Unternehmen mit gleichem (normalisiertem) Namen.
company_id INT UNSIGNED NULL,
location VARCHAR(300) NULL,
country CHAR(2) NULL,
employment_type VARCHAR(60) NULL,
url VARCHAR(1000) NOT NULL,
description MEDIUMTEXT NULL,
published_at DATETIME NULL,
first_seen_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_seen_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_icon_scanner_jobs (source, external_id),
KEY idx_icon_scanner_jobs_published (published_at),
KEY idx_icon_scanner_jobs_company (company_id),
CONSTRAINT fk_icon_scanner_jobs_company FOREIGN KEY (company_id)
REFERENCES icon_companies (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS icon_scanner_matches (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
agent_id INT UNSIGNED NOT NULL,
job_id INT UNSIGNED NOT NULL,
score TINYINT UNSIGNED NOT NULL DEFAULT 0,
-- JSON-Array der gefundenen Schlagwörter
hits TEXT NULL,
status ENUM('neu','gesehen','in_bearbeitung','verworfen') NOT NULL DEFAULT 'neu',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_icon_scanner_matches (agent_id, job_id),
KEY idx_icon_scanner_matches_created (created_at),
CONSTRAINT fk_icon_scanner_matches_agent FOREIGN KEY (agent_id)
REFERENCES icon_scanner_agents (id) ON DELETE CASCADE,
CONSTRAINT fk_icon_scanner_matches_job FOREIGN KEY (job_id)
REFERENCES icon_scanner_jobs (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Protokoll der Läufe: wann, wodurch ausgelöst, was je Börse herauskam.
CREATE TABLE IF NOT EXISTS icon_scanner_runs (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
trigger_kind ENUM('auto','manual') NOT NULL,
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
finished_at TIMESTAMP NULL,
jobs_found INT UNSIGNED NOT NULL DEFAULT 0,
matches_new INT UNSIGNED NOT NULL DEFAULT 0,
-- JSON: { ba: { ok: true, count: 12 }, stepstone: { ok: false, error: "..." } }
per_source TEXT NULL,
KEY idx_icon_scanner_runs_started (started_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;