feat: role 컬럼을 ENUM에서 VARCHAR(20)으로 변경

- 향후 확장성을 위해 VARCHAR 사용
- 새로운 role 값 추가 시 스키마 변경 불필요
- sales@sam.kr만 'sales', 나머지는 'tenant'로 설정
This commit is contained in:
2025-10-14 20:49:51 +09:00
parent d42fd96535
commit 14023e8160
2 changed files with 220 additions and 0 deletions

View File

@@ -1,5 +1,188 @@
# SAM API 저장소 작업 현황
## 2025-10-14 (화) - role 컬럼 타입 변경 (ENUM → VARCHAR)
### 주요 작업
- **role 컬럼 타입 변경**: ENUM에서 VARCHAR(20)으로 변경하여 향후 확장성 확보
- **데이터 마이그레이션**: sales@sam.kr 제외한 모든 sales role을 tenant로 자동 변경
- **마이그레이션 검증**: 스키마 및 데이터 정상 변경 확인
### 추가된 파일:
- `database/migrations/2025_10_14_204237_change_role_column_to_varchar_in_users_table.php` - role 컬럼 타입 변경 마이그레이션
### 작업 내용:
#### 1. 마이그레이션 배경
**기존 문제점:**
- role 컬럼이 ENUM('sales', 'ops')로 정의되어 확장성 제한
- 새로운 role 추가 시마다 DB 스키마 변경 필요 (ALTER TABLE)
- 'tenant' role 추가 필요성 발생
**해결 방안:**
- VARCHAR(20)으로 변경하여 애플리케이션 레벨에서 자유롭게 role 관리
- 스키마 변경 없이 새로운 role 추가 가능
- 향후 확장성 확보
#### 2. 마이그레이션 구현
**up() 메서드:**
```php
public function up(): void
{
// role ENUM을 VARCHAR로 변경
DB::statement("ALTER TABLE users MODIFY COLUMN role VARCHAR(20) NOT NULL DEFAULT 'sales' COMMENT '사용자 역할 (sales: 영업사원, ops: 운영, tenant: 테넌트)'");
// sales@sam.kr 제외한 나머지 sales role을 tenant로 변경
DB::table('users')
->where('role', 'sales')
->where('email', '!=', 'sales@sam.kr')
->update(['role' => 'tenant']);
}
```
**down() 메서드 (롤백):**
```php
public function down(): void
{
// tenant를 sales로 되돌림
DB::table('users')
->where('role', 'tenant')
->update(['role' => 'sales']);
// role을 다시 ENUM으로 변경
DB::statement("ALTER TABLE users MODIFY COLUMN role ENUM('sales', 'ops') NOT NULL DEFAULT 'sales'");
}
```
#### 3. 마이그레이션 실행 결과
**실행 명령:**
```bash
php artisan migrate
```
**실행 시간:**
```
2025_10_14_204237_change_role_column_to_varchar_in_users_table ... 37.02ms DONE
```
#### 4. 검증 결과
**데이터 확인:**
```
현재 사용자 계정 상태:
shine1324@gmail.com : ops (슈퍼 관리자)
ops@sam.kr : ops (일반 운영)
sales@sam.kr : sales (영업사원)
1 : tenant (테넌트)
test@5130.co.kr : tenant (테넌트)
test@gmail.com : tenant (테넌트)
codebridge@gmail.com : tenant (테넌트)
codebridge1@gmail.com : tenant (테넌트)
codebridge2@gmail.com : tenant (테넌트)
codebridge001@gmail.com : tenant (테넌트)
codebridge003@gmail.com : tenant (테넌트)
test01@gmail.com : tenant (테넌트)
```
**스키마 확인:**
```
Field: role
Type: varchar(20)
Null: NO
Key:
Default: sales
Extra:
```
**검증 완료:**
- role 컬럼이 VARCHAR(20)으로 정상 변경
- sales@sam.kr만 'sales' role 유지
- 나머지 사용자 모두 'tenant' role로 변경
- NOT NULL 제약 유지
- Default 값 'sales' 유지
#### 5. 기술적 의사결정
**ENUM vs VARCHAR 비교:**
| 항목 | ENUM | VARCHAR |
|------|------|---------|
| 저장 공간 | 1-2 bytes (효율적) | 20 bytes (여유 있음) |
| 성능 | 약간 빠름 | 충분히 빠름 |
| 확장성 | ❌ 스키마 변경 필요 | ✅ 코드만 변경 |
| 유지보수 | ❌ ALTER TABLE 필요 | ✅ 애플리케이션 레벨 |
| 타입 안전성 | ✅ DB 레벨 검증 | ⚠️ 애플리케이션 검증 |
**최종 결정: VARCHAR 선택**
- SAM 프로젝트는 확장성이 더 중요
- role 종류가 추가될 가능성 높음 (manager, admin, guest 등)
- 성능 차이는 무시할 수준 (users 테이블 규모)
- 타입 검증은 Laravel Validation으로 충분
#### 6. 향후 role 추가 방법
**새로운 role 추가 시:**
```php
// 1. 애플리케이션 코드만 수정 (DB 변경 불필요!)
// User 모델에 상수 추가
class User extends Authenticatable
{
public const ROLE_SALES = 'sales';
public const ROLE_OPS = 'ops';
public const ROLE_TENANT = 'tenant';
public const ROLE_MANAGER = 'manager'; // 새로 추가!
public const ROLES = [
self::ROLE_SALES,
self::ROLE_OPS,
self::ROLE_TENANT,
self::ROLE_MANAGER, // 새로 추가!
];
}
// 2. Validation Rule에 추가
'role' => ['required', Rule::in(User::ROLES)],
// 3. 권한 로직에 추가
public function isManager(): bool
{
return $this->role === self::ROLE_MANAGER;
}
```
**DB 스키마 변경 없음!**
#### 7. SAM API Development Rules 준수
**데이터베이스 설계:**
- VARCHAR(20) 충분한 길이 확보
- NOT NULL 제약 유지
- DEFAULT 값 설정
- COMMENT 추가로 문서화
**마이그레이션 패턴:**
- up()/down() 모두 구현
- 데이터 마이그레이션 포함
- 롤백 가능한 구조
**코드 품질:**
- 명확한 의도 표현
- 주석으로 로직 설명
- 검증 가능한 결과
### 향후 개선 사항:
- [ ] User 모델에 ROLE 상수 정의 추가
- [ ] FormRequest에 role validation Rule::in() 추가
- [ ] 권한 체크 로직을 메서드로 추출 (isAdmin(), isSales() 등)
- [ ] role 변경 이력 감사 로그 추가 고려
---
## 2025-10-13 (월) - Swagger 문서 전면 수정 및 ClientGroup 자동 복원 기능 추가
### 주요 작업

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// role ENUM을 VARCHAR로 변경
DB::statement("ALTER TABLE users MODIFY COLUMN role VARCHAR(20) NOT NULL DEFAULT 'sales' COMMENT '사용자 역할 (sales: 영업사원, ops: 운영, tenant: 테넌트)'");
// sales@sam.kr 제외한 나머지 sales role을 tenant로 변경
DB::table('users')
->where('role', 'sales')
->where('email', '!=', 'sales@sam.kr')
->update(['role' => 'tenant']);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// tenant를 sales로 되돌림
DB::table('users')
->where('role', 'tenant')
->update(['role' => 'sales']);
// role을 다시 ENUM으로 변경
DB::statement("ALTER TABLE users MODIFY COLUMN role ENUM('sales', 'ops') NOT NULL DEFAULT 'sales'");
}
};