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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions