Season-Endpunkte aufräumen: zwei ohne Aufrufer weg, clubCount überall, playerCount weg, 409 statt 400 #130

Open
opened 2026-10-22 16:35:35 +00:00 by claude · 0 comments
Collaborator

Entschieden am 22.10.2026 im Zalando-Review von /api/seasons (Punkte d bis g). Für die Nutzer ändert sich nichts.

d. Zwei Endpunkte ohne Aufrufer löschen

Nach CLAUDE.md „Kein Produktivcode nur für Tests“ (#45) fallen beide weg, zusammen mit ihren Tests.

  • PUT /api/seasons/{id} (SeasonResource.updateSeason) ändert nur den Namen. Keine Oberfläche, kein Skript ruft ihn auf. Tests: die PUT-Fälle in SeasonResourceTest (Z. 66, 172, 263) und in SeasonNameFormatTest (Z. 81). Die Formatprüfung beim Anlegen bleibt und ist dort weiter getestet.
  • GET /api/seasons/active/name (getActiveSeasonName, text/plain). Tests: SeasonActiveNameTest und der /active/name-Fall in SeasonActiveEmptyTest. Die Zeile in ARCHITECTURE.md:97, die ihn als Beispiel für @PermitAll nennt, bekommt ein anderes Beispiel. Im Kommentar an #129 steht „hier oder beim Aufräumen“: Er fällt hier weg.
  • Folge für SeasonRequest: Der Record dient danach nur noch dem Anlegen. preparationDate wird im Schema Pflichtfeld (@Schema(nullable = true) weg), die Prüfung im Backend bleibt. Das Javadoc („dient POST und PUT“) wird angepasst.

e. {id} → {seasonId}

In SeasonResource (getSeason, setPhase, enterPhaseDate) heisst der Pfad-Parameter wie bei den Unterressourcen {seasonId}. Die URL bleibt gleich, es ändern sich nur @PathParam und der Name in openapi.json. Zalando schreibt dazu nichts vor, es geht nur um Einheitlichkeit. Die anderen fünf Ressourcen mit gemischten Namen (clubs, categories, players, team-matches, events mit {eid}) folgen, wenn ihr Knoten im Durchgang dran ist.

f. clubCount überall, playerCount weg

Heute füllt nur GET /api/seasons beide Zahlen. GET /{id}, /active und das Anlegen liefern denselben SeasonResponse mit fest 0 (Zusatzkonstruktor in SeasonResponse). Das verstösst gegen „Eine Bedeutung je Feld“.

  • playerCount fällt weg. Niemand liest ihn. Die Dashboard-Kachel kommt aus /players/count, das bleibt. Danach haben PlayerRepository.countBySeasonId und die Injektion von SeasonReferenceDate in SeasonResource keinen Aufrufer mehr und fallen ebenfalls weg, sofern nichts anderes sie braucht (prüfen).
  • clubCount steht in jeder Antwort, gezählt mit ClubRepository.countBySeasonId. Heute lädt die Liste stattdessen alle Vereine je Saison und nimmt .size(). Der Zusatzkonstruktor mit der 0 fällt weg.
  • ADR 0033: Die Zählung kommt aus einem Service, nicht aus der Resource. Ein neuer Repository-Aufruf in SeasonResource macht den ArchitectureTest rot. Entfallen dadurch eingefrorene Verstösse von SeasonResource (findBySeasonId, countBySeasonId, getActiveSeasonName), schrumpft der Store, und er wird mitcommittet.

g. Datum einer noch nicht erreichten Phase: 409 statt 400

PUT /api/seasons/{seasonId}/phase-dates/{phase} mit einer Phase nach der aktuellen antwortet 409 Conflict statt 400. Die Anfrage ist richtig gebaut, sie passt nur nicht zum Stand der Saison. Der Text „Diese Phase ist noch nicht erreicht“ bleibt. Über die Oberfläche kommt der Fall nicht vor, weil PhaseDialog.tsx:89 nur erreichte Phasen bearbeiten lässt. Den Test, der heute 400 erwartet, findet der Bau beim Umstellen (SeasonPhaseEndpointTest, MeldeschlussNachtragenTest oder SeasonResourceTest).

Abnahme

  • mvn -B clean verify, die Frontend-Builds, E2E und metrics.py diff sind grün. Der ArchUnit-Store wächst nicht.
  • openapi.json:
    • Kein PUT /api/seasons/{seasonId} und kein /active/name mehr.
    • SeasonResponse ohne playerCount.
    • In SeasonRequest ist preparationDate Pflicht.
    • Die Pfad-Parameter heissen seasonId.
  • Gegenprobe f: Ein Backend-Test holt eine Saison mit Vereinen über GET /{seasonId} und erwartet clubCount > 0. Heute schlägt er fehl.
  • Dashboard „Vergangene Saisons“ zeigt die Vereinszahlen wie bisher.
Entschieden am 22.10.2026 im Zalando-Review von `/api/seasons` (Punkte d bis g). Für die Nutzer ändert sich nichts. ## d. Zwei Endpunkte ohne Aufrufer löschen Nach CLAUDE.md „Kein Produktivcode nur für Tests“ (#45) fallen beide weg, zusammen mit ihren Tests. - **`PUT /api/seasons/{id}`** (`SeasonResource.updateSeason`) ändert nur den Namen. Keine Oberfläche, kein Skript ruft ihn auf. Tests: die PUT-Fälle in `SeasonResourceTest` (Z. 66, 172, 263) und in `SeasonNameFormatTest` (Z. 81). Die Formatprüfung beim **Anlegen** bleibt und ist dort weiter getestet. - **`GET /api/seasons/active/name`** (`getActiveSeasonName`, `text/plain`). Tests: `SeasonActiveNameTest` und der `/active/name`-Fall in `SeasonActiveEmptyTest`. Die Zeile in `ARCHITECTURE.md:97`, die ihn als Beispiel für `@PermitAll` nennt, bekommt ein anderes Beispiel. Im Kommentar an #129 steht „hier oder beim Aufräumen“: Er fällt **hier** weg. - **Folge für `SeasonRequest`:** Der Record dient danach nur noch dem Anlegen. `preparationDate` wird im Schema Pflichtfeld (`@Schema(nullable = true)` weg), die Prüfung im Backend bleibt. Das Javadoc („dient POST und PUT“) wird angepasst. ## e. `{id}` → `{seasonId}` In `SeasonResource` (`getSeason`, `setPhase`, `enterPhaseDate`) heisst der Pfad-Parameter wie bei den Unterressourcen `{seasonId}`. Die URL bleibt gleich, es ändern sich nur `@PathParam` und der Name in `openapi.json`. Zalando schreibt dazu nichts vor, es geht nur um Einheitlichkeit. Die anderen fünf Ressourcen mit gemischten Namen (`clubs`, `categories`, `players`, `team-matches`, `events` mit `{eid}`) folgen, wenn ihr Knoten im Durchgang dran ist. ## f. `clubCount` überall, `playerCount` weg Heute füllt nur `GET /api/seasons` beide Zahlen. `GET /{id}`, `/active` und das Anlegen liefern denselben `SeasonResponse` mit fest **0** (Zusatzkonstruktor in `SeasonResponse`). Das verstösst gegen „Eine Bedeutung je Feld“. - **`playerCount` fällt weg.** Niemand liest ihn. Die Dashboard-Kachel kommt aus `/players/count`, das bleibt. Danach haben `PlayerRepository.countBySeasonId` und die Injektion von `SeasonReferenceDate` in `SeasonResource` keinen Aufrufer mehr und fallen ebenfalls weg, sofern nichts anderes sie braucht (prüfen). - **`clubCount` steht in jeder Antwort**, gezählt mit `ClubRepository.countBySeasonId`. Heute lädt die Liste stattdessen alle Vereine je Saison und nimmt `.size()`. Der Zusatzkonstruktor mit der 0 fällt weg. - **ADR 0033:** Die Zählung kommt aus einem Service, nicht aus der Resource. Ein neuer Repository-Aufruf in `SeasonResource` macht den `ArchitectureTest` rot. Entfallen dadurch eingefrorene Verstösse von `SeasonResource` (`findBySeasonId`, `countBySeasonId`, `getActiveSeasonName`), schrumpft der Store, und er wird mitcommittet. ## g. Datum einer noch nicht erreichten Phase: 409 statt 400 `PUT /api/seasons/{seasonId}/phase-dates/{phase}` mit einer Phase nach der aktuellen antwortet `409 Conflict` statt `400`. Die Anfrage ist richtig gebaut, sie passt nur nicht zum Stand der Saison. Der Text „Diese Phase ist noch nicht erreicht“ bleibt. Über die Oberfläche kommt der Fall nicht vor, weil `PhaseDialog.tsx:89` nur erreichte Phasen bearbeiten lässt. Den Test, der heute 400 erwartet, findet der Bau beim Umstellen (`SeasonPhaseEndpointTest`, `MeldeschlussNachtragenTest` oder `SeasonResourceTest`). ## Abnahme - `mvn -B clean verify`, die Frontend-Builds, E2E und `metrics.py diff` sind grün. Der ArchUnit-Store wächst nicht. - `openapi.json`: - Kein `PUT /api/seasons/{seasonId}` und kein `/active/name` mehr. - `SeasonResponse` ohne `playerCount`. - In `SeasonRequest` ist `preparationDate` Pflicht. - Die Pfad-Parameter heissen `seasonId`. - **Gegenprobe f:** Ein Backend-Test holt eine Saison mit Vereinen über `GET /{seasonId}` und erwartet `clubCount` > 0. Heute schlägt er fehl. - Dashboard „Vergangene Saisons“ zeigt die Vereinszahlen wie bisher.
Sign in to join this conversation.
No description provided.