Commit Graph
137 Commits
Author SHA1 Message Date
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 fd11facadd Add centered live company search to the overview
A modern search bar at the top center of the index page filters the
applications table live by firma/stelle. Status group headers hide when
their group has no visible rows, per-group counts update with the
filtered result, and an empty-state row shows when nothing matches.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 19:17:54 +02:00
thomasandClaude 106b184fda Let postfach e-mails expand to full body
The unlinked-e-mail cards clipped the body to a preview height. Add a
toggle to show the complete body inline and collapse it back.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 19:12:24 +02:00
thomasandClaude 4418c15553 Add Postfach page to manually assign unlinked e-mails
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>
2026-07-03 19:07:54 +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 b1c92dd77b Guard against duplicate applications + capture jobs on any website
Duplicate safeguard: before creating an application (manual add and
browser import) the server checks for an existing one for the same job —
matched on a normalised source URL (job-id params like Indeed's jk pin
the posting across paths/tracking) or an identical company + role
(case/umlaut/whitespace-insensitive). On a match it returns 409 with the
matches; the web form and the extension show the existing entry and
re-submit with force=true only if the user confirms. Not a hard block, so
legitimate re-applications stay possible.

Universal capture: the extension popup becomes an editable capture form
that works on any site. It extracts the active page on demand (schema.org
JobPosting JSON-LD -> OpenGraph/meta -> h1/title/selection -> canonical
URL), lets the user review/correct, and sends. The import route is now
source-agnostic and derives the application source (art) from the URL
instead of hardcoding Indeed; the Indeed on-page button remains as a fast
path. Adds scripting/activeTab permissions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:32:17 +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 05357acddb Fix monthly PDF export to include only the selected month
The month dropdown carried only the month (e.g. "07") while the year was
a separate select; the export required month AND year, so a month-only
selection fell through to exporting every application. Encode the year in
the month option value ("YYYY-MM"), parse it client-side to always send
the exact month+year, and harden /api/export so a month can never fall
through to "export all".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:39:46 +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
thomasandClaude Opus 4.8 cd66e2ef4c Restyle PDFs as a two-column template (dark sidebar + main column)
- Fixed, high-quality CV/cover-letter template modelled on the user's reference:
  navy sidebar (name, headline, contact, skills with bullets, languages, hobbys)
  and a white main column with accent-underlined section headings and dated
  entries (date gutter, bold title, blue company line, description).
- The LLM now supplies only the text; layout/design is owned by the renderer.
- Extended the extracted fields with headline, birth date, driving licence and
  hobbys (grounded in the base documents, empty when absent).
- Two-column auto-fit keeps each document on a single A4 page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:13:17 +02:00
thomasandClaude Opus 4.8 27734c77e5 Redesign generated PDFs: structured AI output + single-page A4 layout
- AI now returns structured data (contact, cover-letter paragraphs, CV
  experience/education/skills/languages) instead of flowing text.
- Modern CV renderer: header with name + contact, tracked section titles with
  hairlines, entries with right-aligned dates and bullets, skill chips, languages.
- Clean DIN-style cover letter with matching header, recipient block,
  right-aligned date, subject, salutation, body, closing.
- Auto-fit engine scales fonts/spacing so each document always fits one A4 page.
- Tolerant parsing (key synonyms, object date ranges, markdown fences) + an
  explicit JSON skeleton in the prompt, since the model honours the schema loosely.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:45:25 +02:00
thomasandClaude Opus 4.8 fd20ca0daf Add AI application assistant: Indeed import + Ollama document generation
- 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>
2026-07-02 22:21:28 +02:00
thomas 6952309de9 update 2026-06-19 04:32:02 +02:00
thomasandClaude Opus 4.8 c2a629e2c0 Refactor UI/views, rework Docker build, untrack local data
- Views umstrukturiert: einstellungen.ejs -> bewerbung.ejs, neues
  partials/head.ejs, header/footer/index angepasst
- CSS umbenannt: style.css -> styles.css
- server.js und public/js/main.js ueberarbeitet
- Dockerfile auf schlankes Multi-Stage-Setup umgestellt;
  docker-compose.yml und .dockerignore entfernt
- npm-Scripts docker:build/push/deploy ergaenzt
- SQLite-DB und .idea aus Git entfernt und via .gitignore ignoriert

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 04:01:37 +02:00
thomasandClaude Sonnet 4.6 34cfcecc1e Add Docker setup with multi-stage build and Compose deploy config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 18:29:58 +02:00
thomasandClaude Sonnet 4.6 c65c9f1751 Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 18:15:11 +02:00