From 12ca2cf4d3632d594f557cf6200ccf70b691a19a Mon Sep 17 00:00:00 2001 From: kent Date: Wed, 14 Jan 2026 20:29:00 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=82=AC=EC=9B=90=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EC=8B=9C=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=20=EC=B2=B4=ED=81=AC=20=EB=B0=8F=20user=5Fid=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이메일 중복 체크 추가 (삭제된 사용자 포함) - generateUniqueUserId() 메서드 추가 (중복 시 최대 10회 재시도) - email_already_exists 에러 메시지 추가 Co-Authored-By: Claude --- app/Services/EmployeeService.php | 38 +++++++++++++++++++++++++------- lang/ko/error.php | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/app/Services/EmployeeService.php b/app/Services/EmployeeService.php index 94f6d7f..8baddd9 100644 --- a/app/Services/EmployeeService.php +++ b/app/Services/EmployeeService.php @@ -98,14 +98,23 @@ public function store(array $data): TenantUserProfile $tenantId = $this->tenantId(); $userId = $this->apiUserId(); - return DB::transaction(function () use ($data, $tenantId, $userId) { - // 1. 비밀번호 결정: password가 있으면 시스템 계정 생성 + // 1. 이메일 중복 체크 (전역 유니크) + $existingUser = User::withTrashed()->where('email', $data['email'])->first(); + if ($existingUser) { + throw new \InvalidArgumentException(__('error.email_already_exists')); + } + + // 2. user_id 중복 체크 및 유니크 ID 생성 + $userIdValue = $data['user_id'] ?? $this->generateUniqueUserId($data['email']); + + return DB::transaction(function () use ($data, $tenantId, $userId, $userIdValue) { + // 3. 비밀번호 결정: password가 있으면 시스템 계정 생성 // User 모델에 'password' => 'hashed' 캐스트가 있으므로 Hash::make() 불필요 $password = ! empty($data['password']) ? $data['password'] : null; - // 2. users 테이블에 사용자 생성 + // 4. users 테이블에 사용자 생성 $user = User::create([ - 'user_id' => $data['user_id'] ?? $this->generateUserId($data['email']), + 'user_id' => $userIdValue, 'name' => $data['name'], 'email' => $data['email'], 'phone' => $data['phone'] ?? null, @@ -377,13 +386,26 @@ public function revokeAccount(int $id): TenantUserProfile } /** - * 사용자 ID 자동 생성 + * 유니크한 사용자 ID 자동 생성 + * 중복 시 최대 10회까지 재시도 */ - private function generateUserId(string $email): string + private function generateUniqueUserId(string $email): string { $prefix = explode('@', $email)[0]; - $suffix = Str::random(4); + $prefix = strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $prefix)); - return strtolower($prefix.'_'.$suffix); + $maxAttempts = 10; + for ($i = 0; $i < $maxAttempts; $i++) { + $suffix = Str::random(6); // 4자리 → 6자리로 증가 + $userId = $prefix.'_'.$suffix; + + // 중복 체크 (삭제된 사용자 포함) + if (! User::withTrashed()->where('user_id', $userId)->exists()) { + return $userId; + } + } + + // 최대 시도 후에도 실패 시 타임스탬프 추가 + return $prefix.'_'.time().'_'.Str::random(4); } } diff --git a/lang/ko/error.php b/lang/ko/error.php index a733978..c25e8e7 100644 --- a/lang/ko/error.php +++ b/lang/ko/error.php @@ -22,6 +22,7 @@ // 검증/파라미터 'validation_failed' => '요청 데이터 검증에 실패했습니다.', // 422 'missing_parameter' => '필수 파라미터가 누락되었습니다.', // 400 + 'email_already_exists' => '이미 사용 중인 이메일 주소입니다.', // 400 'business_num_format' => '사업자등록번호 형식이 올바르지 않습니다 (000-00-00000)', 'business_num_duplicate_active' => '이미 등록된 사업자등록번호입니다 (정식 서비스 업체)', 'user_id_format' => '아이디는 영문, 숫자, _, - 만 사용할 수 있습니다',