- Der automatisch generierte Verlaufs-Titel (aus der ersten Nachricht) erscheint
jetzt sofort in der Sidebar, nicht erst nach Reload. Der titel wird im
done-Event mitgeschickt und clientseitig gesetzt.
- Floating-Button-Icon durch eine saubere Chat-Bubble ersetzt.
Co-Authored-By: Claude <noreply@anthropic.com>
Eigenes Chat-Interface mit SSE-Streaming gegen das hinterlegte Ollama-Modell,
gegroundet in den Bewerbungs-/E-Mail-/Termindaten des Nutzers.
- lib/chat.js: streamChat (Ollama stream:true, NDJSON-Token) + buildContextPrompt
- chat_threads/chat_messages Tabellen (CASCADE, Index)
- Routen: GET /chat, Thread-CRUD, POST /messages (SSE, AbortController)
- views/chat.ejs + public/js/chat.js + Floating-Button im Footer
- hasApiKey-Gating (503 ohne OLLAMA_API_KEY)
Co-Authored-By: Claude <noreply@anthropic.com>
Mehrere Labels pro Stelle (Regional, Remote-Deutschlandweit,
Homeoffice-Deutschlandweit), gespeichert als JSON-Array in einer neuen
labels-Spalte beider Tabellen (Migration). Geteiltes lib/labels.js mit
parse/serialize; wiederverwendbare Partials fuer Chips + Mehrfachauswahl.
- Web: setzen im Hinzufuegen-Modal, auf der Bearbeiten-Seite und im
Jobangebot-Bearbeiten-Formular; Anzeige als Chips in den Listen.
- Uebernahme eines Angebots traegt dessen Labels in die neue Bewerbung.
- REST-API: labels[] in /applications und /joboffers (GET/POST/PUT),
Filter ?label=…; OpenAPI/Swagger-Schemas + Enums erweitert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Body als Flex-Column, main mit flex-1 drueckt den Footer nach unten.
Footer-Jahr serverseitig gerendert (immer aktuell).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Antworten werden meist automatisch einer Bewerbung zugeordnet und
tauchten daher nie im Postfach auf - man bemerkte sie nicht. Eine Glocke
im Header zeigt jetzt auf jeder Seite die Zahl ungelesener empfangener
E-Mails (inkl. zugeordneter Antworten) und listet sie in einem Dropdown
mit Absender, Betreff, Auszug und Link zur Bewerbung bzw. zum Postfach.
- GET /api/notifications: Anzahl + neueste ungelesene Nachrichten.
- POST /api/emails/mark-all-read: alle als gelesen markieren.
- Postfach-Ansicht markiert unverknuepfte Mails als gelesen (leert die
Glocke), zugeordnete Antworten werden beim Oeffnen der Bewerbung gelesen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Offers are now de-duplicated by normalized URL (tracking params stripped)
in addition to (quelle, external_id), so the same posting never lands
twice — even re-scraped under a new id. Deleting an offer (web or API)
auto-blacklists it, so it can never reappear.
lib/blacklist.js provides shared normalization + matching. Manual entries
can block a URL, a whole domain, a company, or a company+title posting
(gender-marker tolerant). New /blacklist page lists and manages entries.
REST API: GET/POST /joboffers/blacklist, DELETE /joboffers/blacklist/{id};
POST /joboffers returns 409 when blacklisted; DELETE /joboffers/{id}
auto-blacklists (opt out with ?blacklist=false). Swagger updated with the
new paths and schemas.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- REST API under /api/v1 with X-API-Key auth (API_TOKEN), documented with
OpenAPI 3.0; Swagger UI at /swagger, spec at /swagger.json
- Endpoints: applications CRUD + timeline, attachments/emails download,
generation trigger/status, settings, statistics, export, templates, joboffers
- Jobangebote page (/jobangebote) listing offers ingested via the REST API,
with "Als Bewerbung übernehmen" and delete actions; header nav + badge
- jobangebote table with (quelle, external_id) upsert for third-party ingestion
Co-Authored-By: Claude <noreply@anthropic.com>
Incoming e-mails that IMAP matching could not link to an application
(bewerbung_id IS NULL) were invisible. Add a dedicated page listing
them with a dropdown of existing applications to assign each one by
hand. A header badge on every page shows the count of unlinked e-mails
via a small /api/emails/unassigned-count endpoint.
Co-Authored-By: Claude <noreply@anthropic.com>
- Browser extension (Chromium MV3) injecting a "send to tracker" button next
to the Indeed job description; scrapes job info and posts it to a new
/api/indeed-import endpoint (CORS-enabled), configurable tracker URL via popup.
- New "Entwurf" status. Imports create a draft and trigger background AI
generation of tailored Anschreiben + Lebenslauf (PDF attachments) via the
Ollama Cloud API, grounded strictly in user-provided base documents.
- Vorlagen page to manage base documents; attachments UI, generation status
polling, regenerate and download routes on the application page.
- Schema: ort/stellenbeschreibung/quelle_url/generierung_* columns, plus
basis_dokumente and anhaenge tables (with migrations).
- Config via .env (OLLAMA_API_KEY/OLLAMA_MODEL/OLLAMA_HOST); dependency-free
.env loader. Dockerfile copies lib/, .dockerignore added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>