# 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 auf `POST /teams` wird entsprechend gelockert. - **Automatische Mitgliedschaft**: der Ersteller wird automatisch **Kapitän** (`captain`, Rollen-ID 3) des neuen Teams — die niedrigste Rollen-ID, die `TeamAccessService.assertManager` bereits als „Manager" behandelt (`id >= 3`). Es gibt kein explizites „Owner"-Konzept, `captain` ist die naheliegende Top-Rolle für den Ersteller. - **Formularumfang**: nur der Teamname wird abgefragt (`CreateTeamDTO` bleibt `{ 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-select` dauerhaft 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-`TeamSetting`s (`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 einen `Player` mit `teamRole = captain` und Verknüpfung zum aufrufenden User an. - Backend (`teams.controller.spec.ts` bzw. e2e): `POST /teams` ist für `RoleEnum.user` erlaubt (nicht mehr nur für `RoleEnum.admin`). - Frontend: Komponententest für den neuen Dialog (analog `penalties.spec.ts`) — Formularvalidierung, Aufruf von `teamsApi.createTeam`. - Frontend: Test, dass `team-select` nach erfolgreicher Erstellung `MyTeamsStore` neu lädt und in das neue Team navigiert. - Manuelle Verifikation: als normaler User (nicht Admin) über `team-select` ein Team anlegen — Aufruf sollte gelingen, User landet automatisch als Kapitän im neuen Team; Swagger-Aufruf von `POST /teams` als 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`).