fix(geschichte): stop exposing author email in the list projection

GET /api/geschichten shipped every author's AppUser email to all readers via
GeschichteSummary.AuthorSummary — contradicting the documented rule that
author projections never expose email or group memberships. The frontend
only used it as a display-name fallback; it now falls back to [Unbekannt],
matching the server-side rule in GeschichteService.toView.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-10 07:25:11 +02:00
parent b3d54a12c4
commit e077dba595
9 changed files with 28 additions and 24 deletions

View File

@@ -37,10 +37,9 @@ public interface GeschichteSummary {
String getBody();
/** Author projection — names only; never email or group memberships (same rule as GeschichteView.AuthorView). */
interface AuthorSummary {
String getFirstName();
String getLastName();
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
String getEmail();
}
}

View File

@@ -87,8 +87,9 @@ class GeschichteListProjectionTest {
// ─── AuthorSummary nested projection ─────────────────────────────────────
@Test
void findSummaries_exposes_nested_author_firstName_lastName_email() {
void findSummaries_exposes_nested_author_names_but_never_email() {
AppUser richAuthor = appUserRepository.save(AppUser.builder()
.firstName("Franz").lastName("Raddatz")
.email("franz@raddatz.de").password("pw").build());
geschichteRepository.save(published("Briefe aus der Front", richAuthor));
@@ -97,7 +98,13 @@ class GeschichteListProjectionTest {
assertThat(result).hasSize(1);
GeschichteSummary.AuthorSummary a = result.get(0).getAuthor();
assertThat(a.getEmail()).isEqualTo("franz@raddatz.de");
assertThat(a.getFirstName()).isEqualTo("Franz");
assertThat(a.getLastName()).isEqualTo("Raddatz");
// Design rule (GeschichteView.AuthorView javadoc): author projections never
// expose email or group memberships to readers.
assertThat(GeschichteSummary.AuthorSummary.class.getMethods())
.extracting(java.lang.reflect.Method::getName)
.doesNotContain("getEmail");
}
// ─── GeschichteType is exposed ────────────────────────────────────────────