docs: API 문서 구조화 및 분석 문서 추가

- docs/INDEX.md: 문서 인덱스 추가
- docs/analysis/: Item DB/API 분석 문서 3종 추가
- docs/swagger/: Swagger 문서화 가이드 4종 추가
- LOGICAL_RELATIONSHIPS.md: 논리적 관계 문서 업데이트
- 이전 버전 문서 정리 (BP-MES, CHECKPOINT 등)
This commit is contained in:
2025-11-24 22:38:38 +09:00
parent 80ca551026
commit 757c5d901c
13 changed files with 5378 additions and 1192 deletions

View File

@@ -1,632 +0,0 @@
# BP-MES Phase 1 통합 테스트 가이드
## 개요
BP-MES Phase 1에서 구현된 Items API의 통합 테스트 가이드입니다.
**구현 완료 항목:**
- ✅ Phase 1 Day 1-2: products/product_components 테이블 확장 (33개 필드)
- ✅ Phase 1 Day 3-5: ItemsController CRUD API (통합 품목 조회/생성/수정/삭제)
- ✅ Phase 1 Day 6-9: ItemsBomController API (BOM 관리 10개 엔드포인트)
- ✅ Phase 1 Day 10-12: ItemsFileController API (파일 업로드/삭제)
**테스트 환경:**
- API Base URL: `http://api.sam.kr/api/v1`
- Swagger UI: `http://api.sam.kr/api-docs/index.html`
- 인증: API Key (X-API-KEY) + Bearer Token (Authorization)
---
## 1. API 엔드포인트 검증
### 1.1 Items CRUD API (5개 엔드포인트)
| Method | Endpoint | Description | Controller |
|--------|----------|-------------|------------|
| GET | `/items` | 품목 목록 조회 (통합) | ItemsController@index |
| POST | `/items` | 품목 생성 | ItemsController@store |
| GET | `/items/code/{code}` | 코드 기반 조회 | ItemsController@showByCode |
| PUT | `/items/{code}` | 품목 수정 | ItemsController@update |
| DELETE | `/items/{code}` | 품목 삭제 | ItemsController@destroy |
### 1.2 Items BOM API (10개 엔드포인트)
| Method | Endpoint | Description | Controller |
|--------|----------|-------------|------------|
| GET | `/items/{code}/bom` | BOM 목록 (flat) | ItemsBomController@index |
| GET | `/items/{code}/bom/tree` | BOM 트리 (계층) | ItemsBomController@tree |
| POST | `/items/{code}/bom` | BOM 추가 (bulk) | ItemsBomController@store |
| PUT | `/items/{code}/bom/{lineId}` | BOM 수정 | ItemsBomController@update |
| DELETE | `/items/{code}/bom/{lineId}` | BOM 삭제 | ItemsBomController@destroy |
| GET | `/items/{code}/bom/summary` | BOM 요약 | ItemsBomController@summary |
| GET | `/items/{code}/bom/validate` | BOM 검증 | ItemsBomController@validate |
| POST | `/items/{code}/bom/replace` | BOM 전체 교체 | ItemsBomController@replace |
| POST | `/items/{code}/bom/reorder` | BOM 정렬 | ItemsBomController@reorder |
| GET | `/items/{code}/bom/categories` | 카테고리 목록 | ItemsBomController@listCategories |
### 1.3 Items File API (2개 엔드포인트)
| Method | Endpoint | Description | Controller |
|--------|----------|-------------|------------|
| POST | `/items/{code}/files` | 파일 업로드 | ItemsFileController@upload |
| DELETE | `/items/{code}/files/{type}` | 파일 삭제 | ItemsFileController@delete |
**지원 파일 타입:**
- `bending_diagram`: 절곡도 (jpg, png, gif, svg - 10MB)
- `specification`: 시방서 (pdf, doc, docx, xls, xlsx, hwp - 20MB)
- `certification`: 인정서 (pdf, doc, docx, xls, xlsx, hwp - 20MB)
---
## 2. 데이터베이스 검증
### 2.1 Migration 상태
```bash
php artisan migrate:status
```
**확인 사항:**
- ✅ 2025_11_14_000001_add_hybrid_fields_to_products_table (batch 27)
- ✅ 2025_11_14_000002_add_attributes_to_product_components_table (batch 27)
- ✅ 2025_11_17_125437_add_file_fields_to_products_table (batch 28)
### 2.2 products 테이블 필드 확인
**파일 관련 필드 (9개):**
```sql
SELECT
bending_diagram,
bending_details,
specification_file,
specification_file_name,
certification_file,
certification_file_name,
certification_number,
certification_start_date,
certification_end_date
FROM products
LIMIT 1;
```
### 2.3 Model 검증
```bash
# Product 모델 fillable 확인
php artisan tinker
>>> (new \App\Models\Products\Product)->getFillable();
# Product 모델 casts 확인
>>> (new \App\Models\Products\Product)->getCasts();
```
**확인 사항:**
- ✅ fillable에 9개 파일 필드 포함
- ✅ casts: bending_details (array), certification_start_date (date), certification_end_date (date)
---
## 3. 통합 테스트 시나리오
### 시나리오 1: 기본 CRUD 흐름
**Step 1: 품목 생성**
```http
POST /api/v1/items
Content-Type: application/json
X-API-KEY: {api_key}
Authorization: Bearer {token}
{
"item_type": "PRODUCT",
"code": "TEST-001",
"name": "테스트 제품",
"unit": "EA",
"category_id": 1,
"product_type": "FG",
"is_sellable": true,
"is_purchasable": false,
"is_producible": true
}
```
**예상 결과:**
- HTTP 200 OK
- `{"success": true, "message": "품목이 등록되었습니다.", "data": {...}}`
**Step 2: 품목 조회**
```http
GET /api/v1/items/code/TEST-001
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- Product 데이터 반환
**Step 3: 품목 수정**
```http
PUT /api/v1/items/TEST-001
Content-Type: application/json
X-API-KEY: {api_key}
Authorization: Bearer {token}
{
"name": "테스트 제품 (수정)",
"margin_rate": 15.5,
"safety_stock": 100
}
```
**예상 결과:**
- HTTP 200 OK
- `{"success": true, "message": "품목이 수정되었습니다.", "data": {...}}`
---
### 시나리오 2: BOM 관리 흐름
**전제 조건:**
- 부모 품목: TEST-001 (생성 완료)
- 자재 1: M-001 (기존 자재)
- 자재 2: M-002 (기존 자재)
**Step 1: BOM 추가 (Bulk)**
```http
POST /api/v1/items/TEST-001/bom
Content-Type: application/json
X-API-KEY: {api_key}
Authorization: Bearer {token}
{
"items": [
{
"ref_type": "MATERIAL",
"ref_id": 1,
"quantity": 2.5,
"sort_order": 1,
"quantity_formula": "W * 2"
},
{
"ref_type": "MATERIAL",
"ref_id": 2,
"quantity": 1.0,
"sort_order": 2,
"condition": "MOTOR='Y'"
}
]
}
```
**예상 결과:**
- HTTP 200 OK
- BOM 항목 2개 생성
**Step 2: BOM 트리 조회**
```http
GET /api/v1/items/TEST-001/bom/tree
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- 계층 구조로 BOM 반환 (depth, children 포함)
**Step 3: BOM 요약 조회**
```http
GET /api/v1/items/TEST-001/bom/summary
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- total_count, material_count, product_count 반환
**Step 4: BOM 검증**
```http
GET /api/v1/items/TEST-001/bom/validate
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- is_valid, errors, warnings 반환
**Step 5: BOM 라인 수정**
```http
PUT /api/v1/items/TEST-001/bom/1
Content-Type: application/json
X-API-KEY: {api_key}
Authorization: Bearer {token}
{
"quantity": 3.0,
"quantity_formula": "W * 3"
}
```
**예상 결과:**
- HTTP 200 OK
- BOM 항목 업데이트 완료
**Step 6: BOM 정렬 변경**
```http
POST /api/v1/items/TEST-001/bom/reorder
Content-Type: application/json
X-API-KEY: {api_key}
Authorization: Bearer {token}
{
"items": [
{"id": 2, "sort_order": 1},
{"id": 1, "sort_order": 2}
]
}
```
**예상 결과:**
- HTTP 200 OK
- BOM 정렬 순서 변경 완료
---
### 시나리오 3: 파일 업로드 흐름
**전제 조건:**
- 품목: TEST-001 (생성 완료)
- 테스트 파일: bending.jpg (절곡도), spec.pdf (시방서), cert.pdf (인정서)
**Step 1: 절곡도 업로드**
```http
POST /api/v1/items/TEST-001/files
Content-Type: multipart/form-data
X-API-KEY: {api_key}
Authorization: Bearer {token}
type: bending_diagram
file: bending.jpg
bending_details: [
{"angle": 90, "length": 100.5, "type": "V형"},
{"angle": 45, "length": 50.0, "type": "Z형"}
]
```
**예상 결과:**
- HTTP 200 OK
- file_url, file_path, file_name 반환
- product.bending_diagram 필드에 파일 경로 저장
- product.bending_details 필드에 배열 저장
**Step 2: 시방서 업로드**
```http
POST /api/v1/items/TEST-001/files
Content-Type: multipart/form-data
X-API-KEY: {api_key}
Authorization: Bearer {token}
type: specification
file: spec.pdf
```
**예상 결과:**
- HTTP 200 OK
- product.specification_file, specification_file_name 업데이트
**Step 3: 인정서 업로드**
```http
POST /api/v1/items/TEST-001/files
Content-Type: multipart/form-data
X-API-KEY: {api_key}
Authorization: Bearer {token}
type: certification
file: cert.pdf
certification_number: CERT-2025-001
certification_start_date: 2025-01-01
certification_end_date: 2026-12-31
```
**예상 결과:**
- HTTP 200 OK
- product.certification_file, certification_file_name, certification_number, certification_start_date, certification_end_date 업데이트
**Step 4: 파일 조회 (품목 정보에 포함)**
```http
GET /api/v1/items/code/TEST-001
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- Product 데이터에 파일 URL 포함
**Step 5: 파일 삭제**
```http
DELETE /api/v1/items/TEST-001/files/bending_diagram
X-API-KEY: {api_key}
Authorization: Bearer {token}
```
**예상 결과:**
- HTTP 200 OK
- 물리적 파일 삭제
- product.bending_diagram, bending_details NULL 처리
---
### 시나리오 4: 전체 통합 시나리오
**목표:** 품목 생성 → BOM 구성 → 파일 업로드 → 검증
**1. 품목 생성**
```http
POST /api/v1/items
{
"item_type": "PRODUCT",
"code": "INT-TEST-001",
"name": "통합 테스트 제품",
"unit": "EA",
"category_id": 1,
"product_type": "FG",
"product_category": "SCREEN",
"is_sellable": true,
"is_purchasable": false,
"is_producible": true,
"margin_rate": 20.0,
"safety_stock": 50,
"lead_time": 7,
"is_variable_size": true
}
```
**2. BOM 구성**
```http
POST /api/v1/items/INT-TEST-001/bom
{
"items": [
{"ref_type": "MATERIAL", "ref_id": 1, "quantity": 2.0, "sort_order": 1, "quantity_formula": "W * 2"},
{"ref_type": "MATERIAL", "ref_id": 2, "quantity": 1.0, "sort_order": 2, "condition": "MOTOR='Y'"},
{"ref_type": "PRODUCT", "ref_id": 5, "quantity": 1.0, "sort_order": 3}
]
}
```
**3. BOM 트리 및 요약 확인**
```http
GET /api/v1/items/INT-TEST-001/bom/tree
GET /api/v1/items/INT-TEST-001/bom/summary
GET /api/v1/items/INT-TEST-001/bom/validate
```
**4. 절곡도 업로드**
```http
POST /api/v1/items/INT-TEST-001/files
type: bending_diagram
file: test_bending.jpg
bending_details: [{"angle": 90, "length": 100, "type": "V형"}]
```
**5. 시방서 업로드**
```http
POST /api/v1/items/INT-TEST-001/files
type: specification
file: test_spec.pdf
```
**6. 인정서 업로드**
```http
POST /api/v1/items/INT-TEST-001/files
type: certification
file: test_cert.pdf
certification_number: TEST-CERT-001
certification_start_date: 2025-01-01
certification_end_date: 2026-12-31
```
**7. 최종 검증**
```http
GET /api/v1/items/code/INT-TEST-001
```
**확인 사항:**
- ✅ 품목 정보 정상 반환
- ✅ BOM 데이터 포함 (componentLines 관계)
- ✅ 파일 URL 3개 포함 (bending_diagram, specification_file, certification_file)
- ✅ 인증 정보 포함 (certification_number, start_date, end_date)
- ✅ 절곡 상세 정보 포함 (bending_details 배열)
**8. 삭제 테스트**
```http
DELETE /api/v1/items/INT-TEST-001/bom/1
DELETE /api/v1/items/INT-TEST-001/files/bending_diagram
DELETE /api/v1/items/INT-TEST-001
```
---
## 4. 에러 처리 검증
### 4.1 파일 업로드 에러
**케이스 1: 잘못된 파일 타입**
```http
POST /api/v1/items/TEST-001/files
type: bending_diagram
file: test.txt (텍스트 파일)
```
**예상:** HTTP 422, "허용되지 않는 파일 형식입니다."
**케이스 2: 파일 크기 초과**
```http
POST /api/v1/items/TEST-001/files
type: bending_diagram
file: huge_image.jpg (15MB)
```
**예상:** HTTP 422, "파일 크기가 너무 큽니다."
**케이스 3: 인증 기간 검증 실패**
```http
POST /api/v1/items/TEST-001/files
type: certification
file: cert.pdf
certification_start_date: 2025-12-31
certification_end_date: 2025-01-01
```
**예상:** HTTP 422, "인증 종료일은 시작일 이후여야 합니다."
### 4.2 BOM 에러
**케이스 1: 존재하지 않는 품목**
```http
POST /api/v1/items/INVALID-CODE/bom
```
**예상:** HTTP 404, "존재하지 않는 URI 또는 데이터입니다."
**케이스 2: 순환 참조**
```http
POST /api/v1/items/TEST-001/bom
{
"items": [
{"ref_type": "PRODUCT", "ref_id": 1, "quantity": 1.0}
]
}
```
(TEST-001의 ID가 1인 경우)
**예상:** BOM 검증 시 순환 참조 경고
### 4.3 CRUD 에러
**케이스 1: 중복 코드**
```http
POST /api/v1/items
{
"code": "TEST-001" (이미 존재)
}
```
**예상:** HTTP 422, "중복된 데이터가 존재합니다."
**케이스 2: 필수 필드 누락**
```http
POST /api/v1/items
{
"code": "TEST-002"
// name 누락
}
```
**예상:** HTTP 422, 검증 실패
---
## 5. 성능 검증
### 5.1 BOM 트리 조회 성능
```bash
# 10개 계층, 각 계층 5개 자식 = 약 50개 노드
GET /api/v1/items/{code}/bom/tree
# 목표: < 1초
# 실제: {측정 필요}
```
### 5.2 파일 업로드 성능
```bash
# 10MB 이미지 업로드
POST /api/v1/items/{code}/files
# 목표: < 5초
# 실제: {측정 필요}
```
### 5.3 목록 조회 성능
```bash
# 1000개 품목 페이징 조회
GET /api/v1/items?page=1&size=20
# 목표: < 500ms
# 실제: {측정 필요}
```
---
## 6. Swagger UI 테스트
### 6.1 접속 확인
```
URL: http://api.sam.kr/api-docs/index.html
```
**확인 사항:**
- ✅ Items Files 태그 표시
- ✅ POST /api/v1/items/{code}/files 엔드포인트 표시
- ✅ DELETE /api/v1/items/{code}/files/{type} 엔드포인트 표시
- ✅ ItemFileUploadResponse 스키마 표시
- ✅ ItemFileDeleteResponse 스키마 표시
- ✅ Try it out 기능 동작
### 6.2 API 문서 완성도
**Items CRUD:**
- ✅ 5개 엔드포인트 모두 문서화
- ✅ Request/Response 스키마 정의
- ✅ 예시 데이터 포함
**Items BOM:**
- ✅ 10개 엔드포인트 모두 문서화
- ✅ BOMLine, BOMTree 스키마 정의
- ✅ 예시 데이터 포함
**Items Files:**
- ✅ 2개 엔드포인트 모두 문서화
- ✅ multipart/form-data 정의
- ✅ 파일 타입별 검증 규칙 설명
---
## 7. 체크리스트
### Phase 1 완료 항목
- [x] products 테이블 확장 (33개 필드)
- [x] product_components 테이블 확장 (5개 필드)
- [x] products 파일 필드 추가 (9개 필드)
- [x] ItemsController CRUD API (5개 엔드포인트)
- [x] ItemsBomController API (10개 엔드포인트)
- [x] ItemsFileController API (2개 엔드포인트)
- [x] FormRequest 검증 (ItemsFileUploadRequest)
- [x] Swagger 문서 작성 (ItemsFileApi)
- [x] Migration 실행 및 검증
- [x] Pint 코드 포맷팅
- [x] Git 커밋
### 테스트 권장 순서
1. [ ] Swagger UI 접속 및 문서 확인
2. [ ] Database 스키마 검증
3. [ ] Model fillable/casts 확인
4. [ ] Items CRUD API 테스트
5. [ ] Items BOM API 테스트
6. [ ] Items File API 테스트
7. [ ] 통합 시나리오 테스트
8. [ ] 에러 처리 검증
9. [ ] 성능 측정
10. [ ] 최종 검증
---
## 8. 다음 단계
**Phase 2 계획 (제안):**
- [ ] Frontend 연동 (React/Vue)
- [ ] 파일 미리보기 기능
- [ ] BOM 계산 로직 (수식 평가)
- [ ] 조건부 BOM 처리
- [ ] 대량 데이터 Import/Export
- [ ] 품목 복제 기능
- [ ] 변경 이력 추적
- [ ] 통합 검색 개선
---
**작성일:** 2025-11-17
**작성자:** Claude Code
**버전:** 1.0

View File

@@ -1,157 +0,0 @@
# SAM 프로젝트 체크포인트
**생성일시**: 2025-09-19 19:45 KST
**목적**: 새로운 개발 작업 시작 전 안전한 복원 지점 생성
## 🎯 현재 상태 요약
### Git 저장소 상태
모든 저장소가 안정된 상태로 정리 완료:
- **API**: 최신 워크플로우 가이드 적용
- **Frontend**: 최신 화면 개발 상태
- **Admin/Shared**: 깨끗한 상태 유지
### 데이터베이스 상태
- **마이그레이션**: Batch 11까지 정상 실행
- **최종 테이블**: `audit_logs` (감사 로그 시스템)
- **상태**: 모든 마이그레이션 정상 적용됨
## 📍 정확한 복원 지점
### Git 커밋 해시
```bash
# API 저장소 (/api)
HEAD: 8d7426d - chore: 프로젝트 가이드 파일 추가
BASE: 785e367 - feat: 통합 감사 로그 도입 및 조회 API/스케줄러 추가
# Frontend 저장소 (/front/www)
HEAD: ec18d70 - 화면 생성 - 수주관리 > 수주하기 - 수주관리 > 수주관리리스트
# Admin 저장소 (/admin)
HEAD: 0624422 - fix : 빈디렉토리 설정
# Shared 저장소 (/shared)
HEAD: 015b3dc - feat : Filament BOARD, TENANT 추가
```
### 데이터베이스 마이그레이션 상태
```bash
# 실행된 마이그레이션 (Batch 11)
- 2025_08_28_000100_alter_product_components_unify_ref_columns
- 2025_09_05_000001_create_models_table
- 2025_09_05_000002_create_model_versions_table
- 2025_09_05_000003_create_bom_templates_table
- 2025_09_05_000004_create_bom_template_items_table
- 2025_09_10_000002_add_indexes_to_model_versions_table
- 2025_09_11_000100_create_audit_logs_table
```
### 파일 상태
- **CLAUDE.md**: 워크플로우 가이드 포함된 최신 버전
- **CURRENT_WORKS.md**: 2025-09-19 작업 내용 정리 완료
- **시스템 파일**: 모든 불필요한 파일 정리됨 (52MB 절약)
## 🔄 완전 원복 방법
### 1단계: 데이터베이스 마이그레이션 롤백
```bash
cd /api
php artisan migrate:rollback --step=7 # Batch 11 전체 롤백
php artisan migrate:status # 상태 확인 (Batch 10까지만 남아야 함)
```
### 2단계: Git 저장소 리셋
```bash
# API 저장소
cd /api
git reset --hard 8d7426d # 현재 HEAD로 리셋
# Frontend 저장소
cd /front/www
git reset --hard ec18d70 # 현재 HEAD로 리셋
# Admin 저장소
cd /admin
git reset --hard 0624422 # 현재 HEAD로 리셋
# Shared 저장소
cd /shared
git reset --hard 015b3dc # 현재 HEAD로 리셋
```
### 3단계: 데이터베이스 마이그레이션 재실행
```bash
cd /api
php artisan migrate # 모든 마이그레이션 재실행
```
### 4단계: 환경 정리
```bash
# 임시 파일 정리
find . -name ".DS_Store" -delete
rm -f .phpunit.result.cache
rm -f storage/logs/laravel.log
# Docker 서비스 재시작 (필요시)
docker-compose restart
```
## ⚠️ 주의사항
### 작업 전 확인사항
1. **Docker 서비스**: MySQL, Redis 등이 정상 작동하는지 확인
2. **환경 파일**: `.env` 파일이 올바르게 설정되어 있는지 확인
3. **의존성**: `composer install`, `npm install` 실행 필요 여부 확인
### 데이터 손실 방지
- 중요한 데이터가 있다면 먼저 백업 수행
- 마이그레이션 롤백 시 데이터 손실 가능성 있음
- 테스트 환경에서 먼저 검증 후 적용
### 복원 후 검증
```bash
# API 서버 정상 작동 확인
php artisan serve
curl http://localhost:8000/health
# 마이그레이션 상태 재확인
php artisan migrate:status
# 전체 Git 상태 확인
git status # 각 저장소에서 실행
```
## 📝 추가 복원 스크립트
### 빠른 복원 스크립트 (`restore-checkpoint.sh`)
```bash
#!/bin/bash
echo "🔄 SAM 프로젝트 체크포인트 복원 중..."
# 데이터베이스 롤백
cd /Users/hskwon/Works/@KD_SAM/SAM/api
php artisan migrate:rollback --step=7
# Git 리셋
git reset --hard 8d7426d
cd ../front/www
git reset --hard ec18d70
cd ../../admin
git reset --hard 0624422
cd ../shared
git reset --hard 015b3dc
# 마이그레이션 재실행
cd ../api
php artisan migrate
echo "✅ 체크포인트 복원 완료!"
```
---
**체크포인트 생성자**: Claude Code
**복원 가능 기간**: 무제한 (Git 히스토리 보존시)
**검증 상태**: ✅ 모든 시스템 정상 작동 확인

View File

@@ -1,316 +0,0 @@
# SAM 데이터베이스 스키마 보고서
**점검일시**: 2025-09-19 19:50 KST
**데이터베이스**: samdb (MySQL 8.0.43)
**연결정보**: 127.0.0.1:3306 (samuser)
## 📊 전체 현황
- **총 테이블 수**: 70개
- **전체 DB 크기**: 3.42 MB
- **연결 상태**: 정상 (1 active connection)
- **엔진**: InnoDB
- **문자셋**: utf8mb4_unicode_ci
## 🏗️ 핵심 테이블 구조
### 1. **Multi-Tenant 기반 구조**
#### `tenants` (80KB)
```sql
-- 테넌트(회사/조직) 마스터
- id: bigint (PK, auto_increment)
- company_name: varchar(100) -- 회사명
- code: varchar(50) UNIQUE -- 테넌트 코드
- email, phone, address: 연락처 정보
- business_num: varchar(12) -- 사업자번호
- corp_reg_no: varchar(13) -- 법인등록번호
- ceo_name, homepage, fax, logo: 추가 정보
- admin_memo: text -- 관리자 메모
- options: json -- 설정 옵션
- tenant_st_code: varchar(20) -- 상태 코드
- plan_id, subscription_id: 구독 관련
- max_users: int -- 최대 사용자 수
- trial_ends_at, expires_at, last_paid_at: 구독 일정
- billing_tp_code: varchar(20) DEFAULT 'monthly'
- created_at, updated_at, deleted_at
```
#### `users` (48KB)
```sql
-- 사용자 계정 마스터
- id: bigint (PK, auto_increment)
- user_id: varchar(100) UNIQUE -- 사용자 ID
- phone: varchar(30)
- options: json
- name: varchar(255)
- email: varchar(255) UNIQUE
- email_verified_at: timestamp
- password: varchar(255)
- last_login_at: timestamp
- two_factor_secret, two_factor_recovery_codes: 2FA 관련
- two_factor_confirmed_at: timestamp
- remember_token: varchar(100)
- current_team_id: bigint
- profile_photo_path: varchar(2048)
- created_at, updated_at, deleted_at
```
#### `user_tenants` (48KB)
```sql
-- 사용자-테넌트 매핑 (M:N)
- user_id tenant_id
- is_active, is_default 플래그
```
### 2. **권한 관리 시스템**
#### Spatie Permission 기반
- `permissions` (48KB): 권한 정의
- `roles` (48KB): 역할 정의
- `model_has_permissions` (64KB): 모델별 권한 할당
- `model_has_roles` (48KB): 모델별 역할 할당
- `role_has_permissions` (32KB): 역할별 권한 매핑
#### 확장 권한 시스템
- `permission_overrides` (64KB): 수동 권한 재정의
- `departments` (80KB): 부서별 계층 구조
- `department_user` (16KB): 사용자-부서 매핑
### 3. **제품 및 자재 관리**
#### `products` (432KB) - 가장 큰 테이블
```sql
-- 제품 카탈로그 마스터
- id: bigint (PK)
- tenant_id: bigint (테넌트 격리)
- code: varchar(30) -- 제품 코드 (테넌트별 유니크)
- name: varchar(100)
- unit: varchar(10) -- 단위
- category_id: bigint (FK categories)
- product_type: varchar(30) DEFAULT 'PRODUCT'
- attributes: json -- 동적 속성
- description: varchar(255)
- is_sellable: tinyint DEFAULT 1
- is_purchasable: tinyint DEFAULT 0
- is_producible: tinyint DEFAULT 1
- is_active: tinyint DEFAULT 1
- created_by, updated_by: bigint
- created_at, updated_at, deleted_at
```
#### `materials` (336KB)
```sql
-- 자재 마스터
- id: bigint (PK)
- tenant_id: bigint
- category_id: bigint (nullable)
- name: varchar(100)
- item_name: varchar(255)
- specification: varchar(100)
- material_code: varchar(50) UNIQUE
- unit: varchar(10)
- is_inspection: char(1) DEFAULT 'N'
- search_tag: text
- remarks: text
- attributes, options: json
- created_by, updated_by: bigint
- created_at, updated_at, deleted_at
```
#### `categories` (80KB)
```sql
-- 계층형 카테고리 시스템
- 동적 필드 정의 지원
- 버전 관리 (category_templates)
```
### 4. **BOM 및 설계 관리**
#### `models` (16KB)
```sql
-- 설계 모델 마스터
- 제품 설계의 상위 개념
```
#### `model_versions` (16KB)
```sql
-- 모델 버전 관리
- DRAFT/RELEASED 상태 관리
- 버전별 BOM 연결
```
#### `bom_templates` (16KB)
```sql
-- BOM 템플릿
- 모델 버전별 BOM 정의
```
#### `bom_template_items` (16KB)
```sql
-- BOM 아이템
- 자재/제품 구성 요소
- 수량, 손실률 관리
```
#### `product_components` (80KB)
```sql
-- 제품 구성 요소
- ref_type: MATERIAL|PRODUCT
- 다형성 관계 지원
```
### 5. **주문 및 견적 관리**
#### `orders` (80KB)
```sql
-- 주문/견적 마스터
- 워크플로우 상태 관리
```
#### `order_items` (64KB)
```sql
-- 주문 항목
- 설계 코드 연결
```
#### `order_item_components` (64KB)
```sql
-- 주문별 소요 자재/제품
```
#### `order_histories` (64KB)
```sql
-- 주문 변경 이력
```
### 6. **감사 로그 시스템**
#### `audit_logs` (16KB) - 최신 추가
```sql
-- 통합 감사 로그
- id: bigint (PK)
- tenant_id: bigint (테넌트 격리)
- target_type: varchar(100) -- 대상 모델
- target_id: bigint -- 대상 ID
- action: varchar(50) -- 액션 (created, updated, deleted 등)
- before: json -- 변경 전 데이터
- after: json -- 변경 후 데이터
- actor_id: bigint -- 수행자
- ip: varchar(45) -- IP 주소
- ua: varchar(255) -- User Agent
- created_at: timestamp DEFAULT CURRENT_TIMESTAMP
-- 최적화된 인덱스
- ix_audit_tenant_actor_created (tenant_id, actor_id, created_at)
- ix_audit_tenant_target_created (tenant_id, target_type, target_id, created_at)
```
### 7. **인벤토리 관리**
#### `material_receipts` (32KB)
```sql
-- 자재 입고
- 로트 추적 지원
```
#### `lots` (48KB)
```sql
-- 로트 관리
```
#### `material_inspections` (32KB)
```sql
-- 품질 검사
```
### 8. **시스템 및 설정**
#### `api_keys` (32KB)
```sql
-- API 키 관리
- 활성 상태 관리
```
#### `classifications` (48KB)
```sql
-- 코드 테이블
- 그룹별 코드 관리
```
#### `setting_field_defs` (32KB)
```sql
-- 글로벌 필드 정의
```
#### `tenant_field_settings` (32KB)
```sql
-- 테넌트별 필드 설정
```
### 9. **게시판 시스템**
#### `boards` (32KB)
```sql
-- 게시판 설정
```
#### `posts` (64KB)
```sql
-- 게시물
- 동적 필드 지원
```
#### `board_comments` (80KB)
```sql
-- 계층형 댓글
```
## 🔍 데이터베이스 특징
### **Multi-Tenant Architecture**
- 모든 주요 테이블에 `tenant_id` 컬럼으로 데이터 격리
- 테넌트별 코드 유니크 제약 (`tenant_id, code`)
- 글로벌 스키마 + 테넌트별 데이터 패턴
### **동적 필드 시스템**
- `attributes`, `options` JSON 컬럼 활용
- 카테고리별 동적 필드 정의 지원
- 버전 관리된 템플릿 시스템
### **감사 추적**
- 통합 감사 로그 시스템 구현
- 변경 전후 데이터 JSON 저장
- 성능 최적화된 인덱스 구조
### **BOM 관리**
- 계층적 제품 구성 관리
- 자재/제품 다형성 참조
- 설계 버전별 BOM 템플릿
### **권한 관리**
- Spatie Permission + 커스텀 확장
- 부서별 계층 권한
- 시간 기반 권한 재정의
## ⚠️ 주의사항
### **데이터 무결성**
- Foreign Key 제약조건 최소화 (성능 고려)
- 애플리케이션 레벨에서 참조 무결성 관리
- Soft Delete 패턴 적용 (`deleted_at`)
### **성능 고려사항**
- 대용량 테이블: `products` (432KB), `materials` (336KB)
- JSON 컬럼 활용으로 스키마 유연성 확보
- 테넌트별 데이터 분리로 쿼리 성능 최적화
### **백업 및 복원**
- 테넌트별 데이터 분리 백업 가능
- 감사 로그 별도 보관 정책 필요 (13개월 보존)
- JSON 데이터 백업시 인코딩 주의
---
**보고서 생성**: Claude Code
**검증 상태**: ✅ 모든 테이블 스키마 정상 확인
**다음 검토**: 주요 업데이트시 또는 분기별

View File

@@ -1,6 +1,6 @@
# 논리적 데이터베이스 관계 문서
> **자동 생성**: 2025-11-20 16:28:56
> **자동 생성**: 2025-11-24 19:27:59
> **소스**: Eloquent 모델 관계 분석
## 📊 모델별 관계 현황

View File

@@ -1,86 +0,0 @@
# 논리적 데이터베이스 관계 문서 (간소화)
> **생성일**: 2025-09-24 22:15:54
> **소스**: 알려진 비즈니스 관계 기반
> **참고**: FK 제거 후 논리적 관계 명세
## 📊 테이블별 논리적 관계
### 📋 `users` - 사용자 계정
- **user_tenants (hasMany)**: `user_tenants.user_id → users.id`
- **user_roles (hasMany)**: `user_roles.user_id → users.id`
- **audit_logs (hasMany)**: `audit_logs.actor_id → users.id (생성자)`
### 📋 `tenants` - 테넌트 (회사/조직)
- **user_tenants (hasMany)**: `user_tenants.tenant_id → tenants.id`
- **classifications (hasMany)**: `classifications.tenant_id → tenants.id (논리적)`
- **departments (hasMany)**: `departments.tenant_id → tenants.id`
- **products (hasMany)**: `products.tenant_id → tenants.id`
- **orders (hasMany)**: `orders.tenant_id → tenants.id`
### 📋 `categories` - 제품 카테고리 (계층구조)
- **parent (belongsTo)**: `categories.parent_id → categories.id`
- **children (hasMany)**: `categories.parent_id → categories.id`
- **products (hasMany)**: `products.category_id → categories.id`
- **estimates (hasMany)**: `estimates.model_set_id → categories.id (논리적)`
### 📋 `products` - 제품 마스터
- **category (belongsTo)**: `products.category_id → categories.id`
- **tenant (belongsTo)**: `products.tenant_id → tenants.id`
- **product_components (hasMany)**: `product_components.parent_product_id → products.id (논리적)`
- **order_items (hasMany)**: `order_items.product_id → products.id`
### 📋 `departments` - 부서 관리 (계층구조)
- **parent (belongsTo)**: `departments.parent_id → departments.id (논리적)`
- **children (hasMany)**: `departments.parent_id → departments.id (논리적)`
- **tenant (belongsTo)**: `departments.tenant_id → tenants.id`
### 📋 `estimates` - 견적서 (스냅샷 데이터)
- **category (belongsTo)**: `estimates.model_set_id → categories.id (논리적)`
- **tenant (belongsTo)**: `estimates.tenant_id → tenants.id`
- **estimate_items (hasMany)**: `estimate_items.estimate_id → estimates.id (논리적)`
### 📋 `estimate_items` - 견적 아이템
- **estimate (belongsTo)**: `estimate_items.estimate_id → estimates.id (논리적)`
- **tenant (belongsTo)**: `estimate_items.tenant_id → tenants.id`
### 📋 `product_components` - BOM 구성요소 (통합 참조구조)
- **parent_product (belongsTo)**: `product_components.parent_product_id → products.id (논리적)`
- **material_or_product (polymorphic)**: `product_components.ref_id → materials.id OR products.id (ref_type 기반)`
- **tenant (belongsTo)**: `product_components.tenant_id → tenants.id`
### 📋 `classifications` - 분류 코드
- **tenant (belongsTo)**: `classifications.tenant_id → tenants.id (논리적)`
## 🚨 중요 사항
### 논리적 관계 (FK 제거됨)
- `classifications.tenant_id → tenants.id`
- `departments.parent_id → departments.id`
- `estimates.model_set_id → categories.id`
- `estimate_items.estimate_id → estimates.id`
- `product_components` 모든 관계 (통합 구조)
### 물리적 FK 유지됨
- 모든 `tenant_id` 관계 (멀티테넌트 보안)
- 권한 관리 시스템 FK
- 기타 중요 비즈니스 FK
## 📝 개발 가이드
1. **Service 레이어**에서 논리적 무결성 검증 필수
2. **Eloquent 관계 메서드** 적극 활용
3. **Soft Delete**로 데이터 보호
4. **BelongsToTenant** 트레잇으로 테넌트 격리
---
*이 문서는 개발 참조용입니다. 모델 변경 시 업데이트 해주세요.*

40
docs/INDEX.md Normal file
View File

@@ -0,0 +1,40 @@
# API 프로젝트 문서
> 📌 **SAM API 전용 문서 허브**
---
## 📋 Swagger 문서
API 엔드포인트별 Swagger 문서입니다.
- **[Audit Log API](swagger/SWAGGER_AUDIT.md)** - 감사 로그 API 스펙
- **[Product API](swagger/SWAGGER_PHASE3_1_PRODUCT.md)** - 제품 관리 API
- **[Material API](swagger/SWAGGER_PHASE3_2_MATERIAL.md)** - 자재 관리 API
- **[Client API](swagger/SWAGGER_PHASE3_3_CLIENT.md)** - 거래처 관리 API
---
## 🔍 분석 문서
Item 관리 시스템 분석 문서입니다.
- **[Item DB 분석 v3 (최신)](analysis/SAM_Item_DB_API_Analysis_v3_FINAL.md)** - Item DB 최종 분석
- **[Item DB 분석 v2](analysis/SAM_Item_DB_API_Analysis_v2.md)** - Item DB 분석 v2
- **[Item 관리 모델링](analysis/SAM_Item_Management_DB_Modeling_Analysis.md)** - Item DB 모델링 분석
---
## 🔗 관련 문서
- **[API Rules](../docs/reference/api-rules.md)** - API 개발 규칙
- **[Swagger Guide](../docs/guides/swagger-guide.md)** - Swagger 작성 가이드
- **[Database Schema](../docs/specs/database-schema.md)** - 전체 DB 스키마
---
## 📝 문서 추가
새로운 API 문서는 다음 디렉토리에 추가:
- Swagger 문서 → `swagger/`
- 분석 문서 → `analysis/`

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
# SAM API Swagger 문서 점검 현황
## 📋 점검 개요
**목적:** SAM API의 Swagger 문서 품질을 체계적으로 점검하고 개선
**범위:** 총 30개 Swagger API 파일 (app/Swagger/v1/)
**진행 방식:** Phase별 순차 점검 (세션 독립적)
## 🎯 Phase 구성
### Phase 1: 기본 설정 및 보안 (완료 ✅)
**완료일:** 2025-11-06
#### 수정 내용:
1.**SAMInfo.php - Auth 태그 개선**
- 상세한 인증 흐름 설명 추가
- API Key 및 Bearer Token 사용 예시 추가
- IP 기반 접근 제어 안내 추가
2.**RegisterApi.php - 보안 어노테이션 추가**
- `security={{"ApiKeyAuth": {}}}` 추가
- "Authentication: Not Required" 오류 해결
3. **서버 URL 설정**
- .env 파일의 L5_SWAGGER_CONST_HOST 변수로 관리
- 사용자가 직접 수정 예정 (http://api.sam.kr/ → https://api.codebridge-x.com)
### Phase 2: Auth API 상세 점검 (완료 ✅)
**완료일:** 2025-11-06
**대상 파일:** AuthApi.php
#### 수정 내용:
1.**debug-apikey API 개선**
- description 추가 (API Key 유효성 확인 설명)
- 응답 형식 명시 (`{message: "API Key 인증 성공"}`)
2.**logout API 응답 형식 수정**
- Swagger: `{success, message, data}` → 실제: `{message}`
- 실제 코드와 일치하도록 수정
3.**login API 검증**
- 요청/응답 스키마와 실제 코드 일치 확인
- user, tenant, menus 구조 정확성 확인
4.**signup API 중복 확인**
- AuthApi.php와 RegisterApi.php가 동일 엔드포인트
- RegisterApi.php가 더 상세 (테넌트 생성 포함)
- 두 파일 모두 유지 (태그 및 구조 차이)
### Phase 3: 리소스별 순차 점검 (예정)
**총 30개 파일 중 28개 남음**
**우선순위 높음 (핵심 기능):**
- [ ] ProductApi.php
- [ ] MaterialApi.php
- [ ] ClientApi.php
- [ ] UserApi.php
- [ ] TenantApi.php
- [ ] CategoryApi.php
**우선순위 중간 (관리 기능):**
- [ ] RoleApi.php
- [ ] PermissionApi.php
- [ ] DepartmentApi.php
- [ ] MenuApi.php
- [ ] FieldProfileApi.php
- [ ] FileApi.php
**우선순위 낮음 (부가 기능):**
- [ ] ModelApi.php
- [ ] BomCalculationApi.php
- [ ] PricingApi.php
- [ ] ClassificationApi.php
- [ ] AuditLogApi.php
- [ ] CommonApi.php
**스키마 정의 파일:**
- [ ] CommonComponents.php
- [ ] ProductExtraSchemas.php
- [ ] CategoryExtras.php
- [ ] DesignBomTemplateExtras.php
## 📝 표준 점검 체크리스트
각 API 파일 점검 시 다음 항목을 확인합니다:
### 보안 및 인증
- [ ] security 어노테이션 정확성 (ApiKeyAuth, BearerAuth)
- [ ] 인증 불필요 API의 명시적 표시 (security={})
### 요청 스키마
- [ ] RequestBody 정의 완성도
- [ ] required 필드 정확성
- [ ] 타입 및 format 정확성
- [ ] example 값의 실제 동작 일치성
- [ ] nullable 속성 정확성
### 응답 스키마
- [ ] Response 정의 완성도 (200, 400, 401, 403, 404, 422, 500)
- [ ] 성공 응답의 data 구조 정확성
- [ ] 에러 응답의 message/errors 구조 일치성
- [ ] example 값과 실제 응답 일치성
- [ ] nullable/oneOf 구분 정확성
### 문서 품질
- [ ] summary 명확성
- [ ] description 상세성
- [ ] 파라미터 설명 충실도
- [ ] 예시 값의 실용성
- [ ] tags 분류 적절성
### 스키마 재사용
- [ ] 중복 스키마 존재 여부
- [ ] 공통 스키마 활용 여부
- [ ] ref 참조 정확성
## 🐛 발견된 이슈
### 해결됨 (✅)
1. **RegisterApi.php - 인증 필수 미표시**
- 문제: "Authentication: Not Required"로 표시됨
- 원인: security 어노테이션 누락
- 해결: `security={{"ApiKeyAuth": {}}}` 추가
- 완료일: 2025-11-06
2. **SAMInfo.php - Auth 태그 설명 부족**
- 문제: 인증 흐름 및 사용 예시 부족
- 해결: 상세한 설명 및 예시 추가
- 완료일: 2025-11-06
3. **AuthApi.php - logout 응답 형식 불일치**
- 문제: Swagger `{success, message, data}` vs 실제 `{message}`
- 원인: Swagger 문서가 표준 응답 형식으로 작성됨
- 해결: 실제 코드에 맞춰 `{message}` 형식으로 수정
- 완료일: 2025-11-06
4. **AuthApi.php - debug-apikey 설명 부족**
- 문제: 응답 형식 미명시
- 해결: description 및 응답 형식 추가
- 완료일: 2025-11-06
### 진행 중 (🔄)
없음
### 대기 중 (⏳)
1. **서버 URL 변경**
- 현재: http://api.sam.kr/
- 목표: https://api.codebridge-x.com
- 방법: .env 파일의 L5_SWAGGER_CONST_HOST 수정
- 담당: 사용자 직접 수정
## 📊 진행 상황
### 전체 진도
- **Phase 1:** ✅ 완료 (3/3)
- **Phase 2:** ✅ 완료 (4/4)
- **Phase 3:** ⏳ 대기 중 (0/28)
### 파일별 상태
| 파일명 | 상태 | 점검일 | 비고 |
|--------|------|--------|------|
| SAMInfo.php | ✅ 완료 | 2025-11-06 | Auth 태그 개선 |
| RegisterApi.php | ✅ 완료 | 2025-11-06 | 보안 어노테이션 추가 |
| AuthApi.php | ✅ 완료 | 2025-11-06 | logout/debug-apikey 수정 |
| ProductApi.php | ⏳ 대기 | - | Phase 3 (우선순위 높음) |
| MaterialApi.php | ⏳ 대기 | - | Phase 3 (우선순위 높음) |
| ... | ... | ... | ... |
## 🔄 다음 단계
### 즉시 실행 가능
1. Phase 1 변경사항 검증
- Swagger 재생성: `php artisan l5-swagger:generate`
- Swagger UI에서 Auth 태그 및 Register API 확인
- 실제 API 호출 테스트
2. Phase 2 시작 준비
- AuthApi.php 파일 분석
- 실제 Controller 및 Service 코드 확인
- 요청/응답 검증 계획 수립
### 사용자 조치 필요
- .env 파일의 L5_SWAGGER_CONST_HOST 수정 (운영 도메인 반영)
## 📌 참고 사항
### 세션 독립성 유지 방법
- 이 문서를 통해 작업 진행 상황 추적
- Phase별 독립 실행 가능
- 각 Phase 완료 후 Git 커밋으로 체크포인트 생성
### 품질 기준
- SAM API Development Rules 준수
- 실제 Controller/Service 코드와 100% 일치
- 사용자가 직접 테스트 가능한 예시 값
- i18n 메시지 키 사용 확인
### 관련 문서
- `CLAUDE.md` - SAM 프로젝트 전체 가이드
- `SAM API Development Rules` - API 개발 규칙
- `l5-swagger` 문서 - Swagger 어노테이션 가이드

View File

@@ -0,0 +1,201 @@
# Product API Swagger 점검 및 개선 (Phase 3-1)
**날짜:** 2025-11-07
**작업자:** Claude Code
**이슈:** Phase 3-1: ProductApi.php Swagger 점검 및 개선
## 📋 변경 개요
ProductApi.php Swagger 문서 점검 후, SAM API Development Rules에 따라 FormRequest 적용 및 i18n 메시지 키 적용
## 🔧 사용된 도구
### MCP 서버
- Sequential Thinking: 복잡한 분석 및 검증 로직 수행
- Native Tools: Read, Write, Edit, Bash, Glob 등 파일 작업
### SuperClaude 페르소나
- backend-architect: API 구조 분석 및 설계 검증
- code-workflow: 체계적 코드 수정 프로세스 적용
### 네이티브 도구
- Read: 9회 (파일 내용 확인)
- Write: 2회 (FormRequest 파일 생성)
- Edit: 2회 (Controller, message.php 수정)
- Bash: 7회 (파일 검색, 문법 체크)
- Glob: 3회 (패턴 기반 파일 검색)
## 📁 수정된 파일
### 1. `app/Http/Requests/Product/ProductStoreRequest.php` (신규 생성)
**목적:** 제품 생성 시 입력 검증을 FormRequest로 분리
**주요 내용:**
- required: code, name, category_id, product_type
- nullable: attributes, description, is_sellable, is_purchasable, is_producible, is_active
- 검증 규칙: Service에서 Controller로 이동 (SAM 규칙 준수)
### 2. `app/Http/Requests/Product/ProductUpdateRequest.php` (신규 생성)
**목적:** 제품 수정 시 입력 검증을 FormRequest로 분리
**주요 내용:**
- sometimes 규칙 적용 (부분 업데이트 지원)
- nullable 필드 동일하게 유지
### 3. `app/Http/Controllers/Api/V1/ProductController.php` (수정)
**변경 전:**
```php
public function store(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->store($request->all());
}, '제품 생성');
}
```
**변경 후:**
```php
public function store(ProductStoreRequest $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->store($request->validated());
}, __('message.product.created'));
}
```
**변경 이유:**
- FormRequest 적용으로 검증 로직 분리 (SAM 규칙)
- `$request->all()``$request->validated()` (보안 강화)
- 하드코딩된 한글 메시지 → i18n 키 사용
**적용된 메서드:**
- getCategory(): `__('message.product.category_fetched')`
- index(): `__('message.product.fetched')`
- store(): `__('message.product.created')`
- show(): `__('message.product.fetched')`
- update(): `__('message.product.updated')`
- destroy(): `__('message.product.deleted')`
- search(): `__('message.product.searched')`
- toggle(): `__('message.product.toggled')`
### 4. `lang/ko/message.php` (수정)
**변경 전:**
```php
'product' => [
'created' => '제품이 등록되었습니다.',
'updated' => '제품이 수정되었습니다.',
'deleted' => '제품이 삭제되었습니다.',
'toggled' => '제품 상태가 변경되었습니다.',
],
```
**변경 후:**
```php
'product' => [
'fetched' => '제품을 조회했습니다.',
'category_fetched' => '제품 카테고리를 조회했습니다.',
'created' => '제품이 등록되었습니다.',
'updated' => '제품이 수정되었습니다.',
'deleted' => '제품이 삭제되었습니다.',
'toggled' => '제품 상태가 변경되었습니다.',
'searched' => '제품을 검색했습니다.',
],
```
**변경 이유:** Controller의 모든 메서드에 대응하는 i18n 키 추가
## 🔍 분석 결과
### BOM API 확인
- ✅ ProductBomItemController 존재 확인
- ✅ Route 정의 확인 (/api/v1/products/{id}/bom/*)
- ✅ ProductBomService 존재
- ✅ Swagger 정의 (ProductApi.php)와 실제 구현 일치
### 스키마 확인
- ✅ ProductExtraSchemas.php 존재
- ✅ Product, ProductPagination, ProductCreateRequest, ProductUpdateRequest 스키마 정의됨
- ✅ BomItem, BomItemBulkUpsertRequest, BomItemUpdateRequest, BomReorderRequest 스키마 정의됨
- ✅ BomTreeNode, BomCategoryStat, BomReplaceRequest 스키마 정의됨 (ProductApi.php 내부)
### SAM API Rules 준수 확인
#### ✅ 준수 항목
1. **FormRequest 사용**
- ProductStoreRequest, ProductUpdateRequest 생성
- Controller에서 타입 힌트 적용
- `$request->validated()` 사용
2. **i18n 메시지 키 사용**
- 모든 하드코딩된 한글 메시지 제거
- `__('message.product.xxx')` 형식 적용
3. **Service-First 패턴**
- 비즈니스 로직은 Service에 유지
- Controller는 DI + ApiResponse::handle()만 사용
4. **Multi-tenancy**
- ProductService에서 BelongsToTenant 적용 확인
- tenant_id 필터링 확인
#### ⚠️ 개선 여부 결정 필요
1. **검증 로직 중복**
- ProductService에 Validator::make() 로직 존재
- FormRequest에서 기본 검증, Service에서 비즈니스 검증 (code 중복 체크 등)
- **현재 상태:** 유지 (비즈니스 검증은 Service에서 처리하는 것이 적절)
## ✅ 테스트 체크리스트
- [x] PHP 문법 체크 (php -l)
- [x] ProductStoreRequest 문법 확인
- [x] ProductUpdateRequest 문법 확인
- [x] ProductController 문법 확인
- [x] message.php 문법 확인
- [ ] Swagger 재생성 (`php artisan l5-swagger:generate`)
- [ ] Swagger UI 확인 (http://api.sam.kr/api-docs/index.html)
- [ ] 실제 API 호출 테스트
- [ ] GET /api/v1/product/category
- [ ] GET /api/v1/products
- [ ] POST /api/v1/products (FormRequest 검증 확인)
- [ ] GET /api/v1/products/{id}
- [ ] PATCH /api/v1/products/{id} (FormRequest 검증 확인)
- [ ] DELETE /api/v1/products/{id}
- [ ] GET /api/v1/products/search
- [ ] POST /api/v1/products/{id}/toggle
## ⚠️ 배포 시 주의사항
1. **FormRequest 적용으로 검증 로직 변경**
- 기존: Service에서 모든 검증
- 변경 후: FormRequest(기본 검증) + Service(비즈니스 검증)
- 영향: 검증 에러 응답 형식 동일 (422 Unprocessable Entity)
2. **i18n 메시지 변경**
- 기존: 하드코딩된 한글 메시지
- 변경 후: i18n 키 사용
- 영향: 응답 메시지 내용 약간 변경 (의미는 동일)
3. **BOM API 미수정**
- ProductBomItemController는 별도 Controller
- 현재 작업에서는 제외
- Phase 3-1 완료 후 별도 점검 필요
## 🔗 관련 문서
- `CLAUDE.md` - SAM 프로젝트 가이드
- `SWAGGER_AUDIT.md` - Swagger 전체 점검 현황
- SAM API Development Rules (CLAUDE.md 내 섹션)
## 📊 변경 통계
- **신규 파일:** 2개 (FormRequest)
- **수정 파일:** 2개 (Controller, message.php)
- **삭제 파일:** 0개
- **총 변경 라인:** ~50줄
- **SAM 규칙 준수:** 100%
## 🎯 다음 작업
1. Swagger 재생성 및 검증
2. 실제 API 테스트
3. Phase 3-2: MaterialApi.php Swagger 점검

View File

@@ -0,0 +1,335 @@
# Material API Swagger 점검 및 개선 (Phase 3-2)
**날짜:** 2025-11-07
**작업자:** Claude Code
**이슈:** Phase 3-2: MaterialApi.php Swagger 점검 및 개선
## 📋 변경 개요
MaterialApi.php Swagger 문서 점검 후, SAM API Development Rules에 따라:
- **경로 불일치 해결**: `/api/v1/materials``/api/v1/products/materials`
- **Swagger 주석 분리**: Controller에서 MaterialApi.php로 완전 이전
- **FormRequest 적용**: MaterialStoreRequest, MaterialUpdateRequest 생성
- **i18n 메시지 키 적용**: 하드코딩된 한글 메시지 제거
## 🔍 분석 결과
### 1. 경로 불일치 문제 발견
**문제점:**
- MaterialApi.php: `/api/v1/materials` (잘못된 경로)
- MaterialController.php: `/api/v1/products/materials` (실제 경로)
- Route 파일: `/api/v1/products/materials` (실제 정의)
**선택지:**
1. ~~MaterialApi.php 삭제, Controller 주석 유지~~
2. **MaterialApi.php 경로 수정, Controller 주석 삭제**
3. ~~둘 다 유지, 경로만 일치시키기~~
**사용자 결정:** 옵션 2 선택 (MaterialApi.php를 표준으로 사용)
### 2. Swagger 주석 중복
- MaterialController.php에 327줄의 Swagger 주석 존재
- SAM API Development Rules: Swagger 주석은 별도 파일에 작성
- **해결:** Controller의 모든 Swagger 주석 제거 (327줄 → 50줄)
### 3. FormRequest 누락
- Controller에서 `Request $request` 사용 (검증 로직 없음)
- MaterialService에 Validator::make() 로직 존재 (추정)
- **해결:** MaterialStoreRequest, MaterialUpdateRequest 생성
### 4. i18n 메시지 하드코딩
- Controller에서 `__('message.materials.xxx')` 사용
- lang/ko/message.php에 'materials' 키 존재 (복수형)
- **해결:** 'material' (단수형)로 통일
## 📁 수정된 파일
### 1. `app/Http/Requests/Material/MaterialStoreRequest.php` (신규 생성)
**목적:** 자재 생성 시 입력 검증을 FormRequest로 분리
**주요 내용:**
```php
public function rules(): array
{
return [
'category_id' => 'nullable|integer',
'name' => 'required|string|max:100',
'unit' => 'required|string|max:20',
'is_inspection' => 'nullable|in:Y,N',
'search_tag' => 'nullable|string|max:255',
'remarks' => 'nullable|string|max:500',
'attributes' => 'nullable|array',
'attributes.*.label' => 'required|string|max:50',
'attributes.*.value' => 'required|string|max:100',
'attributes.*.unit' => 'nullable|string|max:20',
'options' => 'nullable|array',
'material_code' => 'nullable|string|max:30',
'specification' => 'nullable|string|max:255',
];
}
```
**검증 규칙:**
- **필수 필드**: name, unit
- **중첩 배열 검증**: attributes 배열 내부 label, value 필수
- **제약 조건**: is_inspection은 Y/N만 허용
### 2. `app/Http/Requests/Material/MaterialUpdateRequest.php` (신규 생성)
**목적:** 자재 수정 시 입력 검증을 FormRequest로 분리
**주요 내용:**
- StoreRequest와 동일한 필드 구조
- 모든 필드에 'sometimes' 규칙 적용 (부분 업데이트 지원)
- name, unit은 'sometimes' + 'string' (필수 아님)
### 3. `app/Swagger/v1/MaterialApi.php` (수정)
**변경 전:**
```php
/**
* @OA\Get(
* path="/api/v1/materials",
* ...
* )
*/
```
**변경 후:**
```php
/**
* @OA\Get(
* path="/api/v1/products/materials",
* ...
* )
*/
```
**적용된 엔드포인트:**
- GET `/api/v1/products/materials` (목록 조회)
- POST `/api/v1/products/materials` (자재 등록)
- GET `/api/v1/products/materials/{id}` (단건 조회)
- PUT `/api/v1/products/materials/{id}` (전체 수정)
- PATCH `/api/v1/products/materials/{id}` (부분 수정)
- DELETE `/api/v1/products/materials/{id}` (삭제)
**변경 이유:**
- Route 정의와 경로 일치 (`/api/v1/products/materials`)
- Products 그룹 내 Materials 서브 리소스로 구조화
### 4. `app/Http/Controllers/Api/V1/MaterialController.php` (수정)
**변경 전:** 327줄 (Swagger 주석 포함)
```php
/**
* @OA\Tag(
* name="Products & Materials - Materials",
* description="자재 관리 API (Products 그룹 내 통합)"
* )
*/
class MaterialController extends Controller
{
/**
* @OA\Get(
* path="/api/v1/products/materials",
* summary="자재 목록 조회",
* ...
* )
*/
public function index(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->getMaterials($request->all());
}, __('message.materials.fetched'));
}
// ... 300줄의 Swagger 주석
}
```
**변경 후:** 50줄 (비즈니스 로직만 유지)
```php
class MaterialController extends Controller
{
public function __construct(private MaterialService $service) {}
public function index(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->getMaterials($request->all());
}, __('message.material.fetched'));
}
public function store(MaterialStoreRequest $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->setMaterial($request->validated());
}, __('message.material.created'));
}
public function show(int $id)
{
return ApiResponse::handle(function () use ($id) {
return $this->service->getMaterial($id);
}, __('message.material.fetched'));
}
public function update(MaterialUpdateRequest $request, int $id)
{
return ApiResponse::handle(function () use ($request, $id) {
return $this->service->updateMaterial($id, $request->validated());
}, __('message.material.updated'));
}
public function destroy(int $id)
{
return ApiResponse::handle(function () use ($id) {
return $this->service->destroyMaterial($id);
}, __('message.material.deleted'));
}
}
```
**변경 이유:**
1. **Swagger 주석 분리**: Controller는 비즈니스 로직만 담당 (SAM 규칙)
2. **FormRequest 적용**: `Request``MaterialStoreRequest`, `MaterialUpdateRequest`
3. **validated() 사용**: `$request->all()``$request->validated()` (보안 강화)
4. **i18n 키 사용**: `materials.xxx``material.xxx` (단수형 통일)
5. **불필요한 파라미터 제거**: show()와 destroy()에서 `Request $request` 제거
**적용된 메서드:**
- index(): `__('message.material.fetched')`
- store(): `__('message.material.created')`
- show(): `__('message.material.fetched')`
- update(): `__('message.material.updated')`
- destroy(): `__('message.material.deleted')`
### 5. `lang/ko/message.php` (수정)
**변경 전:**
```php
'materials' => [
'created' => '자재가 등록되었습니다.',
'updated' => '자재가 수정되었습니다.',
'deleted' => '자재가 삭제되었습니다.',
'fetched' => '자재 목록을 조회했습니다.',
],
```
**변경 후:**
```php
'material' => [
'fetched' => '자재를 조회했습니다.',
'created' => '자재가 등록되었습니다.',
'updated' => '자재가 수정되었습니다.',
'deleted' => '자재가 삭제되었습니다.',
],
```
**변경 이유:**
1. **단수형 통일**: 'materials' → 'material' (product, category와 일관성)
2. **순서 정렬**: CRUD 순서로 재배치 (fetched, created, updated, deleted)
3. **메시지 개선**: "자재 목록을 조회했습니다." → "자재를 조회했습니다." (단건/목록 공통 사용)
## 🔍 SAM API Rules 준수 확인
### ✅ 준수 항목
1. **Swagger 주석 분리**
- MaterialApi.php에 모든 Swagger 주석 집중
- Controller는 비즈니스 로직만 유지
2. **FormRequest 사용**
- MaterialStoreRequest, MaterialUpdateRequest 생성
- Controller에서 타입 힌트 적용
- `$request->validated()` 사용
3. **i18n 메시지 키 사용**
- 모든 하드코딩된 한글 메시지 제거
- `__('message.material.xxx')` 형식 적용
4. **경로 일치성**
- Swagger 문서와 실제 Route 경로 일치
- `/api/v1/products/materials` 통일
5. **Service-First 패턴**
- 비즈니스 로직은 MaterialService에 유지
- Controller는 DI + ApiResponse::handle()만 사용
6. **Multi-tenancy**
- MaterialService에서 BelongsToTenant 적용 (추정)
- tenant_id 필터링 유지
## ✅ 테스트 체크리스트
- [x] PHP 문법 체크 (php -l)
- [x] MaterialStoreRequest 문법 확인
- [x] MaterialUpdateRequest 문법 확인
- [x] MaterialApi.php 문법 확인
- [x] MaterialController 문법 확인
- [x] message.php 문법 확인
- [ ] Swagger 재생성 (`php artisan l5-swagger:generate`)
- [ ] Swagger UI 확인 (http://api.sam.kr/api-docs/index.html)
- [ ] 실제 API 호출 테스트
- [ ] GET /api/v1/products/materials
- [ ] POST /api/v1/products/materials (FormRequest 검증 확인)
- [ ] GET /api/v1/products/materials/{id}
- [ ] PATCH /api/v1/products/materials/{id} (FormRequest 검증 확인)
- [ ] DELETE /api/v1/products/materials/{id}
## ⚠️ 배포 시 주의사항
1. **경로 변경 없음**
- 실제 Route는 변경되지 않음 (이미 `/api/v1/products/materials` 사용 중)
- Swagger 문서만 실제 경로와 일치하도록 수정
- **영향:** 기존 API 클라이언트는 영향 없음
2. **FormRequest 적용으로 검증 로직 변경**
- 기존: Service에서 모든 검증 (추정)
- 변경 후: FormRequest(기본 검증) + Service(비즈니스 검증)
- **영향:** 검증 에러 응답 형식 동일 (422 Unprocessable Entity)
3. **i18n 메시지 변경**
- 기존: `__('message.materials.xxx')`
- 변경 후: `__('message.material.xxx')`
- **영향:** 응답 메시지 내용 약간 변경 (의미는 동일)
4. **Controller 코드 간소화**
- 327줄 → 50줄 (Swagger 주석 제거)
- **영향:** 유지보수성 향상, 기능은 동일
## 📊 변경 통계
- **신규 파일:** 2개 (FormRequest)
- **수정 파일:** 3개 (MaterialApi.php, MaterialController.php, message.php)
- **삭제 파일:** 0개
- **코드 감소:** -212줄 (Controller Swagger 주석 제거)
- **실질 추가:** +88줄 (FormRequest + i18n)
- **SAM 규칙 준수:** 100%
## 🎯 다음 작업
1. Swagger 재생성 및 검증
2. 실제 API 테스트
3. Phase 3-3: ClientApi.php Swagger 점검
## 🔗 관련 문서
- `CLAUDE.md` - SAM 프로젝트 가이드
- `SWAGGER_AUDIT.md` - Swagger 전체 점검 현황
- `SWAGGER_PHASE3_1_PRODUCT.md` - Phase 3-1 작업 문서
- SAM API Development Rules (CLAUDE.md 내 섹션)
## 📝 커밋 정보
**커밋 해시:** f4d663a
**커밋 메시지:**
```
feat: MaterialApi.php Swagger 점검 및 개선 (Phase 3-2)
- MaterialStoreRequest.php 생성 (검증 로직 분리)
- MaterialUpdateRequest.php 생성 (검증 로직 분리)
- MaterialApi.php 경로 수정 (/api/v1/products/materials)
- MaterialController.php Swagger 주석 제거, FormRequest 적용
- lang/ko/message.php material 메시지 키 추가
- SAM API Development Rules 준수 완료
```
---
**Phase 3-2 완료 ✅**

View File

@@ -0,0 +1,284 @@
# Client API Swagger 점검 및 개선 (Phase 3-3)
**날짜:** 2025-11-07
**작업자:** Claude Code
**이슈:** Phase 3-3: ClientApi.php Swagger 점검 및 개선
## 📋 변경 개요
ClientApi.php Swagger 문서 점검 후, SAM API Development Rules에 따라:
- **FormRequest 적용**: ClientStoreRequest, ClientUpdateRequest 생성
- **i18n 메시지 키 적용**: 리소스별 키 사용 (`message.client.xxx`)
- **Controller 패턴 통일**: ApiResponse::handle 두 번째 인자로 메시지 전달
- **코드 간소화**: 불필요한 배열 래핑 제거
## 🔍 분석 결과
### ✅ 좋은 점
1. **Swagger 구조**: ClientApi.php가 별도 파일로 잘 분리되어 있음
2. **스키마 완성도**: Client, ClientPagination, ClientCreateRequest, ClientUpdateRequest 모두 정의됨
3. **Controller 간결함**: Swagger 주석이 없어서 깔끔함 (Phase 3-1, 3-2와 동일)
4. **경로 일치성**: Swagger와 실제 Route 경로가 일치 (`/api/v1/clients`)
### ⚠️ 개선이 필요한 점
1. **FormRequest 누락**: ClientStoreRequest, ClientUpdateRequest 없음
2. **i18n 메시지**: 공통 키만 사용 (`message.fetched`, `message.created`) - 리소스별 키 필요
3. **Controller 패턴 불일치**:
- 기존: `return ['data' => $data, 'message' => __('message.xxx')]` (배열 래핑)
- Product/Material: `return $this->service->xxx()` + ApiResponse::handle 두 번째 인자
4. **Constructor 스타일**: `protected` + 수동 할당 (PHP 8.2+ constructor property promotion 미사용)
## 📁 수정된 파일
### 1. `app/Http/Requests/Client/ClientStoreRequest.php` (신규 생성)
**목적:** 거래처 생성 시 입력 검증을 FormRequest로 분리
**주요 내용:**
```php
public function rules(): array
{
return [
'client_group_id' => 'nullable|integer',
'client_code' => 'required|string|max:50',
'name' => 'required|string|max:100',
'contact_person' => 'nullable|string|max:100',
'phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:255',
'is_active' => 'nullable|in:Y,N',
];
}
```
**검증 규칙:**
- **필수 필드**: client_code, name
- **이메일 검증**: email 규칙 적용
- **제약 조건**: is_active는 Y/N만 허용
### 2. `app/Http/Requests/Client/ClientUpdateRequest.php` (신규 생성)
**목적:** 거래처 수정 시 입력 검증을 FormRequest로 분리
**주요 내용:**
- StoreRequest와 동일한 필드 구조
- client_code, name에 'sometimes' 규칙 적용 (부분 업데이트 지원)
- 나머지 필드는 nullable (선택적 업데이트)
### 3. `app/Http/Controllers/Api/V1/ClientController.php` (수정)
**변경 전:** 73줄
```php
class ClientController extends Controller
{
protected ClientService $service;
public function __construct(ClientService $service)
{
$this->service = $service;
}
public function index(Request $request)
{
return ApiResponse::handle(function () use ($request) {
$data = $this->service->index($request->all());
return ['data' => $data, 'message' => __('message.fetched')];
});
}
public function store(Request $request)
{
return ApiResponse::handle(function () use ($request) {
$data = $this->service->store($request->all());
return ['data' => $data, 'message' => __('message.created')];
});
}
// ... 나머지 메서드들도 동일한 패턴
}
```
**변경 후:** 58줄
```php
class ClientController extends Controller
{
public function __construct(private ClientService $service) {}
public function index(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->index($request->all());
}, __('message.client.fetched'));
}
public function store(ClientStoreRequest $request)
{
return ApiResponse::handle(function () use ($request) {
return $this->service->store($request->validated());
}, __('message.client.created'));
}
public function update(ClientUpdateRequest $request, int $id)
{
return ApiResponse::handle(function () use ($request, $id) {
return $this->service->update($id, $request->validated());
}, __('message.client.updated'));
}
public function destroy(int $id)
{
return ApiResponse::handle(function () use ($id) {
$this->service->destroy($id);
return 'success';
}, __('message.client.deleted'));
}
public function toggle(int $id)
{
return ApiResponse::handle(function () use ($id) {
return $this->service->toggle($id);
}, __('message.client.toggled'));
}
}
```
**주요 변경사항:**
1. **Constructor Property Promotion**: `protected` + 수동 할당 → `private` + 자동 할당
2. **FormRequest 적용**: `Request``ClientStoreRequest`, `ClientUpdateRequest`
3. **validated() 사용**: `$request->all()``$request->validated()` (보안 강화)
4. **패턴 통일**: 배열 래핑 제거, ApiResponse::handle 두 번째 인자로 메시지 전달
5. **i18n 키 사용**: `message.xxx``message.client.xxx` (리소스별 키)
**적용된 메서드:**
- index(): `__('message.client.fetched')`
- show(): `__('message.client.fetched')`
- store(): `__('message.client.created')`
- update(): `__('message.client.updated')`
- destroy(): `__('message.client.deleted')`
- toggle(): `__('message.client.toggled')`
### 4. `lang/ko/message.php` (수정)
**추가된 내용:**
```php
// 거래처 관리
'client' => [
'fetched' => '거래처를 조회했습니다.',
'created' => '거래처가 등록되었습니다.',
'updated' => '거래처가 수정되었습니다.',
'deleted' => '거래처가 삭제되었습니다.',
'toggled' => '거래처 상태가 변경되었습니다.',
],
```
**추가 이유:**
- Product, Material과 일관성 유지
- 리소스별 명확한 메시지 제공
- toggle() 메서드용 메시지 추가 (상태 변경 전용)
## 🔍 SAM API Rules 준수 확인
### ✅ 준수 항목
1. **Swagger 주석 분리**
- ClientApi.php에 모든 Swagger 주석 집중 (이미 준수됨)
- Controller는 비즈니스 로직만 유지
2. **FormRequest 사용**
- ClientStoreRequest, ClientUpdateRequest 생성
- Controller에서 타입 힌트 적용
- `$request->validated()` 사용
3. **i18n 메시지 키 사용**
- 모든 공통 키를 리소스별 키로 변경
- `__('message.client.xxx')` 형식 적용
4. **Controller 패턴 통일**
- Product, Material과 동일한 패턴 적용
- ApiResponse::handle 두 번째 인자로 메시지 전달
- 불필요한 배열 래핑 제거
5. **Service-First 패턴**
- 비즈니스 로직은 ClientService에 유지
- Controller는 DI + ApiResponse::handle()만 사용
6. **Modern PHP 문법**
- Constructor Property Promotion 사용 (PHP 8.0+)
- Private property로 캡슐화 강화
## ✅ 테스트 체크리스트
- [x] PHP 문법 체크 (php -l)
- [x] ClientStoreRequest 문법 확인
- [x] ClientUpdateRequest 문법 확인
- [x] ClientController 문법 확인
- [x] message.php 문법 확인
- [ ] Swagger 재생성 (`php artisan l5-swagger:generate`)
- [ ] Swagger UI 확인 (http://api.sam.kr/api-docs/index.html)
- [ ] 실제 API 호출 테스트
- [ ] GET /api/v1/clients (목록 조회)
- [ ] POST /api/v1/clients (FormRequest 검증 확인)
- [ ] GET /api/v1/clients/{id} (단건 조회)
- [ ] PUT /api/v1/clients/{id} (FormRequest 검증 확인)
- [ ] DELETE /api/v1/clients/{id} (삭제)
- [ ] PATCH /api/v1/clients/{id}/toggle (상태 토글)
## ⚠️ 배포 시 주의사항
1. **FormRequest 적용으로 검증 로직 변경**
- 기존: Service에서 모든 검증 (추정)
- 변경 후: FormRequest(기본 검증) + Service(비즈니스 검증)
- **영향:** 검증 에러 응답 형식 동일 (422 Unprocessable Entity)
2. **i18n 메시지 변경**
- 기존: `__('message.fetched')`, `__('message.created')` (공통 키)
- 변경 후: `__('message.client.xxx')` (리소스별 키)
- **영향:** 응답 메시지 내용 약간 변경 (의미는 동일)
3. **Controller 응답 패턴 변경**
- 기존: `return ['data' => $data, 'message' => __('message.xxx')]`
- 변경 후: `return $data` + ApiResponse::handle 두 번째 인자
- **영향:** 응답 JSON 구조는 동일 (ApiResponse::handle이 래핑 처리)
4. **코드 간소화**
- 73줄 → 58줄 (15줄 감소)
- **영향:** 유지보수성 향상, 기능은 동일
## 📊 변경 통계
- **신규 파일:** 2개 (FormRequest)
- **수정 파일:** 2개 (ClientController.php, message.php)
- **삭제 파일:** 0개
- **코드 감소:** -15줄 (Controller 간소화)
- **실질 추가:** +60줄 (FormRequest)
- **SAM 규칙 준수:** 100%
## 🎯 다음 작업
1. Swagger 재생성 및 검증
2. 실제 API 테스트
3. Phase 3-4: UserApi.php Swagger 점검
## 🔗 관련 문서
- `CLAUDE.md` - SAM 프로젝트 가이드
- `SWAGGER_AUDIT.md` - Swagger 전체 점검 현황
- `SWAGGER_PHASE3_1_PRODUCT.md` - Phase 3-1 작업 문서
- `SWAGGER_PHASE3_2_MATERIAL.md` - Phase 3-2 작업 문서
- SAM API Development Rules (CLAUDE.md 내 섹션)
## 📝 커밋 정보
**커밋 해시:** c87aadc
**커밋 메시지:**
```
feat: ClientApi.php Swagger 점검 및 개선 (Phase 3-3)
- ClientStoreRequest.php 생성 (검증 로직 분리)
- ClientUpdateRequest.php 생성 (검증 로직 분리)
- ClientController.php FormRequest 적용 및 패턴 통일
- lang/ko/message.php client 메시지 키 추가
- ApiResponse::handle 패턴 통일 (메시지 두 번째 인자)
- SAM API Development Rules 준수 완료
```
---
**Phase 3-3 완료 ✅**