feat(selbstauskunft): Mitarbeiter sehen ihre eigenen Geraete (#55)
„Was ist eigentlich mit meinem Notebook passiert?“ musste bisher ein Techniker nachsehen. Ein Mitarbeiter kann die Arbeiten an **seinen** Geraeten jetzt selbst ansehen — mit der fuenften Rolle MITARBEITER, zugeordnet beim Anmelden ueber den UPN. Was er sieht, sind Titel, Zeitraum und Status. Keine Schritte, keine Notizen, keine Kommentare, keine Anhaenge: in einem Lauf stehen Arbeitsnotizen ueber Menschen und Befehle mit Platzhaltern fuer Zugangsdaten. Eine Selbstauskunft ist keine Akteneinsicht, und das haelt nicht die Seite fest, sondern das Lesemodell — eine Seite, die filtert, ist eine Seite, die es vergessen kann. `selbstauskunft` ist ein **Ersatz** fuer `lesen` und kein Zusatz; auch ein ADMIN hat es nicht. Ein zweiter Weg zu denselben Daten waere eine zweite Stelle, an der jemand die Einschraenkung auf die eigene Person vergisst. Die Datenbank verlangt das sogar: ein CHECK haelt fest, dass Rolle und Zuordnung zusammengehoeren, in beide Richtungen. Ein mehrdeutiger UPN wird abgewiesen und protokolliert. Zwei Kunden koennen dieselbe Person fuehren; ein findFirst entschiede nach Sortierung darueber, wessen Geraete jemand sieht. **Verhaltensaenderung:** wer sich anmeldet und in keiner Rollengruppe steht, bekommt nicht mehr automatisch LESER — also nicht mehr Lesezugriff auf alle Laeufe des Hauses. Das greift nur mit konfigurierten OIDC_GROUP_*; ohne sie bleibt alles wie vorher, denn ohne abgebildete Gruppen laesst sich Techniker nicht von Mitarbeiter unterscheiden. Nebenbei behoben: `staerksteRolle` benutzte LESER als Startwert und damit als Untergrenze — mit einer Rolle darunter lieferte sie mehr Rechte als uebergeben. Gefunden von einem Test, der seit #007 unveraendert dasteht. Closes #55 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a417426f43
commit
0158d0292f
@@ -0,0 +1,69 @@
|
||||
# Meine Geräte
|
||||
|
||||
> **Dieses Kapitel ist für dich, wenn du kein IT-Mitarbeiter bist.** Alle anderen Kapitel richten
|
||||
> sich an die Leute, die Laufzettel bedienen — dieses hier an die, über die darin etwas steht.
|
||||
|
||||
Wenn die IT an deinem Rechner gearbeitet hat, hält sie das in Laufzettel fest: was gemacht wurde,
|
||||
wann und mit welchem Gerät. Unter **Meine Geräte** siehst du den Teil davon, der dich betrifft.
|
||||
|
||||
## Anmelden
|
||||
|
||||
Du meldest dich mit demselben Konto an wie überall sonst im Haus — über den Knopf **Mit dem Anbieter
|
||||
anmelden**. Ein eigenes Passwort für Laufzettel gibt es nicht.
|
||||
|
||||
Danach landest du direkt auf **Meine Geräte**. Mehr gibt es für dich nicht zu sehen, und das ist
|
||||
keine Einschränkung aus Versehen: alles andere in Laufzettel sind Arbeitsunterlagen der IT.
|
||||
|
||||
## Was dort steht
|
||||
|
||||
Für jedes Gerät, das auf dich läuft:
|
||||
|
||||
- **Name und Typ** — etwa „NB-042, Notebook“
|
||||
- **Seriennummer und Aufkleber-Code** — hilfreich, wenn du bei der IT anrufst
|
||||
- **Die Arbeiten daran**, neueste zuerst: Titel, Zeitraum und ob sie fertig sind
|
||||
|
||||
Darunter, falls es das gibt, ein Abschnitt **Zu mir persönlich**: Arbeiten, die an keinem Gerät
|
||||
hängen — etwa das Einrichten deines Kontos, als du angefangen hast.
|
||||
|
||||
Und ganz oben **Meine Daten**: dein Name, deine Funktion, deine Abteilung und deine Mailadresse, so
|
||||
wie das Verzeichnis sie führt. Stimmt da etwas nicht, sag es der IT — ändern lässt es sich hier
|
||||
nicht, denn diese Angaben kommen aus dem Verzeichnis des Hauses.
|
||||
|
||||
## Was dort nicht steht, und warum
|
||||
|
||||
Du siehst **Titel, Zeitraum und Status** einer Arbeit. Du siehst **nicht**:
|
||||
|
||||
- die einzelnen Schritte
|
||||
- Notizen der Techniker
|
||||
- Kommentare
|
||||
- angehängte Fotos
|
||||
|
||||
Das ist Absicht und keine Geheimniskrämerei. In einem Lauf stehen Arbeitsnotizen, die während der
|
||||
Arbeit entstehen, und Befehle mit Platzhaltern für Zugangsdaten. Beides ist nicht dafür gedacht,
|
||||
gelesen zu werden — weder von dir noch von sonst jemandem außerhalb der IT.
|
||||
|
||||
**Wenn du wissen willst, was genau gemacht wurde, frag die IT.** Dann antwortet ein Mensch, der den
|
||||
Zusammenhang kennt, statt einer Liste, die man missverstehen kann.
|
||||
|
||||
## Ein archiviertes Gerät steht weiter da
|
||||
|
||||
Geräte, die nicht mehr in Benutzung sind, bleiben in der Liste — mit dem Vermerk **nicht mehr in
|
||||
Benutzung**. „Was war eigentlich mit meinem alten Notebook?“ ist genau die Frage, um die es hier
|
||||
geht, und das alte Notebook ist archiviert.
|
||||
|
||||
## Die Liste ist leer
|
||||
|
||||
Dann hat die IT zu dir nichts festgehalten. Kein Fehler — es heißt nur, dass auf dich gerade kein
|
||||
Gerät läuft und keine Arbeit zu dir vermerkt ist.
|
||||
|
||||
## „Dein Konto ist keiner Person im Verzeichnis zugeordnet“
|
||||
|
||||
Diese Meldung bei der Anmeldung heißt: Laufzettel konnte dein Konto keiner Person zuordnen. Meist
|
||||
liegt es daran, dass dein Anmeldename im Verzeichnis anders geschrieben steht als beim
|
||||
Anmeldeanbieter. Das kann nur die IT auflösen — melde dich dort.
|
||||
|
||||
## Keine Mail, keine Benachrichtigung
|
||||
|
||||
Laufzettel schickt dir nichts. Die Benachrichtigungen, die es gibt, gehen an die IT: wenn eine
|
||||
Arbeit jemandem zugewiesen wird, überfällig ist oder fertig. Du erfährst von einer Arbeit an deinem
|
||||
Gerät auf dem üblichen Weg — der Techniker sagt es dir.
|
||||
@@ -29,6 +29,14 @@ nie an ein zweites Gerät vergeben — er ist die einzige Angabe am Gerät, die
|
||||
- [06 Verzeichnis anbinden](06-verzeichnis.md) — Active Directory als Quelle der Personen
|
||||
- [07 Verwaltung](07-admin.md) — Benutzer, Rollen, Einstellungen, Betriebsmodus, Kunden
|
||||
|
||||
**Mitarbeiter** — du bedienst Laufzettel nicht, sondern willst nur wissen, was mit deinem Gerät
|
||||
passiert ist:
|
||||
|
||||
- [09 Meine Geräte](09-selbstauskunft.md) — anmelden, was dort steht und was nicht
|
||||
|
||||
Dieses eine Kapitel ist **an Mitarbeiter gerichtet** und nicht an die IT. Wer die Selbstauskunft im
|
||||
Haus freigibt, kann es weitergeben, ohne den Rest der Anleitung mitzuschicken.
|
||||
|
||||
## Zwei Betriebsmodi
|
||||
|
||||
Laufzettel läuft in einem von zwei Modi. Der Modus entscheidet, ob es eine Kundenebene gibt, und
|
||||
|
||||
@@ -265,6 +265,41 @@ Tabelle wie die des Abgleichs: hinter einem Lastverteiler laufen zwei Instanzen,
|
||||
*keine* Mail aus. Beides sieht die Live-Aktualisierung sofort (Abschnitt 5d); eine Mail dafür wäre
|
||||
Lärm. Mehr Anlässe wären ein Benachrichtigungsbaukasten, und der ist eine Phase für sich.
|
||||
|
||||
### Warum ein Mitarbeiter keine Akteneinsicht bekommt
|
||||
|
||||
Ein `Mitarbeiter` ist kein `Benutzer`. Die vier Rollen bis #035 waren für Leute, die **arbeiten**;
|
||||
ein Mitarbeiter ist Gegenstand der Arbeit, nicht ihr Träger. Mit der Selbstauskunft kommt die fünfte
|
||||
Rolle `MITARBEITER` dazu, und sie ist die einzige, die **nicht** `lesen` darf.
|
||||
|
||||
**`selbstauskunft` ist ein Ersatz für `lesen`, kein Zusatz.** Darum hat auch ein `ADMIN` dieses
|
||||
Recht nicht: er sieht über `lesen` ohnehin alles, und ein zweiter Weg zu denselben Daten wäre eine
|
||||
zweite Stelle, an der jemand die Einschränkung auf die eigene Person vergisst. Wer beides braucht,
|
||||
braucht zwei Konten — und genau das hält die Datenbank fest: der CHECK
|
||||
`Benutzer_mitarbeiter_nur_bei_rolle` verlangt, dass Rolle und Zuordnung zusammengehören, in beide
|
||||
Richtungen.
|
||||
|
||||
**Was zurückkommt, entscheidet das Lesemodell und nicht die Seite.**
|
||||
`src/server/queries/selbstauskunft.ts` liefert Titel, Status, Zeitraum und Gerät — keine Schritte,
|
||||
keine Notizen, keine Kommentare, keine Anhänge. In einem Lauf stehen Arbeitsnotizen über Menschen
|
||||
(„Nutzerin war unkooperativ“) und Befehle mit Platzhaltern für Zugangsdaten; beides ist nicht dafür
|
||||
gedacht, gelesen zu werden. Eine Seite, die filtert, wäre eine Seite, die es vergessen kann.
|
||||
|
||||
Geprüft wird das an der **Antwort** und nicht an der Seite: `tests/selbstauskunft.test.ts` hängt an
|
||||
einen Lauf eine Notiz, einen Kommentar, einen Anhang und einen Befehlsschritt mit
|
||||
`{{generiertes_passwort}}` und prüft, dass nichts davon durchkommt. Dazu ein struktureller Test, der
|
||||
das `select` selbst liest — denn eine Gegenprobe zeigte, dass der erste Test grün blieb, als das
|
||||
`select` versuchsweise Notizen mitholte: gerettet hatte ihn die Abbildungsfunktion, nicht die
|
||||
Abfrage.
|
||||
|
||||
**Zugeordnet wird über den UPN, und mehrdeutig ist ein Fehler.** Zwei Kunden können dieselbe Person
|
||||
führen; ein `findFirst` entschiede dann nach Sortierung darüber, wessen Geräte jemand sieht. Lieber
|
||||
kein Zugang als der falsche — die Anmeldung wird abgewiesen und der Fall protokolliert.
|
||||
|
||||
**Die Weiche greift nur mit eingerichteter Gruppenzuordnung.** Ohne abgebildete Gruppen kann die
|
||||
Anwendung nicht unterscheiden, ob jemand Techniker oder Mitarbeiter ist; dort bleibt alles wie vor
|
||||
#035. Das ist keine Vorsicht, sondern Notwendigkeit: ein Update, das jeden aussperrt, dem die
|
||||
Gruppen fehlen, wäre ein kaputtes Update.
|
||||
|
||||
## 5e. Der Aufkleber ist die Schnittstelle
|
||||
|
||||
Jedes Objekt traegt einen QR-Aufkleber mit einem `tagCode`, der **nie geaendert
|
||||
|
||||
@@ -58,9 +58,16 @@ Lege in authentik vier Gruppen an und trage die Mitglieder ein:
|
||||
| `lz-redakteur` | `REDAKTEUR` | Vorlagen anlegen, bearbeiten, veröffentlichen |
|
||||
| `lz-techniker` | `TECHNIKER` | Läufe starten, abarbeiten, abschließen, archivieren; Geräte pflegen |
|
||||
| `lz-leser` | `LESER` | nur lesen |
|
||||
| *(keine davon)* | `MITARBEITER` | **nur die eigenen Geräte**, siehe unten |
|
||||
|
||||
Ist jemand in mehreren Gruppen, gewinnt die stärkere Rolle.
|
||||
|
||||
> **Die fünfte Zeile hat keine Gruppe, und das ist Absicht.** Wer sich anmeldet und in keiner der
|
||||
> vier Gruppen steht, ist für Laufzettel ein Mitarbeiter des Hauses und bekommt die
|
||||
> Selbstauskunft — vorausgesetzt, er lässt sich einer Person im Verzeichnis zuordnen. Eine eigene
|
||||
> Gruppe dafür anzulegen hieße, jeden Mitarbeiter einzeln einzutragen; „alle übrigen“ ist genau die
|
||||
> Menge, die gemeint ist.
|
||||
|
||||
## 5. Laufzettel konfigurieren
|
||||
|
||||
In der `.env`:
|
||||
@@ -93,11 +100,47 @@ docker compose up -d
|
||||
- Ein unbekannter Benutzer wird beim ersten Login **angelegt** (JIT-Provisioning)
|
||||
- Die Rolle wird bei **jedem** Login aus `groups` neu gesetzt — eine Änderung in authentik greift
|
||||
ab der nächsten Anmeldung
|
||||
- Ist der Benutzer in keiner der vier Gruppen, bekommt er `LESER`
|
||||
- Ist der Benutzer in keiner der vier Gruppen, versucht Laufzettel, ihn über seinen **UPN** einer
|
||||
Person im Verzeichnis zuzuordnen. Klappt das, bekommt er `MITARBEITER` und sieht nur seine
|
||||
eigenen Geräte; klappt es nicht, wird die Anmeldung **abgewiesen** — mit einer Begründung auf der
|
||||
Anmeldeseite
|
||||
- **Bis Version 0.2.0 bekam er stattdessen `LESER`**, also Lesezugriff auf alle Läufe des Hauses.
|
||||
Wer das Verhalten von damals braucht, trägt die betreffenden Leute in `lz-leser` ein
|
||||
- Wer vor dem Login eine bestimmte Seite aufgerufen hat (z. B. `/t/LZ-7K3F9Q` nach dem Scannen
|
||||
eines QR-Codes), landet danach genau dort
|
||||
|
||||
## 7. Notfallzugang
|
||||
## 7. Selbstauskunft für Mitarbeiter
|
||||
|
||||
Ein Mitarbeiter, der in keiner Rollengruppe steht, sieht unter **Meine Geräte** die Arbeiten an
|
||||
seinen eigenen Geräten — Titel, Zeitraum, Status. **Keine Schritte, keine Notizen, keine Kommentare,
|
||||
keine Anhänge**; warum, steht in `docs/architektur.md` unter „Warum ein Mitarbeiter keine Akteneinsicht bekommt“.
|
||||
|
||||
Zugeordnet wird über den **UPN**. Laufzettel liest ihn in dieser Reihenfolge:
|
||||
|
||||
1. der Anspruch `upn` (so heißt er bei Entra ID)
|
||||
2. `preferred_username` (authentik und Keycloak schicken dort den Anmeldenamen)
|
||||
3. die Mailadresse
|
||||
|
||||
Verglichen wird mit `Mitarbeiter.upn`, unabhängig von Groß- und Kleinschreibung. Damit das greift,
|
||||
muss der UPN in authentik derselbe sein wie der im Active Directory — bei einem AD als Quelle von
|
||||
authentik ist er das meist von selbst.
|
||||
|
||||
**Zwei Fälle, die bewusst nicht durchgehen:**
|
||||
|
||||
| Fall | Was passiert |
|
||||
|---|---|
|
||||
| Zu dem UPN gibt es **keine aktive** Person | Anmeldung abgewiesen, mit Begründung auf der Anmeldeseite |
|
||||
| Zu dem UPN gibt es **mehr als eine** Person | Anmeldung abgewiesen und im Protokoll festgehalten |
|
||||
|
||||
Der zweite Fall kommt im Modus **Dienstleistung** vor, wenn zwei Kunden dieselbe Person führen. Ein
|
||||
Zufallstreffer wäre dort schlimmer als kein Zugang: er entschiede nach Sortierung darüber, wessen
|
||||
Geräte jemand sieht.
|
||||
|
||||
**Abschalten lässt sich das Ganze**, indem du keine Rollengruppen konfigurierst — dann greift die
|
||||
Weiche nicht, und alles bleibt wie vor 0.2.0. Oder indem du jeden, der hinein soll, in `lz-leser`
|
||||
einträgst.
|
||||
|
||||
## 8. Notfallzugang
|
||||
|
||||
Fällt authentik aus, kommt niemand mehr in Laufzettel. Für diesen Fall gibt es den lokalen Login:
|
||||
|
||||
@@ -112,7 +155,7 @@ Passwörter liegen als argon2-Hash in der Datenbank.
|
||||
Empfehlung: ein einziges lokales Admin-Konto, Passwort im Passwortmanager, `AUTH_LOCAL_ENABLED`
|
||||
im Normalbetrieb auf `false` und nur im Notfall umgestellt.
|
||||
|
||||
## 8. Fehlersuche
|
||||
## 9. Fehlersuche
|
||||
|
||||
| Symptom | Ursache |
|
||||
|---|---|
|
||||
|
||||
+70
-2
@@ -33,12 +33,13 @@ als Unterpunkte mit Aufgabe und Dauer.
|
||||
| #032 | M19 – Anhänge und Fotos an Schritten | 3 h 05 min |
|
||||
| #033 | M20 – Live-Aktualisierung per SSE statt Polling | 1 h 40 min |
|
||||
| #034 | M21 – Benachrichtigungen per Mail und Webhook | 3 h 30 min |
|
||||
| | **Summe** | **53 h 35 min** |
|
||||
| #035 | M22 – Mitarbeiter-Selbstauskunft | 2 h 50 min |
|
||||
| | **Summe** | **56 h 25 min** |
|
||||
|
||||
| Meilenstein | Tatsächlich | Status |
|
||||
|---|---|---|
|
||||
| v0.1.0 | 35 h 20 min | veröffentlicht |
|
||||
| v0.2.0 | 18 h 15 min | in Arbeit |
|
||||
| v0.2.0 | 21 h 05 min | in Arbeit |
|
||||
|
||||
---
|
||||
|
||||
@@ -1302,3 +1303,70 @@ und nicht nach jeder einzelnen — das ist der Grund, warum er alles auf einmal
|
||||
eigenen Benachrichtigungen abschalten kann.
|
||||
- **M15 (#028)** Graph-Quelle und **M16 (#029)** SCIM sind die beiden großen verbliebenen.
|
||||
- Weiter offen und nicht von hier aus machbar: **#024** Proxmox-Einzeiler auf einem echten PVE-Host.
|
||||
|
||||
---
|
||||
|
||||
## 2026-10-06 · Sitzung 20 · 06:00–08:50
|
||||
|
||||
**Issue:** #035 (M22)
|
||||
**Version:** 0.2.0 (unveröffentlicht)
|
||||
|
||||
### Erledigt
|
||||
|
||||
- **Die fünfte Rolle `MITARBEITER`** mit genau einem Recht: `selbstauskunft`. Zugeordnet beim
|
||||
Anmelden über den UPN, festgehalten in `Benutzer.mitarbeiterId`.
|
||||
- **`/meine-geraete`**: meine Geräte, je Gerät die Arbeiten chronologisch, dazu meine Stammdaten aus
|
||||
dem Verzeichnis. Titel, Zeitraum, Status — nichts weiter.
|
||||
- **Drei PRs von gestern sind auf `main`** (#59, #60, #61); die beiden Folgezweige mussten nach dem
|
||||
ersten Squash rebased werden.
|
||||
- 1341 Vitest-Tests (vorher 1302), davon 25 neue. Im gebauten Stand mit einem echten
|
||||
MITARBEITER-Konto durchgeklickt.
|
||||
|
||||
### Entscheidungen
|
||||
|
||||
- **`selbstauskunft` ist ein Ersatz für `lesen`, kein Zusatz** — deshalb hat auch ein ADMIN es
|
||||
nicht. Ein zweiter Weg zu denselben Daten wäre eine zweite Stelle, an der jemand die
|
||||
Einschränkung auf die eigene Person vergisst.
|
||||
- **Was zurückkommt, entscheidet das Lesemodell und nicht die Seite.** Eine Seite, die filtert, ist
|
||||
eine Seite, die es vergessen kann.
|
||||
- **Kein zusammengesetzter Fremdschlüssel**, obwohl die Aufgabe ihn verlangte: ein `Benutzer` trägt
|
||||
keine `kundeId`. Stattdessen ein CHECK, dass Rolle und Zuordnung zusammengehören, und ein
|
||||
eindeutiger Index, dass eine Person höchstens ein Konto hat.
|
||||
- **Ein mehrdeutiger UPN wird abgewiesen**, nicht geraten. Zwei Kunden können dieselbe Person
|
||||
führen; ein `findFirst` entschiede nach Sortierung darüber, wessen Geräte jemand sieht.
|
||||
- **Die Weiche greift nur mit konfigurierten Rollengruppen.** Ein Update, das jeden aussperrt, dem
|
||||
die Gruppen fehlen, wäre ein kaputtes Update.
|
||||
- **Nicht `/kein-zugriff` bei gescheiterter Anmeldung**, wie das Issue vorsah: diese Seite verlangt
|
||||
eine Sitzung, die es dann nicht gibt — das wäre eine Schleife. Die Begründung steht auf der
|
||||
Anmeldeseite, mit zwei eigenen Codes.
|
||||
|
||||
### Probleme
|
||||
|
||||
- **Eine Gegenprobe blieb grün, und das war der eigentliche Befund.** Der Test „sieht keine Notizen“
|
||||
prüft die Antwort, und die ist durch `laufBauen` sicher. Als ich im `select` versuchsweise
|
||||
`ergebnisse: { notiz }` ergänzte, blieb er deshalb grün — während der Kopfkommentar behauptet, das
|
||||
`select` hole es „gar nicht erst“. **Eine Zusage ohne eigenen Test ist keine Zusage**, auch wenn
|
||||
ein Nachbartest sie zufällig mitträgt. Jetzt liest ein Test die Datei selbst.
|
||||
- **Ein Test von #007 fand eine echte Lücke.** `staerksteRolle` benutzte `LESER` als Startwert und
|
||||
damit als Untergrenze; mit einer Rolle darunter lieferte sie **mehr** Rechte als übergeben. Drei
|
||||
Jahre Projektzeit hätte das niemand gemerkt, weil es keine Rolle unter `LESER` gab.
|
||||
- **Zwei Bedienfehler beim Durchklicken**, beide dieselbe Ursache: das Standardziel nach der
|
||||
Anmeldung ist `/`, und die Übersicht verlangt `lesen`. Ein Mitarbeiter sah als Erstes „Dafür fehlt
|
||||
dir die Berechtigung“ — und der Knopf dort führte zurück auf `/`, also im Kreis. Ohne Klickprobe
|
||||
wäre das bis zum ersten echten Nutzer unentdeckt geblieben: **alle Tests waren grün.**
|
||||
- **Die Navigation hätte sechs tote Links angeboten.** `recht` stand nur am Admin-Bereich, weil
|
||||
bisher jede Rolle `lesen` durfte.
|
||||
- **Ein falscher Satz in `docs/betrieb/authentik.md`:** „Ist der Benutzer in keiner der vier
|
||||
Gruppen, bekommt er `LESER`.“ Richtig war er bis zu dieser Sitzung.
|
||||
- **Drei eigene Testfehler**, keine Produktfehler: Tag-Codes müssen dem Alphabet ohne `0`, `1`, `I`
|
||||
und `O` folgen; die Kundenbindungstests gaben nur eine Kundengruppe mit und hingen damit an der
|
||||
neuen Weiche; und ein Einfüge-Skript meldete „ok“, ohne geschrieben zu haben — seitdem prüfe ich
|
||||
nach dem Einfügen mit `grep`.
|
||||
|
||||
### Nächster Schritt
|
||||
|
||||
- **Phase 2 ist bis auf die beiden großen Verzeichnis-Themen fertig:** **M15 (#028)**
|
||||
Microsoft-Graph-Quelle und **M16 (#029)** SCIM-Endpunkt.
|
||||
- Vor beiden wäre ein unabhängiger Review über die sechs Meilensteine dieser Phase angebracht —
|
||||
M17 bis M22 liegen ohne fremden Blick auf `main`.
|
||||
- Weiter offen und nicht von hier aus machbar: **#024** Proxmox-Einzeiler auf einem echten PVE-Host.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# #035 M22 – Mitarbeiter-Selbstauskunft
|
||||
|
||||
**Status:** offen
|
||||
**Status:** erledigt
|
||||
**Im Tracker:** [#55](https://git.wilde-server.de/florian.wilde/Laufzettel/issues/55)
|
||||
**Meilenstein:** v0.2.0
|
||||
**Labels:** phase-2, backend, frontend
|
||||
**Geschätzt:** 8 h **Tatsächlich:** –
|
||||
**Geschätzt:** 8 h **Tatsächlich:** 2 h 50 min
|
||||
|
||||
## Ziel
|
||||
|
||||
@@ -20,42 +20,95 @@ Anmeldung zu einer `Mitarbeiter`-Zeile zu kommen.
|
||||
|
||||
## Zu entscheiden
|
||||
|
||||
- [ ] **Anmeldung über OIDC, Zuordnung über den UPN, neue Rolle `MITARBEITER`** — Empfehlung. Das
|
||||
- [x] **Anmeldung über OIDC, Zuordnung über den UPN, neue Rolle `MITARBEITER`** — Empfehlung. Das
|
||||
Haus hat seine Leute ohnehin im Identitätsanbieter; wer sich anmeldet und keiner
|
||||
Rollengruppe angehört, wird über `upn` einer `Mitarbeiter`-Zeile zugeordnet und bekommt genau
|
||||
ein Recht: `selbstauskunft`. `Benutzer.mitarbeiterId` hält die Zuordnung fest.
|
||||
Die Alternative — ein Link mit Token je Person — braucht keine Anmeldung, aber jeder
|
||||
weitergeleitete Link ist dann ein Datenleck, und widerrufen müsste man je Person.
|
||||
- [ ] **Was der Mitarbeiter sieht:** Titel, Status, Zeitraum und Gerät eines Laufs. **Nicht** die
|
||||
- [x] **Was der Mitarbeiter sieht:** Titel, Status, Zeitraum und Gerät eines Laufs. **Nicht** die
|
||||
Schritte, nicht die Notizen, nicht die Kommentare, nicht die Anhänge. In einem Lauf stehen
|
||||
Arbeitsnotizen über Menschen und Zugangsdaten-Platzhalter; eine Selbstauskunft ist keine
|
||||
Akteneinsicht. Das ist die wichtigste Entscheidung dieses Meilensteins und gehört in die
|
||||
Anleitung, nicht nur in den Code.
|
||||
- [ ] **Kein Zugang ohne Zuordnung.** Wer sich anmeldet und zu keiner `Mitarbeiter`-Zeile passt,
|
||||
- [x] **Kein Zugang ohne Zuordnung.** Wer sich anmeldet und zu keiner `Mitarbeiter`-Zeile passt,
|
||||
bekommt `/kein-zugriff` mit Begründung — nicht eine leere Seite, die wie ein Fehler aussieht.
|
||||
|
||||
## Aufgaben
|
||||
|
||||
- [ ] `Rolle` um `MITARBEITER` erweitern; `RECHTE` bekommt `selbstauskunft: ["MITARBEITER", …]`.
|
||||
- [x] `Rolle` um `MITARBEITER` erweitern; `RECHTE` bekommt `selbstauskunft: ["MITARBEITER", …]`.
|
||||
**Jede** Rollenprüfung in `tests/rollen.test.ts` wächst um eine Spalte — die Matrix ist
|
||||
ausgeschrieben und nicht berechnet, genau damit das auffällt
|
||||
- [ ] `Benutzer.mitarbeiterId` mit Mandantengrenze als zusammengesetzter Fremdschlüssel
|
||||
- [ ] Zuordnung beim Login über `upn`, unabhängig von Groß- und Kleinschreibung; mehrdeutig ist ein
|
||||
- [x] `Benutzer.mitarbeiterId` mit Mandantengrenze als zusammengesetzter Fremdschlüssel
|
||||
- [x] Zuordnung beim Login über `upn`, unabhängig von Groß- und Kleinschreibung; mehrdeutig ist ein
|
||||
Fehler und kein Zufallstreffer
|
||||
- [ ] Eigene Seite `/meine-geraete`: meine Geräte, je Gerät die Läufe chronologisch, Titel und Status
|
||||
- [ ] **Jede Abfrage schränkt auf die eigene Person ein** — nicht die Seite. Ein Lesemodell trägt
|
||||
- [x] Eigene Seite `/meine-geraete`: meine Geräte, je Gerät die Läufe chronologisch, Titel und Status
|
||||
- [x] **Jede Abfrage schränkt auf die eigene Person ein** — nicht die Seite. Ein Lesemodell trägt
|
||||
seine Sicht selbst (CLAUDE.md)
|
||||
- [ ] Die Navigation zeigt einem `MITARBEITER` nur diese Seite; alles andere ist weg, nicht grau
|
||||
- [ ] Anleitung: ein eigenes kurzes Kapitel, an Mitarbeiter gerichtet und nicht an Techniker
|
||||
- [x] Die Navigation zeigt einem `MITARBEITER` nur diese Seite; alles andere ist weg, nicht grau
|
||||
- [x] Anleitung: ein eigenes kurzes Kapitel, an Mitarbeiter gerichtet und nicht an Techniker
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
||||
- [ ] Test: ein `MITARBEITER` sieht die Läufe seiner Geräte und keinen anderen
|
||||
- [ ] Test: er sieht **keine** Schritte, Notizen, Kommentare oder Anhänge — geprüft über die Antwort,
|
||||
- [x] Test: ein `MITARBEITER` sieht die Läufe seiner Geräte und keinen anderen
|
||||
- [x] Test: er sieht **keine** Schritte, Notizen, Kommentare oder Anhänge — geprüft über die Antwort,
|
||||
nicht über die Seite
|
||||
- [ ] Test: er kann nichts schreiben — jede Server Action weist ihn ab (`tests/zugang.test.ts`
|
||||
- [x] Test: er kann nichts schreiben — jede Server Action weist ihn ab (`tests/zugang.test.ts`
|
||||
erkennt eine ungeprüfte Aktion ohnehin)
|
||||
- [ ] Test: ohne passende `Mitarbeiter`-Zeile führt die Anmeldung auf `/kein-zugriff` mit Begründung
|
||||
- [ ] Test: ein mehrdeutiger UPN wird abgewiesen und protokolliert
|
||||
- [ ] Test: die Rollenmatrix ist vollständig — jede der fünf Rollen gegen jedes Recht
|
||||
- [ ] Am Handy kein horizontales Scrollen
|
||||
- [x] Test: ohne passende `Mitarbeiter`-Zeile führt die Anmeldung auf `/kein-zugriff` mit Begründung
|
||||
- [x] Test: ein mehrdeutiger UPN wird abgewiesen und protokolliert
|
||||
- [x] Test: die Rollenmatrix ist vollständig — jede der fünf Rollen gegen jedes Recht
|
||||
- [x] Am Handy kein horizontales Scrollen
|
||||
|
||||
## Beim Umsetzen dazugekommen
|
||||
|
||||
- **Kein zusammengesetzter Fremdschlüssel, und zwar aus einem Grund.** Die Aufgabe verlangte
|
||||
`Benutzer.mitarbeiterId` „mit Mandantengrenze als zusammengesetzter Fremdschlüssel“. Das geht
|
||||
nicht: ein `Benutzer` trägt keine `kundeId`, gegen die man zusammensetzen könnte — ein
|
||||
Administrator sieht alle Kunden. Stattdessen hält die Datenbank das fest, was hier wirklich zählt:
|
||||
ein **CHECK**, dass Rolle und Zuordnung zusammengehören (in beide Richtungen), und ein
|
||||
**eindeutiger Index**, dass eine Person höchstens ein Konto hat. Die Zusage „sieht nur seine
|
||||
eigenen Läufe“ hängt an der einen Kennung, und stärker als ein Fremdschlüssel darauf wird sie
|
||||
nicht.
|
||||
- **Nicht `/kein-zugriff`, sondern die Anmeldeseite.** Das Kriterium sah vor, dass eine Anmeldung
|
||||
ohne passende Person auf `/kein-zugriff` führt. Diese Seite verlangt aber eine **Sitzung**, und
|
||||
bei gescheiterter Anmeldung gibt es keine — sie würde auf die Anmeldeseite zurückleiten, also im
|
||||
Kreis. Die Begründung steht deshalb dort, mit zwei eigenen Fehlercodes (`keine-person`,
|
||||
`upn-mehrdeutig`). Der Geist des Kriteriums ist damit erfüllt: keine leere Seite, die wie ein
|
||||
Fehler aussieht.
|
||||
- **Ein bestehender Test seit #007 fand eine echte Lücke.** `staerksteRolle` benutzte `LESER` als
|
||||
Startwert, und das war zugleich eine **Untergrenze**: `staerksteRolle(["MITARBEITER"])` ergab
|
||||
`LESER`, also **mehr** Rechte als übergeben. Solange alle Rollen mindestens `LESER` waren, fiel
|
||||
das nie auf. Der Test „gibt bei nur <Rolle> diese Rolle zurück“ war sofort rot.
|
||||
- **Jeder Navigationseintrag nennt jetzt sein Recht.** Bis hierher stand `recht` nur am
|
||||
Admin-Bereich — das genügte, weil jede Rolle `lesen` durfte. Mit `MITARBEITER` stimmt das nicht
|
||||
mehr, und ohne diese Änderung hätte die Seitenleiste ihm sechs Links angeboten, die alle auf
|
||||
`/kein-zugriff` führen.
|
||||
- **Zwei Bedienfehler beim Durchklicken gefunden**, beide dieselbe Ursache: das Standardziel nach
|
||||
der Anmeldung ist `/`, und die Übersicht verlangt `lesen`. Ein Mitarbeiter sah als Erstes „Dafür
|
||||
fehlt dir die Berechtigung“ — und der Knopf auf jener Seite führte zurück auf `/`, also im Kreis.
|
||||
Beides behebt `startseite(rolle)` in `src/server/auth/rollen.ts`, an einer Stelle und mit Test.
|
||||
- **Eine Gegenprobe blieb grün, und das war der Befund.** Der Test „sieht keine Notizen“ prüft die
|
||||
**Antwort**, und die ist sicher: `laufBauen` setzt sie aus den erlaubten Feldern zusammen. Als ich
|
||||
im `select` versuchsweise `ergebnisse: { notiz }` ergänzte, blieb er deshalb grün — während der
|
||||
Kopfkommentar der Datei behauptet, das `select` hole es „gar nicht erst“. Diese Behauptung hat
|
||||
jetzt ihren eigenen Test, der die Datei selbst liest. Ein `select`, das Notizen mitliest, zieht
|
||||
sie durch Protokolle und Fehlerberichte.
|
||||
- **`selbstauskunft` hat auch der ADMIN nicht.** Es ist ein **Ersatz** für `lesen`, kein Zusatz: ein
|
||||
zweiter Weg zu denselben Daten wäre eine zweite Stelle, an der jemand die Einschränkung auf die
|
||||
eigene Person vergisst. Wer beides braucht, braucht zwei Konten — und der CHECK verlangt das.
|
||||
- **Der Rang von `MITARBEITER` liegt unter `LESER`.** Der Rang entscheidet, wer gewinnt, wenn jemand
|
||||
in mehreren abgebildeten Gruppen steht. Stünde er darüber, verlöre ein Techniker seine Rechte,
|
||||
weil er auch Mitarbeiter des Hauses ist.
|
||||
- **Ein struktureller Test, dass keine Server Action `selbstauskunft` verlangt.** Die Zusage „kann
|
||||
nichts schreiben“ steht nicht in einer Prüfung, sondern in der **Abwesenheit** einer Aktion mit
|
||||
diesem Recht — und die muss jemand bewachen.
|
||||
- **Die Weiche greift nur mit eingerichteter Gruppenzuordnung.** Ohne abgebildete Gruppen kann die
|
||||
Anwendung nicht unterscheiden, ob jemand Techniker oder Mitarbeiter ist. Ein Update, das jeden
|
||||
aussperrt, dem die Gruppen fehlen, wäre ein kaputtes Update — mit eigenem Test.
|
||||
- **Die authentik-Doku enthielt jetzt einen falschen Satz:** „Ist der Benutzer in keiner der vier
|
||||
Gruppen, bekommt er `LESER`.“ Richtiggestellt, mit einem eigenen Abschnitt zur Selbstauskunft und
|
||||
dem Hinweis, wie man das alte Verhalten behält.
|
||||
- **Das Anleitungskapitel 09 ist an Mitarbeiter gerichtet**, nicht an die IT — das erste Kapitel
|
||||
dieser Anleitung, das sich an jemanden außerhalb der IT wendet. Es lässt sich weitergeben, ohne
|
||||
den Rest mitzuschicken, und sagt ausdrücklich, **warum** man die Schritte nicht sieht.
|
||||
|
||||
@@ -39,5 +39,5 @@ Diese Dateien sind die Quelle; `pnpm issues:sync` spiegelt sie in den Gitea-Trac
|
||||
| #032 | [M19 – Anhänge und Fotos an Schritten](032-anhaenge.md) | erledigt | v0.2.0 | 10 h | 3 h 05 min |
|
||||
| #033 | [M20 – Live-Aktualisierung per SSE statt Polling](033-sse-live.md) | erledigt | v0.2.0 | 6 h | 1 h 40 min |
|
||||
| #034 | [M21 – Benachrichtigungen per Mail und Webhook](034-benachrichtigungen.md) | erledigt | v0.2.0 | 10 h | 3 h 30 min |
|
||||
| #035 | [M22 – Mitarbeiter-Selbstauskunft](035-selbstauskunft.md) | offen | v0.2.0 | 8 h | – |
|
||||
| | **Summe** | | | **229 h** | **53 h 35 min** |
|
||||
| #035 | [M22 – Mitarbeiter-Selbstauskunft](035-selbstauskunft.md) | erledigt | v0.2.0 | 8 h | 2 h 50 min |
|
||||
| | **Summe** | | | **229 h** | **56 h 25 min** |
|
||||
|
||||
Reference in New Issue
Block a user