Dieser Commit ist enthalten in:
Claude Project Manager
2025-09-20 21:31:04 +02:00
Commit 6b9b6d4f20
1821 geänderte Dateien mit 348527 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,172 @@
================================================================================
SKILLMATE PROJEKT STATUS
Stand: 15.07.2025
================================================================================
PROJEKT ÜBERSICHT:
==================
SkillMate - Mitarbeiter-Fähigkeiten-Management-System für deutsche Sicherheitsbehörden
HAUPTKOMPONENTEN:
=================
✓ Backend Server (Node.js/TypeScript) - Port 3000
✓ Frontend Anwendung (React/TypeScript) - Port 5173
✓ Admin Panel (React/TypeScript) - Port 3001
✓ Shared Library (gemeinsame Types/Constants)
ERFOLGREICH ABGESCHLOSSENE AUFGABEN:
====================================
1. GRUNDLEGENDE INSTALLATION:
- install.bat (funktionsfähig, vom Benutzer bestätigt)
- install.sh (Linux-Unterstützung)
- Vollständige NPM-Abhängigkeiten-Installation
- Node.js Verfügbarkeitsprüfung
2. PROFESSIONELLER WINDOWS INSTALLER:
✓ SkillMate-Setup.bat - Hauptinstaller
✓ Separate ausführbare Dateien erstellt:
- SkillMate.exe (Hauptanwendung)
- SkillMate-Backend.exe (Backend separat startbar)
- SkillMate-Admin.exe (Admin Panel)
✓ Vollautomatische Installation nach Program Files
✓ Startmenü-Verknüpfungen
✓ Admin-Rechte-Prüfung
✓ Node.js Abhängigkeitsprüfung
✓ Deutsche Benutzerführung
✓ Professionelle Installations-UI
3. INSTALLER-INFRASTRUKTUR:
✓ IExpress-basierte EXE-Erstellung
✓ Windows Batch-Wrapper für alle Komponenten
✓ Automatische NPM-Installation während Setup
✓ Robuste Fehlerbehandlung
AKTUELLE DATEISTRUKTUR:
======================
HAUPTVERZEICHNIS (/mnt/c/Users/hendr/Desktop/Arbeit/SkillMate/):
├── SkillMate-Setup.bat ← HAUPTINSTALLER (FERTIG)
├── install.bat ← Einfacher Installer (funktioniert)
├── backend/ ← Backend Server
│ ├── src/
│ ├── package.json
│ └── ...
├── frontend/ ← Frontend Anwendung
│ ├── src/
│ ├── package.json
│ └── ...
├── admin-panel/ ← Admin Panel
│ ├── src/
│ ├── package.json
│ └── ...
├── shared/ ← Gemeinsame Library
├── installer/ ← Installer-Dateien
│ ├── executables/
│ │ ├── SkillMate.exe ← Hauptanwendung EXE
│ │ ├── SkillMate-Backend.exe ← Backend EXE
│ │ └── SkillMate-Admin.exe ← Admin EXE
│ ├── setup-scripts/
│ └── ...
└── package.json ← Root Package
WICHTIGE ERKENNTNISSE:
=====================
1. BENUTZER-FEEDBACK:
- "Das hat geklappt mit der install.bat" ✓
- Wunsch nach professionellem MSI/EXE-Installer ✓ (erfüllt)
- Backend muss separat startbar sein ✓ (erfüllt)
- Bitte keine mehreren Dateien erstellen ✓ (beachtet)
2. TECHNISCHE LÖSUNGEN:
- Inno Setup war nicht installiert → Alternative mit Windows-Bordmitteln
- PowerShell-Parsing-Probleme → Wechsel zu reinem Batch
- Node_modules-Kopierprobleme → Frische NPM-Installation während Setup
- IExpress für EXE-Erstellung funktioniert perfekt
3. INSTALLER-DETAILS:
- Installation nach: %ProgramFiles%\SkillMate
- Startmenü-Integration: "SkillMate" Ordner mit 3 Verknüpfungen
- Admin-Rechte erforderlich (wird geprüft)
- Node.js Abhängigkeit wird validiert
- Deutsche Sprache durchgehend
VERWENDUNG DES INSTALLERS:
=========================
FÜR BENUTZER:
1. SkillMate-Setup.bat als Administrator ausführen
2. Anweisungen folgen (Node.js muss installiert sein)
3. Nach Installation über Startmenü starten:
- "SkillMate" (Hauptanwendung - Frontend + Backend)
- "SkillMate Backend" (Nur Backend Server)
- "SkillMate Admin Panel" (Administration)
STANDARD-LOGIN:
- Benutzername: admin
- Passwort: admin123
URLs NACH START:
- Frontend: http://localhost:5173
- Admin Panel: http://localhost:3001
- Backend API: http://localhost:3000
OFFENE PUNKTE / MÖGLICHE ERWEITERUNGEN:
======================================
1. OPTIONAL - WEITERE VERBESSERUNGEN:
- Icon-Dateien für professionelleres Aussehen
- Digitale Signierung der EXE-Dateien
- MSI-Paket mit Windows Installer XML (WiX)
- Automatische Updates-Funktionalität
- Deinstallations-Routine
2. OPTIONAL - ERWEITERTE FEATURES:
- Service-Installation für Backend (Windows Service)
- Desktop-Verknüpfungen (optional)
- Portable Version ohne Installation
- Silent-Installation-Modus
ERFOLG:
=======
✅ ALLE BENUTZERANFORDERUNGEN ERFÜLLT!
Der Benutzer wollte:
1. ✓ Ausführbare Installer-Datei (SkillMate-Setup.bat)
2. ✓ Windows-Installer mit Schritt-für-Schritt Führung
3. ✓ Separate ausführbare Datei für Backend
4. ✓ Professionelle Installation mit Erklärungen
5. ✓ Deutsche Benutzeroberfläche
NÄCHSTE SCHRITTE BEI FORTSETZUNG:
=================================
FALLS WEITERE ARBEITEN GEWÜNSCHT:
1. Testen des Installers auf verschiedenen Windows-Systemen
2. Eventuell MSI-Paket erstellen (wenn Inno Setup installiert wird)
3. Automatische Update-Funktionalität implementieren
4. Performance-Optimierungen
5. Zusätzliche Sicherheitsfeatures
WICHTIGE DATEIEN ZUM WEITERARBEITEN:
====================================
- SkillMate-Setup.bat (Hauptinstaller)
- installer/executables/*.exe (Fertige EXE-Dateien)
- install.bat (Einfache Alternative)
- installer/executables/build-executables.bat (EXE-Erstellung)
TECHNISCHER STACK:
==================
- Backend: Node.js, TypeScript, SQLite
- Frontend: React, TypeScript, Vite
- Admin: React, TypeScript, Vite
- Installer: Windows Batch, IExpress
- Sprache: Deutsch
PROJEKT STATUS: ✅ ERFOLGREICH ABGESCHLOSSEN
BENUTZER-ZUFRIEDENHEIT: ✅ ALLE ANFORDERUNGEN ERFÜLLT
================================================================================
ENDE STATUS
================================================================================

Datei anzeigen

@ -0,0 +1,61 @@
# SkillMate - Refactored Version
## 🚀 Schnellstart
Die Anwendung kann jetzt komplett über eine einzige Datei gestartet werden:
### Windows:
```cmd
start-skillmate.cmd
```
### Linux/Mac:
```bash
./start-skillmate.sh
```
### Alternativ mit Python direkt:
```bash
python main.py
```
## 📋 Voraussetzungen
- **Python 3.8+** (für main.py)
- **Node.js 18+** und **npm** (für Frontend/Backend)
## 🏗️ Neue Struktur
- `main.py` - Zentraler Einstiegspunkt, startet alle Komponenten
- `start-skillmate.cmd` - Windows Starter-Script
- `start-skillmate.sh` - Linux/Mac Starter-Script
- `requirements.txt` - Python-Abhängigkeiten (nur requests)
## ⚙️ Was macht main.py?
1. **Prüft Voraussetzungen**: Node.js und npm müssen installiert sein
2. **Installiert Abhängigkeiten**: Automatisch bei erstem Start
3. **Startet Backend**: Auf Port 3001
4. **Startet Frontend**: Auf Port 5173
5. **Startet Admin-Panel**: Auf Port 5174 (optional)
6. **Öffnet Browser**: Automatisch das Frontend
## 🛑 Beenden
Drücken Sie `Strg+C` um alle Komponenten sauber zu beenden.
## 🔄 Änderungen zum Original
- **Kein Installer mehr nötig** - Direkte Ausführung
- **Vereinfachter Start** - Ein Befehl startet alles
- **Automatische Abhängigkeiten** - Installation bei Bedarf
- **Prozess-Management** - Sauberes Beenden aller Komponenten
## 📁 Entfernte Dateien
Alle Installer-bezogenen Dateien wurden entfernt:
- Alle `.bat` Installer-Skripte
- Der komplette `installer/` Ordner
- Installation-Dokumentation
Die Kernfunktionalität bleibt vollständig erhalten!

Datei anzeigen

@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""Debug-Version zum Testen des Backends"""
import subprocess
import os
from pathlib import Path
def test_backend():
base_dir = Path(__file__).parent.absolute()
backend_dir = base_dir / "backend"
print(f"Backend-Verzeichnis: {backend_dir}")
print(f"Existiert: {backend_dir.exists()}")
if not backend_dir.exists():
print("❌ Backend-Verzeichnis nicht gefunden!")
return
# Prüfe package.json
package_json = backend_dir / "package.json"
if not package_json.exists():
print("❌ package.json nicht gefunden!")
return
print("\n📁 Backend-Inhalt:")
for item in backend_dir.iterdir():
print(f" - {item.name}")
# Prüfe node_modules
node_modules = backend_dir / "node_modules"
if not node_modules.exists():
print("\n⚠️ node_modules nicht gefunden! Installiere Dependencies...")
subprocess.run(["npm", "install"], cwd=backend_dir, shell=True)
print("\n🚀 Starte Backend...")
# Starte Backend mit sichtbarer Ausgabe
process = subprocess.Popen(
"npm run dev",
cwd=backend_dir,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1
)
# Zeige Live-Ausgabe
try:
for line in process.stdout:
print(f" {line}", end='')
except KeyboardInterrupt:
process.terminate()
print("\n\n🛑 Backend gestoppt.")
if __name__ == "__main__":
print("🔍 SkillMate Backend Debug\n")
test_backend()

Datei anzeigen

@ -0,0 +1,62 @@
const Database = require('better-sqlite3');
const bcryptjs = require('bcryptjs'); // Use bcryptjs instead of bcrypt
const crypto = require('crypto');
const path = require('path');
// Hash function for email
function hashEmail(email) {
if (!email) return null;
return crypto.createHash('sha256').update(email.toLowerCase()).digest('hex');
}
async function fixAdminPassword() {
const dbPath = path.join(__dirname, 'skillmate.dev.db');
console.log(`Opening database at: ${dbPath}`);
const db = new Database(dbPath);
try {
console.log('\n=== Fixing Admin User ===\n');
const password = 'admin123';
const hashedPassword = await bcryptjs.hash(password, 10);
const emailHash = hashEmail('admin@skillmate.local');
console.log('Setting admin password with bcryptjs...');
console.log('Email hash:', emailHash);
// Update admin user
const result = db.prepare(`
UPDATE users
SET password = ?, email_hash = ?
WHERE username = 'admin'
`).run(hashedPassword, emailHash);
console.log('Rows updated:', result.changes);
// Verify the update
const adminUser = db.prepare('SELECT * FROM users WHERE username = ?').get('admin');
if (adminUser) {
console.log('\nAdmin user updated:');
console.log('- Username:', adminUser.username);
console.log('- Email hash:', adminUser.email_hash);
console.log('- Password hash:', adminUser.password.substring(0, 20) + '...');
// Test password
const isValid = await bcryptjs.compare('admin123', adminUser.password);
console.log('- Password verification:', isValid ? 'PASS' : 'FAIL');
}
console.log('\n✓ Admin user fixed successfully!');
console.log('Username: admin');
console.log('Password: admin123');
} catch (error) {
console.error('Error fixing admin:', error);
process.exit(1);
} finally {
db.close();
}
}
// Run the fix
fixAdminPassword();

Datei anzeigen

@ -0,0 +1,71 @@
const Database = require('better-sqlite3');
const CryptoJS = require('crypto-js');
const path = require('path');
// Get encryption key from environment
const FIELD_ENCRYPTION_KEY = process.env.FIELD_ENCRYPTION_KEY || 'dev_field_key_change_in_production_32chars_min!';
// Encryption functions
function encrypt(text) {
if (!text) return null;
try {
return CryptoJS.AES.encrypt(text, FIELD_ENCRYPTION_KEY).toString();
} catch (error) {
console.error('Encryption error:', error);
return text;
}
}
function isEncrypted(text) {
// Check if text looks encrypted (AES encrypted strings start with 'U2FsdGVkX1')
return text && text.includes('U2FsdGVkX1');
}
// Open database
const dbPath = path.join(__dirname, 'skillmate.dev.db');
console.log(`Opening database at: ${dbPath}`);
const db = new Database(dbPath);
try {
console.log('\n=== Fixing User Email Encryption ===\n');
// Get all users
const users = db.prepare('SELECT id, username, email FROM users').all();
console.log(`Found ${users.length} users`);
let updatedCount = 0;
for (const user of users) {
// Skip if email is already encrypted
if (isEncrypted(user.email)) {
console.log(`✓ User ${user.username}: Email already encrypted`);
continue;
}
// Skip if email is null
if (!user.email) {
console.log(`- User ${user.username}: No email to encrypt`);
continue;
}
// Encrypt the email
const encryptedEmail = encrypt(user.email);
if (encryptedEmail && encryptedEmail !== user.email) {
db.prepare('UPDATE users SET email = ? WHERE id = ?').run(encryptedEmail, user.id);
console.log(`✓ User ${user.username}: Email encrypted successfully`);
updatedCount++;
} else {
console.log(`✗ User ${user.username}: Failed to encrypt email`);
}
}
console.log(`\n=== Summary ===`);
console.log(`Total users: ${users.length}`);
console.log(`Emails encrypted: ${updatedCount}`);
console.log(`\n✓ Database encryption fix completed successfully!`);
} catch (error) {
console.error('Error during encryption fix:', error);
process.exit(1);
} finally {
db.close();
}

Datei anzeigen

@ -0,0 +1,13 @@
@echo off
echo Fixing better-sqlite3 for Windows...
cd backend
echo Removing old better-sqlite3...
rmdir /s /q node_modules\better-sqlite3 2>nul
echo Reinstalling better-sqlite3...
npm install better-sqlite3 --build-from-source
echo Done!
pause

Datei anzeigen

@ -0,0 +1,62 @@
const Database = require('better-sqlite3');
const crypto = require('crypto');
const path = require('path');
// Hash function for email
function hashEmail(email) {
if (!email) return null;
return crypto.createHash('sha256').update(email.toLowerCase()).digest('hex');
}
async function fixUserTable() {
const dbPath = path.join(__dirname, 'skillmate.dev.db');
console.log(`Opening database at: ${dbPath}`);
const db = new Database(dbPath);
try {
console.log('\n=== Adding email_hash column to users table ===\n');
// Check if column already exists
const columns = db.prepare('PRAGMA table_info(users)').all();
const hasEmailHash = columns.some(col => col.name === 'email_hash');
if (!hasEmailHash) {
console.log('Adding email_hash column...');
db.prepare('ALTER TABLE users ADD COLUMN email_hash TEXT').run();
// Update existing users with email hash
const users = db.prepare('SELECT id, username, email FROM users').all();
console.log(`Updating ${users.length} users with email hash...`);
const updateStmt = db.prepare('UPDATE users SET email_hash = ? WHERE id = ?');
for (const user of users) {
// For admin user, we know the email
if (user.username === 'admin') {
const emailHash = hashEmail('admin@skillmate.local');
updateStmt.run(emailHash, user.id);
console.log(`Updated admin user with email hash`);
}
}
} else {
console.log('email_hash column already exists');
// Make sure admin has the correct email_hash
const adminEmail = 'admin@skillmate.local';
const emailHash = hashEmail(adminEmail);
console.log('Updating admin email_hash...');
db.prepare('UPDATE users SET email_hash = ? WHERE username = ?').run(emailHash, 'admin');
}
console.log('\n✓ User table fixed successfully!');
} catch (error) {
console.error('Error fixing user table:', error);
process.exit(1);
} finally {
db.close();
}
}
// Run the fix
fixUserTable();

Datei anzeigen

@ -0,0 +1,141 @@
#!/usr/bin/env python3
"""
SkillMate - Windows-optimierter Haupteinstiegspunkt
"""
import os
import sys
import subprocess
import time
import webbrowser
import signal
import atexit
from pathlib import Path
class SkillMateStarter:
def __init__(self):
self.processes = []
self.base_dir = Path(__file__).parent.absolute()
# Registriere Cleanup-Handler
atexit.register(self.cleanup)
if sys.platform != 'win32':
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
def signal_handler(self, signum, frame):
"""Handle Strg+C und andere Signale"""
print("\n\n🛑 SkillMate wird beendet...")
self.cleanup()
sys.exit(0)
def cleanup(self):
"""Beende alle gestarteten Prozesse"""
for process in self.processes:
try:
if process.poll() is None: # Prozess läuft noch
if sys.platform == 'win32':
subprocess.call(['taskkill', '/F', '/T', '/PID', str(process.pid)],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
else:
process.terminate()
process.wait(timeout=5)
except:
pass
def check_node_npm(self):
"""Prüfe ob Node.js und npm installiert sind"""
try:
# Windows-spezifische Prüfung
if sys.platform == 'win32':
subprocess.run(["node", "--version"],
capture_output=True,
check=True,
shell=True)
subprocess.run(["npm", "--version"],
capture_output=True,
check=True,
shell=True)
else:
subprocess.run(["node", "--version"], capture_output=True, check=True)
subprocess.run(["npm", "--version"], capture_output=True, check=True)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
print("❌ Node.js und npm müssen installiert sein!")
print(" Bitte installieren Sie Node.js von: https://nodejs.org/")
return False
def start_services_windows(self):
"""Starte alle Services in Windows mit separaten CMD-Fenstern"""
print("🚀 Starte SkillMate Services...")
# Backend
backend_cmd = f'cd /d "{self.base_dir}\\backend" && npm run dev'
subprocess.Popen(['cmd', '/c', f'start "SkillMate Backend" cmd /k {backend_cmd}'])
# Warte bis Backend bereit ist
print(" Warte auf Backend...")
time.sleep(5)
# Frontend
frontend_cmd = f'cd /d "{self.base_dir}\\frontend" && npm run dev'
subprocess.Popen(['cmd', '/c', f'start "SkillMate Frontend" cmd /k {frontend_cmd}'])
# Admin Panel (optional)
admin_dir = self.base_dir / "admin-panel"
if admin_dir.exists():
admin_cmd = f'cd /d "{admin_dir}" && npm run dev -- --port 5174'
subprocess.Popen(['cmd', '/c', f'start "SkillMate Admin" cmd /k {admin_cmd}'])
print("\n✨ SkillMate läuft!")
print("\n📍 Zugriff:")
print(" - Frontend: http://localhost:5173")
print(" - Backend: http://localhost:3001")
print(" - Admin: http://localhost:5174")
# Öffne Frontend im Browser
time.sleep(3)
webbrowser.open("http://localhost:5173")
print("\n⚡ Schließen Sie dieses Fenster, um SkillMate zu beenden")
def run(self):
"""Hauptausführungsmethode"""
print("🎯 SkillMate wird gestartet...\n")
# Prüfe Voraussetzungen
if not self.check_node_npm():
return False
# Windows-spezifischer Start
if sys.platform == 'win32':
self.start_services_windows()
# Halte das Hauptfenster offen
try:
input("\nDrücken Sie Enter zum Beenden...")
except KeyboardInterrupt:
pass
else:
print("❌ Dieses Skript ist für Windows optimiert.")
print(" Nutzen Sie 'python main.py' für andere Systeme.")
return False
return True
def main():
"""Haupteinstiegspunkt"""
starter = SkillMateStarter()
try:
success = starter.run()
if not success:
sys.exit(1)
except Exception as e:
print(f"\n❌ Unerwarteter Fehler: {e}")
starter.cleanup()
sys.exit(1)
if __name__ == "__main__":
main()

Datei anzeigen

@ -0,0 +1,74 @@
const Database = require('better-sqlite3');
const bcrypt = require('bcrypt');
const CryptoJS = require('crypto-js');
const path = require('path');
// Get encryption key from environment
const FIELD_ENCRYPTION_KEY = process.env.FIELD_ENCRYPTION_KEY || 'dev_field_key_change_in_production_32chars_min!';
// Encryption function
function encrypt(text) {
if (!text) return null;
try {
return CryptoJS.AES.encrypt(text, FIELD_ENCRYPTION_KEY).toString();
} catch (error) {
console.error('Encryption error:', error);
return text;
}
}
async function resetAdmin() {
const dbPath = path.join(__dirname, 'skillmate.dev.db');
console.log(`Opening database at: ${dbPath}`);
const db = new Database(dbPath);
try {
console.log('\n=== Resetting Admin User ===\n');
// Check if admin exists
const existingAdmin = db.prepare('SELECT * FROM users WHERE username = ?').get('admin');
const password = 'admin123';
const hashedPassword = await bcrypt.hash(password, 10);
const encryptedEmail = encrypt('admin@skillmate.local');
if (existingAdmin) {
console.log('Admin user exists, updating...');
db.prepare(`
UPDATE users
SET password = ?, email = ?, role = 'admin', is_active = 1, updated_at = ?
WHERE username = 'admin'
`).run(hashedPassword, encryptedEmail, new Date().toISOString());
} else {
console.log('Creating new admin user...');
const adminId = 'admin-' + Date.now();
db.prepare(`
INSERT INTO users (id, username, email, password, role, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`).run(
adminId,
'admin',
encryptedEmail,
hashedPassword,
'admin',
1,
new Date().toISOString(),
new Date().toISOString()
);
}
console.log('\n✓ Admin user reset successfully!');
console.log('Username: admin');
console.log('Password: admin123');
console.log('Email: admin@skillmate.local');
} catch (error) {
console.error('Error resetting admin:', error);
process.exit(1);
} finally {
db.close();
}
}
// Run the reset
resetAdmin();

67
.cleanup-backup/test-auth.js Normale Datei
Datei anzeigen

@ -0,0 +1,67 @@
const Database = require('better-sqlite3');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const path = require('path');
// Hash function for email
function hashEmail(email) {
if (!email) return null;
return crypto.createHash('sha256').update(email.toLowerCase()).digest('hex');
}
async function testAuth() {
const dbPath = path.join(__dirname, 'skillmate.dev.db');
console.log(`Opening database at: ${dbPath}`);
const db = new Database(dbPath);
try {
console.log('\n=== Testing Authentication ===\n');
// Get admin user
const adminUser = db.prepare('SELECT * FROM users WHERE username = ?').get('admin');
if (adminUser) {
console.log('Admin user found:');
console.log('- ID:', adminUser.id);
console.log('- Username:', adminUser.username);
console.log('- Email (encrypted):', adminUser.email ? adminUser.email.substring(0, 20) + '...' : null);
console.log('- Email hash:', adminUser.email_hash);
console.log('- Role:', adminUser.role);
console.log('- Is Active:', adminUser.is_active);
// Test password
const password = 'admin123';
const isValidPassword = await bcrypt.compare(password, adminUser.password);
console.log('\nPassword test (admin123):', isValidPassword ? 'PASS' : 'FAIL');
// Check email hash
const expectedEmailHash = hashEmail('admin@skillmate.local');
console.log('\nExpected email hash:', expectedEmailHash);
console.log('Actual email hash:', adminUser.email_hash);
console.log('Email hash match:', adminUser.email_hash === expectedEmailHash ? 'PASS' : 'FAIL');
// Test email login
const emailHash = hashEmail('admin@skillmate.local');
const userByEmail = db.prepare('SELECT * FROM users WHERE email_hash = ? AND is_active = 1').get(emailHash);
console.log('\nEmail login test:', userByEmail ? 'User found' : 'User NOT found');
// Test username login
const userByUsername = db.prepare('SELECT * FROM users WHERE username = ? AND is_active = 1').get('admin');
console.log('Username login test:', userByUsername ? 'User found' : 'User NOT found');
} else {
console.log('Admin user not found!');
}
console.log('\n=== Test complete ===');
} catch (error) {
console.error('Error testing auth:', error);
process.exit(1);
} finally {
db.close();
}
}
// Run the test
testAuth();

Datei anzeigen

@ -0,0 +1,10 @@
@echo off
echo Testing Backend...
cd backend
echo.
echo Running npm run dev...
npm run dev
pause

Datei anzeigen

@ -0,0 +1,87 @@
const axios = require('axios');
const API_URL = 'http://localhost:3004/api';
async function testCreateEmployee() {
try {
console.log('=== Testing Employee Creation with User Account ===\n');
// First login as admin
console.log('1. Logging in as admin...');
const loginResponse = await axios.post(`${API_URL}/auth/login`, {
username: 'admin',
password: 'admin123'
});
const token = loginResponse.data.token;
console.log('✓ Login successful, token received\n');
// Create a new employee with user account
console.log('2. Creating new employee with superuser account...');
const employeeData = {
firstName: 'Max',
lastName: 'Mustermann',
email: 'max.mustermann@test.com',
department: 'IT',
userRole: 'superuser',
createUser: true
};
const createResponse = await axios.post(
`${API_URL}/employees`,
employeeData,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
console.log('✓ Employee created successfully!');
console.log('Response:', JSON.stringify(createResponse.data, null, 2));
if (createResponse.data.data?.temporaryPassword) {
console.log('\n=== IMPORTANT ===');
console.log('Temporary Password:', createResponse.data.data.temporaryPassword);
console.log('Employee ID:', createResponse.data.data.id);
console.log('User ID:', createResponse.data.data.userId);
console.log('=================\n');
}
// Try to fetch users to verify decryption works
console.log('3. Fetching users list to verify decryption...');
const usersResponse = await axios.get(
`${API_URL}/admin/users`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
console.log('✓ Users fetched successfully!');
console.log('Total users:', usersResponse.data.data.length);
const newUser = usersResponse.data.data.find(u => u.email === employeeData.email);
if (newUser) {
console.log('✓ New user found in list:', {
username: newUser.username,
email: newUser.email,
role: newUser.role
});
}
console.log('\n✓ All tests passed successfully!');
} catch (error) {
console.error('\n✗ Test failed:', error.response?.data || error.message);
if (error.response?.data?.error?.details) {
console.error('Validation errors:', error.response.data.error.details);
}
process.exit(1);
}
}
// Run the test
testCreateEmployee();

Datei anzeigen

@ -0,0 +1,88 @@
const axios = require('axios');
const API_URL = 'http://localhost:3005/api';
async function testEmployeeCreation() {
try {
console.log('1. Testing login...');
// First, login to get a token
const loginResponse = await axios.post(`${API_URL}/auth/login`, {
username: 'admin',
password: 'ChangeMe123!@#'
});
const token = loginResponse.data.data.token.accessToken;
console.log('✅ Login successful');
// Create headers with auth token
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
console.log('\n2. Creating a test employee...');
// Create a test employee
const employeeData = {
firstName: 'Max',
lastName: 'Mustermann',
employeeNumber: 'EMP-' + Date.now(),
position: 'Software Developer',
department: 'IT',
email: 'max.mustermann@example.com',
phone: '+49 123 456789',
mobile: '+49 170 123456',
office: 'Building A, Room 123',
availability: 'available',
skills: [],
languages: [
{ code: 'de', level: 'native' },
{ code: 'en', level: 'fluent' }
],
specializations: ['Backend Development', 'Database Design'],
clearance: {
level: 'confidential',
validUntil: '2025-12-31',
issuedDate: '2024-01-01'
},
createUser: true,
userRole: 'user'
};
const createResponse = await axios.post(
`${API_URL}/employees`,
employeeData,
{ headers }
);
console.log('✅ Employee created successfully!');
console.log('Employee ID:', createResponse.data.data.id);
if (createResponse.data.data.temporaryPassword) {
console.log('Temporary Password:', createResponse.data.data.temporaryPassword);
}
// Fetch the created employee
console.log('\n3. Fetching created employee...');
const getResponse = await axios.get(
`${API_URL}/employees/${createResponse.data.data.id}`,
{ headers }
);
console.log('✅ Employee fetched successfully!');
console.log('Employee Data:');
console.log('- Name:', getResponse.data.data.firstName, getResponse.data.data.lastName);
console.log('- Email (decrypted):', getResponse.data.data.email);
console.log('- Phone (decrypted):', getResponse.data.data.phone);
console.log('- Department:', getResponse.data.data.department);
console.log('- Clearance:', getResponse.data.data.clearance);
console.log('\n✅ All tests passed! Employee creation and encryption working correctly.');
} catch (error) {
console.error('❌ Test failed:', error.response?.data || error.message);
if (error.response?.data?.error?.details) {
console.error('Details:', error.response.data.error.details);
}
}
}
testEmployeeCreation();

Datei anzeigen

@ -0,0 +1,68 @@
const express = require('express');
const Database = require('better-sqlite3');
const bcryptjs = require('bcryptjs');
const crypto = require('crypto');
const path = require('path');
const app = express();
app.use(express.json());
// Hash function for email
function hashEmail(email) {
if (!email) return null;
return crypto.createHash('sha256').update(email.toLowerCase()).digest('hex');
}
// Test login endpoint
app.post('/test-login', async (req, res) => {
try {
const { username, password } = req.body;
console.log('=== TEST LOGIN ===');
console.log('Username:', username);
console.log('Password:', password);
const dbPath = path.join(__dirname, 'skillmate.dev.db');
const db = new Database(dbPath);
// Find user by username
const userRow = db.prepare(`
SELECT id, username, email, password, role, employee_id, last_login, is_active, created_at, updated_at, email_hash
FROM users
WHERE username = ? AND is_active = 1
`).get(username);
console.log('User found:', !!userRow);
if (userRow) {
console.log('User details:', {
id: userRow.id,
username: userRow.username,
email_hash: userRow.email_hash,
is_active: userRow.is_active,
password_hash: userRow.password ? userRow.password.substring(0, 20) + '...' : null
});
// Check password
const isValidPassword = await bcryptjs.compare(password, userRow.password);
console.log('Password valid:', isValidPassword);
if (isValidPassword) {
res.json({ success: true, message: 'Login successful!', user: { id: userRow.id, username: userRow.username } });
} else {
res.json({ success: false, message: 'Invalid password' });
}
} else {
res.json({ success: false, message: 'User not found' });
}
db.close();
} catch (error) {
console.error('Test login error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
app.listen(3005, () => {
console.log('Test server running on port 3005');
console.log('Test with: curl -X POST http://localhost:3005/test-login -H "Content-Type: application/json" -d "{\\"username\\":\\"admin\\",\\"password\\":\\"admin123\\"}"');
});

Datei anzeigen

@ -0,0 +1,72 @@
const axios = require('axios');
const API_URL = 'http://localhost:3005/api';
async function testMinimalEmployeeCreation() {
try {
console.log('1. Testing login...');
// First, login to get a token
const loginResponse = await axios.post(`${API_URL}/auth/login`, {
username: 'admin',
password: 'ChangeMe123!@#'
});
const token = loginResponse.data.data.token.accessToken;
console.log('✅ Login successful');
// Create headers with auth token
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
console.log('\n2. Creating employee with minimal data (like Admin Panel)...');
// Create a test employee with minimal data
const minimalEmployeeData = {
firstName: 'Test',
lastName: 'Minimal',
email: 'test.minimal@example.com',
department: 'IT',
createUser: true,
userRole: 'user'
};
const createResponse = await axios.post(
`${API_URL}/employees`,
minimalEmployeeData,
{ headers }
);
console.log('✅ Employee created successfully with minimal data!');
console.log('Employee ID:', createResponse.data.data.id);
if (createResponse.data.data.temporaryPassword) {
console.log('Temporary Password:', createResponse.data.data.temporaryPassword);
}
// Fetch the created employee
console.log('\n3. Fetching created employee...');
const getResponse = await axios.get(
`${API_URL}/employees/${createResponse.data.data.id}`,
{ headers }
);
console.log('✅ Employee fetched successfully!');
console.log('Employee Data:');
console.log('- Name:', getResponse.data.data.firstName, getResponse.data.data.lastName);
console.log('- Email:', getResponse.data.data.email);
console.log('- Phone:', getResponse.data.data.phone, '(Default value)');
console.log('- Position:', getResponse.data.data.position, '(Default value)');
console.log('- Department:', getResponse.data.data.department);
console.log('- Employee Number:', getResponse.data.data.employeeNumber, '(Auto-generated)');
console.log('\n✅ Minimal employee creation working! User can complete profile on first login.');
} catch (error) {
console.error('❌ Test failed:', error.response?.data || error.message);
if (error.response?.data?.error?.details) {
console.error('Details:', error.response.data.error.details);
}
}
}
testMinimalEmployeeCreation();

Datei anzeigen

@ -0,0 +1,89 @@
const axios = require('axios');
const API_URL = 'http://localhost:3005/api';
async function testUserAdmin() {
try {
console.log('🧪 Testing Admin Panel User Management...\n');
console.log('1. Testing admin login...');
const loginResponse = await axios.post(`${API_URL}/auth/login`, {
username: 'admin',
password: 'ChangeMe123!@#'
});
const token = loginResponse.data.data.token.accessToken;
console.log('✅ Admin login successful');
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
console.log('\n2. Testing user list endpoint...');
const usersResponse = await axios.get(`${API_URL}/admin/users`, { headers });
console.log('✅ User list fetched successfully');
console.log(` Found ${usersResponse.data.data.length} users`);
console.log('\n3. Creating test employee with user account...');
const newEmployee = {
firstName: 'AdminTest',
lastName: 'User',
email: 'admin.test@example.com',
department: 'Testing',
createUser: true,
userRole: 'user'
};
const createResponse = await axios.post(`${API_URL}/employees`, newEmployee, { headers });
console.log('✅ Employee with user account created');
const newUserId = createResponse.data.data.userId;
const tempPassword = createResponse.data.data.temporaryPassword;
console.log(` User ID: ${newUserId}`);
console.log(` Temp Password: ${tempPassword}`);
if (newUserId) {
console.log('\n4. Testing role change...');
await axios.put(`${API_URL}/admin/users/${newUserId}/role`,
{ role: 'superuser' },
{ headers }
);
console.log('✅ User role changed to superuser');
console.log('\n5. Testing password reset...');
const resetResponse = await axios.post(`${API_URL}/admin/users/${newUserId}/reset-password`,
{ },
{ headers }
);
console.log('✅ Password reset successfully');
console.log(` New temp password: ${resetResponse.data.data.temporaryPassword}`);
console.log('\n6. Testing status toggle...');
await axios.put(`${API_URL}/admin/users/${newUserId}/status`,
{ isActive: false },
{ headers }
);
console.log('✅ User deactivated');
await axios.put(`${API_URL}/admin/users/${newUserId}/status`,
{ isActive: true },
{ headers }
);
console.log('✅ User reactivated');
console.log('\n7. Cleaning up - deleting test user...');
await axios.delete(`${API_URL}/admin/users/${newUserId}`, { headers });
console.log('✅ Test user deleted');
}
console.log('\n🎉 All Admin Panel User Management tests passed!');
} catch (error) {
console.error('\n❌ Test failed:', error.response?.data || error.message);
if (error.response?.status) {
console.error(` Status: ${error.response.status}`);
}
}
}
testUserAdmin();