docs: [QA] QA 점검 이슈 6건 추가 + Phase 1~4 진행 상태 업데이트

- 추가 이슈: #38 제어기 계산(Critical), #39 개소분리, #40 미터단위, #41 재고조정API, #42 검사모달, #43 절곡바라시(보류)
- Phase 1 완료(3건), Phase 2 진행중(5/9), Phase 4 일부 완료
- 총 37건 → 43건, 진행률 16/43 (37%)
This commit is contained in:
2026-03-17 13:39:08 +09:00
parent db8e9ae94c
commit 560d63eb06

View File

@@ -1,7 +1,7 @@
# 경동dev QA 점검 이슈 수정 계획
> **작성일**: 2026-03-13
> **목적**: 경동dev 모듈별 기능 및 UI 점검 결과 37건 이슈 체계적 수정
> **목적**: 경동dev 모듈별 기능 및 UI 점검 결과 43건 이슈 체계적 수정
> **기준 문서**: `경동dev_모듈별_기능 및 UI점검 - 시트1.csv`
> **상태**: 🔄 진행중
@@ -11,10 +11,10 @@
| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | 컨펌 대기 6건 결정 완료 |
| **다음 작업** | Phase 1: Critical 수정 |
| **진행률** | 0/37 (0%) — 컨펌 완료, 수정 대기 |
| **마지막 업데이트** | 2026-03-14 |
| **마지막 완료 작업** | Phase 1 Critical 3건 + Phase 2 Major 5건 완료 (2026-03-16) |
| **다음 작업** | Phase 2: #25 거래처 담당자 자동채움, #39 개소별 분리 |
| **진행률** | 16/43 (37%) — Phase 1 완료, Phase 2 진행중, Phase 4 일부 완료 |
| **마지막 업데이트** | 2026-03-16 |
---
@@ -22,26 +22,31 @@
### 1.1 배경
경동dev 환경에서 모듈별 기능 및 UI를 점검한 결과 37건의 이슈가 발견됨.
2026-03-16 추가 점검으로 6건 추가 등록 (총 43건).
Critical 2건은 데이터 정합성에 직접 영향을 주므로 즉시 수정 필요.
### 1.2 이슈 통계
| 중요도 | 건수 | 비고 |
|--------|------|------|
| **Critical** | 2건 | 데이터 정합성 파괴 |
| **Major** | 12건 | 핵심 기능 오류 |
| **Minor** | 14건 | UI/UX 개선 |
| **Critical** | 3건 | 데이터 정합성 파괴 (#6 제어기 계산 오류 추가) |
| **Major** | 15건 | 핵심 기능 오류 (#1,#2,#5 추가) |
| **Minor** | 15건 | UI/UX 개선 (#3 추가) |
| **확인 필요** | 9건 | 정책 확인 후 결정 |
| **보류 (mng 선행)** | 1건 | #4 절곡 바라시 |
| 모듈 | 건수 |
|------|------|
| 견적관리 | 20건 |
| 수주관리 | 5건 |
| 거래처관리 | 2건 |
| 단가관리 | 2건 |
| 품목관리 | 2건 |
| 생산/작업지시 | 2건 |
| 공통 | 4건 |
| 견적관리 | 22건 | +#5 개소분리, +#6 제어기 계산 |
| 수주관리 | 5건 | |
| 거래처관리 | 2건 | |
| 단가관리 | 2건 | |
| 품목관리 | 2건 | |
| 생산/작업지시 | 3건 | +#1 미터단위 자재투입 |
| 재고관리 | 1건 | +#2 재고조정 API |
| 품질검사 | 1건 | +#3 검사모달 페이지이동 |
| 절곡(mng 선행) | 1건 | +#4 바라시보기 (보류) |
| 공통 | 4건 | |
### 1.3 변경 승인 정책
@@ -80,11 +85,11 @@ Critical 2건은 데이터 정합성에 직접 영향을 주므로 즉시 수정
---
### 2.1 Phase 1: Critical 수정 (2건) — 예상 1일
### 2.1 Phase 1: Critical 수정 (3건) — ✅ 완료
> 데이터 정합성에 직접 영향. 최우선 수정.
> 데이터 정합성에 직접 영향. 최우선 수정. **3건 모두 완료 (2026-03-16)**
#### #27 수주등록 - 견적 불러오기 실패 `Critical`
#### #27 수주등록 - 견적 불러오기 실패 `Critical`
| 항목 | 내용 |
|------|------|
@@ -147,7 +152,7 @@ Critical 2건은 데이터 정합성에 직접 영향을 주므로 즉시 수정
---
#### #31 생산지시 후 견적 수정 가능 → 금액 불일치 `Critical`
#### #31 생산지시 후 견적 수정 가능 → 금액 불일치 `Critical`
| 항목 | 내용 |
|------|------|
@@ -219,9 +224,30 @@ public function isEditable(): bool
---
### 2.2 Phase 2: Major - 견적관리 (8건) — 예상 2.5일
#### #38 견적 금액 제어기 값 오류 (1개소만 계산) `Critical` ✅
#### 2.2.1 BOM 탭 순서 통일 (#18, #19, #20, #22) — 4건 묶음
| 항목 | 내용 |
|------|------|
| **현상** | 제어기(controller) BOM 금액이 1개소분만 계산됨. 다른 항목(주자재, 모터 등)은 수량에 맞게 정상 계산 |
| **기대** | 제어기도 개소 수량에 맞게 금액 계산 |
| **모듈** | 견적관리 |
**수정 대상:**
| 파일 | 변경 내용 |
|------|----------|
| `api/app/Services/Quote/FormulaEvaluatorService.php` | 제어기(controller) 카테고리 수량 계산 로직 확인 — 1개소 고정 버그 |
| `react/src/components/quotes/` | 프론트 BOM 결과 표시 시 제어기 수량/금액 확인 |
**검증:**
- [ ] 2개소 이상 견적에서 제어기 금액이 개소 수량에 맞게 계산되는지 확인
- [ ] 1개소 견적에서 기존 동작 유지 확인
- [ ] 다른 BOM 카테고리(주자재, 모터 등) 영향 없음 확인
---
### 2.2 Phase 2: Major - 견적관리 (9건) — 🔄 진행중 (5/9 완료)
#### 2.2.1 BOM 탭 순서 통일 (#18, #19, #20, #22) — 4건 묶음 ✅
| 항목 | 내용 |
|------|------|
@@ -281,7 +307,7 @@ public function isEditable(): bool
---
#### 2.2.2 스크린+스틸 혼합 등록 차단 (#16)
#### 2.2.2 스크린+스틸 혼합 등록 차단 (#16)
| 항목 | 내용 |
|------|------|
@@ -303,7 +329,7 @@ public function isEditable(): bool
---
#### 2.2.3 견적 저장/확정 분리 (#23)
#### 2.2.3 견적 저장/확정 분리 (#23)
| 항목 | 내용 |
|------|------|
@@ -331,7 +357,7 @@ public function isEditable(): bool
---
#### 2.2.4 기타 품목 수동추가 이슈 (#14, #21)
#### 2.2.4 기타 품목 수동추가 이슈 (#14, #21)
**근본 원인**: `LocationDetailPanel.tsx:175-176`
- 기타 탭은 `tabs.push({ value: "etc", label: "기타" })`로 항상 마지막 추가
@@ -346,7 +372,7 @@ public function isEditable(): bool
---
#### 2.2.5 필터 셀렉트박스 라벨 (#8)
#### 2.2.5 필터 셀렉트박스 라벨 (#8)
**근본 원인**: `QuoteManagementClient.tsx:312-336`
- 두 셀렉트박스 모두 `placeholder` 설정은 있음 ("제품분류", "상태")
@@ -384,7 +410,29 @@ const handleClientChange = (selectedClient: Client | null) => {
---
### 2.3 Phase 3: Major - 기타 모듈 (4건+) — 예상 2.25일
#### 2.2.7 견적→수주 변환 시 개소별 분리 (#39)
| 항목 | 내용 |
|------|------|
| **현상** | 견적에서는 수량 2개 이상(여러 개소)을 하나로 등록 가능하나, 수주로 변환 시 그대로 넘어감 |
| **기대** | 수주 등록 시 **개소별로 쪼개서** 각 개소별 견적 단위로 분리되어 들어가야 함 |
| **예시** | 견적 1건(3개소, 수량3) → 수주 등록 시 개소별 3건으로 분리 |
| **모듈** | 견적관리 → 수주관리 |
**수정 대상:**
| 파일 | 변경 내용 |
|------|----------|
| `api/app/Services/Order/OrderService.php` | 견적→수주 변환(`store`) 시 개소별 분리 로직 추가 |
| `react/src/components/orders/` | 견적 불러오기 후 개소별 분리 표시 처리 |
**검증:**
- [ ] 2개소 이상 견적 → 수주 변환 시 개소별 분리 확인
- [ ] 1개소 견적은 기존 동작 유지
- [ ] 분리된 수주 각각의 금액/수량 정합성 확인
---
### 2.3 Phase 3: Major - 기타 모듈 (7건) — 예상 2.5일
#### #6 거래처 등록 미노출
@@ -437,16 +485,23 @@ const handleClientChange = (selectedClient: Client | null) => {
---
#### #34 품목목록 규격 컬럼 비어있음
#### #34 품목목록 규격 컬럼 비어있음 — 🔄 부분 완료
**분석**: `api/app/Models/Items/Item.php:21-29`
- 규격은 `attributes` JSON 컬럼에 저장 (cast: array)
- **API 목록 조회 시 `attributes` 필드가 응답에 포함되는지, 프론트에서 올바르게 바인딩하는지 확인 필요**
**원인**: `attributes.spec`(레거시)에 규격 저장. Item 모델에 accessor 미존재 → API 응답에 미포함.
**데이터**: 경동 893건 중 604건(68%) 규격 보유.
| 파일 | 변경 내용 |
|------|----------|
| `api/app/Services/ItemService.php` | 목록 조회 시 attributes에서 규격 값 추출하여 응답에 포함 |
| 프론트 품목 목록 컴포넌트 | 규격 컬럼 데이터 바인딩 확인 |
**✅ 완료 (2026-03-16)**:
- `Item.php`에 `specification` accessor 추가 (`attributes.spec` → `attributes.specification` 순서로 조회)
- `$appends = ['specification']`으로 API 응답에 자동 포함
- **품목 목록 페이지** 규격 표시 해결
**⏳ 미완료 — 별도 세션 처리 (TODO)**:
| 영역 | 현황 | 필요 작업 |
|------|------|----------|
| **WorkOrder items** | `work_order_items.options`에 width/height만 있고 spec 없음 | WorkOrder API 응답에 마스터 Item.specification 조인 또는 options에 spec 추가 |
| **중간검사 성적서** | `BendingWipInspectionContent`에서 `order.items[0].specification` 참조 | WorkOrder API에서 specification 내려줘야 표시됨 |
| **템플릿 검사 성적서** | `TemplateInspectionContent`에서 `field.default_value` 사용 (실제 규격 무시) | WorkOrder.specification으로 대체 필요 |
| **QMS 문서** | Mock data 사용 중 | API 연동 시 함께 처리 |
---
@@ -478,40 +533,111 @@ const handleClientChange = (selectedClient: Client | null) => {
---
### 2.4 Phase 4: Minor 수정 (14건) — 예상 1.75일
#### #40 작업자 화면 — 자재투입 미터 단위 지원 `Major`
| 항목 | 내용 |
|------|------|
| **현상** | 자재투입 시 EA(개수) 단위는 기본 지원되지만, 미터(m) 단위 설정이 안 되어 있음 |
| **대상 품목** | 원단, 내화실, 슬랫코일 등 미터 단위로 관리되는 자재 |
| **운영 방식** | 미터 단위 차감을 하다가, 특정 개소에서 **"소진" 체크**로 해당 자재를 일괄 소진 처리 |
| **사유** | 로스가 많고 정확한 측정이 어려워 정밀 차감이 아닌 소진 방식으로 운영 |
| **모듈** | 생산/작업지시 (작업자 화면) |
**수정 대상:**
| 파일 | 변경 내용 |
|------|----------|
| `react/src/components/production/Worker/` | 자재투입 UI에 미터(m) 단위 입력 지원 + 소진 체크 기능 추가 |
| `api/` (관련 Service) | 미터 단위 차감 로직 + 소진 처리 API |
| `items` 테이블 `options` | 해당 품목의 단위(unit) 정보 활용 (EA/m 구분) |
**검증:**
- [ ] 미터 단위 품목 투입 시 m 단위로 입력/차감 확인
- [ ] 소진 체크 시 해당 자재 일괄 소진 처리 확인
- [ ] EA 단위 품목은 기존 동작 유지
---
#### #41 재고관리 — 재고 조정 API 개발 `Major`
| 항목 | 내용 |
|------|------|
| **현상** | 재고 조정 화면(모달)은 재고관리 또는 입고관리에 이미 개발되어 있으나, **API가 미구현** |
| **기대** | 재고 조정 API 개발 + 조정 히스토리(이력) 적재 |
| **목적** | 재고 수정 사유/내역을 추적 가능하게 |
| **모듈** | 재고관리 |
**수정 대상:**
| 파일 | 변경 내용 |
|------|----------|
| `api/app/Services/Inventory/` | 재고 조정 API (store/update) 구현 + 조정 사유 저장 |
| `api/app/Http/Controllers/` | 재고 조정 엔드포인트 추가 |
| `api/` (마이그레이션) | 재고 조정 히스토리 테이블 (또는 기존 audit_logs 활용) |
**검증:**
- [ ] 재고 조정 API 정상 동작 (수량 증가/감소)
- [ ] 조정 히스토리 정상 적재 (사유, 변경 전/후 수량, 작업자)
- [ ] 프론트 모달에서 API 연동 확인
---
### 2.4 Phase 4: Minor 수정 (15건) — 예상 1.75일
> **진행 상태**: 8건 완료, 4건 스킵/이미적용, 2건 다른 Phase로 이관, 1건 별도 세션
#### 4.1 공통 UI (4건)
| # | 이슈 | 파일:라인 | 원인 및 수정 |
|---|------|----------|-------------|
| 1 | 리스트 열 너비 정책 | `react/src/components/templates/UniversalListPage/index.tsx:227-240` | 컬럼별 `w-[Npx]`/`min-w-[Npx]` 설정. `useColumnSettings()` 훅(라인 845) 활용하여 열 너비 고정 정책 적용 |
| 2 | 스티키 취소 레이어 | `react/src/components/organisms/FormActions.tsx:22-73` | FormActions 자체는 스티키 미적용. 부모에서 `sticky bottom-0` 추가 필요. 취소/저장 영역 구분 강화 (배경색, 구분선) |
| 3 | 모달 닫힘 정책 | `react/src/components/organisms/SearchableSelectionModal/SearchableSelectionModal.tsx:233` | shadcn/ui Dialog의 `onOpenChange` 콜백 사용 중. 외부 클릭 시 닫힘은 동작이나, 특정 모달에서 비활성화되었을 수 있음 |
| 4 | 밸리데이션 워딩 | 공통 에러 메시지 파일 | 에러 텍스트 전체 검증 및 일률 조정 필요 |
| # | 이슈 | 상태 | 비고 |
|---|------|------|------|
| 1 | 리스트 열 너비 정책 | ⏭️ 패스 | 범위 넓어 별도 검토 필요 |
| 2 | 스티키 취소 레이어 | ✅ 이미 적용됨 | IntegratedDetailTemplate에 sticky 기본 내장 확인 |
| 3 | 모달 닫힘 정책 | ⏭️ 패스 | 현재 동작 확인 필요 (QA 동작 불명확) |
| 4 | 밸리데이션 워딩 | ✅ 이미 정리됨 | Zod 기반 한글 메시지 통일 확인 |
#### 4.2 견적 UI (4건)
| # | 이슈 | 파일:라인 | 원인 및 수정 |
|---|------|----------|-------------|
| 7 | 필터 버튼 활성화 스타일 | `QuoteManagementClient.tsx` | 선택된 날짜 필터 버튼에 active 스타일 클래스 추가 |
| 22 | inspection → 검사비 | `LocationDetailPanel.tsx:112` | **Phase 2 #18-20에서 함께 처리 완료** — `getTenantCategoryName()`에 inspection→검사비 매핑 추가 |
| 24 | 견적상태 3곳 불일치 | `QuoteFooterBar.tsx:23` status 타입, `QuoteManagementClient.tsx:115` getRevisionBadge(), `QuoteSummaryPanel.tsx:43` (상태 미표시) | 3곳의 상태 참조 체계가 다름. 통일된 상태 표시 컴포넌트 또는 유틸 함수 필요 |
| 26 | 수식 모달 하단 여백 | `FormulaViewModal.tsx` | padding-bottom 추가 |
| # | 이슈 | 상태 | 비고 |
|---|------|------|------|
| 7 | 필터 셀렉트박스 라벨 | ✅ 수정 완료 | "전체" → "제품분류: 전체" / "상태: 전체" |
| 22 | inspection → 검사비 | ⏭️ Phase 2 | #18-20 BOM 탭 순서와 함께 처리 |
| 24 | 견적상태 3곳 불일치 | ⏭️ Phase 2 | #23 저장/확정 분리와 함께 처리 |
| 26 | 수식 모달 하단 여백 | ✅ 수정 완료 | LocationDetail div에 pb-6 추가 |
#### 4.3 수주 UI (2건)
| # | 이슈 | 파일:라인 | 원인 및 수정 |
|---|------|----------|-------------|
| 28 | 수신처 필드 | OrderRegistration.tsx | `react/src/components/ui/phone-input.tsx` 컴포넌트 존재. 수신처 필드에 phone-input 교체 |
| 30 | "만원원" 이중 표시 | `react/src/lib/utils/amount.ts:53-61` | `formatAmount()`는 정상 ("만원" 반환). **수주 상세에서 별도로 "원"을 붙이는 코드가 있을 가능성** → 호출처 확인 필요 |
| # | 이슈 | 상태 | 비고 |
|---|------|------|------|
| 28 | 수신처 필드 | ✅ 수정 완료 | Input → PhoneInput 교체 (자동 포맷팅) |
| 30 | "만원원" 이중 표시 | ✅ 수정 완료 | 수주 관련 4파일 19곳 "원" 중복 제거 |
#### 4.4 기타 (3건)
#### 4.4 품질검사 (1건)
| # | 이슈 | 파일:라인 | 원인 및 수정 |
|---|------|----------|-------------|
| 5 | 거래처 카운트 불일치 | `api/app/Services/ClientService.php:28-54` | index()에서 `is_active`/`client_type` 필터 적용 후 카운트 vs 전체 카운트 쿼리 불일치. stats() 메서드와 index() 필터 조건 동기화 필요 |
| 35-1 | 품목 수정이력 | `api/app/Services/ItemService.php` update() | AuditLogger 호출 여부 확인. 누락 시 추가 |
| 35-2 | 생산현황판 데이터 불일치 | `ProductionDashboard/actions.ts` vs `WorkOrders/actions.ts` | 두 곳에서 `getWorkOrders` 호출 시 `per_page`, 필터 파라미터 차이. 대시보드는 `per_page: 100`, 목록은 별도 필터 |
| # | 이슈 | 상태 | 비고 |
|---|------|------|------|
| 42 | 제품검사 모달 페이지 이동/검색 | ⏭️ 별도 세션 | QMS 네비게이션 구조 변경 필요 (Major급) |
#### 4.5 기타 (3건)
| # | 이슈 | 상태 | 비고 |
|---|------|------|------|
| 5 | 거래처 카운트 불일치 | ✅ 수정 완료 | 프론트 자체계산 → stats API 호출로 교체. 백엔드 active/inactive 추가 |
| 35-1 | 품목 수정이력 | ✅ 수정 완료 | ItemService.update()에 AuditLogger 감사 로그 추가 |
| 35-2 | 생산현황판 데이터 불일치 | ✅ 수정 완료 | Dashboard 통계를 work-orders/stats API 활용으로 교체 |
---
### 2.5 보류 — mng 선행 필요 (1건)
#### #43 절곡 바라시보기 기능 `Major` `보류`
| 항목 | 내용 |
|------|------|
| **현상** | SAM에 절곡 바라시(전개도) 보기 기능이 없음 |
| **레퍼런스** | 5130: `viewBendingWork_slat.php` → 절곡 바라시 버튼 (`bendingview.php`) |
| **선행 조건** | **mng에서 먼저 기능 개발** 완료 필요 |
| **적용 방식** | mng 완료 후 해당 데이터를 호출하는 형태로 react에 적용 |
| **모듈** | 절곡/생산 |
> mng 개발 완료 시점에 Phase 배정 예정
---
@@ -519,25 +645,26 @@ const handleClientChange = (selectedClient: Client | null) => {
```
Phase 0: 사전 조사 (대부분 완료) [0.5일] ██
Phase 1: Critical [1일] ████
Phase 2: 견적 Major [2.5일] ██████████
Phase 3: 기타 Major + #15,#29 [2.5일] ██████████
Phase 4: Minor [1.75일] ███████
Phase 1: Critical (3건) [1.5일] ██████
Phase 2: 견적 Major (9건) [3일] ████████████
Phase 3: 기타 Major (7건) [3일] ████████████
Phase 4: Minor (15건) [2일] ████████
보류: mng 선행 (1건) [TBD]
─────────────────
총계 약 8.25일
총계 약 10일 (+보류)
```
**병렬 처리 가능:**
- Phase 2 (견적) + Phase 3 (기타 모듈): 독립적 → **2.5일로 단축**
- Phase 2 (견적) + Phase 3 (기타 모듈): 독립적 → **3일로 단축**
- Phase 4: Phase 1~3 중 동일 파일 수정 시 함께 처리
**최적 일정 (병렬 적용):**
```
Day 1 : Phase 0 마무리 + Phase 1 (Critical 2건)
Day 2-3.5 : Phase 2 + Phase 3 (병렬)
Day 4-5 : Phase 4 (Minor) + Phase 0 결과 반영
Day 1-1.5 : Phase 0 마무리 + Phase 1 (Critical 3건)
Day 2-4 : Phase 2 + Phase 3 (병렬)
Day 5-6 : Phase 4 (Minor) + Phase 0 결과 반영
─────────────────
최적 총계 약 5일
최적 총계 약 6일 (+보류 #43)
```
---
@@ -603,6 +730,10 @@ Phase 4 (Minor) ── 모두 독립 (#22는 Phase 2에서 함께 처리)
| 2026-03-13 | - | 문서 초안 작성 | - | - |
| 2026-03-13 | - | 코드 레벨 심층 분석 반영 (4개 에이전트 병렬 분석) | - | - |
| 2026-03-14 | #31,#18-20,#16,#23,#33,#10 | 컨펌 대기 6건 결정 반영 (5건 확정, 1건 보류) | - | ✅ |
| 2026-03-16 | #38~#43 | 추가 이슈 6건 등록: #38 제어기 계산(Critical), #39 개소분리(Major), #40 미터단위(Major), #41 재고조정API(Major), #42 검사모달(Minor), #43 절곡바라시(보류) | - | ✅ |
| 2026-03-16 | Phase 4 | Minor 8건 수정 완료: #26 수식모달여백, #7 필터라벨, #30 만원원, #28 수신처, #5 거래처카운트, #35-1 품목이력, #35-2 생산현황판. 4건 스킵(#2 이미적용, #4 이미정리, #1/#3 패스), 2건 이관(#22→P2, #24→P2), 1건 별도(#42 Major급) | react `aa42360`, api `80cd341` | ✅ |
| 2026-03-16 | Phase 1 | Critical 3건 완료: #27 견적 불러오기(QuoteService 필터 수정+order_id 동기화), #31 생산지시 후 수정 차단(isEditable+프론트 연동), #38 제어기 수량 미반영(FormulaHandler 수량 곱셈) | api QuoteService/Quote.php/FormulaHandler, react QuoteFooterBar/QuoteRegistration/types | - |
| 2026-03-16 | Phase 2 | 5건 완료: #18-22 BOM 탭 순서(백+프론트 정렬+inspection 라벨), #16 혼합 등록 차단(모델 레벨 필터링), #23 저장/확정 분리(버튼 라벨+조건 분리), #14/#21 품목 수동추가(items.options에 bom_category 추가+API 필터+모달 연동), #8 필터 라벨(접두어 추가) | api FormulaEvaluatorService/ItemService/ItemsController/마이그레이션, react LocationDetailPanel/LocationListPanel/QuoteManagementClient/ItemSearchModal/types | - |
---