Commit Graph
53 Commits
Author SHA1 Message Date
thomasandClaude Opus 4.8 65a5943993 KI-Prompts unter Vorlagen editierbar statt hardcoded
Rolle, Tonfall und Regeln der KI (Unterlagen, Chat, E-Mail-Antwort,
E-Mail-Absage, gemeinsame Stilregeln) lagen fest im Code. Sie liegen jetzt
als Defaults in lib/prompts.js und lassen sich auf der Vorlagen-Seite je
Prompt anpassen und wieder zuruecksetzen.

Nur die System-Prompts sind editierbar. Die User-Prompts tragen das
JSON-Skeleton, gegen das die Antwort geparst wird - ein Tippfehler dort
wuerde die Generierung lahmlegen, also bleiben sie im Code.

Gespeichert wird nur, was abweicht: ein Override ist eine Zeile in der neuen
Tabelle `prompts`, "Zuruecksetzen" loescht sie. Damit bleiben die Defaults im
Code die Wahrheit und wandern bei Updates automatisch mit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 00:09:03 +02:00
thomasandClaude 0a0b0b4724 E-Mail: KI-Absage generieren (andere Stelle angenommen)
Im Antwort-Formular gibt es neben dem KI-Button jetzt ein Dropdown Antwort/Absage.
Für Absage formuliert die KI eine kurze, höfliche E-Mail: Bewerber hat eine andere
Stelle angenommen, bedankt sich, zieht sich aus dem Prozess zurück.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-10 20:51:37 +02:00
thomasandClaude 0c7502cfd7 KI-Chat: Bewerbungsdaten per Tool-Calling nachschlagen statt in Prompt stopfen
Der Systemprompt enthielt früher nur die 12 jüngsten Bewerbungen (LIMIT 12),
daher fand die KI ältere Firmen wie QBS KLIMTAX nicht. Alle Bewerbungen in den
Prompt zu laden machte den Chat sehr langsam, da der Prompt bei jedem Turn
voll neu verarbeitet wird.

Jetzt nutzt der Assistent Ollama-Tool-Calling, um Datenbankdaten on demand
nachzuschlagen. Der Systemprompt bleibt klein und konstant (nur Profil +
Datum), unabhängig von der Anzahl der Bewerbungen.

- lib/chat.js: streamChat mit tools + runChat-Tool-Schleife (max 4 Runden)
- server.js: Tools suche_bewerbungen/list_bewerbungen/bewerbung_detail/
  kommende_termine mit SQL-Queries; gatherChatContext auf Kern reduziert
- public/js/chat.js: Tool-Indikator ("durchsucht Bewerbungen…") im UI

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-09 05:41:14 +02:00
thomasandClaude cf6cf9ee33 KI-Chat: reichhaltigerer Kontext (Stellenbeschreibung, Korrespondenz, Profil)
Der Assistent kannte nur Firma/Stelle/Status/Notizen und konnte daher keine
firmenspezifischen Fragen beantworten. gatherChatContext lädt jetzt pro
Bewerbung: Ort, interne Notizen, Stellenbeschreibung (bzw. verknüpftes
Jobangebot), Kontakt/Ansprechpartner und die E-Mail-Korrespondenz (Betreffe).
Zusätzlich wird der Lebenslauf des Bewerbers injiziert, damit Antworten auf
"was für mich wichtig" zugeschnitten werden können.

Relevante Bewerbungen = Termin-Bewerbungen + 12 jüngste (gebunden im Token-Budget).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-07 14:36:45 +00:00
thomasandClaude c389d3d5ec KI-Chat: Kontext-Injection repariert (SQL from-Alias) + Datum im Prompt
gatherChatContext() brach mit SQLITE_ERROR ab, weil "e.from_addr AS from"
das SQL-Schlüsselwort from als Alias nutzte. Der Fehler wurde im Route-Handler
geschluckt (context={}), sodass der Assistent keinen Zugriff auf Bewerbungen/
Termine/E-Mails hatte. Alias entfernt.

