364 lines
14 KiB
Markdown
364 lines
14 KiB
Markdown
# SAM API 저장소 작업 현황
|
||
|
||
## 2025-10-13 (일) - 고객그룹별 차등 가격 시스템 구축
|
||
|
||
### 주요 작업
|
||
- **고객 그룹 관리 시스템 구축**: 고객별 차등 가격 관리를 위한 client_groups 테이블 및 모델 구현
|
||
- **가격 이력 시스템 확장**: price_histories 테이블에 고객그룹별 가격 지원 추가
|
||
- **PricingService 신규 구축**: 우선순위 기반 가격 조회 로직 구현
|
||
- **EstimateService 통합**: 견적 생성 시 자동 가격 계산 기능 추가
|
||
|
||
### 추가된 파일:
|
||
- `database/migrations/2025_10_13_213549_create_client_groups_table.php` - 고객 그룹 테이블 생성
|
||
- `database/migrations/2025_10_13_213556_add_client_group_id_to_clients_table.php` - clients 테이블에 그룹 ID 추가
|
||
- `database/migrations/2025_10_13_213602_add_client_group_id_to_price_histories_table.php` - price_histories 테이블에 그룹 ID 추가
|
||
- `app/Models/Orders/ClientGroup.php` - 고객 그룹 모델
|
||
- `app/Services/Pricing/PricingService.php` - 가격 조회/관리 서비스
|
||
|
||
### 수정된 파일:
|
||
- `app/Models/Orders/Client.php` - ClientGroup 관계 추가
|
||
- `app/Models/Products/PriceHistory.php` - ClientGroup 관계 추가, 다양한 스코프 메서드 추가
|
||
- `app/Services/Estimate/EstimateService.php` - PricingService 의존성 주입 및 가격 계산 로직 통합
|
||
- `lang/ko/error.php` - price_not_found 에러 메시지 추가
|
||
|
||
### 작업 내용:
|
||
|
||
#### 1. 데이터베이스 스키마 설계
|
||
|
||
**client_groups 테이블:**
|
||
```sql
|
||
- id, tenant_id
|
||
- group_code (그룹 코드)
|
||
- group_name (그룹명)
|
||
- price_rate (가격 배율: 1.0 = 기준가, 0.9 = 90%, 1.1 = 110%)
|
||
- is_active (활성 여부)
|
||
- created_by, updated_by, deleted_by (감사 컬럼)
|
||
- created_at, updated_at, deleted_at
|
||
- UNIQUE(tenant_id, group_code)
|
||
```
|
||
|
||
**clients 테이블 확장:**
|
||
- `client_group_id` 컬럼 추가 (NULL 허용 = 기본 그룹)
|
||
|
||
**price_histories 테이블 확장:**
|
||
- `client_group_id` 컬럼 추가 (NULL = 기본 가격, 값 있으면 그룹별 차등 가격)
|
||
- 인덱스 재구성: (tenant_id, item_type_code, item_id, client_group_id, started_at)
|
||
|
||
#### 2. 모델 관계 설정
|
||
|
||
**ClientGroup 모델:**
|
||
- `clients()` → hasMany 관계
|
||
- `scopeActive()` → 활성 그룹만 조회
|
||
- `scopeCode()` → 코드로 검색
|
||
|
||
**Client 모델:**
|
||
- `clientGroup()` → belongsTo 관계
|
||
|
||
**PriceHistory 모델:**
|
||
- `clientGroup()` → belongsTo 관계
|
||
- `item()` → Polymorphic 관계 (Product/Material)
|
||
- 다양한 스코프 메서드:
|
||
- `scopeForItem()` → 특정 항목 필터링
|
||
- `scopeForClientGroup()` → 고객 그룹 필터링
|
||
- `scopeValidAt()` → 기준일 기준 유효한 가격
|
||
- `scopeSalePrice()` → 매출단가만
|
||
- `scopePurchasePrice()` → 매입단가만
|
||
|
||
#### 3. PricingService 핵심 로직
|
||
|
||
**가격 조회 우선순위:**
|
||
```php
|
||
1순위: 고객 그룹별 매출단가 (client_group_id 있음)
|
||
2순위: 기본 매출단가 (client_group_id = NULL)
|
||
3순위: NULL (경고 발생)
|
||
|
||
// ❌ 제거: 매입단가는 견적에서 사용하지 않음 (순수 참고용)
|
||
```
|
||
|
||
**주요 메서드:**
|
||
- `getItemPrice()` → 단일 항목 가격 조회
|
||
- `getBulkItemPrices()` → 여러 항목 일괄 조회
|
||
- `upsertPrice()` → 가격 등록/수정
|
||
- `listPrices()` → 가격 이력 조회 (페이지네이션)
|
||
- `deletePrice()` → 가격 삭제 (Soft Delete)
|
||
|
||
#### 4. EstimateService 통합
|
||
|
||
**견적 생성 프로세스:**
|
||
```php
|
||
1. BOM 계산 (수량만)
|
||
2. 각 BOM 항목의 가격 조회 (PricingService)
|
||
3. unit_price × quantity = total_price 계산
|
||
4. 전체 항목의 total_price 합산 = total_amount
|
||
5. 가격 없는 항목 경고 로그 기록
|
||
```
|
||
|
||
**수정된 메서드:**
|
||
- `createEstimate()` → client_id 전달, total_amount 재계산
|
||
- `updateEstimate()` → 파라미터 변경 시 가격 재계산
|
||
- `createEstimateItems()` → 가격 조회 로직 추가, float 반환
|
||
|
||
#### 5. 에러 처리 및 로깅
|
||
|
||
**가격 없는 항목 처리:**
|
||
- 경고 메시지 반환: `__('error.price_not_found', [...])`
|
||
- Laravel Log에 경고 기록
|
||
- 견적 생성은 계속 진행 (unit_price = 0)
|
||
- 프론트엔드에서 경고 표시 가능
|
||
|
||
### 비즈니스 규칙 정리:
|
||
|
||
#### 매입단가 vs 매출단가
|
||
- **매입단가 (PURCHASE)**: 순수 참고용, 견적 계산에 미사용
|
||
- **매출단가 (SALE)**: 실제 견적 계산에 사용
|
||
- **STANDARD 가격**: 경동 비즈니스에서는 불필요 (사용하지 않음)
|
||
|
||
#### 고객 그룹별 차등 가격
|
||
```
|
||
예시 데이터:
|
||
- 기본 가격: 100,000원 (client_group_id = NULL)
|
||
- A그룹 가격: 90,000원 (client_group_id = 1, price_rate = 0.9)
|
||
- B그룹 가격: 110,000원 (client_group_id = 2, price_rate = 1.1)
|
||
|
||
조회 로직:
|
||
- A그룹 고객 → 90,000원 (1순위)
|
||
- B그룹 고객 → 110,000원 (1순위)
|
||
- 일반 고객 → 100,000원 (2순위)
|
||
- 가격 없음 → NULL + 경고 (3순위)
|
||
```
|
||
|
||
### 마이그레이션 실행 결과:
|
||
```bash
|
||
✅ 2025_10_13_213549_create_client_groups_table (46.85ms)
|
||
✅ 2025_10_13_213556_add_client_group_id_to_clients_table (38.75ms)
|
||
✅ 2025_10_13_213602_add_client_group_id_to_price_histories_table (38.46ms)
|
||
```
|
||
|
||
### 코드 품질:
|
||
- Laravel Pint 포맷팅 완료 (5 files, 4 style issues fixed)
|
||
- SAM API Development Rules 준수
|
||
- Service-First 아키텍처 유지
|
||
- BelongsToTenant 멀티테넌트 스코프 적용
|
||
- SoftDeletes 적용
|
||
- 감사 컬럼 (created_by, updated_by, deleted_by) 포함
|
||
|
||
### 예상 효과:
|
||
1. **유연한 가격 관리**: 고객 그룹별 차등 가격 설정 가능
|
||
2. **자동 가격 계산**: 견적 생성 시 수동 입력 불필요
|
||
3. **이력 관리**: 기간별 가격 변동 이력 추적
|
||
4. **확장성**: 향후 복잡한 가격 정책 적용 가능
|
||
5. **투명성**: 가격 출처 추적 가능 (price_history_id, client_group_id)
|
||
|
||
### 향후 작업:
|
||
- [x] PricingService 구현
|
||
- [x] EstimateService 통합
|
||
- [ ] 가격 관리 API 엔드포인트 추가 (CRUD)
|
||
- [ ] Swagger 문서 작성 (가격 관련 API)
|
||
- [ ] 고객 그룹 관리 API 엔드포인트 추가
|
||
- [ ] Frontend 가격 관리 화면 구현
|
||
- [ ] 가격 일괄 업로드 기능 추가
|
||
|
||
### Git 커밋 준비:
|
||
- 다음 커밋 예정: `feat: 고객그룹별 차등 가격 시스템 구축`
|
||
|
||
---
|
||
|
||
## 2025-10-01 (화) - Client API 및 Swagger 문서 구조 개선
|
||
|
||
### 주요 작업
|
||
- **Client API Swagger 문서 생성**: Controller에서 분리된 Swagger 파일 생성
|
||
- **Swagger 구조 표준화**: Controller는 비즈니스 로직만, Swagger는 별도 파일로 관리
|
||
- **CLAUDE.md 업데이트**: Swagger 문서 작성 규칙 명확화
|
||
|
||
### 추가된 파일:
|
||
- `app/Swagger/v1/ClientApi.php` - Client API Swagger 문서 (Tag, Schemas, Endpoints)
|
||
|
||
### 수정된 파일:
|
||
- `app/Http/Controllers/Api/V1/ClientController.php` - Swagger 어노테이션 제거 (비즈니스 로직만 유지)
|
||
- `CLAUDE.md` - Swagger 문서 작성 규칙 섹션 업데이트
|
||
|
||
### 작업 내용:
|
||
|
||
#### 1. Swagger 문서 구조 표준화
|
||
**기존 방식 (잘못된 방식):**
|
||
- Controller에 Swagger 어노테이션 직접 작성
|
||
- 비즈니스 로직과 API 문서가 혼재
|
||
- Controller 가독성 저하
|
||
|
||
**새로운 방식 (표준 방식):**
|
||
- `app/Swagger/v1/{Resource}Api.php` 별도 파일로 관리
|
||
- Controller는 순수 비즈니스 로직만 포함
|
||
- Swagger 문서는 독립적으로 관리
|
||
|
||
#### 2. ClientApi.php 구조
|
||
```php
|
||
namespace App\Swagger\v1;
|
||
|
||
/**
|
||
* @OA\Tag - 리소스 태그 정의
|
||
* @OA\Schema(schema="Client") - 모델 스키마
|
||
* @OA\Schema(schema="ClientPagination") - 페이지네이션
|
||
* @OA\Schema(schema="ClientCreateRequest") - 생성 요청
|
||
* @OA\Schema(schema="ClientUpdateRequest") - 수정 요청
|
||
*/
|
||
class ClientApi {
|
||
public function index() {} // GET /api/v1/clients
|
||
public function show() {} // GET /api/v1/clients/{id}
|
||
public function store() {} // POST /api/v1/clients
|
||
public function update() {} // PUT /api/v1/clients/{id}
|
||
public function destroy() {} // DELETE /api/v1/clients/{id}
|
||
public function toggle() {} // PATCH /api/v1/clients/{id}/toggle
|
||
}
|
||
```
|
||
|
||
#### 3. CLAUDE.md 규칙 업데이트
|
||
**추가된 내용:**
|
||
- Swagger 파일 위치: `app/Swagger/v1/`
|
||
- 파일 네이밍: `{Resource}Api.php`
|
||
- Controller 정책: Swagger 어노테이션 금지
|
||
- Schemas 구성: Model, Pagination, CreateRequest, UpdateRequest
|
||
- 재생성 명령어: `php artisan l5-swagger:generate`
|
||
|
||
#### 4. Client API 엔드포인트 구성
|
||
- **GET** `/api/v1/clients` - 거래처 목록 (페이지네이션)
|
||
- **GET** `/api/v1/clients/{id}` - 거래처 상세
|
||
- **POST** `/api/v1/clients` - 거래처 생성
|
||
- **PUT** `/api/v1/clients/{id}` - 거래처 수정
|
||
- **DELETE** `/api/v1/clients/{id}` - 거래처 삭제 (soft)
|
||
- **PATCH** `/api/v1/clients/{id}/toggle` - 활성/비활성 토글
|
||
|
||
### 시스템 개선 효과:
|
||
1. **코드 가독성 향상**: Controller가 순수 비즈니스 로직만 포함
|
||
2. **문서 관리 효율성**: Swagger 문서를 독립적으로 관리 가능
|
||
3. **표준화**: 모든 API가 동일한 구조로 문서화
|
||
4. **유지보수성**: Swagger 변경 시 Controller 영향 없음
|
||
|
||
### Swagger 재생성:
|
||
```bash
|
||
php artisan l5-swagger:generate
|
||
```
|
||
- Client API가 Swagger UI에 "Client" 태그로 표시됨
|
||
- `/api-docs/index.html`에서 확인 가능
|
||
|
||
### 향후 작업:
|
||
- 다른 Controller에도 동일한 패턴 적용
|
||
- Swagger 문서 품질 검증
|
||
- API 엔드포인트 테스트
|
||
|
||
---
|
||
|
||
## 2025-09-24 (화) - FK 제약조건 최적화 및 데이터베이스 성능 개선
|
||
|
||
### 주요 작업
|
||
- 데이터베이스 FK 제약조건 분석 및 최적화
|
||
- 성능과 관리 편의성을 위한 비중요 FK 제거
|
||
- 3단계 점진적 FK 제거 마이그레이션 구현
|
||
|
||
### 추가된 파일:
|
||
- `database/migrations/2025_09_24_214146_remove_non_critical_foreign_keys_phase1.php` - 1차 FK 제거 (Classifications, Departments)
|
||
- `database/migrations/2025_09_24_214200_remove_estimate_foreign_keys_phase2.php` - 2차 FK 제거 (견적 시스템)
|
||
- `database/migrations/2025_09_24_214300_remove_material_foreign_key_phase3.php` - 3차 FK 제거 (제품-자재 관계)
|
||
- `CURRENT_WORKS.md` - 저장소별 작업 현황 추적
|
||
|
||
### 수정된 파일:
|
||
- `CLAUDE.md` - CURRENT_WORKS.md 파일 위치 규칙 명확화
|
||
- `database/migrations/2025_09_24_000002_create_dynamic_estimate_fields.php` - level 컬럼 제거로 마이그레이션 오류 해결
|
||
|
||
### 작업 내용:
|
||
|
||
#### 1. FK 제약조건 현황 분석
|
||
- 현재 8개 마이그레이션에서 FK 제약조건 사용 확인
|
||
- 권한 관리, 제품/자재 관리, 견적 시스템, 기타 시스템별 분류
|
||
- 총 15+개의 FK 제약조건 식별
|
||
|
||
#### 2. 중요도별 테이블 분류
|
||
**🔴 핵심 테이블 (FK 유지 필수):**
|
||
- 인증/권한 시스템: users, roles, permissions 관계
|
||
- 제품/BOM 관리 핵심: products.category_id, product_components 내부 관계
|
||
- 멀티테넌트 핵심: 모든 tenant_id 참조
|
||
|
||
**🟡 중요 테이블 (FK 선택적 유지):**
|
||
- 견적 시스템: estimates, estimate_items 관계
|
||
- 자재 관리: product_components.material_id
|
||
|
||
**🟢 일반 테이블 (FK 제거 권장):**
|
||
- 분류/코드 관리: classifications.tenant_id
|
||
- 부서 관리: departments.parent_id (자기참조)
|
||
- 감사 로그: 모든 audit 관련 FK
|
||
|
||
#### 3. 코드 영향도 분석 결과
|
||
**✅ 중요 결론: 모델/컨트롤러/서비스 코드 수정 불필요!**
|
||
- Laravel Eloquent 관계가 FK 제약조건과 독립적으로 작동
|
||
- 현재 코드가 CASCADE 동작에 의존하지 않음
|
||
- BelongsToTenant 트레잇과 소프트 딜리트로 무결성 관리
|
||
- 비즈니스 로직이 애플리케이션 레벨에서 처리됨
|
||
|
||
#### 4. 3단계 점진적 FK 제거 전략
|
||
|
||
**Phase 1 (즉시 적용 가능):**
|
||
- `classifications.tenant_id` → `tenants`
|
||
- `departments.parent_id` → `departments` (자기참조)
|
||
- 영향도: 낮음, 관리 편의성 증가
|
||
|
||
**Phase 2 (견적 시스템):**
|
||
- `estimates.model_set_id` → `categories`
|
||
- `estimate_items.estimate_id` → `estimates`
|
||
- 영향도: 중간, 성능 향상 효과
|
||
- 멀티테넌트 보안 FK는 유지
|
||
|
||
**Phase 3 (신중한 검토 필요):**
|
||
- `product_components.material_id` → `materials`
|
||
- 영향도: 중간, 자재 관리 유연성 증가
|
||
- 핵심 제품 관계 FK는 유지
|
||
|
||
#### 5. 마이그레이션 특징
|
||
- 동적 FK 이름 탐지로 안전한 제거
|
||
- 성능을 위한 인덱스 유지/추가
|
||
- 상세한 진행 상황 로깅
|
||
- 완전한 롤백 기능
|
||
- 각 단계별 영향도와 주의사항 문서화
|
||
|
||
### 데이터베이스 마이그레이션 상태:
|
||
- 기존 마이그레이션 오류 해결 완료 (level 컬럼 이슈)
|
||
- 새로운 FK 제거 마이그레이션 3개 생성
|
||
- 롤백 가능한 안전한 구조로 설계
|
||
|
||
### 예상 효과:
|
||
1. **성능 향상**: 견적 시스템과 분류 관리에서 FK 검증 오버헤드 제거
|
||
2. **관리 편의성**: 부서 구조 변경, 자재 관리 시 유연성 증가
|
||
3. **개발 생산성**: 데이터 변경 시 FK 제약 에러 감소
|
||
4. **확장성**: 향후 시스템 확장 시 유연한 스키마 변경 가능
|
||
|
||
### 향후 작업:
|
||
1. Phase 1 마이그레이션 개발 서버 테스트
|
||
2. 각 단계별 성능 영향 모니터링
|
||
3. Service 레벨에서 데이터 무결성 검증 로직 보강 검토
|
||
4. 프로덕션 적용 전 백업 및 롤백 계획 수립
|
||
|
||
### 논리적 관계 자동화 시스템 구축:
|
||
- **자동화 도구 4개 생성**: 관계 문서 생성/업데이트/모델생성 명령어
|
||
- **Provider 시스템**: 마이그레이션 후 자동 문서 업데이트
|
||
- **간소화 문서**: 즉시 사용 가능한 관계 문서 생성 (LOGICAL_RELATIONSHIPS_SIMPLE.md)
|
||
|
||
### 새로운 명령어:
|
||
- `php artisan db:update-relationships` - 모델에서 관계 자동 추출
|
||
- `php artisan db:generate-simple-relationships` - 기본 관계 문서 생성
|
||
- `php artisan make:model-with-docs` - 모델 생성 후 관계 문서 자동 업데이트
|
||
|
||
### ERD 생성 시스템:
|
||
- **ERD 생성 도구**: beyondcode/laravel-er-diagram-generator 활용
|
||
- **GraphViz 설치**: `brew install graphviz`로 dot 명령어 지원
|
||
- **모델 오류 해결**: BelongsToTenantTrait → BelongsToTenant 수정
|
||
- **생성 결과**: 60개 모델의 완전한 관계도 생성 (`graph.png`, 4.1MB)
|
||
- **명령어**: `php artisan generate:erd --format=png`
|
||
|
||
### 예상 효과 (업데이트):
|
||
1. **시각화 개선**: 복잡한 다중 테넌트 구조의 시각적 이해 향상
|
||
2. **개발 생산성**: ERD를 통한 빠른 스키마 파악 및 설계 검증
|
||
3. **문서화 자동화**: 스키마 변경 시 ERD 자동 업데이트 가능
|
||
4. **기존 효과 유지**: 성능 향상, 관리 편의성, 확장성은 FK 제거로 달성
|
||
|
||
### Git 커밋:
|
||
- `cfd4c25` - fix: categories 테이블 level 컬럼 제거로 마이그레이션 오류 해결
|
||
- `7dafab3` - docs: CURRENT_WORKS.md 파일 위치 규칙 명확화
|
||
- `c63e676` - feat: 데이터베이스 FK 제약조건 최적화 및 3단계 마이그레이션 구현 |