GET /documents listet alle Dokumente und machte damit jede UUID auffindbar — das Zugriffsmodell "unerratbarer Link" waere hinfaellig. Der Endpunkt verlangt jetzt HTTP Basic; alles andere bleibt bewusst offen. Ohne konfigurierten Hash ist die Liste ausdruecklich gesperrt (denyAll), nicht offen: Ein vergessener Umgebungswert gaebe sonst jede UUID preis, und niemandem fiele es auf, weil alles funktioniert. Bewusst als Regel und nicht bloss als zufaelliges Passwort, das niemand kennt — der Unterschied ist pruefbar: Mit dem Zufallspasswort blieb die Gegenprobe stumm, mit denyAll faellt genau die danach benannte Zusicherung. Die Sperre nach Fehlversuchen ist global statt je Adresse: Es gibt genau ein Passwort, und hinter dem Reverse Proxy der Zielumgebung saehe der Server ohnehin fuer alle dieselbe Adresse. Preis benannt (D76-Nachtrag 6). 135 Tests. Gegenproben: Schutz entfernt, Sperre entfernt, Voreinstellung geoeffnet -> es faellt jeweils genau die danach benannte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.0 KiB
Werkbaum · Backend
Kotlin/Spring-Boot-Anwendung. Aufgaben: Persistenz der Notationstexte,
Live-Editing (D76), Taiga-Integration (REST-API, #ref-Auflösung,
Status-Sync), später Tenzu-Adapter.
Stand: Gerüst steht — Dokumenten-CRUD mit Historie und Wiederherstellung,
API-First aus src/main/resources/openapi/api.yaml, H2 mit Liquibase.
Kommandos in README.md hier. Live-Editing (D76,
docs/live-editing-proposal.md) ist in Arbeit: Schritte 1–5 der Reihenfolge
dort sind gebaut (Zeilen-Diff in de.werkbaum.diff, Historie in zwei Ebenen,
PATCH /content und der Änderungsfeed im LiveEditingService,
Master-Passwort für die Dokumentenliste); offen sind PATCH /title und der
Client im Frontend.
Konventionen
- Kotlin, Spring Boot 4, Gradle (Kotlin DSL), JDK 21.
- Paketwurzel
de.werkbaum; Schichten:api(Controller),domain,service,repository(Interfaces),persistence(JPA), späterintegration.taiga(Client, Mapping). - API First: Interfaces und Modelle werden aus der OpenAPI-Spezifikation generiert; der Controller implementiert sie. Ändert sich die Spec, schlägt der Compile fehl — genau so ist es gewollt.
- Tests mit JUnit 5 als Runner + Kotest-Assertions (
shouldBe,shouldContain,shouldThrow) und MockK; Verhalten per Cucumber gegen die laufende Anwendung (RestTestClient, nicht TestRestTemplate — das ist in Boot 4 Auslaufmodell). Taiga-Client gegen aufgezeichnete Antworten (WireMock), nie gegen Live-Instanzen. - Konfiguration über
application.yaml+ Umgebungsvariablen; keine Zugangsdaten im Repository. - Keine neuen Laufzeit-Abhängigkeiten ohne Rückfrage (Wurzel-CLAUDE.md); Test-Abhängigkeiten sind unkritisch, sie landen in keinem Artefakt.
Spring Boot 4 — drei Fallen (D13-Nachtrag)
Vieles ist aus dem Kern in eigene Module gewandert. Was uns getroffen hat:
spring-boot-starter-testbringt keinTestRestTemplate/RestTestClientmit — dafürspring-boot-resttestclient.@SpringBootTeststellt die Test-Client-Bean nicht mehr von selbst bereit:@AutoConfigureRestTestClientgehört an die Testkonfiguration.org.liquibase:liquibase-coreallein bringt die Autokonfiguration nicht mehr mit; ohnespring-boot-starter-liquibaseläuft keine Migration, und der Fehler zeigt sich erst spät als „Schema validation: missing table".
Wichtig (D14 — Parser-Hoheit)
Das Backend parst die Notation nicht. Es speichert den Text als Ganzes und arbeitet mit expliziten Metadaten. Sollte Backend-Parsen doch nötig werden: zuerst DECISIONS ergänzen, dann gegen die gemeinsamen Fixtures aus docs/SPEC.md §10 testen — niemals eine zweite, abweichende Grammatik pflegen.
Taiga-Mapping (Vorgabe aus docs/ROADMAP.md)
#123referenziert Epic/User Story/Task/Issue; Auflösung liefert Titel, URL, Status. Status-Mapping Taiga-Workflow → Notation konfigurierbar (Default: „New"→[ ], „In progress"→[~], „Ready for test"→[/], „Done"→[x], „Archived"→[^]).