Skip to content

feat(store): group delete keeps the row(soft delete) - #2016

Merged
AmanGIT07 merged 2 commits into
mainfrom
feat/group-soft-delete
Oct 23, 2026
Merged

AmanGIT07 merged 2 commits into
mainfrom
feat/group-soft-delete

Conversation

@AmanGIT07

Copy link
Copy Markdown
Contributor

Summary

DeleteGroup now keeps the group row and sets deleted_at on it, instead of removing it. Group reads already skip deleted rows, and the name is free again because uq_groups_org_id_name_live covers live rows only. No table has a foreign key to groups.

The rest of the delete is unchanged: OnGroupDeleted still removes the members' policies and relations, the policies where the group is the principal, and the link between the org and the group. The app.group.deleted audit log is still written. The org delete deletes every group of the org the same way, disabled ones included.

Changes

  • internal/store/postgres/group_repository.go: Delete uses softDelete. When no live row matches, it returns group.ErrNotExist, as before.
  • internal/store/postgres/group_repository_test.go: TestDelete covers the kept row, a second delete, an unknown id, an id that is not a uuid, and reusing the name.
  • test/e2e/regression/api_test.go: TestGroupAPI case 11 and TestOrganizationDeleteAlsoDeletesDisabledProjectsAndGroups check the kept rows. The org test's subtest "no group row of the org is left" is renamed to "no group of the org is listed", since the row now stays.

Technical Details

  • A second delete of the same group gets group.ErrNotExist from the repository, as before. Through the API it is refused earlier, at the permission check, because the group's tuples are already gone.
  • Group create rolls back through the same delete when its setup fails, so a failed create now leaves a row marked deleted. The name stays free. Projects have the same behaviour: A failed project or group create leaves a deleted row behind #2009.

Test Plan

  • TestDelete: the row stays with deleted_at set and reads no longer find it; a second delete and an unknown id return group.ErrNotExist; an id that is not a uuid, and an empty id, return group.ErrInvalidUUID; a new group in the same org can take the name.
  • e2e TestGroupAPI case 11: after DeleteGroup, the row has deleted_at set, GetGroup and a second DeleteGroup are refused, and a new group with the same name is created and listed while the deleted one is not.
  • e2e TestOrganizationDeleteAlsoDeletesDisabledProjectsAndGroups: after the org delete, the enabled and the disabled group both have deleted_at set, and no live policy is on either group or names it as principal. Before the delete, the disabled group holds a policy on the org as principal.
  • go test ./internal/store/postgres/... passes.
  • go test ./test/e2e/... passes.
  • golangci-lint run ./internal/store/postgres/... ./test/e2e/... reports no issues.

SQL Safety

  • The id flows through goqu.Ex{}. The only goqu.L is now() inside softDelete, with no values.
  • ToSQL() callers capture and forward params (query, params, err := stmt.ToSQL(); db.…Context(ctx, …, query, params...)). Never query, _, err := ….
  • No ? placeholders inside single-quoted SQL literals in goqu.L.
  • No new //nolint:forbidigo or // #nosec G20x annotations.

The group row now gets deleted_at instead of being removed. Deleting a
group that is already deleted, or does not exist, still returns not found.
Tests check that the row stays, reads skip it, no live policy is left on
the group or names it, and the name can be used again, after DeleteGroup
and after an org delete.
@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
frontier Ready Ready Preview Oct 22, 2026 12:08pm UTC

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Group deletion now preserves records while hiding deleted groups from standard lookups and listings.
    • Group names can be reused within the same organization after deletion.
    • Repeated deletion requests and references to already-deleted groups are handled more consistently.
    • Organization deletion continues when a group is already absent, while ensuring deleted groups and their live policy references do not appear in results.

Group deletion now marks groups as deleted instead of removing their rows. Organization deletion continues when a group is already absent. Repository and end-to-end tests cover these behaviors.

Changes: Group soft deletion

