Die max-height/overflow-Variante griff beim Bewerbung-hinzufügen-Formular
nicht zuverlässig. Stattdessen scrollt jetzt das Overlay selbst wie eine
Seite; das Panel wächst auf natürliche Höhe und wird über margin:auto
zentriert (kurzer Inhalt) bzw. ohne Top-Clipping erreichbar (langer Inhalt).
Close- und Speichern-Button bleiben beide erreichbar.
Co-Authored-By: Claude <noreply@anthropic.com>
- Neue users-Spalten darf_suchlauf_starten / darf_zeitplan_aendern
(Default 0 = deaktiviert); idempotente ALTER-Migration für Bestands-DBs.
- Admin-Detailseite: zwei Toggles (Erlaubt/Gesperrt) je Nutzer.
- /jobsuche: ohne Recht ist „Jetzt suchen" ausgeblendet und der Zeitplan
(aktiv/Tage/Uhrzeit) read-only; Speichern und manueller Start sind
serverseitig abgesichert. Admin (fremd) ist nie beschränkt.
- Default-Zeitplan bleibt Mo–Fr 17:00 (suchprofil-Defaults).
Co-Authored-By: Claude <noreply@anthropic.com>
- Bewerbungsdetail: Toggle zwischen Bewerbungsunterlagen und E-Mail-Korrespondenz
(hash-basiert), weniger Scroll auf der Seite.
- Admin: Klick auf einen Nutzer öffnet neue Verwaltungsseite
/admin/users/:id (Passwort, Anmelden als, Jobsuche, Admin-Status, Löschen).
- Admin-Tabelle: Löschen und Jobsuche aus den Aktionen entfernt
(jetzt auf der Nutzerdetailseite).
Co-Authored-By: Claude <noreply@anthropic.com>
- Zweispalter auf >=lg (links: Bewerbungsdaten+Status+Termine,
rechts: Unterlagen+Korrespondenz), vorher alles untereinander auf
max-w-3xl. Seite deutlich kürzer, keine Grid-Row-Lücken dank
unabhängiger Spalten-Container. Unter lg weiter einspaltig.
- Eigene Anhänge: amber durch neutral grau ersetzt, Papierclip durch
Schloss-Icon ersetzt (signalisiert „nur für dich / nicht im PDF").
- Größte Textareas etwas kürzer (notizen 6->4, Begleit-E-Mail 12->10,
Versand-Nachricht 10->8).
Co-Authored-By: Claude <noreply@anthropic.com>
Entfernt den ausklappbaren Detailbereich (Status-Verlauf, Notizen,
interne Notizen) unter jeder Bewerbungs-Zeile auf der Startseite. Ein
Klick auf die Zeile öffnet stattdessen die ganze Bewerbung unter
/bewerbung/:id. Die Aktions-Buttons (Merken, Bearbeiten, Löschen)
bleiben separat bedienbar.
Co-Authored-By: Claude <noreply@anthropic.com>
- Modal „Bewerbung hinzufügen" lässt sich auf allen Bildschirmgrößen scrollen
(nicht nur ≤640px), sonst war Speichern abgeschnitten
- Aktionen-Spalte der Bewerbungen von 4.5rem auf 5.5rem (passt zur
Cluster-Breite, Icons wandern nicht mehr nach rechts)
- Merken-Stern im Compact-Modus ohne Rahmen
- E-Mail-Uhrzeiten in Postfach, Bewerbung und Reply-Quote in Europe/Berlin
Co-Authored-By: Claude <noreply@anthropic.com>
Favorisierte Angebote erscheinen ausschließlich im Gemerkt-Tab und werden
aus der Offen-Liste, dem Offen-Zähler (Header-Badge) und dem Tab-Zähler
ausgeblendet. Auf der Offen-Seite wird die Zeile beim Merken live entfernt.
Co-Authored-By: Claude <noreply@anthropic.com>
- Startseite zeigt alle anstehenden Termine (vorher auf 6 begrenzt)
- Termine lassen sich inline bearbeiten (CalDAV-Update, Neu-Anlage bei 404/412)
- Neuer Bewerbungsstatus Telefonat (Listen, Farben, API, PDF, Statistik)
Co-Authored-By: Claude <noreply@anthropic.com>
Favoriten-Sektion wird nicht mehr ganz oben gerendert, sondern direkt
unter der Terminkarte; bei aktiver Suche wird sie nun ebenfalls ausge-
blendet. Karte bewusst dezenter gehalten (Border statt Schatten,
kleinere Überschrift, gedämpfte Akzente) mit modernen weichen Kanten.
Co-Authored-By: Claude <noreply@anthropic.com>
Abstand über der Ort/Datum-Zeile von 5,5 auf 9,4 Einheiten erhöht, damit
sie klar unter dem Empfängerblock steht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ort und Datum standen direkt unter der Kontaktspalte und lasen sich wie
eine weitere Kontaktzeile. Abstand von 1,6 auf 5,5 Einheiten erhöht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der rechte Absenderblock des Anschreibens ist ohnehin eine Zeilenspalte —
die Anschrift wird jetzt an Komma/Zeilenumbruch aufgebrochen, sodass die
Straße wie in einer Anschrift über der Stadt steht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zwei neue, pro Benutzer gespeicherte Konfigurationswerte:
GEN_DOKUMENTE_DEFAULT (Standard: Anschreiben + Lebenslauf) und
GEN_ANLAGEN_DEFAULT (Standard: keine). Sie belegen die Häkchen auf der
Bewerbungsseite vor; eine bereits getroffene Dokumentenauswahl der
Bewerbung gewinnt weiterhin. Die REST-API nutzt die Vorauswahl, wenn
dokumente/anlagen im Body fehlen.
Die Einstellungsseite kennt dafür jetzt Checkbox-Gruppen, deren Optionen
auch erst zur Renderzeit feststehen dürfen (die eigenen Anlagen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Weiße Seite, Name groß und mittig in Tinte, luftiger Blocksatz — und
korallfarbene Punkte in den Rändern, teils vom Seitenrand angeschnitten,
als einzige Farbe des Blattes. Der Lebenslauf greift das Motiv auf: die
Punkte markieren die Abschnitte, führen die Bullets und bilden als
Fünfer-Reihe die Sprach-Skala (gespeist aus niveauLevel(), also aus der
Formulierung des Lebenslaufs selbst).
Die Punkte skalieren bewusst nicht mit der Schrift: sie gehören zur Seite
wie die Ränder. Das Anschreiben reserviert dafür unten ein Band, in das
der Text nicht hineinläuft.
Der Brief behält das DIN-Anschriftenfeld, das der Vorlage fehlt — es sitzt
in deren zweispaltiger Meta-Zeile (Empfänger links, Datum und Kontakt
rechts), so bleibt die Komposition erhalten und die Bewerbung deutsch.
Dazu:
- neue Akzentfarbe "Koralle"
- write() kann optional Blocksatz. jsPDF stretcht eine Zeile nur, wenn es
weiß, dass eine weitere folgt — der Absatz geht deshalb in einem Aufruf
rüber, wodurch die Schlusszeile ungestretcht bleibt.
- Infobox unter /vorlagen beschreibt jetzt auch Sunny (fehlte) und Tupfen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Jobangebote lassen sich per Stern merken — eigene Spalte `favorit`,
getrennt von den Bewerbungs-Favoriten. Gemerkte Angebote stehen oben in
der offenen Liste und haben einen eigenen Tab, der Favoriten quer über
alle Status zeigt und ausgeblendet bleibt, solange es keine gibt.
Der Stern wird nur in der Weboberfläche gesetzt; ein erneutes Einspielen
desselben Angebots über die REST-API überschreibt ihn nicht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das Anschreiben war ein zweites Poster: Konfetti im Band, solides
Akzent-Badge, Betreff und Anrede beide in der Akzentfarbe, ein pastellener
Marker-Strich hinter dem Namen und eine Farbleiste als Fußzeile. Neben dem
Lebenslauf las sich das als Lärm, nicht als Set.
Jetzt trägt die Seite genau eine Farbfläche — das Kopfband —, alles darunter
ist Typografie:
- Kopfband ohne Konfetti, Name 27pt -> 22pt
- Rollen-Badge als weiße Pille mit Akzentschrift (der Lebenslauf behält sein
solides Badge; die Umstellung sitzt in der Letter-Palette)
- Datum als schlichte rechtsbündige Zeile statt Pastell-Chip
- Betreff und Anrede in Tinte; die Bar über dem Betreff bleibt der einzige
Farbakzent im Textkörper
- Signatur ohne Bild: Name über feinem Haarstrich statt Marker-Swipe
- Fußzeile: Haarlinie mit gedämpftem Kontakttext statt Farbleiste
suKonfetti/suDot hatten damit keinen Aufrufer mehr und fallen weg.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Brief trug bisher nur dieselbe Farbe wie der Lebenslauf, nicht dieselbe
Sprache. Jetzt bekommt er denselben Kopf: Name plakativ auf dem Farbband, Ziel-
position als solides Badge, Kontaktdaten als weiße Chips mit Icons rechts
gestapelt, dazu Konfetti in den Randstreifen. Das Datum ist ein Pastell-Chip
neben dem Anschriftfeld statt einer einsamen rechtsbündigen Zeile, der Betreff
bekommt Balken und Größe einer Sektionsüberschrift, die Anrede die Akzentfarbe,
die Anlagen werden zu Chips, und der getippte Name liegt auf einem Pastell-
Streifen wie mit dem Marker gezogen – der Ersatz für die fehlende Handschrift.
DIN-5008 bleibt unangetastet: Anschriftfeld, Datum, Betreff, Anrede, Fließtext,
Gruß, Unterschrift und Anlagen stehen, wo ein deutscher Leser sie erwartet.
Zwei Dinge, die erst im Render auffielen:
- Die Konfetti-Punkte saßen in der linken Rinne direkt neben dem Namen und lasen
sich als Aufzählungszeichen davor statt als Deko. Sie liegen jetzt rechts; nur
ein Funkeln bleibt links, tief im Band und weit weg vom Namen.
- Die Kontaktzeile der Fußzeile lief bei langer Anschrift plus langer E-Mail über
das Band hinaus und schob sich über die Punkte. Sie skaliert jetzt passend und
lässt notfalls die Anschrift weg, damit Telefon und E-Mail lesbar bleiben.
suBar las seine Farbe fest aus der Lebenslauf-Palette (t.rc), obwohl der Brief
t.lc benutzt – das ging nur gut, weil beide Werte zufällig gleich sind. Die
Palette wird jetzt übergeben.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eine zu große oder nicht erlaubte Datei wurde von multer abgewiesen, der Fehler
nur auf die Server-Konsole geloggt und der Browser kommentarlos auf /vorlagen
zurückgeleitet. Für den Benutzer sah das aus, als sei der Upload durchgelaufen,
die Anlage tauchte nur nirgends auf ("Upload error: File too large" im Log, die
Teildatei räumt multer selbst wieder weg). Betroffen waren alle drei Uploads der
Vorlagen-Seite: Anlagen, Unterschrift und Bewerbungsfoto.
Die Routen leiten jetzt mit ?fehler=… um – dasselbe Muster wie auf der Jobsuche –
und die Seite zeigt den Grund als Banner: zu groß (mit Limit), Dateityp nicht
erlaubt, oder keine Datei gewählt. Das Limit steht zusätzlich am Datei-Feld,
bevor jemand eine zu große Datei auswählt.
Limit für Anlagen von 15 auf 30 MB angehoben; gescannte Zeugnisse liegen
regelmäßig darüber. Die Größen sind Konstanten (ANHANG_MAX_MB / BILD_MAX_MB),
aus denen sowohl multer als auch die Meldung und der Hinweis im Formular lesen –
eine Meldung, die ein anderes Limit nennt als das durchgesetzte, wäre schlimmer
als gar keine. Der Bild-Filter für Unterschrift/Foto lehnt jetzt ebenfalls mit
einem Fehler ab statt die Datei still zu verwerfen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Plakatives Layout nach Vorlage eines Referenz-Lebenslaufs: weiße Seite,
Pastellband im Kopf mit überstehendem Foto, Name groß daneben, Zielposition
als solides Badge, überdimensionale Display-Überschriften unter Pastellbalken,
die abwechselnd links und rechts stehen, zweispaltige Einträge und Level-Balken
für die Sprachen.
Die Balkenlänge kommt aus dem im Lebenslauf genannten Niveau (Muttersprache,
C1, B1 …) – es wird kein Prozentwert erfunden, der nicht in den Unterlagen
steht. Studium, Berufsausbildung und Weiterbildungen laufen unter einer
gemeinsamen Überschrift "Ausbildung": drei Überschriften dieser Größe
hintereinander würden die Seite auffressen.
Neue Akzentfarbe "Beere" als Standard für das Layout. Die Layout-Weiche steckt
jetzt in einer Tabelle (CV_LAYOUT / LETTER_LAYOUT) statt in Ternären – ein
weiteres Layout ist eine Zeile dort plus seine Palette in lib/design.js.
Sidebar und Social bleiben unverändert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In multer/busboy-Upload-Callbacks ist der per-request AsyncLocalStorage-
Kontext nicht zuverlässig propagiert, sodass currentUserId() dort null
liefern kann und basis_anhaenge-/interne_anhaenge-Zeilen mit user_id=NULL
verwaisten (für den User unsichtbar). Die INSERTs nutzen jetzt uidFromReq
(= req.user.id mit uid()-Fallback) wie bereits userStorageDirForReq für
Signatur/Foto. Zwei bestehende verwaiste Zeilen wurden repariert.
Co-Authored-By: Claude <noreply@anthropic.com>
Jeder Suchlauf läuft nun in einem frischen Container pro Benutzer, dessen
pro-Benutzer-Home als ~/.claude gemountet ist — Memories und Session-Contexte
liegen damit strikt getrennt pro Benutzer. Die Such-Skills sind Shared-Code
aus dem Image und werden im Container nur nach ~/.claude/skills verlinkt.
Der Host-Runner startet pro Lauf `docker run --rm` und führt bis zu
JOBSUCHE_MAX_PARALLEL (Default 4) Läufe parallel über verschiedene Benutzer
aus (jeder hat eigenen Ollama-Key = getrennte Rate-Limits). Der alte gemeinsame
~/.claude-Pfad wird vom Runner nicht mehr beschrieben.
- source/agent/: neues Agent-Image (Dockerfile + entrypoint + drei Skills)
- scripts/jobsuche-runner.js: agentStarten als docker run, ensureAgentDir, runPool
- scripts/jobsuche-runner.sh + bin/-Kopie: Image-Guard
- package.json: docker:build-agent (lokal, ohne Registry-Push)
Co-Authored-By: Claude <noreply@anthropic.com>
Der Aktivitäten-Feed (Startseite, /aktivitaeten, /statistik) führt Status-
änderungen und E-Mails per UNION zusammen, sortiert nach Erfassungszeit.
E-Mail-Einträge bekommen einen eigenen Farbpunkt (blau = erhalten, sky =
gesendet); ohne verknüpfte Bewerbung wird Absender bzw. Empfänger als
Kopfzeile gezeigt. Das UNION steckt in einem Subselect, weil SQLite ORDER BY
an einem Compound-SELECT keine Ergebnisspalten nach Namen aufloest. Die
Paginierung von /aktivitaeten zaehlt jetzt Statusaenderungen + E-Mails.
Co-Authored-By: Claude <noreply@anthropic.com>
Stern zum Merken einzelner Bewerbungen auf der Startseiten-Liste, der
Bewerbungsdetailseite und einer neuen 'Gemerkte Bewerbungen'-Sektion ganz
oben — unabhaengig vom Status. Die bisherigen Jobangebot-Favoriten werden
durchgaengig entfernt (Endpoint, Migration, UI, Startseiten-Sektion), da
nur Bewerbungen gemerkt werden sollen.
Co-Authored-By: Claude <noreply@anthropic.com>
Stellen lassen sich per Stern merken — unabhängig vom Status (offen /
uebernommen / abgelehnt). Neue Spalte jobangebote.favorit (PRAGMA-Migration),
JSON-Toggle-Endpunkt /jobangebote/:id/favorit, Stern-Button auf den Karten
sowie eine "Gemerkte Stellen"-Sektion ganz oben auf der Startseite. Toggle
laeuft per fetch mit optimistischem UI; beim Entfernen auf der Startseite
verschwindet die Zeile sofort.
Co-Authored-By: Claude <noreply@anthropic.com>
Der Assistent deckt nun alle Bereiche aus /einstellungen ab. Neue Schritte
fuer E-Mail (SMTP/IMAP) & CalDAV sowie REST-API; Indikator auf 7 Schritte.
Secrets (Passwort, Token) werden nie vorausgefuellt und beim Speeren leerer
Felder nicht ueberschrieben. Neuer Endpunkt /api/einrichtung/config mit
SSRF-Guard (Mail-Host, CalDAV-URL, Ollama-Host) und API-Token-Kollisionspruefung.
Abschluss-Checkliste trennt Pflicht- von optionalen Verbindungen.
Co-Authored-By: Claude <noreply@anthropic.com>
Nutzer ohne Bewerbungen sehen einen mehrstufigen Wizard, der Persoenliche
Angaben, Basis-Unterlagen und Ollama-KI per fetch speichert. Dashboard bleibt
im DOM (hidden), damit main.js und "Bewerbung manuell anlegen" funktionieren.
Neue Endpunkte /api/einrichtung/{persoenlich,basis,ollama,verstecken} mit
SSRF-Guard; Ollama gezielt via setForUser, ohne Mail/Kalender/Token zu leeren.
Co-Authored-By: Claude <noreply@anthropic.com>
express.static setzte kein Cache-Control, also legte der Browser die
Lebensdauer selbst fest (heuristisch, aus dem Alter der Datei). Folge: nach
einem Deploy lief die Oberflaeche im offenen Tab weiter mit dem alten
chat.js - die frisch ausgelieferten Tabellen wurden dort weiter als
Pipe-Wueste gerendert, obwohl der Server die neue Datei schon hatte.
no-cache heisst nicht "nicht cachen": der Browser behaelt die Datei, fragt
aber per ETag nach, ob sie noch gilt (304, kein erneuter Download).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Feinschliff schlug per KI Technologien vor ("Proxmox", "Rechenzentrum")
und verbot Rollenbezeichnungen ausdruecklich - die sollte die Suche selbst
aus dem Lebenslauf ableiten. Das war schief: Welche Anzeigen ueberhaupt
gefunden werden, entscheidet die Suchanfrage, also der Stellentitel.
Technologien gewichten nur, was schon da ist. Damit schlug die KI genau das
vor, was der Such-Agent ohnehin selbst ableitet, waehrend die eine Sache,
die der Nutzer weder sieht noch steuern kann - unter welchen Titeln gesucht
wird -, bei jedem Lauf neu improvisiert wurde. Faellt "Fachinformatiker
Systemintegration" weg, merkt das niemand; es kommt nur wenig zurueck.
- Neues Profilfeld berufsbezeichnungen: die KI schlaegt es vor, der Nutzer
editiert es, der Such-Agent fragt jeden Titel einzeln ab.
- zusatz_begriffe bleibt, aber als Kontext (Branche, Umfeld, Arbeitszeit),
nicht als Stellentitel; ausschluesse unveraendert.
- Leeres Feld = altes Verhalten (Titel aus dem Lebenslauf), niemandes
Profil aendert sich durch das Update.
- Spalte wird fuer bestehende Installationen nachgezogen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Titel in der Seitenleiste waren bisher die ersten 60 Zeichen der
ersten Nachricht - abgeschnitten mitten im Wort ("Ich habe mich bei der
Hetzner Online GmbH bewor..."). Jetzt formuliert das Modell daraus einen
kurzen Titel, wie man es aus ChatGPT kennt.
- Der Aufruf laeuft NACH dem done-Event: die Antwort wartet nicht auf die
Titelgenerierung (1-3 s), der Titel kommt als eigenes Event nach und die
Seitenleiste zieht live nach.
- Der abgeschnittene Titel bleibt als Platzhalter, solange die Antwort
streamt - die Seitenleiste ist also nie leer, und faellt die
Titelgenerierung aus, bleibt es schlicht dabei.
- Nur beim ersten Schlagabtausch und nur, wenn der Thread noch keinen
Titel hatte: ein selbst vergebener Name wird nicht ueberschrieben.
- Eigener Mini-Systemprompt statt des Chat-Prompts, der will beraten,
nicht betiteln. Anfuehrungszeichen/"Titel:"-Praefixe werden abgeraeumt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Mini-Renderer kannte weder Tabellen noch ---, also landeten beide als
roher Text in einem Absatz: aus einer Anforderung/Erfahrung-Tabelle wurde
eine einzeilige Pipe-Wueste, aus --- blieb ---. Das Modell nutzt aber
gerade fuer Passungs-Vergleiche gern Tabellen.
- GFM-Tabellen inkl. Ausrichtung (:--:), auch ohne Rand-Pipes.
- Krumme Zeilen werden auf die Kopfbreite gezogen (fehlende Zellen leer,
ueberzaehlige raus), sonst zerreisst eine Zeile das Raster.
- Wrapper scrollt horizontal, damit eine breite Tabelle die Chat-Blase
auf dem Handy nicht auseinanderzieht.
- Zellinhalte laufen durch dieselbe Escape-/inlineFmt-Kette wie der Rest,
HTML aus dem Modell kann also weiterhin nichts injizieren.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Assistent kannte bisher nur die Datenbank. Fragen wie "Was muss ich
ueber die Firma wissen?" konnte er damit nicht beantworten - Groesse,
Produkte, News, Kultur stehen nirgends in der Bewerbung.
Zwei neue Werkzeuge (web_suche, web_seite_lesen) ueber die Web-Search-API
von ollama.com. Sie authentifizieren sich mit demselben OLLAMA_API_KEY,
den der Benutzer fuer Chat und Dokumente ohnehin hinterlegt hat: keine
zusaetzliche Konfiguration. Anders als /api/chat haengt die Websuche
nicht an OLLAMA_HOST - wer rein lokal chattet, hat schlicht keine
Websuche, der Rest laeuft unveraendert weiter.
- Tool-Runden 4 -> 8: Bewerbung holen, suchen, Seiten lesen, antworten
lief vorher ins Limit, statt zu antworten.
- Antworten der Websuche hart gedeckelt, sie wandern sonst in jeder
weiteren Runde erneut ins Kontextfenster.
- Status-Label zeigt, wonach gesucht wird - sonst sieht der Nutzer nicht,
ob die richtige Firma erwischt wurde.
- Nackte URLs im Chat sind klickbar: Belege nennt das Modell meist als
reine URL, nicht als Markdown-Link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Link unter "Letzte Aktivitaeten" heisst jetzt "Alle" und fuehrt auf
/aktivitaeten - den vollstaendigen Verlauf ueber alle Bewerbungen, 25 Eintraege
je Seite. Die Blaetterleiste sind echte Links (kein JS), damit Zurueck-Taste,
Lesezeichen und Neuer-Tab funktionieren; eine Seitenzahl ausserhalb des Bereichs
wird auf den gueltigen Rand geklemmt statt eine leere Seite zu zeigen.
Dabei ein Fehler von mir aus dem letzten Commit behoben: Ich hatte den Tag-Namen
samt href per <%= %> zusammengesetzt, was die Anfuehrungszeichen escaped -
heraus kam href=""/bewerbung/121"" und damit die URL
/%22/bewerbung/121%22. Jetzt zwei ausgeschriebene Zweige (Link bzw. Block).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unter der Liste stehen jetzt die acht juengsten Statusaenderungen quer ueber
alle Bewerbungen - mit Firma, Stelle, Status, Datum und Kommentar, verlinkt auf
die Bewerbung. Sortiert nach Erfassungszeit statt nach fachlichem Datum, damit
ein nachgetragener alter Eintrag nicht oben steht.
Der Kopf der Listen-Karte nennt die Gesamtzahl. Er sitzt bewusst ausserhalb des
md:min-w-Rahmens, damit er auf dem Handy nicht horizontal mitscrollt.
Beides verschwindet waehrend einer Suche, wie Liste und Termine auch. Die
Status-Farbkarte ist eine Ebene hoeher gewandert, weil Liste und Aktivitaeten
sie jetzt beide brauchen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Benachrichtigungen: Das Panel haengt per right:0 am Wrapper der Glocke, rechts
von ihr stehen aber noch Konto und Burger - die 20rem Breite wuchsen dadurch
nach links aus dem Viewport (gemessen -51px bei 375px Breite). Unter 768px
spannt es sich jetzt ueber den Header: `position: static` auf dem Anker macht
den Header zum Bezugsrahmen, was auch die vertikale Lage inklusive
Impersonation-Banner richtig haelt.
Bewerbungsliste: Das gestapelte Karten-Layout griff erst unter 640px, die
minmax()-Spalten des Rasters brauchen aber ~764px und die Karte bekommt ihre
min-w-[760px] erst ab md (768px). Im Band dazwischen - Handy quer, grosse
Phones - galt also das Desktop-Raster, und Stelle, Art und Status lagen
ausserhalb (132px Ueberhang bei 667px). Grenze auf 767px gezogen, damit sie an
md anschliesst.
Nachgemessen im Headless-Browser bei 375/390/412/667/740/820px: nichts ragt
mehr heraus, die Liste scrollt nicht mehr horizontal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Platzhalter und Doku-Beispiele nannten durchgehend den Wohnort des
Entwicklers (Gladbeck, Bottrop, Gelsenkirchen, Essen), dessen Vorwahl
(02043), PLZ und Strasse. Ersetzt durch Berlin/Hamburg/Muenchen sowie eine
zum Beispielort passende Vorwahl (030). Betrifft die Platzhalter fuer
Telefon/Ort (Vorlagen), die Staedte-Eingabe (Jobsuche), das Adressbeispiel
in den LLM-Notizen, die OpenAPI-Beispiele und zwei Code-Kommentare.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Station zwischen Vorstellungsgespraech und Einstellung - in der
Statusliste, der Gruppierung auf der Startseite, den Farbskalen (Lime,
zwischen dem Gelb des Gespraechs und dem Gruen der Einstellung), im
PDF-Export, in der Statistik und in der REST-API/OpenAPI.
Der Statistik-Funnel zaehlte bisher ever('Vorstellungsgespraech') +
ever('Einstellung') und damit eine Bewerbung, die beide Stationen
durchlaufen hat, doppelt. Mit einer weiteren Stufe waere das schlimmer
geworden, deshalb zaehlt der Funnel jetzt pro Bewerbung statt pro
Statuszeile: jede Stufe zaehlt eine Bewerbung genau einmal, ein spaeterer
Status impliziert die frueheren.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher bekam jeder Login pauschal ein 30-Tage-Cookie. Die Checkbox ist per
Default gesetzt (unveraendertes Verhalten); wird sie abgewaehlt, gilt ein
Session-Cookie ohne Ablaufdatum (weg beim Schliessen des Browsers) und
serverseitig eine Frist von 12 Stunden Inaktivitaet - die serverseitige Frist
ist die verbindliche, ein Client kann sein Cookie manipulieren.
Bestehende Sessions behalten per Spalten-Default die 30 Tage, niemand wird
durch das Update ausgeloggt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drei Erweiterungen, die sich server.js und lib/documents.js teilen und
deshalb zusammen liegen:
Jobsuche: Der Feinschliff (Zusatzbegriffe/Ausschluesse) laesst sich per KI
aus den eigenen Basis-Unterlagen vorschlagen. Der Rollen-Prompt ist wie die
uebrigen unter Vorlagen editierbar; gespeichert wird erst auf Klick.
Suche: Startseite und KI-Chat durchsuchen jetzt per SQLite-FTS5 auch die
E-Mail-Korrespondenz (Absender, Betreff, Text), Notizen und
Stellenbeschreibung - ein Name aus einer Mail findet die Bewerbung. Ranking
per bm25, Fundstellen mit Snippet, Feldfilter (firma:, von:), Phrasen,
Ausschluesse, Umlaut-Varianten (mueller/muller/mueller). Der Index wird von
SQL-Triggern gepflegt, weil Bewerbungen und Mails aus UI, REST-API, IMAP und
KI-Import geschrieben werden.
E-Mail: Vor dem Generieren laesst sich vorgeben, was in der Antwort stehen
soll; die Vorgabe geht als verbindliche Anweisung in den Prompt. Steht schon
ein Entwurf im Feld, ueberarbeitet die KI ihn, statt neu anzufangen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Dashboard-Bewerbungsliste auf Handy als gestapelte Karten statt horizontal gescrolltem 760px-Raster
- Modals auf Handy scrollbar (Inhalt wurde bisher unten abgeschnitten)
- Chat: Thread-Aktionen auf Touch sichtbar, Sidebar/Chat-Höhen für mobil
- Bewerbungs-Antwort-Toolbar & Admin-Stat-Boxen umbruchfähig
Co-Authored-By: Claude <noreply@anthropic.com>
Die gefilterten Export-Zweige bauten `SELECT * FROM (<subquery>) AND
strftime(...)` — ohne WHERE nach der abgeleiteten Tabelle. SQLite
quittierte das mit "near \"AND\": syntax error" => HTTP 500, der Client
erhielt {error:'Serverfehler'} statt des Bewerbungs-Arrays und
generatePdfDocument crashte mit "applications.map is not a function".
Fix: `AND` => `WHERE` in den drei gefilterten Zweigen (month+year,
month, year). Die Per-User-Isolation bleibt unberuehrt (user_id-Filter
steht weiterhin in der Subquery). Zusaetzlich prueft generatePDF jetzt
Array.isArray(applications) und zeigt eine klare Fehlermeldung statt
des .map-Crashs.
Co-Authored-By: Claude <noreply@anthropic.com>
loadPdfLibraries() hat im "bereits ladend"-Zweig aufgeloest, sobald jsPDF
vorhanden war — das Autotable-Plugin (zweites Script) war dann aber noch
nicht angehaengt, sodass doc.autoTable undefined war und die Generierung
mit "doc.autoTable is not a function" fehlschlug. Die Polling-Bedingung
prueft jetzt auch jsPDF.API.autoTable, und generatePDF wartet zusaetzlich
auf loadPdfLibraries(), bevor das Dokument gebaut wird.
Co-Authored-By: Claude <noreply@anthropic.com>
- Header mit Icon + Statistikleiste (Benutzer / Admins / Bewerbungen)
- Karten-Layout (rund, Shadow), Sektionen mit Icons
- Aktionen als einheitliche Icon+Label Buttons (Jobsuche, Anmelden als,
Passwort, Löschen) statt gequetschter Textlinks, je eigene Farbe
- Avatar-Initial + Admin-Badge mit Icon in der Tabelle
- Passwort-Reset als eingeblendete Karte mit Abbrechen + Hinweis
- Relative Zeitangaben (Erstellt, Audit) mit Tooltips
- Audit-Sektion als eigene Karte
Co-Authored-By: Claude <noreply@anthropic.com>
- sessions.impersonator_id: Admin-Session behält Token, schaltet user_id
aufs Ziel, Admin bleibt in impersonator_id gespeichert (Stack, keine
Verschachtelung). uid()/Config/Dateien laufen als Ziel-Nutzer.
- Admin sieht in /admin pro Nutzer "Anmelden als"; Bestätigungsdialog.
- Dauerhaftes amber Banner im Header mit "Zurück zum Admin" (POST, kein JS
nötig) erscheint auf jeder Seite während Impersonation.
- requireAdmin verweigert während Impersonation -> keine Admin-Aktionen als
fremder Nutzer; Stop-Route prüft impersonator_id (kein Escalation-Pfad für
Normalnutzer). Selbst-Imitation blockiert.
- audit_log-Tabelle protokolliert Start/Stop persistent; Admin-Seite zeigt
Audit-Liste (/admin/audit/impersonations).
- Migration: idempotentes ALTER ADD COLUMN impersonator_id fuer Bestand.
Co-Authored-By: Claude <noreply@anthropic.com>
- Passendes SVG-Favicon (Gradient-Mark wie in der Top-Navi) +
theme-color, registriert im <head>
- 'Bewerbungs-Tracker' als zweifarbiger Schriftzug: Bewerbungs in
Slate, Tracker im Sky->Blue-Gradient
Co-Authored-By: Claude <noreply@anthropic.com>
Keine eigene Oberflaeche mehr (nur Seitenhintergrund + Haarlinie),
kleinere und stummere Schrift — gleiche ruhige Sprache wie die
Top-Navigation.
Co-Authored-By: Claude <noreply@anthropic.com>
Node laeuft unter nvm, dessen bin-Verzeichnis nicht im Cron-PATH
lag. Jeder Cron-Tick schlug mit `node: command not found` fehl,
weshalb manuell angeforderte Suchlaeufe ewig im Status 'angefordert'
(wartet) haengen blieben. nvm.sh wird jetzt vor dem Aufruf gesourced.
Co-Authored-By: Claude <noreply@anthropic.com>