Bislang gab es keine vom Nutzer-Rollenmodell (creator/agentur/marke/
kanzlei) getrennte Betreiber-Rolle — jede Verwaltungsaufgabe (welche
Kanzlei darf im öffentlichen Verzeichnis stehen, wer sind unsere
Accounts) wäre nur per Hand in der Datenbank möglich gewesen. Admin
ist von Anfang an als fünfte app_user-Rolle im Datenmodell verankert,
nicht nachträglich aufgesetzt.
Migration 0004:
- app_user.role erlaubt zusätzlich 'admin' (kein Self-Service-Weg
dorthin — /register bietet die Rolle nicht an, erster Admin wird
einmalig per SQL angelegt, siehe CLAUDE.md).
- account.verified: Freigabe fürs kostenlose Kanzlei-Verzeichnis
(§ 49b Abs. 3 BRAO: reine Auflistung, kein Routing/keine Vermittlung).
- audit_log: append-only-Protokoll jeder Admin-Aktion (gleicher Trigger
wie finding/extraction/evidence_package).
Neue Routen:
- GET /admin, /admin/accounts, /admin/accounts/{id}: Accounts-Übersicht
und -Detail (Logins je Account), requireAdmin (404 statt 403 für
angemeldete Nicht-Admins, wie beim bestehenden Mandanten-404-Muster).
- POST /admin/accounts/{id}/verifizieren: Kanzlei-Freigabe umschalten,
schreibt einen Audit-Log-Eintrag.
- GET /admin/audit-log: Protokoll ansehen.
- GET /kanzleien: öffentliches Verzeichnis (kein Login), zeigt nur
Accounts, die sowohl verified sind als auch einen Nutzer der Rolle
"kanzlei" haben.
Volle Testsuite inkl. echter Postgres-Tests grün; End-to-End manuell
gegen einen laufenden Server verifiziert (Admin-Login, Verify-Toggle,
Erscheinen im öffentlichen Verzeichnis, Audit-Log-Eintrag, 404 für
Nicht-Admin-Zugriff).
40 lines
1.2 KiB
HTML
40 lines
1.2 KiB
HTML
{{define "admin-account-detail"}}<!doctype html>
|
|
<html lang="de">
|
|
<head>{{template "head" .}}</head>
|
|
<body>
|
|
{{template "nav" .}}
|
|
<div class="page">
|
|
<p><a href="/admin/accounts">← Alle Accounts</a></p>
|
|
<h1>{{.Name}}</h1>
|
|
<p class="hinweis">Angelegt am {{.CreatedAt}}</p>
|
|
|
|
<h2>Nutzer</h2>
|
|
<ul class="beteiligte">
|
|
{{range .Users}}
|
|
<li class="beteiligter">
|
|
<div class="beteiligter-kopf">{{.Email}} <span class="rolle">({{.Role}})</span></div>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
|
|
{{if .HasKanzlei}}
|
|
<h2>Kanzlei-Verzeichnis</h2>
|
|
{{if .Verified}}
|
|
<p>Status: <span class="status status-published">verifiziert — im öffentlichen Verzeichnis gelistet</span></p>
|
|
<form method="post" action="/admin/accounts/{{.AccountID}}/verifizieren">
|
|
<input type="hidden" name="verified" value="false">
|
|
<button type="submit">Freigabe entziehen</button>
|
|
</form>
|
|
{{else}}
|
|
<p>Status: <span class="status status-mittel">nicht verifiziert — noch nicht gelistet</span></p>
|
|
<form method="post" action="/admin/accounts/{{.AccountID}}/verifizieren">
|
|
<input type="hidden" name="verified" value="true">
|
|
<button type="submit">Fürs Verzeichnis freigeben</button>
|
|
</form>
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
</body>
|
|
</html>
|
|
{{end}}
|