feat(stammdaten): Mitarbeiter, Abteilungen und Geraete (#25)
This commit was merged in pull request #25.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# #011 M6 – Mitarbeiter, Abteilungen, Geräte
|
||||
|
||||
**Status:** offen
|
||||
**Status:** erledigt
|
||||
**Meilenstein:** v0.1.0
|
||||
**Labels:** phase-1, backend, frontend
|
||||
**Geschätzt:** 9 h **Tatsächlich:** –
|
||||
**Geschätzt:** 9 h **Tatsächlich:** 2 h 15 min
|
||||
|
||||
## Ziel
|
||||
|
||||
@@ -11,23 +11,69 @@ Die Stammdaten, an denen die Historie hängt. Mitarbeiter und Geräte werden nie
|
||||
|
||||
## Aufgaben
|
||||
|
||||
- [ ] Mitarbeiterliste: Suche über Anzeigename, Mail, UPN und `sam`, Filter nach Abteilung und Aktiv-Status
|
||||
- [ ] Mitarbeitersuche als wiederverwendbare Komponente: standardmäßig nur aktive, Umschalter „auch deaktivierte“ fürs Offboarding
|
||||
- [ ] Mitarbeiterseite: Stammdaten, Abteilung, Vorgesetzter, seine Geräte, alle Läufe chronologisch (Onboarding, Übergaben, Offboarding)
|
||||
- [ ] Mitarbeiter manuell anlegen und bearbeiten (`herkunft = MANUELL`); synchronisierte Felder sind bei `herkunft = ABGLEICH` gesperrt
|
||||
- [ ] Deaktivieren statt löschen (`aktiv = false`)
|
||||
- [ ] Abteilungen: Name (eindeutig je Kunde), Ziel-OU, Standardgruppen (`String[]`), Mail-Domain, Notizen
|
||||
- [ ] Geräte: Stammdaten nach Vorgabe, Pflichtregel „`hostname` oder `bezeichnung` muss gesetzt sein“, Besitzer optional
|
||||
- [ ] Geräteliste mit Suche über Hostname, Bezeichnung, Seriennummer und `tagCode`, Filter nach Typ
|
||||
- [ ] CSV-Import für Geräte (`hostname`, `label`, `serialNumber`, `inventoryNumber`, `type`, `model`), `tagCode` wird beim Import erzeugt; eigener `src/lib/csv.ts`
|
||||
- [ ] Archivieren statt Löschen, sobald Läufe an einem Gerät oder einer Abteilung hängen
|
||||
- [ ] Screenshots Mitarbeiterliste, Mitarbeiterseite, Geräteliste, Abteilungen in `docs/screenshots/m6/`
|
||||
- [x] Mitarbeiterliste: Suche über Anzeigename, Mail, UPN und `sam`, Filter nach Abteilung und Aktiv-Status
|
||||
- [x] Mitarbeitersuche als wiederverwendbare Komponente: standardmäßig nur aktive, Umschalter „auch deaktivierte“ fürs Offboarding
|
||||
- [x] Mitarbeiterseite: Stammdaten, Abteilung, Vorgesetzter, seine Geräte, alle Läufe chronologisch (Onboarding, Übergaben, Offboarding)
|
||||
- [x] Mitarbeiter manuell anlegen und bearbeiten (`herkunft = MANUELL`); synchronisierte Felder sind bei `herkunft = ABGLEICH` gesperrt
|
||||
- [x] Deaktivieren statt löschen (`aktiv = false`)
|
||||
- [x] Abteilungen: Name (eindeutig je Kunde), Ziel-OU, Standardgruppen (`String[]`), Mail-Domain, Notizen
|
||||
- [x] Geräte: Stammdaten nach Vorgabe, Pflichtregel „`hostname` oder `bezeichnung` muss gesetzt sein“, Besitzer optional
|
||||
- [x] Geräteliste mit Suche über Hostname, Bezeichnung, Seriennummer und `tagCode`, Filter nach Typ
|
||||
- [x] CSV-Import für Geräte (`hostname`, `label`, `serialNumber`, `inventoryNumber`, `type`, `model`), `tagCode` wird beim Import erzeugt; eigener `src/lib/csv.ts`
|
||||
- [x] Archivieren statt Löschen, sobald Läufe an einem Gerät oder einer Abteilung hängen
|
||||
- [x] Screenshots Mitarbeiterliste, Mitarbeiterseite, Geräteliste, Abteilungen in `docs/screenshots/m6/`
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
||||
- [ ] Test: Mitarbeitersuche liefert standardmäßig nur `aktiv = true`; mit Umschalter auch deaktivierte
|
||||
- [ ] Test: ein Gerät ohne `hostname` und ohne `bezeichnung` wird abgelehnt
|
||||
- [ ] Test: ein Gerät mit Läufen lässt sich nicht löschen, nur archivieren
|
||||
- [ ] Test: `tagCode` eines bestehenden Geräts lässt sich nicht ändern
|
||||
- [ ] Test: CSV-Import erzeugt je Zeile einen `tagCode`, meldet fehlerhafte Zeilen einzeln und bricht nicht ab
|
||||
- [ ] Test: bei `herkunft = ABGLEICH` lehnt der Service Änderungen an synchronisierten Feldern ab
|
||||
- [x] Test: Mitarbeitersuche liefert standardmäßig nur `aktiv = true`; mit Umschalter auch deaktivierte
|
||||
- [x] Test: ein Gerät ohne `hostname` und ohne `bezeichnung` wird abgelehnt
|
||||
- [x] Test: ein Gerät mit Läufen lässt sich nicht löschen, nur archivieren
|
||||
- [x] Test: `tagCode` eines bestehenden Geräts lässt sich nicht ändern
|
||||
- [x] Test: CSV-Import erzeugt je Zeile einen `tagCode`, meldet fehlerhafte Zeilen einzeln und bricht nicht ab
|
||||
- [x] Test: bei `herkunft = ABGLEICH` lehnt der Service Änderungen an synchronisierten Feldern ab
|
||||
|
||||
## Beim Bauen aufgefallen
|
||||
|
||||
- **Der CSV-Import hat Zeilen still verloren und Erfolg gemeldet.** Ein Anführungszeichen, das in
|
||||
einer Zelle beginnt und nicht schließt, verschluckte alle Folgezeilen bis zum nächsten `"` — der
|
||||
Import sagte „3 von 3 Zeilen angelegt“, zwei Geräte fehlten, und in einer Bezeichnung stand der
|
||||
Text der verschluckten Zeilen. Umgekehrt starb der ganze Import an einer Datei, in der nirgends
|
||||
mehr ein `"` folgte. Beides ist genau das Gegenteil des Akzeptanzkriteriums. Der Zerleger setzt
|
||||
jetzt am Zeilenende neu auf: **ein Wert reicht standardmäßig nicht über die Zeile hinaus**. Das
|
||||
Format erlaubt es, für Hostnamen und Seriennummern ist ein Umbruch aber praktisch immer ein
|
||||
vergessenes Anführungszeichen — und mit dieser Grenze endet der Schaden an der Zeile, in der er
|
||||
beginnt. Wer eine selbst erzeugte Datei zurückliest, schaltet `werteUeberZeilen` ein.
|
||||
- **`ungepflegteAbteilungen` kannte die Kundengrenze nicht.** Gruppiert wurde nach dem Namen
|
||||
allein, also galt „Vertrieb“ als gepflegt, sobald **irgendein** Kunde eine Abteilung dieses
|
||||
Namens hatte. Beim Kunden ohne sie blieben `{{ou}}` und `{{gruppen}}` im Lauf leer, ohne dass die
|
||||
Seite es je sagte. Die Funktion direkt darüber machte es seit jeher richtig — zwei Funktionen im
|
||||
selben Modul, die sich widersprachen.
|
||||
- **Die Besitzerauswahl bot Personen fremder Kunden an.** Die Liste wurde einmal für die ganze
|
||||
Seite geholt und in jede Karte gegeben. Der Dienst wies die Wahl ab — aber erst nach dem Klick,
|
||||
und die Oberfläche hatte etwas angeboten, das sie nicht einlösen konnte.
|
||||
- **Ein Techniker konnte ein Gerät endgültig löschen.** Abteilungen und Mitarbeiter haben gar
|
||||
keinen Löschweg, Geräte schon — und der Tag-Code ist danach für immer verbrannt. Löschen verlangt
|
||||
jetzt `verwaltung`; die Ausnahme steht ausdrücklich in `CLAUDE.md`.
|
||||
- **Derselbe Kunde wurde zweimal verschieden dargestellt.** Die Mitarbeiterliste blendete die
|
||||
eigene Organisation immer aus, die Geräteliste zeigte sie immer an. Im Modus Dienstleistung hieß
|
||||
„keine Kundenangabe“ damit nicht „kein Kunde“, sondern „ausgerechnet dieser eine“. Jetzt liefern
|
||||
beide Lesemodelle den Namen, und **die Seite** entscheidet anhand des Betriebsmodus, ob sie ihn
|
||||
zeigt.
|
||||
- **Ein Kommentar hat wieder eine Zusage gemacht, die der Code nicht hielt** („zwei verschiedene
|
||||
Gründe, aber nicht dieselbe Meldung“) — gerendert wurde nur eine, und wer die Rolle nicht hatte,
|
||||
sah gesperrte Felder ohne jede Erklärung. Vierter Meilenstein in Folge mit genau dieser Sorte
|
||||
Fehler.
|
||||
- **`FELD` stand neunmal wortgleich in neun Dateien.** Jetzt einmal in `src/lib/formular.ts`.
|
||||
- **Die E2E-Tests haben ihre Daten liegen gelassen.** Sie können nichts löschen — die Anwendung
|
||||
kennt bewusst keinen Löschweg für Personen und Abteilungen —, also räumen sie am Ende über die
|
||||
Datenbank auf. Ohne das sähe jede Datenbank, gegen die sie laufen, nach ein paar Durchläufen aus
|
||||
wie ein Messie-Keller.
|
||||
- **Die Mitarbeitersuche ist ein eigenes Bauteil** (`src/components/mitarbeiter-suche.tsx`), weil
|
||||
#013 sie beim Starten eines Laufs und #014 beim Zuweisen eines Geräts wieder braucht.
|
||||
|
||||
## Offen geblieben
|
||||
|
||||
- **Ab 501 aktiven Personen** lässt sich ein Besitzer nicht mehr über das Auswahlfeld zuordnen. Die
|
||||
Grenze schützt davor, ein Verzeichnis mit zehntausend Personen in ein `<select>` zu gießen; die
|
||||
Zuweisung über die Geräteseite mit Suche kommt mit #014. Bis dahin sagt das Formular es
|
||||
ausdrücklich, statt einen Weg zu versprechen, den es nicht gibt.
|
||||
|
||||
@@ -15,7 +15,7 @@ Diese Dateien sind die Quelle; `pnpm issues:sync` spiegelt sie in den Gitea-Trac
|
||||
| #008 | [M3 – Betriebsmodus und Kunden](008-betriebsmodus-kunden.md) | erledigt | v0.1.0 | 6 h | 1 h 20 min |
|
||||
| #009 | [M4 – Vorlagen-Versionierung im Service](009-vorlagen-versionierung.md) | erledigt | v0.1.0 | 6 h | 1 h 20 min |
|
||||
| #010 | [M5 – Vorlagen-Editor](010-vorlagen-editor.md) | erledigt | v0.1.0 | 10 h | 2 h 10 min |
|
||||
| #011 | [M6 – Mitarbeiter, Abteilungen, Geräte](011-mitarbeiter-abteilungen-geraete.md) | offen | v0.1.0 | 9 h | – |
|
||||
| #011 | [M6 – Mitarbeiter, Abteilungen, Geräte](011-mitarbeiter-abteilungen-geraete.md) | erledigt | v0.1.0 | 9 h | 2 h 15 min |
|
||||
| #012 | [M7 – Platzhalter, Namensregeln, Escaping](012-platzhalter-namensregeln.md) | offen | v0.1.0 | 8 h | – |
|
||||
| #013 | [M8 – Läufe: Service und Abarbeitung](013-laeufe-abarbeitung.md) | offen | v0.1.0 | 14 h | – |
|
||||
| #014 | [M9 – QR-Tags, Geräteseite, Etiketten, Scanner](014-qr-tags-geraeteseite.md) | offen | v0.1.0 | 12 h | – |
|
||||
@@ -24,4 +24,4 @@ Diese Dateien sind die Quelle; `pnpm issues:sync` spiegelt sie in den Gitea-Trac
|
||||
| #017 | [M12 – Seed der sieben Vorlagen](017-seed-sieben-vorlagen.md) | offen | v0.1.0 | 8 h | – |
|
||||
| #018 | [M13 – E2E-Tests, Anleitung, PDF](018-e2e-anleitung-pdf.md) | offen | v0.1.0 | 14 h | – |
|
||||
| #019 | [M14 – Betriebswege und Release v0.1.0](019-betrieb-release.md) | offen | v0.1.0 | 10 h | – |
|
||||
| | **Summe** | | | **136 h** | **9 h** |
|
||||
| | **Summe** | | | **136 h** | **11 h 15 min** |
|
||||
|
||||
Reference in New Issue
Block a user