Vollständiges Zugangs-/Rollen-/Rechtesystem gebaut (Anforderungsdokument): D1-Datenbank, AES-verschlüsselte Codes nur für Owner einsehbar, granulare Permissions, Session-Auth mit Lockout, Zugänge-&-Teammitglieder-Verwaltungsseite, Bewerbungen mit Status/Notizen/Entwürfen

This commit is contained in:
2026-07-31 00:37:04 +02:00
parent 96087f460e
commit 6a1c0e355c
18 changed files with 2283 additions and 539 deletions
+201
View File
@@ -0,0 +1,201 @@
<!DOCTYPE html>
<html lang="de" data-theme="spicymedia">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex, nofollow" />
<title>Zugänge und Teammitglieder — DOGFATHER UNIVERSE</title>
<meta name="description" content="Interner Bereich: Zugänge, Rollen und Rechte verwalten." />
<link rel="icon" type="image/png" href="assets/img/favicon.png" />
<link rel="stylesheet" href="assets/css/main.css" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" />
<style>
.perm-table { width:100%; border-collapse:collapse; font-size:.85rem; }
.perm-table th, .perm-table td { text-align:left; padding:.5rem .6rem; border-bottom:1px solid var(--border); }
.perm-group-title { font-weight:700; color:var(--accent); margin:1.2rem 0 .4rem; font-size:.8rem; text-transform:uppercase; letter-spacing:.08em; }
.user-row { display:grid; grid-template-columns: 1.4fr 1fr 1fr .8fr 1fr; gap:.6rem; align-items:center; padding:.8rem 0; border-bottom:1px solid var(--border); font-size:.88rem; }
.user-row .actions { display:flex; flex-wrap:wrap; gap:.4rem; grid-column:1/-1; margin-top:.4rem; }
.status-pill { display:inline-block; padding:.15rem .55rem; border-radius:999px; font-size:.7rem; font-weight:700; text-transform:uppercase; }
.status-pill.active { background:rgba(34,197,94,.15); color:#22c55e; }
.status-pill.locked { background:rgba(217,74,92,.15); color:var(--accent); }
.status-pill.pending { background:rgba(232,147,58,.15); color:var(--accent-2); }
.modal-backdrop { position:fixed; inset:0; background:rgba(0,0,0,.7); display:none; align-items:center; justify-content:center; z-index:300; padding:5vh 4vw; }
.modal-backdrop.open { display:flex; }
.modal-box { background:var(--card-bg); border:1px solid var(--border); border-radius:var(--radius); padding:1.6rem; max-width:640px; width:100%; max-height:88vh; overflow:auto; }
.code-reveal-box { font-family:monospace; font-size:1.3rem; letter-spacing:.05em; background:var(--bg-alt); border:1px dashed var(--accent); border-radius:8px; padding:.8rem 1rem; margin:.6rem 0; text-align:center; }
.audit-row { padding:.6rem 0; border-bottom:1px solid var(--border); font-size:.85rem; }
</style>
</head>
<body>
<div id="site-header"></div>
<main>
<section class="hero">
<div class="container">
<span class="eyebrow">🔒 Interner Bereich</span>
<h1>Zugänge und Teammitglieder</h1>
<p class="lead worlds">Rollen, Rechte, Codes — vollständig unter Dogis Kontrolle.</p>
</div>
</section>
<!-- ===== Login-Gate ===== -->
<section class="section-tight" id="gate-container">
<div class="container" style="max-width:480px;">
<form id="code-gate" class="app-form" novalidate>
<div class="field">
<label for="code-input">Zugangscode</label>
<input id="code-input" name="code" type="password" autocomplete="off" required />
</div>
<button class="btn btn-primary" type="submit">Anmelden</button>
<div class="form-status" id="gate-status"></div>
</form>
<p class="small muted" style="margin-top:1rem;">
<a href="postfach.html">← Zurück zum Postfach</a>
</p>
</div>
</section>
<!-- ===== Session-Leiste ===== -->
<section class="section-tight" id="session-bar" style="display:none;padding-top:0;">
<div class="container" style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;">
<span class="badge rank-1" id="role-badge">Eingeloggt</span>
<div class="btn-row" style="margin:0;">
<a class="btn btn-outline" href="postfach.html">Zum Postfach</a>
<button class="btn btn-outline" id="logout-btn" type="button">Abmelden</button>
</div>
</div>
</section>
<!-- ===== Hauptbereich ===== -->
<section id="main-area" style="display:none;">
<div class="container">
<div class="tabs">
<button class="tab-btn active" data-tab="tab-users">Zugänge</button>
<button class="tab-btn" data-tab="tab-roles">Rollen</button>
<button class="tab-btn" data-tab="tab-audit">Aktivitätsprotokoll</button>
</div>
<!-- ---- Tab: Zugänge ---- -->
<div class="tab-panel active" id="tab-users">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;margin-bottom:1rem;">
<h2 style="margin:0;">Alle Zugänge</h2>
<div class="btn-row" style="margin:0;">
<button class="btn btn-outline" id="refresh-users-btn" type="button">Aktualisieren</button>
<button class="btn btn-primary" id="new-user-btn" type="button">+ Neuer Zugang</button>
</div>
</div>
<div id="users-list"></div>
</div>
<!-- ---- Tab: Rollen ---- -->
<div class="tab-panel" id="tab-roles">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;margin-bottom:1rem;">
<h2 style="margin:0;">Rollen</h2>
<button class="btn btn-primary" id="new-role-btn" type="button">+ Neue Rolle</button>
</div>
<div id="roles-list" class="grid grid-2"></div>
</div>
<!-- ---- Tab: Aktivitätsprotokoll ---- -->
<div class="tab-panel" id="tab-audit">
<h2>Aktivitätsprotokoll</h2>
<p class="small muted">Zugangscodes erscheinen hier niemals im Klartext.</p>
<div id="audit-list"></div>
</div>
</div>
</section>
</main>
<!-- ===== Modal: Neuer/Bearbeiten Zugang ===== -->
<div class="modal-backdrop" id="user-modal">
<div class="modal-box">
<h2 id="user-modal-title">Neuer Zugang</h2>
<form id="user-form" class="app-form" novalidate>
<input type="hidden" id="uf-pending-id" />
<div class="field"><label for="uf-name">Name</label><input id="uf-name" required /></div>
<div class="field"><label for="uf-username">Benutzername</label><input id="uf-username" required /></div>
<div class="field"><label for="uf-email">E-Mail (optional)</label><input id="uf-email" type="email" /></div>
<div class="field">
<label for="uf-role">Rolle</label>
<select id="uf-role"></select>
</div>
<div class="field" id="uf-code-field">
<label>Zugangscode</label>
<div class="btn-row" style="margin:.3rem 0;">
<label class="small"><input type="radio" name="uf-code-mode" value="auto" checked /> Automatisch sicher erstellen</label>
<label class="small"><input type="radio" name="uf-code-mode" value="manual" /> Selbst festlegen</label>
</div>
<input id="uf-code-manual" placeholder="eigener Code" style="display:none;" />
</div>
<div class="field">
<label for="uf-expiry">Gültigkeit</label>
<select id="uf-expiry">
<option value="">Dauerhaft</option>
<option value="7">7 Tage</option>
<option value="30">30 Tage</option>
<option value="90">90 Tage</option>
<option value="date">Bestimmtes Datum…</option>
</select>
<input id="uf-expiry-date" type="date" style="display:none;margin-top:.5rem;" />
</div>
<div class="field"><label for="uf-note">Interne Notiz</label><textarea id="uf-note"></textarea></div>
<button class="btn btn-primary" type="submit" id="uf-submit-btn">Zugang erstellen</button>
<div class="form-status" id="user-form-status"></div>
</form>
<div class="code-reveal-box" id="uf-new-code" style="display:none;"></div>
<button class="btn btn-outline" id="user-modal-close" type="button" style="margin-top:1rem;">Schließen</button>
</div>
</div>
<!-- ===== Modal: Code anzeigen (Re-Auth) ===== -->
<div class="modal-backdrop" id="reveal-modal">
<div class="modal-box" style="max-width:420px;">
<h2>Code anzeigen</h2>
<p class="small muted">Aus Sicherheitsgründen bitte deinen Owner-Code erneut eingeben.</p>
<form id="reveal-form" class="app-form" novalidate>
<div class="field"><label for="reveal-reauth">Dein Owner-Code</label><input id="reveal-reauth" type="password" required /></div>
<button class="btn btn-primary" type="submit">Code anzeigen</button>
<div class="form-status" id="reveal-status"></div>
</form>
<div class="code-reveal-box" id="reveal-code-box" style="display:none;"></div>
<button class="btn btn-outline" id="reveal-modal-close" type="button" style="margin-top:1rem;">Schließen</button>
</div>
</div>
<!-- ===== Modal: Rechte pro Person ===== -->
<div class="modal-backdrop" id="perm-modal">
<div class="modal-box">
<h2>Individuelle Rechte</h2>
<p class="small muted">Ausnahmen wirken zusätzlich zur Rolle. „Rolle" = Standardwert der Rolle übernehmen.</p>
<div id="perm-matrix"></div>
<div class="btn-row">
<button class="btn btn-primary" id="perm-save-btn" type="button">Speichern</button>
<button class="btn btn-outline" id="perm-modal-close" type="button">Abbrechen</button>
</div>
<div class="form-status" id="perm-status"></div>
</div>
</div>
<!-- ===== Modal: Rolle erstellen/bearbeiten ===== -->
<div class="modal-backdrop" id="role-modal">
<div class="modal-box">
<h2 id="role-modal-title">Neue Rolle</h2>
<input type="hidden" id="rf-id" />
<div class="field"><label for="rf-name">Name der Rolle</label><input id="rf-name" required /></div>
<div id="role-perm-matrix" style="margin-top:1rem;"></div>
<div class="btn-row">
<button class="btn btn-primary" id="role-save-btn" type="button">Speichern</button>
<button class="btn btn-outline" id="role-modal-close" type="button">Abbrechen</button>
</div>
<div class="form-status" id="role-form-status"></div>
</div>
</div>
<div id="site-footer"></div>
<script src="assets/js/main.js"></script>
<script src="assets/js/admin-auth.js"></script>
<script src="assets/js/zugaenge.js"></script>
</body>
</html>