Brainstormed with the user: any logged-in user should be able to self-service create a team and becomes its captain, via a dialog on team-select. Team deletion/archiving is scoped out as a separate follow-up feature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.9 KiB
Team erstellen über die UI
Status: approved Datum: 2026-08-03
Kontext
Teams können in TeamWallet heute nur über einen bestehenden Backend-Endpoint
(POST /api/v1/teams, teams.controller.ts) angelegt werden, der ausschließlich globalen Admins
vorbehalten ist (@Roles([RoleEnum.admin])). Im modernen Angular-Frontend
(myteamwallet_frontend_modern) existiert dafür keine UI: core/team/teams-api.ts hat keine
createTeam-Methode, und features/team-select/team-select.html zeigt einem User ohne Teams nur
den Hinweistext „Du bist noch keinem Team zugeordnet." ohne jede Handlungsoption.
Ziel: jeder eingeloggte User soll selbstständig ein neues Team gründen können und wird dabei
automatisch dessen Kapitän. Das schließt eine der offensichtlichsten Lücken im Produkt
(Selbstregistrierung eines Teams) und folgt demselben Muster, das an anderer Stelle im Code bereits
als fehlend dokumentiert ist (docs/plans/admin-user-management.md merkt an, dass Admins auch noch
keine User anlegen können — ein verwandtes, aber bewusst getrenntes Folge-Thema).
Entscheidungen aus dem Brainstorming
- Berechtigung: jeder eingeloggte User (
RoleEnum.user) darf ein Team erstellen, nicht nur Admins. Der Guard aufPOST /teamswird entsprechend gelockert. - Automatische Mitgliedschaft: der Ersteller wird automatisch Kapitän (
captain, Rollen-ID 3) des neuen Teams — die niedrigste Rollen-ID, dieTeamAccessService.assertManagerbereits als „Manager" behandelt (id >= 3). Es gibt kein explizites „Owner"-Konzept,captainist die naheliegende Top-Rolle für den Ersteller. - Formularumfang: nur der Teamname wird abgefragt (
CreateTeamDTObleibt{ name: string }). Alias wird weiterhin automatisch aus dem Timestamp generiert, alles Weitere ist später über die Team-Einstellungen anpassbar. - UI-Einstiegspunkt: Button „Team erstellen" ist in
team-selectdauerhaft sichtbar — auch wenn der User bereits Teams hat (nicht nur im Leerzustand), um auch das Anlegen weiterer Teams (z. B. zweite Mannschaft) zu ermöglichen. - UI-Pattern: Dialog/Modal statt eigener Route, passend zum bestehenden
MatDialog-Muster im Repo (z. B.features/team/more/penalties/penalties.ts) und angemessen für ein einzelnes Eingabefeld. - Out of Scope: Team löschen/archivieren ist ein eigenständiges Folge-Feature (andere Berechtigungen/Risiken, z. B. Umgang mit bestehenden Spielern/Transaktionen) und wird separat geplant.
Architektur / Komponenten
1. Backend: teams.controller.ts
Guard auf POST /teams von @Roles([RoleEnum.admin]) auf [RoleEnum.user, RoleEnum.admin]
erweitern — Muster wie an anderen Stellen desselben Controllers (z. B. Zeilen 113-114, 122-123).
Der aufrufende User wird wie überall im Controller über @Req() req → req.user.id an den Service
durchgereicht.
2. Backend: teams.service.ts#createNewTeam
Aktuell (Zeile 166-178) wird nur Team + Default-TeamSettings (generateBasicTeamSettings)
angelegt; es entsteht kein Player-Datensatz, der User bleibt kein Mitglied des neuen Teams.
Erweiterung: nach dem Speichern von Team und Settings zusätzlich einen Player erzeugen —
verknüpft mit dem aufrufenden User (userId) und teamRole = captain (per
rolesRepository.findOneBy({ id: 3 })). Vorgehen spiegelt die bestehende Join-Erzeugung in
createNewPlayer() (Zeilen 122-164), dort wird bereits Player inkl. TeamRole-Verknüpfung für
andere Spieler angelegt.
Audit-Logging (this.logger.info({ event: 'team_create', ... })) bleibt erhalten.
3. Backend: dto/create-team.dto.ts
Unverändert ({ name: string }).
4. Frontend: core/team/teams-api.ts
Neue Methode createTeam(name: string) → POST /teams, analog zu den bestehenden Methoden wie
createPlayer.
5. Frontend: neue Dialog-Komponente
Kleine Standalone-Komponente mit Reactive Form (FormBuilder/ReactiveFormsModule,
MatFormFieldModule), ein Pflichtfeld „Teamname" — nach dem Muster von
features/team/members/members.ts (Form-Aufbau) kombiniert mit dem MatDialog-Öffnungsmuster aus
features/team/more/penalties/penalties.ts.
6. Frontend: features/team-select/team-select.ts / .html
Button „Team erstellen" dauerhaft im Template ergänzen (nicht nur im Leerzustand-Block). Klick öffnet
den Dialog über MatDialog; bei erfolgreichem Abschluss MyTeamsStore neu laden und per Router
direkt in das neu erstellte Team navigieren.
Fehlerbehandlung
- Serverseitige Validierungsfehler (z. B. leerer/zu langer Name) werden als Formularfehler im Dialog angezeigt, der Dialog bleibt offen.
- Netzwerk-/Serverfehler laufen über den bestehenden Snackbar/Toast-Mechanismus des Repos, wie bei
anderen Create-Flows (z. B.
createPlayer).
Testing
- Backend (
teams.service.spec.ts):createNewTeam()legt zusätzlich zu Team und Settings einenPlayermitteamRole = captainund Verknüpfung zum aufrufenden User an. - Backend (
teams.controller.spec.tsbzw. e2e):POST /teamsist fürRoleEnum.usererlaubt (nicht mehr nur fürRoleEnum.admin). - Frontend: Komponententest für den neuen Dialog (analog
penalties.spec.ts) — Formularvalidierung, Aufruf vonteamsApi.createTeam. - Frontend: Test, dass
team-selectnach erfolgreicher ErstellungMyTeamsStoreneu lädt und in das neue Team navigiert. - Manuelle Verifikation: als normaler User (nicht Admin) über
team-selectein Team anlegen — Aufruf sollte gelingen, User landet automatisch als Kapitän im neuen Team; Swagger-Aufruf vonPOST /teamsals normaler User bestätigt den gelockerten Guard.
Out of Scope
- Team löschen/archivieren (eigenes Folge-Feature).
- Auswahl der initialen Rolle des Erstellers (immer
captain, keine Wahlmöglichkeit). - Eigene Alias-Vergabe durch den User (weiterhin automatisch generiert).
- Selbstständiges Anlegen von Usern durch Admins (verwandte, aber separate Lücke, siehe
docs/plans/admin-user-management.md).