Skip to content

DB unique constraints for org membership + domain mappings (close the check-then-insert races) #1844

Description

@sweetmantech

Follow-up from chat#1841: the new organization member/domain endpoints (api#748, api#749) enforce their invariants app-side with check-then-insert, which is racy under concurrent requests. Flagged by review bots on both PRs; deferred there because the correct fix is database-level (this issue), not app-level locking.

Why: concurrent POST /api/organizations/members can insert duplicate membership rows; concurrent POST /api/organizations/domains can double-map a domain, which breaks selectOrgByDomain's .single() and therefore email-domain auto-join. The same check-then-insert race pre-exists in assignAccountToOrg.

Fix:

  1. database migration: UNIQUE (account_id, organization_id) on account_organization_ids; UNIQUE (domain) on organization_domains. Dedupe any existing violations in the same migration (check first — none known as of 2026-07-03).
  2. api: convert the inserts (addAccountToOrganization, insertOrganizationDomain) to upsert/on-conflict so a lost race returns the existing row instead of an error.

Done when: two concurrent identical POST .../members (and .../domains) requests both return 200 with the same row id and exactly one row exists; the migration applies cleanly against prod data; existing endpoint tests still pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions