From f5534e437b01d1cb3bb21bcb151fb6b28be22939 Mon Sep 17 00:00:00 2001 From: kent Date: Sat, 26 Jul 2025 01:23:02 +0900 Subject: [PATCH] =?UTF-8?q?fix=20:=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 신규 (user_roles, user_tenants) - 수정 (roles, tenants, users) --- app/Models/Role.php | 10 ++++ app/Models/Tenant.php | 20 ++++++++ app/Models/User.php | 40 ++++++--------- app/Models/UserRole.php | 31 +++++++++++ app/Models/UserTenant.php | 25 +++++++++ .../2025_07_26_000818_create_roles_table.php | 36 +++++++++++++ .../2025_07_26_000818_create_users_table.php | 51 +++++++++++++++++++ ...5_07_26_000819_create_user_roles_table.php | 31 +++++++++++ ...07_26_000819_create_user_tenants_table.php | 30 +++++++++++ ...1922_remove_tenant_id_from_users_table.php | 26 ++++++++++ 10 files changed, 276 insertions(+), 24 deletions(-) create mode 100644 app/Models/UserRole.php create mode 100644 app/Models/UserTenant.php create mode 100644 database/migrations/2025_07_26_000818_create_roles_table.php create mode 100644 database/migrations/2025_07_26_000818_create_users_table.php create mode 100644 database/migrations/2025_07_26_000819_create_user_roles_table.php create mode 100644 database/migrations/2025_07_26_000819_create_user_tenants_table.php create mode 100644 database/migrations/2025_07_26_011922_remove_tenant_id_from_users_table.php diff --git a/app/Models/Role.php b/app/Models/Role.php index 4043f53..cc2521b 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -14,4 +14,14 @@ public function menuPermissions() { return $this->hasMany(RoleMenuPermission::class, 'role_id'); } + + public function tenant() + { + return $this->belongsTo(Tenant::class); + } + + public function userRoles() + { + return $this->hasMany(UserRole::class); + } } diff --git a/app/Models/Tenant.php b/app/Models/Tenant.php index a6856dc..fe7e18f 100644 --- a/app/Models/Tenant.php +++ b/app/Models/Tenant.php @@ -42,4 +42,24 @@ public function subscription() { return $this->belongsTo(Subscription::class, 'subscription_id'); } + + public function userTenants() + { + return $this->hasMany(UserTenant::class); + } + + public function users() + { + return $this->belongsToMany(User::class, 'user_tenants'); + } + + public function roles() + { + return $this->hasMany(Role::class); + } + + public function userRoles() + { + return $this->hasMany(UserRole::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 8d5ccb6..42dfed1 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,37 +6,29 @@ use Illuminate\Notifications\Notifiable; use Laravel\Fortify\TwoFactorAuthenticatable; use Laravel\Sanctum\HasApiTokens; -use App\Traits\UppercaseAttributes; class User extends Authenticatable { - use HasApiTokens, Notifiable, TwoFactorAuthenticatable; + use HasApiTokens, Notifiable, TwoFactorAuthenticatable, SoftDeletes; - protected $table = 'members'; // 테이블 이름 변경 - - protected $primaryKey = 'mb_id'; // 기본 키 변경 - - protected $fillable = [ - 'mb_id', 'mb_pass', 'mb_name', 'mb_phone', 'mb_mail', - 'email_verified_at', 'mb_type', 'mb_level', 'last_login', - 'reg_date', 'remember_token' - ]; - - protected $hidden = [ - 'mb_pass', 'remember_token', - ]; - - protected $casts = [ - 'reg_date' => 'datetime', - ]; - - public function getAuthPassword() + public function userTenants() { - return $this->mb_pass; // 기본 비밀번호 필드를 mb_pass로 설정 + return $this->hasMany(UserTenant::class); } - public function getAuthIdentifierName() + public function tenants() { - return 'mb_id'; // 기본 로그인 필드를 mb_id로 변경 + return $this->belongsToMany(Tenant::class, 'user_tenants'); + } + + public function userRoles() + { + return $this->hasMany(UserRole::class); + } + + public function roles() + { + return $this->belongsToMany(Role::class, 'user_roles') + ->withPivot('tenant_id', 'assigned_at'); } } diff --git a/app/Models/UserRole.php b/app/Models/UserRole.php new file mode 100644 index 0000000..d3f4955 --- /dev/null +++ b/app/Models/UserRole.php @@ -0,0 +1,31 @@ +belongsTo(User::class); + } + + public function tenant() + { + return $this->belongsTo(Tenant::class); + } + + public function role() + { + return $this->belongsTo(Role::class); + } +} diff --git a/app/Models/UserTenant.php b/app/Models/UserTenant.php new file mode 100644 index 0000000..3361721 --- /dev/null +++ b/app/Models/UserTenant.php @@ -0,0 +1,25 @@ +belongsTo(User::class); + } + + public function tenant() + { + return $this->belongsTo(Tenant::class); + } +} diff --git a/database/migrations/2025_07_26_000818_create_roles_table.php b/database/migrations/2025_07_26_000818_create_roles_table.php new file mode 100644 index 0000000..fed9fc2 --- /dev/null +++ b/database/migrations/2025_07_26_000818_create_roles_table.php @@ -0,0 +1,36 @@ +unsignedBigInteger('tenant_id')->nullable(false)->change(); + $table->string('name', 50)->comment('역할명')->change(); + $table->string('description', 255)->nullable()->comment('설명')->change(); + + // deleted_at 추가 (soft delete) + $table->softDeletes()->comment('삭제일시(소프트삭제)'); + }); + + // 2. (권장) 유니크 인덱스 보장: 한 테넌트 내에서 동일한 역할명 중복 불가 + Schema::table('roles', function (Blueprint $table) { + $table->unique(['tenant_id', 'name'], 'uk_roles_tenant_name'); + }); + } + + public function down(): void + { + Schema::table('roles', function (Blueprint $table) { + // 롤백시 soft delete 및 인덱스 제거 + $table->dropSoftDeletes(); + $table->dropUnique('uk_roles_tenant_name'); + }); + } +}; diff --git a/database/migrations/2025_07_26_000818_create_users_table.php b/database/migrations/2025_07_26_000818_create_users_table.php new file mode 100644 index 0000000..e7fb099 --- /dev/null +++ b/database/migrations/2025_07_26_000818_create_users_table.php @@ -0,0 +1,51 @@ +unsignedBigInteger('tenant_id')->after('id')->comment('FK: 테넌트 ID')->default(1); // default 값은 마이그레이션 중 기존 데이터 보호용 + + // 2. 컬럼별 주석 보강 + $table->string('name', 255)->comment('회원 이름')->change(); + $table->string('email', 255)->comment('이메일')->change(); + $table->string('password', 255)->comment('비밀번호')->change(); + $table->string('profile_photo_path', 2048)->nullable()->comment('프로필 사진 경로')->change(); + $table->string('remember_token', 100)->nullable()->comment('자동로그인 토큰')->change(); + + // 3. soft delete 추가 + $table->softDeletes()->comment('삭제일시(소프트삭제)'); + + // 4. 유니크키 변경: (tenant_id, email)로 + $table->dropUnique(['email']); + $table->unique(['tenant_id', 'email'], 'uk_users_tenant_email'); + }); + + // FK 추가 (이미 tenants 테이블이 있어야 함) + Schema::table('users', function (Blueprint $table) { + $table->foreign('tenant_id')->references('id')->on('tenants'); + }); + } + + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + // 롤백: FK/유니크/컬럼 제거 + $table->dropForeign(['tenant_id']); + $table->dropUnique('uk_users_tenant_email'); + $table->dropColumn('tenant_id'); + $table->dropSoftDeletes(); + }); + + // 기존 유니크 복구 + Schema::table('users', function (Blueprint $table) { + $table->unique('email'); + }); + } +}; diff --git a/database/migrations/2025_07_26_000819_create_user_roles_table.php b/database/migrations/2025_07_26_000819_create_user_roles_table.php new file mode 100644 index 0000000..b9f5f28 --- /dev/null +++ b/database/migrations/2025_07_26_000819_create_user_roles_table.php @@ -0,0 +1,31 @@ +bigIncrements('id')->comment('PK: 회원별 역할 매핑 ID'); + $table->unsignedBigInteger('user_id')->comment('FK: 회원ID'); + $table->unsignedBigInteger('tenant_id')->comment('FK: 테넌트ID'); + $table->unsignedBigInteger('role_id')->comment('FK: 역할ID'); + $table->timestamp('assigned_at')->nullable()->comment('역할 할당일'); + $table->timestamps(); + $table->softDeletes()->comment('삭제일시(소프트삭제)'); + + $table->unique(['user_id', 'tenant_id', 'role_id'], 'uk_user_tenant_role'); + $table->foreign('user_id')->references('id')->on('users'); + $table->foreign('tenant_id')->references('id')->on('tenants'); + $table->foreign('role_id')->references('id')->on('roles'); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_roles'); + } +}; diff --git a/database/migrations/2025_07_26_000819_create_user_tenants_table.php b/database/migrations/2025_07_26_000819_create_user_tenants_table.php new file mode 100644 index 0000000..44753d1 --- /dev/null +++ b/database/migrations/2025_07_26_000819_create_user_tenants_table.php @@ -0,0 +1,30 @@ +bigIncrements('id')->comment('PK: 회원-테넌트 소속 ID'); + $table->unsignedBigInteger('user_id')->comment('FK: 회원ID'); + $table->unsignedBigInteger('tenant_id')->comment('FK: 테넌트ID'); + $table->boolean('is_active')->default(1)->comment('활성화 여부'); + $table->timestamp('joined_at')->nullable()->comment('소속일시'); + $table->timestamp('left_at')->nullable()->comment('탈퇴일시'); + $table->timestamps(); + $table->softDeletes()->comment('삭제일시(소프트삭제)'); + + $table->unique(['user_id', 'tenant_id'], 'uk_user_tenant'); + $table->foreign('user_id')->references('id')->on('users'); + $table->foreign('tenant_id')->references('id')->on('tenants'); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_tenants'); + } +}; diff --git a/database/migrations/2025_07_26_011922_remove_tenant_id_from_users_table.php b/database/migrations/2025_07_26_011922_remove_tenant_id_from_users_table.php new file mode 100644 index 0000000..c623758 --- /dev/null +++ b/database/migrations/2025_07_26_011922_remove_tenant_id_from_users_table.php @@ -0,0 +1,26 @@ +dropForeign('users_tenant_id_foreign'); + // 컬럼 삭제 + $table->dropColumn('tenant_id'); + }); + } + + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->unsignedBigInteger('tenant_id')->nullable()->comment('테넌트ID'); + $table->foreign('tenant_id')->references('id')->on('tenants')->onDelete('set null'); + }); + } +};