Persoenliche Angaben unter Vorlagen statt hardcoded/Settings-Modal

- settings-Tabelle um email/telefon/ort/webseite/geburtsdatum erweitert
  (CREATE + ALTER-Migration + Default-INSERT)
- Vorlagen-Seite: neuer Bereich "Persoenliche Angaben" (8 Felder),
  POST /vorlagen/persoenlich; Settings-Modal + Zahnrad-Button entfernt
- Generierung: Kontakt kommt verbindlich aus den Settings (buildHeader
  laesst gespeicherte Werte ueber die KI-Extraktion gewinnen), bewerber-
  Fakten + Prompt angepasst; Design-Vorschau zeigt echte Kontaktdaten
- main.js: Settings-Modal-Handling entfernt; /api/settings bleibt bestehen

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-13 11:41:32 +02:00
co-authored by Claude
parent d1116d522d
commit e97d1b3687
6 changed files with 147 additions and 165 deletions
+48 -10
View File
@@ -1009,19 +1009,32 @@ function initializeDatabase() {
id INTEGER PRIMARY KEY CHECK (id = 1),
name TEXT,
adresse TEXT,
kundennummer TEXT
kundennummer TEXT,
email TEXT,
telefon TEXT,
ort TEXT,
webseite TEXT,
geburtsdatum TEXT
)
`, (err) => {
if (err) return reject(err);
// Migration: persönliche Kontaktfelder nachträglich anlegen, falls die
// Tabelle aus einer älteren Version stammt (CREATE TABLE IF NOT EXISTS
// ergänzt fehlende Spalten nicht). Fehler "duplicate column" ignorieren.
const kontaktSpalten = ['email', 'telefon', 'ort', 'webseite', 'geburtsdatum'];
kontaktSpalten.forEach((spalte) => {
db.run(`ALTER TABLE settings ADD COLUMN ${spalte} TEXT`, () => {});
});
// Insert default settings if not exists
db.get('SELECT COUNT(*) as count FROM settings WHERE id = 1', (err, result) => {
if (err) return reject(err);
if (result && result.count === 0) {
db.run(
'INSERT INTO settings (id, name, adresse, kundennummer) VALUES (1, ?, ?, ?)',
['Max Mustermann', 'Musterstraße 1, 12345 Musterstadt', ''],
'INSERT INTO settings (id, name, adresse, kundennummer, email, telefon, ort, webseite, geburtsdatum) VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?)',
['Max Mustermann', 'Musterstraße 1, 12345 Musterstadt', '', '', '', '', '', '', ''],
(err) => {
if (err) return reject(err);
resolve();
@@ -1074,7 +1087,6 @@ initializeDatabase().then(() => {
const applications = await dbAll(query, params);
await attachVerlauf(applications);
applications.forEach((a) => { a.labelsArr = parseLabels(a.labels); });
const settings = await dbGet('SELECT * FROM settings WHERE id = 1');
// Upcoming calendar appointments for the dashboard widget.
const kommendeTermine = await upcomingTermine(6);
@@ -1118,7 +1130,6 @@ initializeDatabase().then(() => {
res.render('index', {
applications,
settings,
statistics: {
total: totalCount ? totalCount.count : 0,
byArt,
@@ -1170,13 +1181,17 @@ initializeDatabase().then(() => {
// Save settings
app.post('/api/settings', async (req, res) => {
try {
const { name, adresse, kundennummer } = req.body;
const { name, adresse, kundennummer, email, telefon, ort, webseite, geburtsdatum } = req.body;
await dbRun(
'UPDATE settings SET name = ?, adresse = ?, kundennummer = ? WHERE id = 1',
[sanitizeInput(name), sanitizeInput(adresse), sanitizeInput(kundennummer)]
'UPDATE settings SET name = ?, adresse = ?, kundennummer = ?, email = ?, telefon = ?, ort = ?, webseite = ?, geburtsdatum = ? WHERE id = 1',
[
sanitizeInput(name), sanitizeInput(adresse), sanitizeInput(kundennummer),
sanitizeInput(email), sanitizeInput(telefon), sanitizeInput(ort),
sanitizeInput(webseite), sanitizeInput(geburtsdatum)
]
);
res.json({ success: true });
} catch (error) {
console.error('Error saving settings:', error);
@@ -1953,6 +1968,7 @@ initializeDatabase().then(() => {
res.render('vorlagen', {
basisDokumente,
basisAnhaenge,
settings: await dbGet('SELECT * FROM settings WHERE id = 1'),
prompts: promptStore.list(await loadPrompts()),
designFelder: designStore.list(design),
designAngepasst: designStore.isAngepasst(design),
@@ -1969,6 +1985,28 @@ initializeDatabase().then(() => {
}
});
// ----- Persönliche Angaben (under Vorlagen, formerly the index-page modal) -----
// Registered before /vorlagen/:id so the generic base-document handler doesn't
// swallow this path. Stores name/address/contact data that flows into every
// generated document (replacing the previous KI extraction from basis texts).
app.post('/vorlagen/persoenlich', async (req, res) => {
try {
const { name, adresse, kundennummer, email, telefon, ort, webseite, geburtsdatum } = req.body;
await dbRun(
'UPDATE settings SET name = ?, adresse = ?, kundennummer = ?, email = ?, telefon = ?, ort = ?, webseite = ?, geburtsdatum = ? WHERE id = 1',
[
sanitizeInput(name), sanitizeInput(adresse), sanitizeInput(kundennummer),
sanitizeInput(email), sanitizeInput(telefon), sanitizeInput(ort),
sanitizeInput(webseite), sanitizeInput(geburtsdatum)
]
);
res.redirect('/vorlagen#persoenlich');
} catch (error) {
console.error('Error saving personal data:', error);
res.status(500).send('Serverfehler');
}
});
// ----- Editable KI prompts -----
// Registered before /vorlagen/:id so the generic base-document handlers don't
// swallow these paths. The prompt text is stored raw (no HTML escaping): it is