Layer / File(s) Summary
Group deletion
internal/store/postgres/group_repository.go, internal/store/postgres/group_repository_test.go, test/e2e/regression/api_test.go
GroupRepository.Delete now uses soft deletion. Tests check deleted-row persistence, failed reads and repeated deletion, and reuse of the deleted group’s name.
Organization deletion
core/deleter/service.go, core/deleter/service_test.go, test/e2e/regression/api_test.go
Organization deletion continues when a group is already absent. Tests check that deletion continues to the organization, and that deleted groups are absent from listings and have no live policies referencing them.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature

Suggested reviewers: rohilsurana

Merge Risk: ⚪ Minimal · up to e28a8

The change is mergeable; the remaining recommendation is to cover repository not-found handling directly.

Pre-merge checks: Passed 2
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AmanGIT07 AmanGIT07 changed the title feat(store): group delete keeps the row feat(store): group delete keeps the row(soft delete) Oct 21, 2026
@coveralls

coveralls commented Oct 21, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 39775872666

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage increased (+0.06%) to 55.65%

Details

  • Coverage increased (+0.06%) from the base build.
  • Patch coverage: 1 uncovered change across 1 file (3 of 4 lines covered, 75.0%).
  • 275 coverage regressions across 7 files.

Uncovered Changes

File Changed Covered %
core/deleter/service.go 3 2 66.67%
Total (2 files) 4 3 75.0%

Coverage Regressions

275 previously-covered lines in 7 files lost coverage.

File Lines Losing Coverage Coverage
core/deleter/service.go 69 82.62%
billing/customer/service.go 60 36.0%
internal/store/postgres/billing_customer_repository.go 51 64.2%
internal/store/postgres/billing_transactions_repository.go 42 71.92%
core/deleter/delete_notice.go 34 77.22%
billing/credit/service.go 12 64.96%
core/audit/audit.go 7 0.0%

Coverage Stats

Coverage Status
Relevant Lines: 41862
Covered Lines: 23296
Line Coverage: 55.65%
Coverage Strength: 19.33 hits per line

💛 - Coveralls

@rohilsurana rohilsurana left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more points:

  • core/deleter/service.go:341: the group loop in DeleteOrganization does not skip group.ErrNotExist, while the resource and domain loops do. Please handle ErrNotExist the same way in every delete loop, so a retry behaves the same everywhere.
  • A failed group create now leaves a deleted group row, like the project case. Please add groups to #2009 if they are not already there.

Comment thread test/e2e/regression/api_test.go Resolved
Comment thread test/e2e/regression/api_test.go Resolved
The group loop in DeleteOrganization skips group.ErrNotExist, like the
resource and domain loops. The group e2e asserts PermissionDenied for
GetGroup and a second DeleteGroup on a deleted group.
@AmanGIT07

Copy link
Copy Markdown
Contributor Author

On the two points in the review:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments: 1
core/deleter/service_test.go: 1

454-456: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Exercise the group repository not-found path.

core/deleter.Service.DeleteGroup returns immediately when OnGroupDeleted returns an error. The current setup therefore skips GroupService.DeleteModel for grp-gone.

Return nil from OnGroupDeleted and return group.ErrNotExist from DeleteModel:

Suggested test correction
-		m.mbrSvc.EXPECT().OnGroupDeleted(mock.Anything, "grp-gone").Return(group.ErrNotExist)
+		m.mbrSvc.EXPECT().OnGroupDeleted(mock.Anything, "grp-gone").Return(nil)
+		m.grpSvc.EXPECT().DeleteModel(mock.Anything, "grp-gone").Return(group.ErrNotExist)

This makes DeleteGroup return the repository error, so DeleteOrganization reaches its existing group.ErrNotExist handling branch.


ℹ️ Review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 9720206 and e28a863.

📒 Files selected for processing: 3
  • core/deleter/service.go
  • core/deleter/service_test.go
  • test/e2e/regression/api_test.go

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

@AmanGIT07
AmanGIT07 merged commit bed0064 into main Oct 23, 2026
8 checks passed
@AmanGIT07
AmanGIT07 deleted the feat/group-soft-delete branch October 23, 2026 03:20

This branch was successfully deployed

1 active deployment
Preview — e28a8631 Deployed Oct 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants