feat: Admin-Bereich (Accounts, Kanzlei-Verzeichnis-Freigabe, Audit-Log)
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).
This commit is contained in:
32
CLAUDE.md
32
CLAUDE.md
@@ -139,12 +139,33 @@ Plus drei Tabellen für Auth/Mandantentrennung (`account`, `app_user`,
|
||||
`session`), mehr braucht der MVP nicht:
|
||||
|
||||
- `account` — ein Mandant (Creator, Agentur, Marke oder Kanzlei als
|
||||
eigene Organisation); jede Submission gehört genau einem Account
|
||||
eigene Organisation); jede Submission gehört genau einem Account.
|
||||
`verified` markiert einen Kanzlei-Account als für das öffentliche,
|
||||
kostenlose Kanzlei-Verzeichnis (`GET /kanzleien`) freigegeben — nur
|
||||
vom Admin-Bereich aus setzbar, nie vom Mandanten selbst
|
||||
- `app_user` — ein Login innerhalb eines Accounts (E-Mail, Passwort-
|
||||
Hash, Rolle)
|
||||
Hash, Rolle). Rolle ist eine von `creator`, `agentur`, `marke`,
|
||||
`kanzlei` **oder `admin`**. `admin` ist Betreiber-Personal
|
||||
(Netcell-IT), nicht an einen Mandanten-Geschäftszweck gebunden,
|
||||
zuständig für den Admin-Bereich (`/admin/...`: Accounts-Übersicht,
|
||||
Kanzlei-Verzeichnis-Freigabe, Audit-Log). Es gibt **keine**
|
||||
Selbstregistrierung für `admin` über `POST /register` (das Formular
|
||||
bietet die Rolle nicht an) — der erste Admin wird einmalig per SQL
|
||||
angelegt:
|
||||
```sql
|
||||
INSERT INTO account (name) VALUES ('Deklarix Admin') RETURNING id;
|
||||
INSERT INTO app_user (account_id, email, password_hash, role)
|
||||
VALUES ('<account-id>', '<login>', '<bcrypt-hash>', 'admin');
|
||||
```
|
||||
(bcrypt-Hash z. B. über `internal/auth.HashPassword` in einem
|
||||
Wegwerf-`cmd/`-Programm erzeugen, da `internal/` von außerhalb des
|
||||
Moduls nicht importierbar ist)
|
||||
- `session` — eine angemeldete Sitzung (Token, Ablaufzeit); bewusst
|
||||
eine echte Tabelle statt zustandsloser signierter Tokens, damit
|
||||
Logout eine Sitzung wirklich beendet
|
||||
- `audit_log` — Protokoll der Admin-Aktionen (wer hat wann welchen
|
||||
Account wie verändert); append-only aus demselben Grund wie
|
||||
`finding`/`extraction`/`evidence_package`
|
||||
- `submission` — ein eingereichter Beitrag, Status, Zeitpunkte
|
||||
- `asset` — Bild oder Datei, Pfad, SHA-256
|
||||
- `extraction` — das JSON aus Stufe 1, Modellversion, Prompt-Version
|
||||
@@ -157,9 +178,10 @@ Plus drei Tabellen für Auth/Mandantentrennung (`account`, `app_user`,
|
||||
(`creator`, `agentur`, `marke`, `kanzlei`) und Beitrag zur
|
||||
Verantwortungsmatrix (wer hat vorgegeben, wer freigegeben)
|
||||
|
||||
**Append-only.** Kein UPDATE auf `finding`, `extraction` oder
|
||||
`evidence_package`. Korrekturen sind neue Zeilen mit Verweis auf die alte.
|
||||
Ein Beweisarchiv, in dem man Zeilen ändern kann, ist kein Beweisarchiv.
|
||||
**Append-only.** Kein UPDATE auf `finding`, `extraction`,
|
||||
`evidence_package` oder `audit_log`. Korrekturen sind neue Zeilen mit
|
||||
Verweis auf die alte. Ein Beweisarchiv (bzw. Protokoll), in dem man
|
||||
Zeilen ändern kann, ist keines mehr.
|
||||
|
||||
**Beweiskette:** SHA-256 über jedes Asset und über die kanonisierte
|
||||
JSON-Repräsentation der Metadaten, RFC-3161-Zeitstempel über diesen Hash.
|
||||
|
||||
Reference in New Issue
Block a user