Skip to content

Commit 537cb6b

Browse files
committed
fix: delete branches after content delivery configs in hard delete
hardDeleteProject deleted branches before content_delivery_config rows, which reference branch via branch_id, so deleting a project that had branch-scoped content delivery configs failed with a foreign key violation. This aborted the orphan-project purge batch in production, leaving projects of deleted organizations undeleted. Move branchService.deleteAllByProjectId after the ContentDeliveryConfig deletion, and flush right after it so the branch removals reach the DB before the project row is deleted (branch.project_id references project).
1 parent dd7f597 commit 537cb6b

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

backend/app/src/test/kotlin/io/tolgee/service/project/ProjectHardDeletingServiceTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.tolgee.batch.data.BatchJobType
1010
import io.tolgee.batch.request.DeleteKeysRequest
1111
import io.tolgee.development.testDataBuilder.data.BaseTestData
1212
import io.tolgee.development.testDataBuilder.data.BatchJobsTestData
13+
import io.tolgee.development.testDataBuilder.data.ContentDeliveryConfigBranchingTestData
1314
import io.tolgee.development.testDataBuilder.data.ContentDeliveryConfigTestData
1415
import io.tolgee.development.testDataBuilder.data.MtSettingsTestData
1516
import io.tolgee.development.testDataBuilder.data.ProjectWithQaEntitiesTestData
@@ -133,6 +134,19 @@ class ProjectHardDeletingServiceTest : AbstractSpringTest() {
133134
}
134135
}
135136

137+
@Test
138+
fun `deletes project with content delivery configs on branches`() {
139+
val testData = ContentDeliveryConfigBranchingTestData()
140+
testDataService.saveTestData(testData.root)
141+
executeInNewRepeatableTransaction(platformTransactionManager) {
142+
projectHardDeletingService.hardDeleteProject(testData.projectBuilder.self.refresh())
143+
}
144+
145+
executeInNewTransaction {
146+
projectService.find(testData.projectBuilder.self.id).assert.isNull()
147+
}
148+
}
149+
136150
@Test
137151
fun `deletes project with webhooks`() {
138152
val testData = WebhooksTestData()

backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ class ProjectHardDeletingService(
147147
entityManager.clear()
148148

149149
bigMetaService.deleteAllByProjectId(projectId)
150-
branchService.deleteAllByProjectId(projectId)
151150
projectQaConfigRepository.deleteAllByProjectId(projectId)
152151

153152
// Flush and clear the persistence context to ensure deletions are synchronized
@@ -183,6 +182,13 @@ class ProjectHardDeletingService(
183182
.setParameter("projectId", projectId)
184183
.executeUpdate()
185184

185+
// Branches are referenced by content_delivery_config.branch_id, so they must be
186+
// deleted only after the content delivery configs above are gone. The flush pushes
187+
// the branch removals to the DB before the project delete, which they precede.
188+
branchService.deleteAllByProjectId(projectId)
189+
entityManager.flush()
190+
entityManager.clear()
191+
186192
// Delete ContentStorage children first
187193
entityManager
188194
.createQuery("DELETE FROM AzureContentStorageConfig a WHERE a.contentStorage.project.id = :projectId")

0 commit comments

Comments
 (0)