const path = require('path'); const fs = require('fs'); const Database = require('better-sqlite3'); const dataDir = path.join(__dirname, 'data'); if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }); const dbPath = path.join(dataDir, 'data.db'); const isNew = !fs.existsSync(dbPath); const db = new Database(dbPath); db.pragma('foreign_keys = ON'); const schema = fs.readFileSync(path.join(__dirname, 'schema.sql'), 'utf8'); db.exec(schema); migrateEmployeeName(); seedInitialAdmin(); if (isNew) { seed(); } // Ältere Deployments hatten ein einzelnes "name"-Feld statt first_name/last_name. // Bestehende Daten werden erhalten, indem der Name gesplittet statt die Tabelle neu angelegt wird. function migrateEmployeeName() { const columns = db.prepare('PRAGMA table_info(employees)').all().map((c) => c.name); if (!columns.includes('name') || columns.includes('first_name')) return; db.exec('ALTER TABLE employees ADD COLUMN first_name TEXT'); db.exec('ALTER TABLE employees ADD COLUMN last_name TEXT'); const rows = db.prepare('SELECT id, name FROM employees').all(); const update = db.prepare('UPDATE employees SET first_name = ?, last_name = ? WHERE id = ?'); for (const row of rows) { const parts = (row.name || '').trim().split(/\s+/); const first_name = parts.shift() || ''; const last_name = parts.join(' '); update.run(first_name, last_name, row.id); } db.exec('ALTER TABLE employees DROP COLUMN name'); } // Legt beim allerersten Start einen Admin-Zugang für einen BESTEHENDEN Mitarbeiter an, // dessen employees.email mit ADMIN_EMAIL übereinstimmt. Es wird bewusst kein Passwort // gesetzt: wie bei allen über die Benutzerverwaltung angelegten Konten wird das // Passwort erst beim allerersten Login vom Nutzer selbst vergeben (siehe /api/auth/login). function seedInitialAdmin() { const userCount = db.prepare('SELECT COUNT(*) AS c FROM users').get().c; if (userCount > 0) return; const adminEmail = process.env.ADMIN_EMAIL; if (!adminEmail) { console.log( 'Hinweis: ADMIN_EMAIL ist nicht gesetzt, es wurde kein Start-Admin angelegt. ' + 'Bitte ADMIN_EMAIL auf die E-Mail eines bestehenden Mitarbeiters setzen und neu starten, ' + 'oder scripts/reset-admin.js verwenden.' ); return; } const employee = db.prepare('SELECT id FROM employees WHERE email = ?').get(adminEmail); if (!employee) { console.log( `Hinweis: ADMIN_EMAIL (${adminEmail}) passt zu keinem bestehenden Mitarbeiter, ` + 'es wurde kein Start-Admin angelegt.' ); return; } db.prepare('INSERT INTO users (employee_id, email, password_hash, role) VALUES (?, ?, NULL, ?)').run( employee.id, adminEmail, 'admin' ); console.log(`Start-Admin für ${adminEmail} angelegt. Das Passwort wird beim ersten Login vergeben.`); } function seed() { const insertEmployee = db.prepare( 'INSERT INTO employees (first_name, last_name, email, role, weekly_capacity_hours) VALUES (?, ?, ?, ?, ?)' ); const employees = [ ['Anna', 'Keller', 'anna.keller@example.com', 'Frontend-Entwicklerin', 40], ['Jonas', 'Weber', 'jonas.weber@example.com', 'Backend-Entwickler', 40], ['Mira', 'Schulz', 'mira.schulz@example.com', 'UX-Designerin', 32], ['Tom', 'Fischer', 'tom.fischer@example.com', 'Projektleiter', 40], ['Lea', 'Hoffmann', 'lea.hoffmann@example.com', 'QA-Ingenieurin', 30], ]; const employeeIds = employees.map((e) => insertEmployee.run(...e).lastInsertRowid); const insertTeam = db.prepare('INSERT INTO teams (name, description) VALUES (?, ?)'); const teamWeb = insertTeam.run('Web-Team', 'Frontend & Backend fürs Kundenportal').lastInsertRowid; const teamDesign = insertTeam.run('Design-Team', 'UX/UI und Prototyping').lastInsertRowid; const insertMember = db.prepare( 'INSERT INTO team_members (team_id, employee_id) VALUES (?, ?)' ); insertMember.run(teamWeb, employeeIds[0]); insertMember.run(teamWeb, employeeIds[1]); insertMember.run(teamWeb, employeeIds[3]); insertMember.run(teamDesign, employeeIds[2]); insertMember.run(teamDesign, employeeIds[3]); const insertProject = db.prepare( 'INSERT INTO projects (name, description, start_date, end_date, color) VALUES (?, ?, ?, ?, ?)' ); const projectPortal = insertProject.run( 'Kundenportal Relaunch', 'Neugestaltung des Self-Service-Portals', '2026-07-01', '2026-08-28', '#4f46e5' ).lastInsertRowid; const projectApp = insertProject.run( 'Mobile App v2', 'Neue Funktionen für die mobile App', '2026-07-06', '2026-09-18', '#059669' ).lastInsertRowid; const insertTask = db.prepare( 'INSERT INTO tasks (project_id, name, start_date, end_date, estimated_hours, status) VALUES (?, ?, ?, ?, ?, ?)' ); const t1 = insertTask.run(projectPortal, 'Konzept & Wireframes', '2026-07-01', '2026-07-10', 40, 'in Arbeit').lastInsertRowid; const t2 = insertTask.run(projectPortal, 'Frontend-Umsetzung', '2026-07-13', '2026-08-07', 120, 'geplant').lastInsertRowid; const t3 = insertTask.run(projectPortal, 'Backend-API', '2026-07-13', '2026-08-07', 100, 'geplant').lastInsertRowid; const t4 = insertTask.run(projectPortal, 'QA & Rollout', '2026-08-10', '2026-08-28', 60, 'geplant').lastInsertRowid; const t5 = insertTask.run(projectApp, 'Anforderungsanalyse', '2026-07-06', '2026-07-17', 30, 'in Arbeit').lastInsertRowid; const t6 = insertTask.run(projectApp, 'Umsetzung Feature-Set', '2026-07-20', '2026-09-04', 150, 'geplant').lastInsertRowid; const t7 = insertTask.run(projectApp, 'Test & Release', '2026-09-07', '2026-09-18', 50, 'geplant').lastInsertRowid; const insertDependency = db.prepare( 'INSERT INTO task_dependencies (task_id, depends_on_task_id) VALUES (?, ?)' ); insertDependency.run(t2, t1); insertDependency.run(t3, t1); insertDependency.run(t4, t2); insertDependency.run(t4, t3); insertDependency.run(t6, t5); insertDependency.run(t7, t6); const insertAssignment = db.prepare( 'INSERT INTO assignments (task_id, employee_id, allocated_hours_per_week) VALUES (?, ?, ?)' ); insertAssignment.run(t1, employeeIds[2], 20); insertAssignment.run(t1, employeeIds[3], 10); insertAssignment.run(t2, employeeIds[0], 32); insertAssignment.run(t3, employeeIds[1], 32); insertAssignment.run(t4, employeeIds[4], 24); insertAssignment.run(t4, employeeIds[3], 8); insertAssignment.run(t5, employeeIds[3], 16); insertAssignment.run(t5, employeeIds[2], 12); insertAssignment.run(t6, employeeIds[0], 20); insertAssignment.run(t6, employeeIds[1], 24); insertAssignment.run(t7, employeeIds[4], 24); } module.exports = db;