From 534665459fd806560cddcc4f4650b4fa071600cd Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 6 Jun 2026 11:41:50 +0200 Subject: [PATCH] refactor(person): thin deletePerson to lean on V71 DB cascade (#684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the application-layer sender/receiver detach from deletePerson — the V71 ON DELETE constraints now enforce it. Remove the now-unused reassignSenderToNull repository method and rewrite the unit test to assert only the existence check plus deleteById (verifyNoMoreInteractions). Co-Authored-By: Claude Opus 4.8 --- .../raddatz/familienarchiv/person/PersonRepository.java | 6 ------ .../org/raddatz/familienarchiv/person/PersonService.java | 8 +++----- .../raddatz/familienarchiv/person/PersonServiceTest.java | 7 +++++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java index 50ff4ee9..75b265d0 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java @@ -194,12 +194,6 @@ public interface PersonRepository extends JpaRepository { @Query(value = "UPDATE documents SET sender_id = :target WHERE sender_id = :source", nativeQuery = true) void reassignSender(@Param("source") UUID source, @Param("target") UUID target); - // Used by deletePerson: detach a deleted person from documents they sent, so the hard - // delete cannot orphan a documents.sender_id FK (the column is nullable). - @Modifying - @Query(value = "UPDATE documents SET sender_id = NULL WHERE sender_id = :source", nativeQuery = true) - void reassignSenderToNull(@Param("source") UUID source); - @Modifying @Query(value = """ INSERT INTO document_receivers (document_id, person_id) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonService.java b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonService.java index 2dcdf777..8a8066fe 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonService.java @@ -68,15 +68,13 @@ public class PersonService { } /** - * Hard-deletes a person used by triage. Detaches the person from any documents they - * sent (nulls sender_id) and from any received-document references first, so the delete - * cannot orphan an FK and fail with a 500. + * Hard-deletes a person used by triage. Referential integrity is enforced by the database + * (V71's {@code ON DELETE} constraints: sender_id {@code SET NULL}, receiver and @-mention + * rows {@code CASCADE}), so the service stays thin — it only verifies existence then deletes. */ @Transactional public void deletePerson(UUID id) { getById(id); - personRepository.reassignSenderToNull(id); - personRepository.deleteReceiverReferences(id); personRepository.deleteById(id); } diff --git a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonServiceTest.java index a42a3051..18e70658 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonServiceTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -147,9 +148,11 @@ class PersonServiceTest { personService.deletePerson(id); - verify(personRepository).reassignSenderToNull(id); - verify(personRepository).deleteReceiverReferences(id); + // Integrity is enforced by V71's ON DELETE constraints — the service only checks + // existence then deletes; it no longer detaches sender/receiver references itself. + verify(personRepository).findById(id); verify(personRepository).deleteById(id); + verifyNoMoreInteractions(personRepository); } @Test