Skip to content

fix(communities): adopt the applicant's own organization holding the community slug - #468

Merged
elliotBraem merged 1 commit into
mainfrom
fix/adopt-slug-organization-on-resume
Oct 29, 2026
Merged

elliotBraem merged 1 commit into
mainfrom
fix/adopt-slug-organization-on-resume

Conversation

@elliotBraem

Copy link
Copy Markdown
Contributor

Summary

Resume no longer dead-ends on "The community slug is already used by another organization" when the applicant's own organization — the one holding the community slug — is unbound (no communityProposalId metadata). This mostly hits applications saved before orgId/applicantUserId were added to the payload, like prop_1789100065387_hfx9n44 (chicago): the slug path only saw the conflict.

provisionCommunityOrganization
  legacy path (orgId + applicantUserId)   → unchanged, now via shared bind helper
  slug path
    slug free                             → create org (unchanged)
    slug held, bound to this proposal     → reuse (unchanged)
    slug held, bound to another proposal  → CONFLICT (unchanged)
-   slug held, unbound                    → CONFLICT
+   slug held, unbound                    → adopt + bind

Adoption (bindCommunityOrganization, extracted from the legacy path):

  • approves a pending org (rejected stays a conflict)
  • stamps applicantMetadata + communityLinkedOrg: "true"
  • keeps existing owners; reviewer only becomes admin; applicant is never re-invited (applicantInvited: false)
  • with an applicantUserId, still requires the applicant to be an owner member or requester (mirrors the apply page linkedOrganization rule)

Release safety — releaseCommunityOrganization:

  if (metadata.communityProposalId !== proposalId) return keptReason "not_found"
+ if (metadata.communityLinkedOrg === "true") return keptReason "existing"

Marked orgs are never deleted on a later failed setup (the existing UI already treats "existing" as "organization kept").

Evidence

  • Before: applyCommunityProposal rejects with CONFLICT "The community slug is already used by another organization" for any slug-matched org without matching communityProposalId — including the applicant's own.
  • After (execution, api/tests/integration/community-proposals.test.ts):
    • binds the applicant's own unbound organization at the community slug — owner/requester match → adopted, metadata stamped, teams provisioned, tenant orgId set, resume idempotent
    • binds an unbound slug-matched organization when the application saved no applicant user — adopted on admin trust; release returns { released: false, keptReason: "existing" } and deleteOrganization is not called; re-apply resumes
    • still refuses a slug-matched organization held by another application or another owner — bound-to-other → slug conflict; non-owner applicant → ownership conflict
  • Full run: api 431 passed, ui 1126 passed, plugins 35 passed; typecheck and lint green.

Merge Danger

Door: two-way — provisioning changes are metadata stamps and member/role adjustments; an existing provisioned application can be reverted by releasing and re-applying.

Blast Radius: community apply/resume flows — adopted orgs keep their owners (reviewer is downgraded from owner to admin, matching the reuse path), and organizations already bound to a proposal or another owner's unbound org keep the old conflict behavior.

…community slug

Resume dead-ended on "The community slug is already used by another
organization" when an unbound organization owned by the applicant (or,
for applications saved without an applicant user, any unbound
organization) already held the community slug. The slug path now binds
such an organization to the proposal instead of conflicting: it approves
a pending org, stamps the community metadata plus a communityLinkedOrg
marker, keeps existing owners, adds the reviewer as admin, provisions
default teams, and never re-invites the applicant. Ownership is still
enforced when the payload has an applicant user, and organizations bound
to another proposal still conflict. releaseCommunityOrganization keeps
marked organizations (keptReason "existing") so a later failed setup
cannot delete a pre-existing organization.
@elliotBraem
elliotBraem merged commit d48afd0 into main Oct 29, 2026
7 checks passed
@elliotBraem
elliotBraem deleted the fix/adopt-slug-organization-on-resume branch October 29, 2026 12:51
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.

1 participant