Zusätzlich erhält der System-Prompt jetzt das heutige Datum, damit der
Assistent "morgen"/"heute" aus den UTC-Termin-Zeitstempeln ableiten kann.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-07 14:21:13 +00:00
thomasandClaude ead70efa49 KI-Chat: interaktiver Bewerbungs-Assistent (Ollama-Streaming)
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>
2026-07-07 14:07:38 +00:00
thomasandClaude Opus 4.8 17df46cb6c Reply-Mail: Zeilenumbrüche als <br> statt white-space:pre-wrap
Ausgehende Antwort-Mails (multipart/alternative) rendern den HTML-Teil
bisher über white-space:pre-wrap auf rohen Zeilenumbrüchen ohne <br>.
Beim ersten Empfang korrekt, aber sobald der Empfänger-Client (Outlook)
die Mail zitiert, wird der pre-wrap-Stil verworfen und die nackten
Newlines zu Leerzeichen kollabiert -> unser formatiertes Anschreiben wird
im Zitat zur zusammenhanglosen Textwand. Explizite <br> überleben diesen
Round-Trip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 09:18:44 +00:00
thomasandClaude Opus 4.8 4e1043897d Blacklist: Firmen schreibweisen-robust matchen (eine Firma nur einmal)
sameCompany() vergleicht Firmen-Slugs jetzt per Gleichheit ODER führendem
Bindestrich-Präfix (>=2 Tokens), sodass Kurzname und voller Firmenname
derselben Firma als gleich gelten (z. B. "it-problemloeser" =
"it-problemloeser-verwaltungs-und-handels", "stadtwerke-essen" =
"stadtwerke-essen-netz"). firmaMatch() nutzt das für die Blacklist-Typen
firma/firma_stelle/auto. Distinkte Firmen mit nur gleichem ersten Wort
("meyer-it" vs "meyer-logistik") bleiben getrennt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 07:25:04 +00:00
thomasandClaude Opus 4.8 7e0c27341a CalDAV: HTML-Entities in Terminfeldern dekodieren
Manche Kalender speichern SUMMARY/LOCATION/DESCRIPTION mit wörtlichen
HTML-Entities (z. B. "Vorstellungsgespr&#228;ch &#8211; dot.haus"). Diese
wurden roh angezeigt. Beim Parsen werden sie jetzt in echte Zeichen
dekodiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:58:07 +02:00
thomasandClaude Opus 4.8 22f967c753 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>
2026-07-06 22:42:41 +02:00
thomasandClaude Opus 4.8 f935e00b53 Add robust company slug for job-offer blacklist matching
Company matching relied on normText(), which kept legal-form suffixes,
spacing and umlaut spelling — so "Bosch GmbH", "Bosch AG" and "bosch gmbh"
did not match the same entry, making the blacklist unreliable.

Introduce firmaSlug(): transliterate German umlauts, strip diacritics and
trailing legal-form tokens (GmbH/AG/SE/KG/…), then kebab-join. Add a
firma_slug field to jobangebote_blacklist (schema + ALTER/backfill migration)
and match on it for typ firma/firma_stelle/auto, falling back to firma_norm
for legacy rows. POST /joboffers rejects blacklisted offers via matchBlacklist
automatically since offerSignature now carries the slug.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:25:59 +02:00
thomasandClaude Opus 4.8 c2c51f9fca Neue Bewerbungs-Status: In Bearbeitung, Interessiert, Warten auf Rückmeldung/meine Antwort
Vier mittlere Pipeline-Status ergänzt (nach Eingangsbestätigung, vor
Vorstellungsgespräch), inkl. Farben/Reihenfolge in Übersicht, Detailseite
und PDF-Export sowie REST-API-Validierung und Swagger-Enum.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:06:56 +02:00
thomasandClaude Opus 4.8 03760d293f Labels für Stellen (Bewerbungen + Jobangebote), inkl. API & Swagger
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>
2026-07-05 15:23:44 +02:00
thomasandClaude Opus 4.8 b1531663bb E-Mails als HTML anzeigen; Antworten zitieren Vornachricht (auch KI)
- HTML-Mails werden in einem sandboxed iframe (ohne allow-scripts)
  gerendert statt als Quelltext angezeigt; Höhe an Inhalt angepasst,
  Skripte/Tracking laufen nicht, Layout bleibt isoliert. Reine
  Text-Mails weiterhin als pre-wrap. Gilt für Postfach und Bewerbung.
- Antwortformular ist wie im Mailclient mit der zitierten Vornachricht
  vorbelegt (Attribution + "> "-Zeilen), Cursor darüber.
- KI-Antwort hängt das Zitat unter den generierten Text und erhält den
  bereinigten Klartext (statt HTML) als Eingabe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 23:06:59 +02:00
thomasandClaude Opus 4.8 95b5b8510d Add a two-way application calendar (CalDAV / SOGo)
New lib/caldav.js speaks CalDAV over Basic auth (shared mail account):
reads events in a window, and creates/updates/deletes iCalendar VEVENTs
with a reminder alarm. DST-correct Europe/Berlin <-> UTC handling.

Appointments (Vorstellungsgespräch / general) are managed per application
in a new "Termine" section and mirrored to the SOGo calendar; recording a
"Vorstellungsgespräch" status suggests a prefilled calendar entry
(confirm + click). A dashboard widget lists upcoming appointments. A
background poller reconciles remote edits/deletions via the collection
ctag. Config: CALDAV_URL (+ CALDAV_ALARM_MIN, CALDAV_POLL_MS); disabled
gracefully when unset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:06:38 +02:00
thomasandClaude Opus 4.8 26872ece08 Choose enclosed attachments before generating; drop instant-generate
The generate form now lets the user pick which extra attachments
(basis_anhaenge) to enclose — none selected by default. Only the chosen
ones are attached, and their names are passed to the LLM so the cover
letter's "Anlagen" list and wording reflect exactly what is enclosed.

Job offers keep only "Als Bewerbung übernehmen" (draft first); the
"Übernehmen & KI-Unterlagen" button and its route are removed.

REST API: POST /applications/:id/generate accepts an optional `anlagen`
array of attachment IDs (Swagger updated).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:36:14 +02:00
thomasandClaude Opus 4.8 360e04d677 Confirm before sending; add address + contact to job offers
"Bewerbung senden" now asks for an extra confirmation (with the
recipient) before dispatching.

Job offers gain adresse and ansprechpartner fields — shown, editable,
and carried through the REST API upsert (Swagger updated). Taking an
offer over now writes the employer address (street, number, city) and
the contact person into the application's AI notes (llm_notizen), so the
LLM can use them for the letter's Anschriftfeld and salutation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:10:13 +02:00
thomasandClaude Opus 4.8 dae077486f Add a job-offer blacklist with URL-based de-duplication
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>
2026-07-04 13:33:12 +02:00
thomasandClaude Opus 4.8 1655427b4c Drop the underline rules under the CV sidebar headings
The sidebar section labels no longer carry a short accent underline;
tracking and weight provide the structure, keeping the left column clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:50:50 +02:00
thomasandClaude Opus 4.8 fa25307791 Flatten a multi-line address in the cover-letter footer
doc.text breaks on newlines, which stacked the street above the city in
the footer contact strip. Split the address on newlines and commas and
rejoin as one line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:39:36 +02:00
thomasandClaude Opus 4.8 8281128adc Restyle the cover letter to match the CV; refine the résumé head
Cover letter: a big confident name + role in tracked caps, the shared
hairline-with-accent motif, and a centred contact footer strip (moved
out of the header) so it reads as one set with the monochrome résumé.

Résumé: drop the divider rule above the Profil heading — the section
headings carry the structure on their own.

Prompt: forbid the headline from using a protected professional title
the applicant has not verifiably earned (e.g. Fachinformatiker,
Ingenieur, Meister); fall back to a neutral activity label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:33:32 +02:00
thomasandClaude Opus 4.8 390f9a643b Redesign the Lebenslauf as a monochrome two-column layout
Replace the single-column résumé with a two-column layout: a tinted
grey sidebar (photo, contact, Kernkompetenzen, Sprachen, Interessen)
and a wide main column with a large name header, Profil, a timeline
Berufserfahrung, and education. Strictly black-and-white — the former
navy accent becomes near-black across both the résumé and the cover
letter so the set stays consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:12:48 +02:00
thomasandClaude cb1115ef95 Add kontakt_email to job offers
- New kontakt_email TEXT column on jobangebote (+ ALTER TABLE migration)
- Accept kontakt_email in POST /api/v1/joboffers (create + upsert) and
  document it in the OpenAPI spec
- Render a mailto: link on the /jobangebote page and include it in the
  curl example

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 22:16:55 +02:00
thomasandClaude 5d6fed7041 Show job offer posting date (anzeige_datum) alongside ingestion date
- Add anzeige_datum DATE column to jobangebote (with ALTER TABLE migration
  for pre-existing tables) — the original posting date supplied by the
  third party
- Accept anzeige_datum in POST /api/v1/joboffers (create + upsert) and
  document it in the OpenAPI spec
- Render both on /jobangebote: "Anzeige: <anzeige_datum>" and
  "Einspielung: <created_at>"

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 21:46:12 +02:00
thomasandClaude 88875dbc33 Add third-party REST API (/api/v1) + Swagger UI and Jobangebote page
- 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>
2026-07-03 21:30:33 +02:00
thomasandClaude Opus 4.8 0af731695a Size CV heading accent bar to the word width
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 20:26:28 +02:00
thomasandClaude 482d8d86fa Shorten cover email + strip non-Latin script from AI text
The generated Begleit-E-Mail was too long for an HR reader and sometimes
contained stray non-Latin characters (e.g. CJK "包括"). Make the email a
minimal accompanying note (no repetition of the cover letter, max ~3
sentences), add a German-only/Latin-script instruction to both the
document and reply prompts, and add a backstop sanitizer in str() that
strips any non-Latin script characters the model still emits.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 19:28:34 +02:00
thomasandClaude 931bb85c6a Don't name current employer in cover letter
The LLM was naming the current employer (e.g. "IT-Problemlöser GmbH")
in the cover letter text. Add a prompt rule to keep the company name out
of the Anschreiben; the CV still lists employers as before.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 18:50:59 +02:00
thomasandClaude 57eb19632d Always include languages (esp. English) in CV
Languages were dropped when not explicitly required by the job posting.
Sprachkenntnisse are standard CV content in Germany, so always include
them from the base documents regardless of job relevance.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 18:43:55 +02:00
thomasandClaude Opus 4.8 d8b552e57d Ban hollow filler and self-labels in generated prose
The model produced awkward AI-tells like "Als Muttersprachler kommuniziere
ich serviceorientiert und klar - sowohl mit Anwendern als auch im Team".
Add an explicit style rule (system prompt, shared prose guidance, and the
AI-reply prompt) that forbids empty buzzword pairs and self-labels such as
"Als Muttersprachler ...", quoting the offending sentence as a negative
example. Language proficiency belongs only in the CV's Sprachen section;
every trait must come out of a concrete task or result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:11:31 +02:00
thomasandClaude Opus 4.8 4a896e72e3 Restyle cover letter to match the CV as one application set
Bring the Anschreiben into the résumé's visual language: navy name,
tracked role line, the shared hairline-plus-accent-bar rule under the
letterhead, and a navy bold subject line as the letter's headline. Keep
strict DIN-5008 structure (recipient block, right-aligned date, subject,
salutation/closing, signature space, enclosures) and near-black body for
readability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:04:52 +02:00
thomasandClaude Opus 4.8 ddcf5edbc3 Restyle CV: navy accent system + competency-first structure
Rework the résumé as an HR-first document. Move Kernkompetenzen (renamed
from Fähigkeiten) directly under the Profil so the role-match is visible
in the first seconds, ahead of the reverse-chronological experience.

Introduce one restrained deep navy-slate accent used only for structure:
the name, section labels, a short accent bar starting each section rule,
and small square bullet markers — a coherent, precise motif. Body text
stays near-black for a crisp, ATS-safe read. Verified on the with-photo
and no-photo layouts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:58:22 +02:00
thomasandClaude Opus 4.8 0b44f61410 Add e-mail system: send applications, receive & reply to responses
Send the complete application (body + generated attachments) to a
user-entered address via authenticated SMTP submission through the
account's own server, so it applies DKIM and uses its reputable IP/PTR —
required for deliverability here (domain publishes SPF -all, DMARC
p=reject). From/Return-Path stay aligned on the sending domain.

Reply e-mails are polled over IMAP, parsed, stored and matched to the
right application (via In-Reply-To/References, then sender address);
their attachments are saved and downloadable. The detail page gains a
correspondence thread with compose, threaded reply, and an AI-drafted
reply the user can edit before sending.

New: lib/mailer.js (nodemailer + imapflow + mailparser), generateEmailReply
in lib/documents.js, emails/email_anhaenge/app_state tables, background
poller + manual fetch. Credentials come from MAIL_* env vars (.env, not
committed / not in the image).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:59:32 +02:00
thomasandClaude Opus 4.8 3c553cadf5 Generate an editable norm-compliant cover email per application
Alongside the tailored PDFs, the LLM now produces a short, DIN-style
Begleit-E-Mail (subject + body) grounded in the same data: same
salutation as the cover letter, the target role, a line or two of core
motivation, a pointer to the attached documents, and a friendly close.

