From 491773c092701caedd65a1284d1bf3a1b9e6f74b Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:00:15 +0800 Subject: [PATCH] fix(domain): clear skill.latest_version_id before deleting skill_version The PG FK constraint fk_skill_latest_version blocks deleting a SkillVersion whenever Skill.latest_version_id still references it. Two services had the wrong order: - SkillPublishService.deleteReplaceableVersionArtifacts: triggered when re-uploading the same version (UPLOADED -> overwritten). Reproduced by AstronClaw client retrying personal-skills upload. - SkillGovernanceService.deleteVersion: triggered when admin deletes a draft version that happens to be skill.latest_version_id. Fix: clear skill.latest_version_id and flush BEFORE deleting the SkillVersion row, so PG sees no live reference at delete time. Synced from SAAS commit 4626f0c117d9c0544c4dc1115c3aac7468f0d277 --- .../domain/skill/service/SkillGovernanceService.java | 5 ++++- .../domain/skill/service/SkillPublishService.java | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillGovernanceService.java b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillGovernanceService.java index 820bbba9..bbb748f8 100644 --- a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillGovernanceService.java +++ b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillGovernanceService.java @@ -182,12 +182,15 @@ public class SkillGovernanceService { deleteStorageAfterCommit(skill, namespaceSlug, storageKeys); skillFileRepository.deleteByVersionId(version.getId()); securityScanService.softDeleteByVersionId(version.getId()); - skillVersionRepository.delete(version); + // FK 约束 fk_skill_latest_version 阻止删除 skill_version 当 skill.latest_version_id 还指向它。 + // 必须先解开引用并 flush,让 PG 在 delete 时看不到引用。 if (version.getId().equals(skill.getLatestVersionId())) { skill.setLatestVersionId(findLatestPublishedVersionId(skill.getId())); skill.setUpdatedBy(actorUserId); skillRepository.save(skill); + skillRepository.flush(); } + skillVersionRepository.delete(version); auditLogService.record( actorUserId, "DELETE_SKILL_VERSION", diff --git a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillPublishService.java b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillPublishService.java index fed90cfc..d4271bf8 100644 --- a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillPublishService.java +++ b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillPublishService.java @@ -564,6 +564,14 @@ public class SkillPublishService { throw new DomainBadRequestException("error.skill.version.exists", version.getVersion()); } + // FK 约束 fk_skill_latest_version 阻止删除 skill_version 当 skill.latest_version_id 还指向它。 + // 必须先解开引用并 flush,让 PG 在 delete 时看不到引用。 + if (version.getId().equals(skill.getLatestVersionId())) { + skill.setLatestVersionId(null); + skillRepository.save(skill); + skillRepository.flush(); + } + reviewTaskRepository.findBySkillVersionIdAndStatus(version.getId(), ReviewTaskStatus.PENDING) .ifPresent(reviewTaskRepository::delete); @@ -579,10 +587,6 @@ public class SkillPublishService { securityScanService.softDeleteByVersionId(version.getId()); skillVersionRepository.delete(version); skillVersionRepository.flush(); - - if (version.getId().equals(skill.getLatestVersionId())) { - skill.setLatestVersionId(null); - } } private String resolveNamespaceSlug(Long namespaceId) {