# 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`).
