# Phase 1: 기반 마스터 데이터

**기간:** 1-2주
**우선순위:** 최고 (모든 기능의 선행 조건)

## 📋 Phase 개요

모든 비즈니스 기능의 기반이 되는 핵심 마스터 데이터를 구축합니다.

**포함 기능:**
1. 회원관리 (User Management)
2. 테넌트관리 (Tenant Management)
3. 거래처관리 (Client Management)

---

## 1️⃣ 회원관리 (User Management)

### 기능 목록

#### 1.1 회원 목록 조회
- **경로:** `/mng/users`
- **기능:**
  - 페이지네이션 (기본 20개/페이지)
  - 검색 (이름, 이메일, 부서, 역할)
  - 필터 (활성/비활성, 역할별, 부서별)
  - 정렬 (가입일, 이름, 이메일)
- **권한:** `users.index`

#### 1.2 회원 상세 조회
- **경로:** `/mng/users/{id}`
- **기능:**
  - 기본 정보 표시
  - 소속 테넌트 정보
  - 역할/부서 정보
  - 최근 활동 로그
- **권한:** `users.show`

#### 1.3 회원 생성
- **경로:** `/mng/users/create`
- **기능:**
  - 기본 정보 입력 (이름, 이메일, 비밀번호)
  - 역할 할당 (다중 선택 가능)
  - 부서 할당
  - 활성/비활성 설정
- **권한:** `users.create`
- **검증:**
  - 이메일 중복 체크
  - 비밀번호 강도 검증 (8자 이상, 영문+숫자)
  - 필수 필드 검증

#### 1.4 회원 수정
- **경로:** `/mng/users/{id}/edit`
- **기능:**
  - 기본 정보 수정
  - 역할/부서 변경
  - 비밀번호 재설정
  - 활성/비활성 전환
- **권한:** `users.update`

#### 1.5 회원 삭제
- **경로:** `/mng/users/{id}`
- **기능:**
  - Soft Delete (복구 가능)
  - 삭제 확인 모달
  - 연관 데이터 처리 (담당 영업 등)
- **권한:** `users.delete`

#### 1.6 비밀번호 관리
- **경로:** `/mng/users/{id}/password`
- **기능:**
  - 관리자 비밀번호 재설정
  - 임시 비밀번호 발급 (이메일 전송)
  - 비밀번호 변경 이력 기록
- **권한:** `users.password.reset`

### DB 스키마

```sql
-- users 테이블 (Laravel 기본 + 확장)
CREATE TABLE users (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    tenant_id BIGINT UNSIGNED NULL COMMENT '소속 테넌트 ID',
    name VARCHAR(255) NOT NULL COMMENT '사용자 이름',
    email VARCHAR(255) UNIQUE NOT NULL COMMENT '이메일 (로그인 ID)',
    email_verified_at TIMESTAMP NULL COMMENT '이메일 인증 시각',
    password VARCHAR(255) NOT NULL COMMENT '비밀번호 (해시)',
    phone VARCHAR(20) NULL COMMENT '연락처',
    department_id BIGINT UNSIGNED NULL COMMENT '부서 ID',
    is_active BOOLEAN DEFAULT TRUE COMMENT '활성 여부',
    last_login_at TIMESTAMP NULL COMMENT '마지막 로그인',
    remember_token VARCHAR(100) NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL COMMENT 'Soft Delete',

    INDEX idx_tenant_id (tenant_id),
    INDEX idx_email (email),
    INDEX idx_department_id (department_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (department_id) REFERENCES departments(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- model_has_roles 테이블 (Spatie Permission)
-- 이미 존재하는 테이블 활용
```

### API 엔드포인트

| Method | Endpoint | Description | FormRequest |
|--------|----------|-------------|-------------|
| GET | `/mng/users` | 회원 목록 | - |
| GET | `/mng/users/{id}` | 회원 상세 | - |
| GET | `/mng/users/create` | 회원 생성 폼 | - |
| POST | `/mng/users` | 회원 생성 | `StoreUserRequest` |
| GET | `/mng/users/{id}/edit` | 회원 수정 폼 | - |
| PUT | `/mng/users/{id}` | 회원 수정 | `UpdateUserRequest` |
| DELETE | `/mng/users/{id}` | 회원 삭제 | - |
| POST | `/mng/users/{id}/password/reset` | 비밀번호 재설정 | `ResetPasswordRequest` |

