Two concurrent POST /api/setup/credential requests could both pass isSetupLocked(), observe no unclaimed row, and both insert — leaving two unclaimed admin rows with no recovery path. Wrap the count-check + user insert in a transaction with SELECT COUNT(*) ... FOR UPDATE to acquire a row/gap lock, ensuring at most one unclaimed admin row is created. Returns 409 when a concurrent request already holds an unclaimed row. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>