184 lines
6.2 KiB
Markdown
184 lines
6.2 KiB
Markdown
|
|
# 논리적 데이터베이스 관계 문서
|
||
|
|
|
||
|
|
> FK 제약조건 제거 후 개발자 참조용 논리적 관계 명세서
|
||
|
|
>
|
||
|
|
> **생성일**: 2025-09-24
|
||
|
|
> **마이그레이션 batch**: 17까지 적용됨
|
||
|
|
|
||
|
|
## 🎯 목적
|
||
|
|
|
||
|
|
물리적 FK 제약조건을 제거하여 성능과 관리 편의성을 확보하면서도,
|
||
|
|
개발자들이 비즈니스 로직에서 참조해야 할 **논리적 관계**를 명시합니다.
|
||
|
|
|
||
|
|
## 📋 FK 제거 현황
|
||
|
|
|
||
|
|
### ✅ 제거된 FK 제약조건 (4개)
|
||
|
|
|
||
|
|
| 테이블 | 컬럼 | 참조 테이블 | 참조 컬럼 | 제거 단계 | 효과 |
|
||
|
|
|--------|------|-------------|-----------|----------|------|
|
||
|
|
| `classifications` | `tenant_id` | `tenants` | `id` | Phase 1 | 분류 코드 관리 유연성 |
|
||
|
|
| `departments` | `parent_id` | `departments` | `id` | Phase 1 | 부서 구조 변경 유연성 |
|
||
|
|
| `estimates` | `model_set_id` | `categories` | `id` | Phase 2 | 견적 성능 향상 |
|
||
|
|
| `estimate_items` | `estimate_id` | `estimates` | `id` | Phase 2 | 견적 아이템 성능 향상 |
|
||
|
|
|
||
|
|
### 🔒 유지된 중요 FK 제약조건 (40+개)
|
||
|
|
|
||
|
|
**멀티테넌트 보안 FK** (필수 유지):
|
||
|
|
- 모든 `tenant_id → tenants.id` 관계 유지
|
||
|
|
- 사용자 권한 관련 FK 모두 유지
|
||
|
|
|
||
|
|
**핵심 비즈니스 FK** (필수 유지):
|
||
|
|
- `products.category_id → categories.id`
|
||
|
|
- 권한 관리 시스템 (users, roles, permissions)
|
||
|
|
- 주문 관리 시스템 (orders, order_items, clients)
|
||
|
|
|
||
|
|
## 🧩 논리적 관계 명세
|
||
|
|
|
||
|
|
### 1. 분류 관리 (Classifications)
|
||
|
|
```
|
||
|
|
classifications (분류 코드)
|
||
|
|
├── tenant_id → tenants.id (논리적 - 멀티테넌트)
|
||
|
|
└── [Eloquent Model에서 BelongsToTenant 트레잇으로 관리]
|
||
|
|
```
|
||
|
|
|
||
|
|
**개발 시 주의사항:**
|
||
|
|
- Service 레이어에서 테넌트 격리 검증 필수
|
||
|
|
- 분류 삭제 시 사용 중인 참조 확인 필요
|
||
|
|
|
||
|
|
### 2. 부서 관리 (Departments)
|
||
|
|
```
|
||
|
|
departments (부서)
|
||
|
|
├── parent_id → departments.id (논리적 - 계층 구조)
|
||
|
|
└── [자기 참조 관계, Soft Delete 적용]
|
||
|
|
```
|
||
|
|
|
||
|
|
**개발 시 주의사항:**
|
||
|
|
- 부서 삭제 시 하위 부서 존재 여부 확인
|
||
|
|
- 순환 참조 방지 로직 필요
|
||
|
|
- 사용자 배치 여부 확인 후 삭제
|
||
|
|
|
||
|
|
### 3. 견적 시스템 (Estimates)
|
||
|
|
```
|
||
|
|
estimates (견적)
|
||
|
|
├── model_set_id → categories.id (논리적 - 스냅샷 특성)
|
||
|
|
├── tenant_id → tenants.id (물리적 FK 유지 - 보안)
|
||
|
|
└── [견적은 생성 시점 데이터 보존]
|
||
|
|
|
||
|
|
estimate_items (견적 아이템)
|
||
|
|
├── estimate_id → estimates.id (논리적 - 성능 최적화)
|
||
|
|
├── tenant_id → tenants.id (물리적 FK 유지 - 보안)
|
||
|
|
└── [대량 데이터 처리 성능 우선]
|
||
|
|
```
|
||
|
|
|
||
|
|
**개발 시 주의사항:**
|
||
|
|
- 견적 데이터는 스냅샷 특성상 참조 무결성보다 성능 우선
|
||
|
|
- 카테고리 변경이 기존 견적에 영향주지 않도록 주의
|
||
|
|
- 대량 견적 아이템 처리 시 batch 작업 권장
|
||
|
|
|
||
|
|
### 4. BOM 시스템 (Product Components)
|
||
|
|
```
|
||
|
|
product_components (제품 구성요소)
|
||
|
|
├── parent_product_id → products.id (물리적 FK 없음 - 이미 유연한 구조)
|
||
|
|
├── ref_type: 'MATERIAL' | 'PRODUCT' (참조 타입)
|
||
|
|
├── ref_id → materials.id | products.id (논리적 - ref_type에 따라)
|
||
|
|
└── [통합 참조 구조로 설계됨]
|
||
|
|
```
|
||
|
|
|
||
|
|
**개발 시 주의사항:**
|
||
|
|
- ref_type 값에 따라 ref_id 해석 필요
|
||
|
|
- 자재/제품 삭제 시 BOM 영향도 분석 필수
|
||
|
|
- Service 레이어에서 참조 무결성 검증 구현
|
||
|
|
|
||
|
|
## 📈 성능 최적화 효과
|
||
|
|
|
||
|
|
### 제거된 FK의 성능 영향
|
||
|
|
|
||
|
|
1. **Classifications**: 분류 코드 조회 성능 향상
|
||
|
|
2. **Departments**: 부서 구조 변경 시 락킹 감소
|
||
|
|
3. **Estimates**: 견적 생성/수정 처리량 증가
|
||
|
|
4. **Estimate Items**: 대량 아이템 처리 성능 향상
|
||
|
|
|
||
|
|
### 유지된 인덱스
|
||
|
|
|
||
|
|
모든 제거된 FK에 대해 성능 인덱스는 유지하여 조회 성능 보장:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 유지된 성능 인덱스들
|
||
|
|
CREATE INDEX idx_classifications_tenant_id ON classifications (tenant_id);
|
||
|
|
CREATE INDEX idx_departments_parent_id ON departments (parent_id);
|
||
|
|
CREATE INDEX idx_estimates_tenant_model_set ON estimates (tenant_id, model_set_id);
|
||
|
|
CREATE INDEX idx_estimate_items_tenant_estimate ON estimate_items (tenant_id, estimate_id);
|
||
|
|
CREATE INDEX idx_components_ref_type_id ON product_components (ref_type, ref_id);
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🛡️ 개발 가이드라인
|
||
|
|
|
||
|
|
### Service 레이어 구현 필수사항
|
||
|
|
|
||
|
|
1. **데이터 무결성 검증**
|
||
|
|
```php
|
||
|
|
// 예시: 부서 삭제 전 검증
|
||
|
|
public function deleteDepartment($id) {
|
||
|
|
if ($this->hasChildDepartments($id)) {
|
||
|
|
throw new ValidationException('하위 부서가 존재합니다.');
|
||
|
|
}
|
||
|
|
if ($this->hasAssignedUsers($id)) {
|
||
|
|
throw new ValidationException('배정된 사용자가 존재합니다.');
|
||
|
|
}
|
||
|
|
// 삭제 진행
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Eloquent 관계 적극 활용**
|
||
|
|
```php
|
||
|
|
// 논리적 관계는 Model에서 정의
|
||
|
|
class Department extends Model {
|
||
|
|
public function parent() {
|
||
|
|
return $this->belongsTo(Department::class, 'parent_id');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function children() {
|
||
|
|
return $this->hasMany(Department::class, 'parent_id');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **배치 작업 시 주의사항**
|
||
|
|
- 대량 데이터 변경 시 관련 테이블 영향도 고려
|
||
|
|
- Transaction 사용으로 일관성 보장
|
||
|
|
- 참조 무결성 검증 로직 포함
|
||
|
|
|
||
|
|
## 🚨 주의사항
|
||
|
|
|
||
|
|
### 절대 하지 말아야 할 것
|
||
|
|
|
||
|
|
❌ **직접 SQL로 참조 데이터 삭제**
|
||
|
|
❌ **Service 레이어 무결성 검증 생략**
|
||
|
|
❌ **대량 작업 시 관련 테이블 확인 누락**
|
||
|
|
|
||
|
|
### 권장사항
|
||
|
|
|
||
|
|
✅ **Eloquent ORM 관계 메서드 사용**
|
||
|
|
✅ **Service 레이어에서 비즈니스 규칙 검증**
|
||
|
|
✅ **Soft Delete 활용으로 데이터 보호**
|
||
|
|
✅ **단위 테스트로 무결성 검증**
|
||
|
|
|
||
|
|
## 🔄 복구 방법
|
||
|
|
|
||
|
|
필요시 물리적 FK 제약조건 복구 가능:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 전체 롤백
|
||
|
|
php artisan migrate:rollback --step=4
|
||
|
|
|
||
|
|
# 특정 단계만 롤백
|
||
|
|
php artisan migrate:rollback --step=1
|
||
|
|
```
|
||
|
|
|
||
|
|
**참고**: FK 복구 시 데이터 무결성 위반으로 실패할 수 있으므로,
|
||
|
|
복구 전 데이터 정합성 점검 필수.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**문서 관리**: 이 문서는 데이터베이스 스키마 변경 시 함께 업데이트해야 합니다.
|
||
|
|
**최종 업데이트**: 2025-09-24 (Phase 1~3 FK 제거 완료)
|