Fehlerantworten 400/409 mit ProblemDetails zentral ins Schema (ADR 0037) #129
Labels
No labels
Kind
Bug
Kind
Enhancement
Kind
Maintenance
Priority
P1
Priority
P2
Priority
P3
Status
In Progress
Status
Need More Info
Status
Zur Abnahme
Änderungen Wettspielreglement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sffs-tt-basel/sffs-tt-issues#129
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Entschieden am 22.10.2026, siehe
docs/adr/0037-fehlerantworten-zentral-im-schema.md.Ziel
Das Fehlerformat steht im Vertrag. Zur Laufzeit gibt es das schon:
ProblemDetailsMappermacht aus jederWebApplicationExceptioneinProblemDetails(RFC 9457) mitapplication/problem+json. Im Schema fehlt es, weil kein EndpunktProblemDetailsals Rückgabetyp nennt.Umfang
OASFilter(inshared) hängt an jede POST-, PUT- und DELETE-Operation die Antworten400und409mit$ref: ProblemDetailsund Content-Typeapplication/problem+jsonan. Er wird übermp.openapi.filtereingetragen.ProblemDetailsmuss als Komponente inopenapi.jsonstehen. Der Filter legt sie an, oder sie wird als Schema registriert. Danachmvn -B clean verifylaufen lassen undopenapi.jsonmitcommitten.packages/shared/src/api.tsliest den Fehlerkörper über den generierten TypProblemDetails. Die Tests inpackages/sharedwerden angepasst.SeasonResolver. Wenn ja, bezieht der Filter GET mit ein. Das wird vor dem Bau entschieden und nicht geraten.shared/apioder in ein eigenes Paket? Die Tabelle in ADR 0033 entscheidet. Braucht er ein neues Paket, fragen.Nicht drin
@RolesAllowedins Schema. Ob ihr Körper auchProblemDetailsist, wird im Bau nachgesehen und im Issue festgehalten.Abnahme
mvn -B clean verify, die Frontend-Builds, E2E undmetrics.py diffsind grün.openapi.jsonhat jede schreibende Operation400und409mitProblemDetails.application/problem+jsonunddetail.Zusatz 22.10.2026:
GET /api/seasons/activeliefert 404 statt 204Entschieden beim Zalando-Review von
/api/seasons. Es gehört hierher, weilapi.tsdafür denselben Umbau braucht.Was sich ändert: Ist keine Saison offen, antwortet
GET /api/seasons/activemit404undProblemDetails,detail= „Es ist keine Saison offen.“ Heute kommt ein204ohne Body, der nicht im Schema steht. Zalando verlangt für einen GET auf eine einzelne Ressource, die es nicht gibt, 404. Den Fall gibt es beim Saisonwechsel: Die alte Saison ist abgeschlossen, die neue noch nicht angelegt.api.ts: Der geworfene Fehler trägt den HTTP-Status, und, sobald es den Typ gibt, dasProblemDetails. Heute ist es nur einErrormit Text.Muss im selben Umbau angepasst werden, sonst geht es kaputt:
portal/src/pages/verwaltung/DashboardPage.tsx,loadData): 404 heisst „keine Saison“ und zeigt das Formular „Neue Saison eröffnen“. Ohne Anpassung erscheint ein Fehler-Toast statt des Formulars, und keine neue Saison lässt sich anlegen.portal/src/hooks/useClubRegistration.ts): 404 heisst „Meldung geschlossen“ (CLOSED). Ohne Anpassung bleibtphaseaufnull, und die Seite sieht bearbeitbar aus.Ohne Änderung weiter richtig, weil sie jeden Fehler als „keine Saison“ behandeln: Spielbetrieb, Spielplan, Veröffentlichen, Kategorien zuteilen, Cup-Tableau, Elo-Bestimmung, Turnierliste.
Besser ohne eigenes Zutun: Auf-/Abstieg, Spielwochen und Teilnehmer zeigen statt „Cannot read properties of undefined (reading 'id')“ den Text „Es ist keine Saison offen.“
Skripte:
matchblatt-import.pyundimport-ttvp-termine.pyfragen/activeab. Ohne Saison brechen sie weiter ab. Prüfen, dass die Meldung dabei lesbar ist.Tests (mit Ollis Ja vom 22.10.):
SeasonActiveEmptyTest: Erwartung204→404mitdetail.portal/src/test/DashboardPage.test.tsx: „keine Saison“ als 404 simulieren statt als leere Antwort.workflow-archiveschliesst eine Saison ab und legt eine neue über das Dashboard an. Er deckt den gefährlichen Fall ab und muss grün bleiben.GET /api/seasons/active/nameliefert ebenfalls 204, hat aber keinen Aufrufer und soll wegfallen. Er wird nicht umgestellt, sondern gelöscht. Ob das hier geschieht oder beim Aufräumen der Season-Endpunkte, entscheidet der Bau.Abnahme zusätzlich: Lokal oder auf Staging eine Saison abschliessen. Das Dashboard zeigt „Neue Saison eröffnen“ ohne Fehler-Toast. Die Vereinsmeldung ist gesperrt. Auf-/Abstieg zeigt „Es ist keine Saison offen.“