### Service 클래스

```php
// app/Services/UserService.php
class UserService
{
    public function list(array $filters): LengthAwarePaginator;
    public function find(int $id): User;
    public function create(array $data): User;
    public function update(User $user, array $data): User;
    public function delete(User $user): bool;
    public function resetPassword(User $user, string $newPassword): bool;
    public function assignRoles(User $user, array $roleIds): void;
}
```

### UI/UX 와이어프레임 (텍스트)

```
┌─────────────────────────────────────────────────────────┐
│ 회원 관리                                    [+ 새 회원]  │
├─────────────────────────────────────────────────────────┤
│ 🔍 [검색: 이름, 이메일] [부서▼] [역할▼] [상태▼] [검색]│
├─────────────────────────────────────────────────────────┤
│ ☑ | 이름    | 이메일          | 부서   | 역할  | 상태 | 작업 │
│ ☐ | 홍길동  | hong@ex.com    | 개발팀 | Admin | 활성 | [수정][삭제] │
│ ☐ | 김철수  | kim@ex.com     | 영업팀 | User  | 활성 | [수정][삭제] │
├─────────────────────────────────────────────────────────┤
│ « 1 2 3 ... 10 »                                        │
└─────────────────────────────────────────────────────────┘
```

### 개발 체크리스트

- [ ] `User` 모델에 `BelongsToTenant` trait 추가
- [ ] `UserService` 클래스 작성 (비즈니스 로직)
- [ ] `StoreUserRequest`, `UpdateUserRequest` 작성 (검증)
- [ ] `UserController` 작성 (라우팅 처리)
- [ ] Blade 템플릿 작성 (`users/index.blade.php` 등)
- [ ] Alpine.js 인터랙션 추가 (모달, 검색 필터)
- [ ] 권한 체크 미들웨어 적용 (`can:users.index`)
- [ ] Audit Log 자동 기록 (UserObserver)
- [ ] i18n 키 작성 (`lang/ko/users.php`)
- [ ] Pint 포맷팅 및 PHPStan 검사 통과
- [ ] 테스트 작성 (`UserServiceTest`, `UserControllerTest`)

---

## 2️⃣ 테넌트관리 (Tenant Management)

### 기능 목록

#### 2.1 테넌트 목록 조회
- **경로:** `/mng/tenants`
- **기능:**
  - 페이지네이션
  - 검색 (회사명, 도메인)
  - 필터 (구독 상태, 플랜)
  - 정렬 (생성일, 회사명)
- **권한:** `tenants.index`

#### 2.2 테넌트 상세 조회
- **경로:** `/mng/tenants/{id}`
- **기능:**
  - 기본 정보 (회사명, 도메인, 연락처)
  - 구독 정보 (플랜, 만료일)
  - 사용 통계 (회원 수, 저장 용량)
  - 최근 결제 내역
- **권한:** `tenants.show`

#### 2.3 테넌트 생성
- **경로:** `/mng/tenants/create`
- **기능:**
  - 회사 정보 입력
  - 도메인 설정 (예: company.sam.kr)
  - 초기 구독 플랜 선택
  - 관리자 계정 생성
- **권한:** `tenants.create`

#### 2.4 테넌트 수정
- **경로:** `/mng/tenants/{id}/edit`
- **기능:**
  - 회사 정보 수정
  - 구독 플랜 변경
  - 활성/비활성 전환
- **권한:** `tenants.update`

#### 2.5 테넌트 삭제
- **경로:** `/mng/tenants/{id}`
- **기능:**
  - Soft Delete
  - 연관 데이터 처리 (사용자, 게시물 등)
  - 삭제 전 데이터 백업 권장
- **권한:** `tenants.delete`

### DB 스키마

```sql
CREATE TABLE tenants (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL COMMENT '회사명',
    domain VARCHAR(100) UNIQUE NOT NULL COMMENT '도메인 (예: company)',
    email VARCHAR(255) NOT NULL COMMENT '대표 이메일',
    phone VARCHAR(20) NULL COMMENT '대표 전화',
    address TEXT NULL COMMENT '주소',
    business_number VARCHAR(50) NULL COMMENT '사업자번호',
    subscription_plan ENUM('free', 'basic', 'pro', 'enterprise') DEFAULT 'free' COMMENT '구독 플랜',
    subscription_expires_at TIMESTAMP NULL COMMENT '구독 만료일',
    is_active BOOLEAN DEFAULT TRUE COMMENT '활성 여부',
    max_users INT DEFAULT 10 COMMENT '최대 사용자 수',
    storage_limit BIGINT DEFAULT 1073741824 COMMENT '저장 용량 제한 (바이트, 기본 1GB)',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_domain (domain),
    INDEX idx_subscription_plan (subscription_plan),
    INDEX idx_is_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### API 엔드포인트

| Method | Endpoint | Description | FormRequest |
|--------|----------|-------------|-------------|
| GET | `/mng/tenants` | 테넌트 목록 | - |
| GET | `/mng/tenants/{id}` | 테넌트 상세 | - |
| GET | `/mng/tenants/create` | 테넌트 생성 폼 | - |
| POST | `/mng/tenants` | 테넌트 생성 | `StoreTenantRequest` |
| GET | `/mng/tenants/{id}/edit` | 테넌트 수정 폼 | - |
| PUT | `/mng/tenants/{id}` | 테넌트 수정 | `UpdateTenantRequest` |
| DELETE | `/mng/tenants/{id}` | 테넌트 삭제 | - |

### Service 클래스

```php
// app/Services/TenantService.php
class TenantService
{
    public function list(array $filters): LengthAwarePaginator;
    public function find(int $id): Tenant;
    public function create(array $data): Tenant;
    public function update(Tenant $tenant, array $data): Tenant;
    public function delete(Tenant $tenant): bool;
    public function changePlan(Tenant $tenant, string $plan): bool;
    public function getUsageStats(Tenant $tenant): array;
}
```

### 개발 체크리스트

- [ ] `Tenant` 모델 작성 (BelongsToTenant 제외 - 최상위)
- [ ] `TenantService` 클래스 작성
- [ ] `StoreTenantRequest`, `UpdateTenantRequest` 작성
- [ ] `TenantController` 작성
- [ ] Blade 템플릿 작성
- [ ] 구독 플랜 변경 로직 구현
- [ ] 사용량 통계 계산 로직 (회원 수, 저장 용량)
- [ ] i18n 키 작성
- [ ] 테스트 작성

---

## 3️⃣ 거래처관리 (Client Management)

### 기능 목록

#### 3.1 거래처 목록 조회
- **경로:** `/mng/clients`
- **기능:**
  - 페이지네이션
  - 검색 (회사명, 담당자명)
  - 필터 (거래 상태, 업종)
  - 정렬 (생성일, 회사명)
- **권한:** `clients.index`

#### 3.2 거래처 상세 조회
- **경로:** `/mng/clients/{id}`
- **기능:**
  - 기본 정보 (회사명, 연락처, 주소)
  - 담당자 정보 (이름, 직책, 연락처)
  - 거래 이력 (견적서, 계약)
  - 메모/코멘트
- **권한:** `clients.show`

#### 3.3 거래처 생성
- **경로:** `/mng/clients/create`
- **기능:**
  - 회사 정보 입력
  - 담당자 정보 입력 (다중 가능)
  - 업종/분류 선택
  - 메모 작성
- **권한:** `clients.create`

#### 3.4 거래처 수정
- **경로:** `/mng/clients/{id}/edit`
- **기능:**
  - 기본 정보 수정
  - 담당자 추가/수정/삭제
  - 거래 상태 변경
- **권한:** `clients.update`

#### 3.5 거래처 삭제
- **경로:** `/mng/clients/{id}`
- **기능:**
  - Soft Delete
  - 연관 데이터 체크 (진행 중인 견적서 등)
- **권한:** `clients.delete`

### DB 스키마

```sql
CREATE TABLE clients (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    tenant_id BIGINT UNSIGNED NOT NULL COMMENT '소속 테넌트',
    name VARCHAR(255) NOT NULL COMMENT '회사명',
    business_number VARCHAR(50) NULL COMMENT '사업자번호',
    industry VARCHAR(100) NULL COMMENT '업종',
    phone VARCHAR(20) NULL COMMENT '대표 전화',
    email VARCHAR(255) NULL COMMENT '대표 이메일',
    address TEXT NULL COMMENT '주소',
    status ENUM('active', 'inactive', 'potential') DEFAULT 'potential' COMMENT '거래 상태',
    notes TEXT NULL COMMENT '메모',
    assigned_user_id BIGINT UNSIGNED NULL COMMENT '담당 영업 사원',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_tenant_id (tenant_id),
    INDEX idx_status (status),
    INDEX idx_assigned_user_id (assigned_user_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (assigned_user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE client_contacts (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    client_id BIGINT UNSIGNED NOT NULL COMMENT '거래처 ID',
    name VARCHAR(255) NOT NULL COMMENT '담당자 이름',
    position VARCHAR(100) NULL COMMENT '직책',
    phone VARCHAR(20) NULL COMMENT '연락처',
    email VARCHAR(255) NULL COMMENT '이메일',
    is_primary BOOLEAN DEFAULT FALSE COMMENT '주 담당자 여부',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    INDEX idx_client_id (client_id),
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### API 엔드포인트

| Method | Endpoint | Description | FormRequest |
|--------|----------|-------------|-------------|
| GET | `/mng/clients` | 거래처 목록 | - |
| GET | `/mng/clients/{id}` | 거래처 상세 | - |
| GET | `/mng/clients/create` | 거래처 생성 폼 | - |
| POST | `/mng/clients` | 거래처 생성 | `StoreClientRequest` |
| GET | `/mng/clients/{id}/edit` | 거래처 수정 폼 | - |
| PUT | `/mng/clients/{id}` | 거래처 수정 | `UpdateClientRequest` |
| DELETE | `/mng/clients/{id}` | 거래처 삭제 | - |
| POST | `/mng/clients/{id}/contacts` | 담당자 추가 | `StoreContactRequest` |

### Service 클래스

```php
// app/Services/ClientService.php
class ClientService
{
    public function list(array $filters): LengthAwarePaginator;
    public function find(int $id): Client;
    public function create(array $data): Client;
    public function update(Client $client, array $data): Client;
    public function delete(Client $client): bool;
    public function addContact(Client $client, array $contactData): ClientContact;
    public function getTransactionHistory(Client $client): Collection;
}
```

### 개발 체크리스트

- [ ] `Client`, `ClientContact` 모델 작성 (BelongsToTenant)
- [ ] `ClientService` 클래스 작성
- [ ] FormRequest 작성
- [ ] `ClientController` 작성
- [ ] Blade 템플릿 작성 (담당자 다중 입력 UI)
- [ ] 거래 이력 연동 (견적서, 계약)
- [ ] 담당 영업 사원 할당 기능
- [ ] i18n 키 작성
- [ ] 테스트 작성

---

## 🎯 Phase 1 완료 조건

### 기능 완성도
- [ ] 3개 모듈 모두 CRUD 완성
- [ ] 각 모듈별 검색/필터/정렬 동작
- [ ] 권한 체크 정상 작동

### 코드 품질
- [ ] Service-First 패턴 준수
- [ ] FormRequest 검증 구현
- [ ] BelongsToTenant trait 적용
- [ ] i18n 키 사용 (한글 직접 사용 금지)
- [ ] Pint 포맷팅 통과
- [ ] PHPStan Level 5+ 통과

### 데이터 무결성
- [ ] Multi-tenant 격리 확인
- [ ] Soft Delete 동작 확인
- [ ] Audit Log 자동 기록 확인
- [ ] Foreign Key 제약 조건 정상 작동

### 테스트
- [ ] Service 계층 유닛 테스트
- [ ] Controller 계층 Feature 테스트
- [ ] 권한 체크 테스트
- [ ] 검증 로직 테스트

---

## 📚 참고 자료

- **SAM API Rules:** `API_RULES.md`
- **개발 명령어:** `DEV_COMMANDS.md`
- **품질 체크리스트:** `QUALITY_CHECKLIST.md`

---

**최종 업데이트:** 2025-11-21
**작성자:** Claude Code
**버전:** 1.0.0