Summary
Three more tables have a gorm.DeletedAt (soft delete) plus a plain table-level UNIQUE that ignores deleted_at, so removing a row and re-adding an equivalent one collides with the surviving soft-deleted row and 500s. This is the same class as the cycle_issues bug fixed in #361.
Offenders
Not offenders: workspace_members/project_members are mitigated by upsertWorkspaceMember/upsertProjectMember (Unscoped revive); github_repository_syncs gets a fresh repo UUID each link.
Suggested fix
Same as #361: revive the soft-deleted row on write (upsert), or hard-delete these join rows, or make the constraints partial (WHERE deleted_at IS NULL).
Summary
Three more tables have a
gorm.DeletedAt(soft delete) plus a plain table-levelUNIQUEthat ignoresdeleted_at, so removing a row and re-adding an equivalent one collides with the surviving soft-deleted row and 500s. This is the same class as the cycle_issues bug fixed in #361.Offenders
workspace_integrations(high).UNIQUE(workspace_id, integration_id);Createis a plain insert,Deleteis a soft delete, andGetByInstallationID/GetByWorkspaceAndProviderboth filterdeleted_at IS NULL. Uninstalling GitHub and reinstalling (even the same installation) falls through toCreateand collides. The team added a partial unique index oninstallation_idin migration 000003 but left this constraint non-partial.github_issue_syncs(medium).UNIQUE(repository_sync_id, issue_id);UpsertByPRAndIssuematches on live rows only,DeleteLinkForIssuesoft-deletes. Unlinking a PR from an issue then re-linking collides. (The same constraint also blocks two active PRs on one issue, which may be unintended.)states(medium).UNIQUE(name, project_id). There's aRestoreOrCreateByNameAndProjecthelper that dodges this, but it's only used for default-state seeding,StateService.Createuses the plainss.Create. Deleting a state named "Review" and creating a new one with the same name collides.Not offenders:
workspace_members/project_membersare mitigated byupsertWorkspaceMember/upsertProjectMember(Unscoped revive);github_repository_syncsgets a fresh repo UUID each link.Suggested fix
Same as #361: revive the soft-deleted row on write (upsert), or hard-delete these join rows, or make the constraints partial (
WHERE deleted_at IS NULL).