Admin-Konto mit Nutzeruebersicht und Nutzer-Loeschung #206

Closed
opened 2026-09-27 22:07:28 +02:00 by lena · 3 comments
Collaborator

User Story

Als Betreiber von Checkly moechte ich ein eigenes Admin-Konto, das nach dem Login nicht in die App fuehrt, sondern eine Nutzeruebersicht zeigt, in der ich Nutzerkonten einsehen und loeschen kann - damit ich verwaiste, Test- oder Spam-Konten entfernen kann, ohne direkt in der Datenbank zu arbeiten.

Direkter Auftrag des Menschen im Chat (2026-09-27), daher ohne regulaeren PO-Backlog-Durchlauf.

Akzeptanzkriterien

  • Das Admin-Konto wird per Deployment-Konfiguration angelegt (Admin__UserName, Admin__EmailAddress, Admin__Password), nicht ueber die Registrierung. Existiert bereits ein normales Konto mit diesem Benutzernamen, wird es nicht zum Admin befoerdert (verhindert Uebernahme durch Vorab-Registrierung) - stattdessen Fehler im Log.
  • Nach dem Login sieht ein Admin ausschliesslich die Admin-Oberflaeche (keine Listen, keine Sidebar), unabhaengig von der aufgerufenen URL.
  • Die Uebersicht zeigt Kennzahlen (gesamt, aktiv in 30 Tagen, neu in 30 Tagen, E-Mail unbestaetigt) und eine durchsuch-/filterbare Tabelle: Name, Benutzername, E-Mail, registriert, letzter Login, Anzahl eigener Listen, Status.
  • Loeschen erfordert die Eingabe der E-Mail-Adresse des Nutzers als Bestaetigung (serverseitig geprueft).
  • Loeschen nutzt dieselbe Loeschlogik wie die Selbstloeschung (eigene Listen werden geloescht und per WebSocket als geloescht gemeldet, Mitgliedschaften entfernt, Benachrichtigungs-E-Mail an den Nutzer).
  • Admin-Konten koennen ueber die Admin-Oberflaeche nicht geloescht werden (auch nicht das eigene).
  • Alle Admin-Endpunkte sind serverseitig per Autorisierungs-Handler auf Admins beschraenkt (403 fuer normale Nutzer).
  • Neue Spalten IsAdmin, CreatedAtUtc, LastLoginAtUtc am Nutzer; Bestandsnutzer haben dort null ("unbekannt").

Ausserhalb des Umfangs

  • Nutzer sperren/entsperren, Passwort zuruecksetzen, Rollen per UI vergeben
  • Audit-Log-Oberflaeche (Loeschungen werden nur strukturiert geloggt)
  • Serverseitige Sperre aller App-Endpunkte fuer Admin-Konten (nur UI-seitig getrennt)
## User Story Als Betreiber von Checkly moechte ich ein eigenes Admin-Konto, das nach dem Login nicht in die App fuehrt, sondern eine Nutzeruebersicht zeigt, in der ich Nutzerkonten einsehen und loeschen kann - damit ich verwaiste, Test- oder Spam-Konten entfernen kann, ohne direkt in der Datenbank zu arbeiten. Direkter Auftrag des Menschen im Chat (2026-09-27), daher ohne regulaeren PO-Backlog-Durchlauf. ## Akzeptanzkriterien - [ ] Das Admin-Konto wird per Deployment-Konfiguration angelegt (`Admin__UserName`, `Admin__EmailAddress`, `Admin__Password`), nicht ueber die Registrierung. Existiert bereits ein normales Konto mit diesem Benutzernamen, wird es **nicht** zum Admin befoerdert (verhindert Uebernahme durch Vorab-Registrierung) - stattdessen Fehler im Log. - [ ] Nach dem Login sieht ein Admin ausschliesslich die Admin-Oberflaeche (keine Listen, keine Sidebar), unabhaengig von der aufgerufenen URL. - [ ] Die Uebersicht zeigt Kennzahlen (gesamt, aktiv in 30 Tagen, neu in 30 Tagen, E-Mail unbestaetigt) und eine durchsuch-/filterbare Tabelle: Name, Benutzername, E-Mail, registriert, letzter Login, Anzahl eigener Listen, Status. - [ ] Loeschen erfordert die Eingabe der E-Mail-Adresse des Nutzers als Bestaetigung (serverseitig geprueft). - [ ] Loeschen nutzt dieselbe Loeschlogik wie die Selbstloeschung (eigene Listen werden geloescht und per WebSocket als geloescht gemeldet, Mitgliedschaften entfernt, Benachrichtigungs-E-Mail an den Nutzer). - [ ] Admin-Konten koennen ueber die Admin-Oberflaeche nicht geloescht werden (auch nicht das eigene). - [ ] Alle Admin-Endpunkte sind serverseitig per Autorisierungs-Handler auf Admins beschraenkt (403 fuer normale Nutzer). - [ ] Neue Spalten `IsAdmin`, `CreatedAtUtc`, `LastLoginAtUtc` am Nutzer; Bestandsnutzer haben dort `null` ("unbekannt"). ## Ausserhalb des Umfangs - Nutzer sperren/entsperren, Passwort zuruecksetzen, Rollen per UI vergeben - Audit-Log-Oberflaeche (Loeschungen werden nur strukturiert geloggt) - Serverseitige Sperre aller App-Endpunkte fuer Admin-Konten (nur UI-seitig getrennt)
lena self-assigned this 2026-09-27 22:07:37 +02:00
Author
Collaborator

