diff --git a/App/admin-accounts.html b/App/admin-accounts.html
new file mode 100644
index 0000000..874e4d0
--- /dev/null
+++ b/App/admin-accounts.html
@@ -0,0 +1,171 @@
+
+
+
+
-
+
+
Ihre E-Mail-Adresse ist zugleich Ihr Benutzername für die Anmeldung.
👁
diff --git a/App/php/api/admin-accounts.php b/App/php/api/admin-accounts.php
new file mode 100644
index 0000000..18ab7e0
--- /dev/null
+++ b/App/php/api/admin-accounts.php
@@ -0,0 +1,123 @@
+ 'Nicht eingeloggt']);
+ exit;
+}
+
+$meId = (int)$_SESSION['admin_id'];
+$db = Database::get();
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ Response::error('Nur POST erlaubt', 405);
+}
+
+$body = json_decode(file_get_contents('php://input'), true) ?: [];
+$action = $body['action'] ?? '';
+
+// === LISTE ===
+if ($action === 'list') {
+ $rows = $db->fetchAll('SELECT id, username, email_2fa, created_at FROM admin_users ORDER BY id');
+ foreach ($rows as &$r) {
+ $r['id'] = (int)$r['id'];
+ $r['is_self'] = ($r['id'] === $meId);
+ }
+ unset($r);
+ Response::ok(['admins' => $rows]);
+}
+
+// === ANLEGEN ===
+if ($action === 'create') {
+ $username = trim($body['username'] ?? '');
+ $email = trim($body['email_2fa'] ?? '');
+ $password = (string)($body['password'] ?? '');
+
+ if ($username === '' || $email === '' || $password === '') {
+ Response::error('Benutzername, 2FA-E-Mail und Passwort sind erforderlich.');
+ }
+ if (!preg_match('/^[A-Za-z0-9._\-]{3,64}$/', $username)) {
+ Response::error('Benutzername: 3–64 Zeichen, nur Buchstaben, Ziffern, Punkt, Unterstrich, Bindestrich.');
+ }
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ Response::error('Ungültige 2FA-E-Mail-Adresse.');
+ }
+ if (strlen($password) < 10) {
+ Response::error('Passwort muss mindestens 10 Zeichen haben.');
+ }
+ if ($db->fetchOne('SELECT id FROM admin_users WHERE username = ?', [$username])) {
+ Response::error('Dieser Benutzername ist bereits vergeben.');
+ }
+
+ $hash = password_hash($password, PASSWORD_DEFAULT);
+ $db->execute(
+ 'INSERT INTO admin_users (username, password, email_2fa) VALUES (?, ?, ?)',
+ [$username, $hash, $email]
+ );
+ Response::ok(['message' => 'Admin-Account angelegt.']);
+}
+
+// === AKTUALISIEREN (2FA-Mail und/oder Passwort) ===
+if ($action === 'update') {
+ $id = (int)($body['id'] ?? 0);
+ if (!$id) Response::error('ID fehlt.');
+ if (!$db->fetchOne('SELECT id FROM admin_users WHERE id = ?', [$id])) {
+ Response::error('Admin nicht gefunden.', 404);
+ }
+
+ $didSomething = false;
+
+ if (array_key_exists('email_2fa', $body)) {
+ $email = trim((string)$body['email_2fa']);
+ if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ Response::error('Ungültige 2FA-E-Mail-Adresse.');
+ }
+ $db->execute('UPDATE admin_users SET email_2fa = ? WHERE id = ?', [$email, $id]);
+ $didSomething = true;
+ }
+
+ if (array_key_exists('password', $body) && (string)$body['password'] !== '') {
+ $password = (string)$body['password'];
+ if (strlen($password) < 10) {
+ Response::error('Passwort muss mindestens 10 Zeichen haben.');
+ }
+ $db->execute(
+ 'UPDATE admin_users SET password = ? WHERE id = ?',
+ [password_hash($password, PASSWORD_DEFAULT), $id]
+ );
+ $didSomething = true;
+ }
+
+ if (!$didSomething) Response::error('Nichts zu ändern.');
+ Response::ok(['message' => 'Admin-Account aktualisiert.']);
+}
+
+// === LÖSCHEN ===
+if ($action === 'delete') {
+ $id = (int)($body['id'] ?? 0);
+ if (!$id) Response::error('ID fehlt.');
+ if ($id === $meId) Response::error('Du kannst deinen eigenen Account nicht löschen.');
+
+ $row = $db->fetchOne('SELECT COUNT(*) AS c FROM admin_users');
+ if ((int)($row['c'] ?? 0) <= 1) {
+ Response::error('Der letzte Admin-Account kann nicht gelöscht werden.');
+ }
+
+ $db->execute('DELETE FROM admin_users WHERE id = ?', [$id]);
+ $db->execute('DELETE FROM admin_pins WHERE admin_id = ?', [$id]); // verwaiste PINs aufräumen
+ Response::ok(['message' => 'Admin-Account gelöscht.']);
+}
+
+Response::error('Unbekannte Aktion.');
diff --git a/App/php/api/auth.php b/App/php/api/auth.php
index b5dd939..22b03dd 100644
--- a/App/php/api/auth.php
+++ b/App/php/api/auth.php
@@ -27,7 +27,9 @@ if ($action === 'register') {
$existing = $db->fetchOne('SELECT id FROM teachers WHERE email = ?', [$email]);
if ($existing) Response::error('Diese E-Mail-Adresse ist bereits registriert');
- $username = strtolower(explode('@', $email)[0]) . '_' . rand(100, 999);
+ // Regel (ab 2026-08): Der Benutzername einer Lehrperson IST ihre E-Mail-Adresse.
+ // Bestehende, abweichende Benutzernamen bleiben gültig (Login akzeptiert E-Mail ODER Benutzername).
+ $username = strtolower($email);
$hash = password_hash($password, PASSWORD_DEFAULT);
$db->execute(