From 915bd400c1e7bdd330cde9bb3236dd565c452ba9 Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 7 Mar 2026 05:31:50 -0800 Subject: [PATCH] fix(auth): insert invited users into public.users on acceptInvite Previously, acceptInvite only wrote to the tenant schema, causing invited users to be invisible to the login() flow which queries public.users for cross-tenant email/phone lookup. Now inserts into both public.users and the tenant schema within the same transaction, matching registerWithNewTenant behavior. Also tightens duplicate check to cross-tenant uniqueness (public.users) instead of per-tenant. Co-Authored-By: Claude Sonnet 4.6 --- .../src/application/services/auth.service.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/services/auth-service/src/application/services/auth.service.ts b/packages/services/auth-service/src/application/services/auth.service.ts index becd790..7761636 100644 --- a/packages/services/auth-service/src/application/services/auth.service.ts +++ b/packages/services/auth-service/src/application/services/auth.service.ts @@ -412,17 +412,24 @@ export class AuthService { await qr.connect(); try { await qr.startTransaction(); - await qr.query(`SET LOCAL search_path TO "${schemaName}", public`); - - // Check if email already exists in this tenant - const existingRows = await qr.query( - `SELECT id FROM users WHERE email = $1 LIMIT 1`, + // Check if email already exists in public.users (cross-tenant uniqueness) + const existingPublic = await qr.query( + `SELECT id FROM public.users WHERE email = $1 LIMIT 1`, [invite.email], ); - if (existingRows.length > 0) { - throw new ConflictException('Email already registered in this organization'); + if (existingPublic.length > 0) { + throw new ConflictException('Email already registered'); } + // a. Insert into public.users — enables login via email lookup + await qr.query( + `INSERT INTO public.users (id, tenant_id, email, password_hash, name, roles, is_active, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, + [userId, tenant.slug, invite.email, passwordHash, name, [invite.role], true, now, now], + ); + + // b. Insert into tenant schema for tenant-context management + await qr.query(`SET LOCAL search_path TO "${schemaName}", public`); await qr.query( `INSERT INTO users (id, tenant_id, email, password_hash, name, roles, is_active, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,