fix: resolve circular FK between users and accounts on registration

Account.owner_id and User.account_id are both NOT NULL, creating a
circular dependency that prevents inserting either row first. Fix by:
1. Making owner_id nullable (set immediately after user creation)
2. Creating Account before User, then setting owner_id after flush
3. Removing NOT NULL enforcement on owner_id in migration 020

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-07 02:55:53 -05:00
parent 7a6f839ef4
commit 974e86a502
3 changed files with 29 additions and 21 deletions

View File

@@ -134,35 +134,47 @@ async def register(
detail="Email already registered"
)
# Create new user
new_user = User(
email=user_data.email,
password_hash=get_password_hash(user_data.password),
name=user_data.name,
role="engineer",
invite_code_id=invite_code_record.id if invite_code_record else None
)
db.add(new_user)
await db.flush() # Get user ID before creating account
if account_invite_record:
# Join existing account via account invite
new_user.account_id = account_invite_record.account_id
new_user.account_role = account_invite_record.role
new_user = User(
email=user_data.email,
password_hash=get_password_hash(user_data.password),
name=user_data.name,
role="engineer",
invite_code_id=invite_code_record.id if invite_code_record else None,
account_id=account_invite_record.account_id,
account_role=account_invite_record.role,
)
db.add(new_user)
await db.flush()
# Mark account invite as used
account_invite_record.accepted_by_id = new_user.id
account_invite_record.used_at = datetime.now(timezone.utc)
else:
# Create personal Account + free Subscription
# Create personal Account first (user needs account_id for NOT NULL constraint)
new_account = Account(
name=f"{user_data.name}'s Account",
display_code=_generate_display_code(),
owner_id=new_user.id,
)
db.add(new_account)
await db.flush() # Get account ID
new_user = User(
email=user_data.email,
password_hash=get_password_hash(user_data.password),
name=user_data.name,
role="engineer",
invite_code_id=invite_code_record.id if invite_code_record else None,
account_id=new_account.id,
account_role="owner",
)
db.add(new_user)
await db.flush() # Get user ID
# Now set account owner and create subscription
new_account.owner_id = new_user.id
new_subscription = Subscription(
account_id=new_account.id,
plan="free",
@@ -170,9 +182,6 @@ async def register(
)
db.add(new_subscription)
new_user.account_id = new_account.id
new_user.account_role = "owner"
# Mark platform invite code as used
if invite_code_record:
invite_code_record.used_by_id = new_user.id