Start: direkter Auftrag im Chat. Umsetzung Backend (IsAdmin/CreatedAtUtc/LastLoginAtUtc, Admin-Bootstrap aus Konfiguration, Admin-Queries/-Commands mit eigenem Authorize-Handler, gemeinsame Loeschlogik mit der Selbstloeschung) und Frontend (eigene Admin-Seite statt App).

Start: direkter Auftrag im Chat. Umsetzung Backend (IsAdmin/CreatedAtUtc/LastLoginAtUtc, Admin-Bootstrap aus Konfiguration, Admin-Queries/-Commands mit eigenem Authorize-Handler, gemeinsame Loeschlogik mit der Selbstloeschung) und Frontend (eigene Admin-Seite statt App).
Author
Collaborator

Umgesetzt

Commits auf master: 60f9d48a (Refactor: gemeinsame Loeschlogik), accd84de (Schema: IsAdmin, CreatedAtUtc, LastLoginAtUtc), b38a4a42 (Admin-Backend), 5dd679f4 (Admin-Oberflaeche), 692f091a (Team-Memory).

Umfang

  • Admin-Konto kommt aus der Deployment-Konfiguration (ADMIN_USERNAME, ADMIN_EMAIL, ADMIN_PASSWORD in docker-compose.yml, siehe .env.example). Es wird beim Start angelegt, wenn Benutzername und E-Mail noch frei sind. Ein bestehendes normales Konto wird nie befoerdert (Schutz gegen Vorab-Registrierung), stattdessen gibt es einen Fehler im Log.
  • Nach dem Login sieht ein Admin auf jeder URL nur die Nutzeruebersicht: Kennzahlen, Suche, Statusfilter, Tabelle mit Registrierung, letztem Login, Anzahl eigener Listen und Status.
  • Beim Loeschen muss die E-Mail des Nutzers eingegeben werden, serverseitig geprueft (Gross-/Kleinschreibung egal). Admin-Konten lassen sich so nicht loeschen.
  • Selbst- und Admin-Loeschung nutzen denselben internen EraseUserAccountCommand. Bei der Admin-Loeschung sagt die Benachrichtigungs-E-Mail, dass ein Administrator das Konto geloescht hat.
  • Alle Admin-Requests laufen ueber AuthorizeIsCurrentUserAdminQuery (401 anonym, 403 ohne Admin-Rechte), das IsAdmin bei jedem Aufruf frisch aus der DB liest.

Tests

  • Backend: neue Tests fuer Authorize-, Overview-, IsAdmin-, Delete- und Ensure-Handler; die Loesch-Tests sind zum Erase-Handler umgezogen; Login/CreateUser pruefen die Zeitstempel. Gesamt 1021 + 63 + 119 gruen gegen echtes Postgres.
  • Frontend: AdminPage.test.tsx mit 10 Tests; gesamt 1451 gruen, tsc -b und Build sauber.
  • Live im Review-Container geprueft: Admin-Login zeigt die Uebersicht auch unter /list/1, falsche E-Mail wird abgewiesen, Loeschen eines Wegwerf-Kontos funktioniert, ein normaler Nutzer bekommt 403 auf beiden Admin-Endpunkten und sieht weiter die App, Handy-Ansicht ohne Ueberlauf.

Bewusst offen

  • Das Admin-Konto wird nur ueber die Oberflaeche aus der App herausgehalten, nicht serverseitig (es besitzt keine Daten und bekommt dadurch keinen fremden Zugriff). Siehe SECURITY_NOTES.
  • Das Admin-Passwort gilt nur beim Anlegen; eine spaetere Aenderung der Env-Variable aendert das gespeicherte Passwort nicht.
  • Kein Sperren/Entsperren, kein Passwort-Reset, kein Audit-Log in der Oberflaeche (Loeschungen werden geloggt).
  • Vorbestehende Luecke, nicht Teil dieser Story: eigene Masterpacklisten eines geloeschten Nutzers werden weder bei der Selbst- noch bei der Admin-Loeschung mitgeloescht.
## Umgesetzt Commits auf master: 60f9d48a (Refactor: gemeinsame Loeschlogik), accd84de (Schema: IsAdmin, CreatedAtUtc, LastLoginAtUtc), b38a4a42 (Admin-Backend), 5dd679f4 (Admin-Oberflaeche), 692f091a (Team-Memory). **Umfang** - Admin-Konto kommt aus der Deployment-Konfiguration (`ADMIN_USERNAME`, `ADMIN_EMAIL`, `ADMIN_PASSWORD` in docker-compose.yml, siehe `.env.example`). Es wird beim Start angelegt, wenn Benutzername und E-Mail noch frei sind. Ein bestehendes normales Konto wird nie befoerdert (Schutz gegen Vorab-Registrierung), stattdessen gibt es einen Fehler im Log. - Nach dem Login sieht ein Admin auf jeder URL nur die Nutzeruebersicht: Kennzahlen, Suche, Statusfilter, Tabelle mit Registrierung, letztem Login, Anzahl eigener Listen und Status. - Beim Loeschen muss die E-Mail des Nutzers eingegeben werden, serverseitig geprueft (Gross-/Kleinschreibung egal). Admin-Konten lassen sich so nicht loeschen. - Selbst- und Admin-Loeschung nutzen denselben internen `EraseUserAccountCommand`. Bei der Admin-Loeschung sagt die Benachrichtigungs-E-Mail, dass ein Administrator das Konto geloescht hat. - Alle Admin-Requests laufen ueber `AuthorizeIsCurrentUserAdminQuery` (401 anonym, 403 ohne Admin-Rechte), das `IsAdmin` bei jedem Aufruf frisch aus der DB liest. **Tests** - Backend: neue Tests fuer Authorize-, Overview-, IsAdmin-, Delete- und Ensure-Handler; die Loesch-Tests sind zum Erase-Handler umgezogen; Login/CreateUser pruefen die Zeitstempel. Gesamt 1021 + 63 + 119 gruen gegen echtes Postgres. - Frontend: `AdminPage.test.tsx` mit 10 Tests; gesamt 1451 gruen, `tsc -b` und Build sauber. - Live im Review-Container geprueft: Admin-Login zeigt die Uebersicht auch unter /list/1, falsche E-Mail wird abgewiesen, Loeschen eines Wegwerf-Kontos funktioniert, ein normaler Nutzer bekommt 403 auf beiden Admin-Endpunkten und sieht weiter die App, Handy-Ansicht ohne Ueberlauf. **Bewusst offen** - Das Admin-Konto wird nur ueber die Oberflaeche aus der App herausgehalten, nicht serverseitig (es besitzt keine Daten und bekommt dadurch keinen fremden Zugriff). Siehe SECURITY_NOTES. - Das Admin-Passwort gilt nur beim Anlegen; eine spaetere Aenderung der Env-Variable aendert das gespeicherte Passwort nicht. - Kein Sperren/Entsperren, kein Passwort-Reset, kein Audit-Log in der Oberflaeche (Loeschungen werden geloggt). - Vorbestehende Luecke, nicht Teil dieser Story: eigene Masterpacklisten eines geloeschten Nutzers werden weder bei der Selbst- noch bei der Admin-Loeschung mitgeloescht.
lena closed this issue 2026-09-27 22:49:58 +02:00
Author
Collaborator

Nachtrag: die im Abschlusskommentar erwaehnte Luecke (eigene Masterpacklisten bleiben bei Kontoloeschung liegen) ist mit #209 behoben.

Nachtrag: die im Abschlusskommentar erwaehnte Luecke (eigene Masterpacklisten bleiben bei Kontoloeschung liegen) ist mit #209 behoben.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#206
No description provided.