Persisted in new bewerbungen columns (email_betreff, email_anschreiben)
and surfaced in an editable subject field + textarea on the detail page,
so the applicant can tweak it before sending; a copy button puts subject
and body on the clipboard. Values are stored raw and HTML-escaped on
render to avoid double-escaping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:20:56 +02:00
thomasandClaude Opus 4.8 0bfa5683fb CV: tuck Profil up and flow it around the photo
Drop the dead gap between the contact block and the first section: the
Profil heading and its opening lines now sit beside the photo's lower
flank (hairline stopping short of the photo) and spill to full width
once past the photo's bottom edge. No-photo layout unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:10:25 +02:00
thomasandClaude 5090dbbeb6 Anrede: keep full surname incl. particles (Al/El/van/von/de)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 14:52:31 +02:00
thomasandClaude 7d2640f5d5 CV: enlarge photo 20%, drop header rule above Profil
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 14:45:12 +02:00
thomasandClaude 990a663cdd Optional applicant photo in CV header
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 14:39:13 +02:00
thomasandClaude e914dee855 Anrede: last name only, strip first name (keep titles/particles)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 14:18:02 +02:00
thomasandClaude 86f94ce642 Embed Lato typeface for CV and cover letter (ATS-safe, German glyphs)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 13:50:39 +02:00
thomasandClaude 2a12ab54d0 CV date format MM/YYYY instead of MM.YYYY
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 13:22:50 +02:00
thomasandClaude 798abf67d5 Prompt: hard skills only; neutral unfinished-degree handling (no fake grade)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 13:11:06 +02:00
thomasandClaude 7d46032378 Redesign Lebenslauf: monochrome single-column HR layout
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 12:55:34 +02:00
thomasandClaude 6cf4fb58b0 CV: single-column layout, drop personal fields (Geburtsdatum/Führerschein/Schulbildung)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 12:38:24 +02:00
thomasandClaude a28018f31c CV: contact icons, larger meta text, removed heading rules
Draw small vector icons (phone, mail, pin, globe) in front of each
contact row instead of a pipe-separated single line; drop the title
highlight box and the per-section hair rules for a cleaner header.
Bump experience/education meta to 9.5pt ink and titles to 11.5pt bold,
and tighten section spacing.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 12:20:38 +02:00
thomasandClaude Opus 4.8 3f57474bd1 Redesign résumé: white single-page layout (centered header + two columns)
Replaces the navy-sidebar CV with a white layout modelled on the reference:
centered position title (soft highlight), name, contact row, a tailored Profil
section, then two columns — experience (with bullet points) and education on the
left; skills, languages, interests and personal details on the right.
Restores the profil field and switches experience back to bullet points.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:02:50 +02:00
thomasandClaude Opus 4.8 3fc8b76d39 Enlarge cover-letter signature by 20%
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:41:52 +02:00
thomasandClaude Opus 4.8 78128db422 Signature image in cover letter + fix per-paragraph capitalization
- Only the first body paragraph continues the salutation (lowercase safe
  opener); every following paragraph is a new sentence and is capitalized.
  Handled deterministically so it no longer depends on the model.
- Signature: upload a signature image on the Vorlagen page (preview / replace /
  remove). It is embedded in the cover letter directly under the closing
  salutation, replacing the typed name; falls back to the name when absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:37:03 +02:00
thomasandClaude Opus 4.8 cbdbbc07e3 Manual generation, LLM notes with company address, and static attachments
- Static extra attachments: upload files (e.g. Zeugnisse) once on the Vorlagen
  page; they are attached to every generated application and listed under
  "Anlagen" in the cover letter (via multer upload + basis_anhaenge table).
- Import no longer auto-generates: an imported job is saved as a draft
  ("nicht_gestartet"); generation is triggered manually on the application page.
- Per-application "LLM-Notizen" field: free text (company address, contact
  person, extra context) that is fed to the model at generation time. Saving the
  notes and (re)generating happens in one action.
- Cover letter recipient block is now a structured empfaenger (firma, address,
  city, contact person) the model fills from the job + notes; the salutation
  adapts to a named contact. Falls back to the imported company + city.
- Raise default OLLAMA_TIMEOUT_MS to 300s for slower cloud models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:22:14 +02:00
thomasandClaude Opus 4.8 5f02413410 Norm-compliant CV education sections + redesigned monochrome cover letter
CV:
- Split education into proper German sections (Studium, Berufsausbildung,
  Schulbildung, Weiterbildungen) instead of one lumped "Ausbildung".
- Keep the timeline gap-free (lückenlos) and strip HR red-flag phrases
  ("nicht beendet", "abgebrochen", "arbeitslos", …) defensively.

Cover letter:
- Full refactor to a clean, single-column DIN-5008 business letter: letterhead
  (name left, contact right, hairline), recipient block, right-aligned date,
  bold subject, body, signature space, enclosure note ("Anlage: Lebenslauf").
- Monochrome (grayscale only), no accent colours; own single-page auto-fit.
- Prompt hardened against red flags (no salary, no reasons for leaving, no gaps).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:36:33 +02:00