refactor(WEB): 회계/견적/설정/생산 등 전반적 코드 개선 및 공통화 2차
- 회계 모듈 전면 개선: 청구/입금/출금/매입/매출/세금계산서/일반전표/거래처원장 등 - 견적 모듈 금액 포맷/할인/수식/미리보기 등 코드 정리 - 설정 모듈: 계정관리/직급/직책/권한 상세 간소화 - 생산 모듈: 작업지시서/작업자화면/검수 문서 코드 정리 - UniversalListPage 엑셀 다운로드 및 필터 기능 확장 - 대시보드/게시판/수주 등 날짜 유틸 공통화 적용 - claudedocs 문서 인덱스 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -297,6 +297,77 @@ Phase 3 (Phase 2 완료 후):
|
||||
| 2 | WP-4 + WP-5 | WP-4는 hooks/ + page.tsx, WP-5는 components/accounting/shared/ + 컴포넌트 내부. 파일 겹침 없음 |
|
||||
| 3 | WP-6 단독 | WP-4의 useDateRange 훅을 일부 파일에서 활용해야 하므로 Phase 2 이후 |
|
||||
|
||||
---
|
||||
|
||||
## WP-7: .toLocaleString() → formatNumber() 마이그레이션 ✅ 완료 (2026-02-19)
|
||||
|
||||
**심각도**: 🟢 MEDIUM (코드 일관성)
|
||||
**난이도**: 낮음 | **파일 수**: 52파일, 183건 | **방법**: Node.js 자동 마이그레이션 스크립트
|
||||
|
||||
### 수정 완료
|
||||
- [x] 52개 파일에서 183건 `.toLocaleString()` → `formatNumber()` 자동 치환
|
||||
- [x] `formatNumber` import 자동 추가
|
||||
- [x] 5개 파일 수동 import 수정 (double-quote import 패턴)
|
||||
|
||||
### 검증
|
||||
- [x] `npx tsc --noEmit` 통과
|
||||
- [x] `src/` 내 잔여 `.toLocaleString()` = 0건 (amount.ts 내부 제외)
|
||||
|
||||
---
|
||||
|
||||
## WP-8: 인라인 formatDate → date.ts import 마이그레이션 ✅ 완료 (2026-02-19)
|
||||
|
||||
**심각도**: 🟢 MEDIUM (코드 일관성)
|
||||
**난이도**: 낮음 | **파일 수**: 21파일, 32건 | **방법**: Node.js 자동 마이그레이션 스크립트
|
||||
|
||||
### 수정 완료
|
||||
- [x] `.split('T')[0]` → `formatDate()` 변환 (21파일)
|
||||
- [x] `new Date().toISOString().slice(0, 10)` → `getTodayString()` 변환
|
||||
- [x] `dateVar.toISOString().slice(0, 10)` → `getLocalDateString(dateVar)` 변환
|
||||
- [x] 6개 파일 수동 import 수정 (JSDoc 삽입 버그)
|
||||
|
||||
### 스킵 항목
|
||||
- `?.split('T')[0] || ''` — formatDate는 null일 때 '-' 반환 (falsy 의미 다름)
|
||||
- `.toLocaleDateString()` — 42건, 로케일 표시 형식으로 canonical과 비호환
|
||||
- `.toISOString().slice(0,10).replace(/-/g,'')` — YYYYMMDD 형식 (파일명용)
|
||||
|
||||
### 검증
|
||||
- [x] `npx tsc --noEmit` 통과
|
||||
|
||||
---
|
||||
|
||||
## WP-9: useDeleteDialog 훅 채택 확대 ✅ 완료 (2026-02-20)
|
||||
|
||||
**심각도**: 🟢 MEDIUM (코드 일관성)
|
||||
**난이도**: 중간 | **전체 후보**: ~56파일 | **기존 채택자**: 7파일
|
||||
|
||||
### 완료된 작업 (9파일)
|
||||
- [x] `src/hooks/index.ts`에 useDeleteDialog export 추가
|
||||
- [x] `settings/RankManagement/index.tsx` 마이그레이션 (단건 삭제, number ID)
|
||||
- [x] `settings/TitleManagement/index.tsx` 마이그레이션 (단건 삭제, number ID)
|
||||
- [x] `settings/AccountManagement/AccountDetail.tsx` 마이그레이션 (상세→삭제→목록, number ID)
|
||||
- [x] `settings/PermissionManagement/PermissionDetailClient.tsx` 마이그레이션 (상세→삭제→목록, number ID)
|
||||
- [x] `accounting/DepositManagement/DepositDetail.tsx` 마이그레이션 (상세→삭제→목록)
|
||||
- [x] `accounting/WithdrawalManagement/WithdrawalDetail.tsx` 마이그레이션 (상세→삭제→목록)
|
||||
- [x] `hr/CardManagement/CardDetail.tsx` 마이그레이션 (상세→삭제→목록)
|
||||
- [x] `board/BoardDetail/index.tsx` 마이그레이션 (deletePost 클로저 캡처, 2-arg delete)
|
||||
- [x] `board/BoardManagement/BoardDetailClientV2.tsx` 마이그레이션 (deleteBoard + forceRefreshMenus)
|
||||
|
||||
### 의도적 스킵 (마이그레이션 비적합)
|
||||
- `settings/AccountManagement/AccountDetailForm.tsx` — prop 기반 삭제 + isSaving 공유
|
||||
- `settings/PermissionManagement/PermissionDetail.tsx` — prop 기반 + IntegratedDetailTemplate 연동
|
||||
- `settings/PermissionManagement/index.tsx` — bulk+single 혼합 다이얼로그
|
||||
- `board/CommentSection/CommentItem.tsx` — void onDelete prop, 행동 변경됨
|
||||
- `hr/EmployeeManagement/index.tsx` — 780줄, 복잡한 useMemo, 위험도 높음
|
||||
- `hr/DepartmentManagement/index.tsx` — bulk+single 혼합 다이얼로그
|
||||
- `settings/PopupManagement/PopupDetailClientV2.tsx` — IntegratedDetailTemplate 내부 처리
|
||||
|
||||
### 최종 채택 현황: 7(기존) + 9(신규) = 16파일
|
||||
### 검증
|
||||
- [x] `npx tsc --noEmit` 통과 (모든 수정 파일 tsc 에러 0건)
|
||||
|
||||
---
|
||||
|
||||
### Phase 간 의존성 상세
|
||||
|
||||
| 의존 관계 | 이유 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# claudedocs 문서 맵
|
||||
|
||||
> 프로젝트 기술 문서 인덱스 (Last Updated: 2026-02-12)
|
||||
> 프로젝트 기술 문서 인덱스 (Last Updated: 2026-02-19)
|
||||
|
||||
## 빠른 참조
|
||||
|
||||
@@ -214,6 +214,62 @@ export const remove = service.remove;
|
||||
- `toPaginationMeta` 자동 활용 (직접 import 불필요)
|
||||
- URL 빌딩 패턴 완전 일관화 (undefined/null/'' 자동 필터링, boolean/number 자동 변환)
|
||||
|
||||
### KST 안전 날짜 유틸리티 — `toISOString` 사용 금지 (2026-02-19)
|
||||
|
||||
**현황**: `new Date().toISOString().split('T')[0]` — 15개 파일 26곳에서 사용 중이었음
|
||||
|
||||
**문제**: `toISOString()`은 **UTC 기준**으로 변환. 한국(KST, UTC+9)에서 오전 9시 이전에 실행하면 **전날 날짜** 반환
|
||||
```
|
||||
// 2026-02-19 08:30 KST → UTC는 2026-02-18 23:30
|
||||
new Date().toISOString().split('T')[0] // "2026-02-18" ← 잘못됨
|
||||
```
|
||||
|
||||
**결정**: KST 안전 유틸리티 함수로 전량 교체, 직접 `toISOString` 사용 금지
|
||||
|
||||
**유틸리티** (`src/lib/utils/date.ts`):
|
||||
| 함수 | 용도 | 대체 대상 |
|
||||
|------|------|-----------|
|
||||
| `getTodayString()` | 오늘 날짜 문자열 | `new Date().toISOString().split('T')[0]` |
|
||||
| `getLocalDateString(date)` | 임의 Date 객체 문자열 | `someDate.toISOString().split('T')[0]` |
|
||||
|
||||
**사용 규칙**:
|
||||
```typescript
|
||||
// ✅ 올바른 패턴
|
||||
import { getTodayString, getLocalDateString } from '@/lib/utils/date';
|
||||
const today = getTodayString(); // "2026-02-19"
|
||||
const thirtyDaysAgo = getLocalDateString(pastDate); // "2026-01-20"
|
||||
|
||||
// ❌ 금지 패턴
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
```
|
||||
|
||||
**현재 상태**: `src/` 내 `toISOString().split` 사용 0건 (date.ts 내 구현부 제외)
|
||||
|
||||
### `useDateRange` 훅 — 날짜 필터 보일러플레이트 제거 (2026-02-19)
|
||||
|
||||
**현황**: 20+ 리스트 페이지에서 `useState('2025-01-01')` / `useState('2025-12-31')` 하드코딩
|
||||
|
||||
**문제**: 연도가 바뀌면 수동으로 모든 파일 수정 필요 (2025→2026 전환 시 데이터 미표시 버그 발생)
|
||||
|
||||
**결정**: `useDateRange` 훅으로 동적 날짜 범위 자동 계산
|
||||
|
||||
**훅** (`src/hooks/useDateRange.ts`):
|
||||
```typescript
|
||||
import { useDateRange } from '@/hooks';
|
||||
|
||||
// 프리셋
|
||||
const { startDate, endDate, setStartDate, setEndDate } = useDateRange('currentYear'); // 2026-01-01 ~ 2026-12-31
|
||||
const { startDate, endDate, setStartDate, setEndDate } = useDateRange('currentMonth'); // 2026-02-01 ~ 2026-02-28
|
||||
const { startDate, endDate, setStartDate, setEndDate } = useDateRange('today'); // 2026-02-19 ~ 2026-02-19
|
||||
```
|
||||
|
||||
**적용 규칙**:
|
||||
- 리스트 페이지 날짜 필터 → `useDateRange` 필수 사용
|
||||
- 연간 조회 → `'currentYear'`, 월간 조회 → `'currentMonth'`
|
||||
- `useState('YYYY-MM-DD')` 하드코딩 금지
|
||||
|
||||
**현재 상태**: `useState('2025` 패턴 0건 (전량 `useDateRange`로 전환 완료)
|
||||
|
||||
### Zod 스키마 검증 — 신규 폼 적용 규칙 (2026-02-11)
|
||||
|
||||
**결정**: 기존 폼은 건드리지 않음. **신규 폼에만 Zod + zodResolver 적용**
|
||||
|
||||
Reference in New Issue
Block a user