feat(timeline): add TimelineEventRequest input DTO

Flat input DTO with Bean Validation (@NotBlank/@NotNull/@Size). createdBy/
updatedBy deliberately absent (server-populated; CWE-639). version is an
optional concurrency token, exempt from the server-only audit rule. Per #775.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-13 10:45:45 +02:00
committed by marcel
parent 262568f577
commit 0eea19c0d4

View File

@@ -0,0 +1,40 @@
package org.raddatz.familienarchiv.timeline;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.raddatz.familienarchiv.document.DatePrecision;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
/**
* Flat input DTO for creating/updating a {@link TimelineEvent}. Bean Validation fires at the
* controller boundary (via {@code @Valid}) and produces a 400 {@code VALIDATION_ERROR} for the
* presence/size constraints below; cross-field rules (the RANGE invariant), date normalization,
* id dedupe, and the title-length structured-error guard live in {@code TimelineEventService}.
*
* <p><strong>{@code createdBy}/{@code updatedBy} are intentionally absent.</strong> Authorship is
* server-populated from the session principal only — accepting it from the body would be an
* authorship-forgery / mass-assignment vector (CWE-639; see ADR-040 §7).
*
* @param version optional optimistic-lock concurrency token (the {@code @Version} the client last
* saw), applied on <em>update</em> only. This is a concurrency token, <strong>not</strong>
* an authorship field, so it is deliberately exempt from the §7 server-only audit rule.
* Null on update means "no concurrency check" (last-write-wins). No range validation —
* a stale/negative value is simply a mismatch the lock rejects at flush; the lock, not
* a validator, is the control.
*/
public record TimelineEventRequest(
@NotBlank @Size(max = 255) String title,
@NotNull EventType type,
@NotNull LocalDate eventDate,
DatePrecision precision,
LocalDate eventDateEnd,
@Size(max = 5000) String description,
Long version,
@Size(max = 50) List<UUID> personIds,
@Size(max = 50) List<UUID> documentIds
) {}