Marcel 404d874b4e feat(person): translate optimistic-lock conflicts on rename to PERSON_RENAME_CONFLICT 409
When the propagation listener saves blocks with a stale @Version (because
another transcriber's autosave incremented version mid-rename), Hibernate
raises ObjectOptimisticLockingFailureException — Spring's translation of
the underlying JPA exception. PersonService.updatePerson now wraps the
publishEvent call in a catch for OptimisticLockingFailureException and
re-throws as DomainException(PERSON_RENAME_CONFLICT, 409). The whole
@Transactional boundary still rolls back, but the client gets a structured
409 with the localised "please retry" message instead of a generic 500.

The listener was switched from saveAll to saveAllAndFlush so the conflict
fires inside the listener call (where the catch can see it), not at
transaction commit (which is too late for in-method handling).

Test stubs the eventPublisher to throw OptimisticLockingFailureException
and asserts the translated DomainException carries PERSON_RENAME_CONFLICT
and HTTP 409. End-to-end DB-level reproduction of the JPA optimistic-lock
race requires multi-threading or two physical connections, which is
impractical inside @DataJpaTest; the underlying JPA mechanism is well
covered by Hibernate's own test suite.

Refs #362

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 20:57:16 +02:00
Description
No description provided
44 MiB
Languages
Python 73.2%
TypeScript 11.5%
Java 10.8%
Svelte 4.2%
Shell 0.1%