2026-01-22 09:47:29 +09:00
|
|
|
|
## 2026-01-21 (화) - TodayIssue 헤더 알림 API (Phase 3 완료)
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- TodayIssue + 알림 시스템 통합 Phase 3: 헤더 알림 API 구현
|
|
|
|
|
|
- 읽지 않은 이슈 목록/개수 조회, 읽음 처리 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Services/TodayIssueService.php` | getUnreadList(), getUnreadCount(), markAllAsRead() 추가 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/TodayIssueController.php` | unread(), unreadCount(), markAsRead(), markAllAsRead() 추가 |
|
|
|
|
|
|
| `routes/api.php` | 4개 엔드포인트 추가 |
|
|
|
|
|
|
| `lang/ko/message.php` | today_issue.marked_as_read, all_marked_as_read 메시지 추가 |
|
|
|
|
|
|
| `app/Swagger/v1/TodayIssueApi.php` | 4개 엔드포인트 + 스키마 문서화 |
|
|
|
|
|
|
| `app/Swagger/v1/ComprehensiveAnalysisApi.php` | 스키마 이름 충돌 해결 (TodayIssueItem → ComprehensiveTodayIssueItem) |
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/api/v1/today-issues/unread` | 읽지 않은 이슈 목록 (헤더 알림 드롭다운용) |
|
|
|
|
|
|
| GET | `/api/v1/today-issues/unread/count` | 읽지 않은 이슈 개수 (헤더 뱃지용) |
|
|
|
|
|
|
| POST | `/api/v1/today-issues/{id}/read` | 단일 이슈 읽음 처리 |
|
|
|
|
|
|
| POST | `/api/v1/today-issues/read-all` | 모든 이슈 읽음 처리 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- [x] Pint 코드 스타일 통과
|
|
|
|
|
|
- [x] Swagger 문서 생성 완료
|
|
|
|
|
|
- [x] PHP 문법 검증 통과
|
|
|
|
|
|
- [x] Service-First 아키텍처 준수
|
|
|
|
|
|
- [x] Multi-tenancy (tenant_id 필터링) 적용
|
|
|
|
|
|
- [x] i18n 메시지 키 사용
|
|
|
|
|
|
|
|
|
|
|
|
### 계획 문서
|
|
|
|
|
|
- `docs/plans/today-issue-notification-integration-plan.md`
|
|
|
|
|
|
- 백엔드 작업 완료 (Phase 1-3: 100%)
|
|
|
|
|
|
- Phase 4 (React 헤더 연동)는 프론트엔드 담당
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-11 23:29:32 +09:00
|
|
|
|
## 2026-01-11 (토) - Labor(노임관리) API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 시공관리 > 노임관리 API 백엔드 구현
|
|
|
|
|
|
- Frontend actions.ts API 연동
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Models/Labor.php` | 노임 모델 (BelongsToTenant, SoftDeletes) |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/LaborController.php` | 노임 컨트롤러 (7개 메서드) |
|
|
|
|
|
|
| `app/Services/LaborService.php` | 노임 서비스 (비즈니스 로직) |
|
|
|
|
|
|
| `app/Http/Requests/Labor/LaborIndexRequest.php` | 목록 조회 검증 |
|
|
|
|
|
|
| `app/Http/Requests/Labor/LaborStoreRequest.php` | 등록 요청 검증 |
|
|
|
|
|
|
| `app/Http/Requests/Labor/LaborUpdateRequest.php` | 수정 요청 검증 |
|
|
|
|
|
|
| `app/Http/Requests/Labor/LaborBulkDeleteRequest.php` | 일괄 삭제 검증 |
|
|
|
|
|
|
| `database/migrations/2026_01_11_000000_create_labors_table.php` | 마이그레이션 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `routes/api.php` | Labor 라우트 7개 추가 (line 1005-1014) |
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/api/v1/labor` | 목록 조회 |
|
|
|
|
|
|
| GET | `/api/v1/labor/stats` | 통계 조회 |
|
|
|
|
|
|
| POST | `/api/v1/labor` | 등록 |
|
|
|
|
|
|
| GET | `/api/v1/labor/{id}` | 상세 조회 |
|
|
|
|
|
|
| PUT | `/api/v1/labor/{id}` | 수정 |
|
|
|
|
|
|
| DELETE | `/api/v1/labor/{id}` | 삭제 |
|
|
|
|
|
|
| DELETE | `/api/v1/labor/bulk` | 일괄 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- [x] 마이그레이션 실행 완료
|
|
|
|
|
|
- [x] Pint 코드 스타일 통과
|
|
|
|
|
|
- [x] Service-First 아키텍처 준수
|
|
|
|
|
|
- [x] FormRequest 검증 사용
|
|
|
|
|
|
- [x] Multi-tenancy (BelongsToTenant) 적용
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
# SAM API 작업 현황
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
2026-01-11 23:29:32 +09:00
|
|
|
|
## 2025-01-09 (목) - 작업지시 코드 리뷰 기반 전면 개선
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 작업지시(Work Orders) 기능 코드 리뷰 결과 기반 전면 개선
|
|
|
|
|
|
- Critical, High, Medium 우선순위 항목 전체 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Models/Production/WorkOrderItem.php` | BelongsToTenant 트레이트 적용 |
|
|
|
|
|
|
| `app/Models/Production/WorkOrderBendingDetail.php` | BelongsToTenant 트레이트 적용 |
|
|
|
|
|
|
| `app/Models/Production/WorkOrderIssue.php` | BelongsToTenant 트레이트 적용 |
|
|
|
|
|
|
| `app/Models/Production/WorkOrder.php` | 상태 전이 규칙 (STATUS_TRANSITIONS, canTransitionTo, transitionTo) |
|
|
|
|
|
|
| `app/Services/WorkOrderService.php` | 감사 로그, 다중 담당자, 부분 수정 지원 |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Models/Production/WorkOrderAssignee.php` | 다중 담당자 피벗 모델 |
|
|
|
|
|
|
| `database/migrations/*_create_work_order_assignees_table.php` | 다중 담당자 테이블 마이그레이션 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **Multi-tenancy 적용**: 하위 모델 4개에 BelongsToTenant 트레이트 적용
|
|
|
|
|
|
2. **감사 로그 적용**: 품목 삭제, 상태 변경, 이슈 등록/해결, 담당자 배정 시 기록
|
|
|
|
|
|
3. **상태 전이 규칙**: STATUS_TRANSITIONS 상수 + canTransitionTo(), transitionTo() 메서드
|
|
|
|
|
|
4. **다중 담당자 지원**:
|
|
|
|
|
|
- WorkOrderAssignee 피벗 모델 생성
|
|
|
|
|
|
- assign() 메서드에서 배열 담당자 지원
|
|
|
|
|
|
- is_primary 플래그로 주 담당자 구분
|
|
|
|
|
|
5. **부분 수정 지원**: 품목 업데이트 시 ID 기반 upsert/delete (기존 삭제 후 재생성 → ID 기반 부분 수정)
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- [x] Pint 코드 스타일 (3개 파일)
|
|
|
|
|
|
- [x] Service-First 아키텍처 준수
|
|
|
|
|
|
- [x] Eager loading에 assignees.user:id,name 추가
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `349917f refactor(work-orders): 코드 리뷰 기반 전면 개선`
|
|
|
|
|
|
|
|
|
|
|
|
### 관련 문서
|
|
|
|
|
|
- 계획: `~/.claude/plans/purring-sparking-pinwheel.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-08 11:11:54 +09:00
|
|
|
|
## 2026-01-08 (수) - Order Management API Phase 1.1 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 수주관리(Order Management) API 기본 CRUD 및 상태 관리 기능 구현
|
|
|
|
|
|
- WorkOrderService/Controller 패턴을 참고하여 SAM API 규칙 준수
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Services/OrderService.php` | 수주 비즈니스 로직 서비스 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/OrderController.php` | 수주 API 컨트롤러 |
|
|
|
|
|
|
| `app/Http/Requests/Order/StoreOrderRequest.php` | 생성 요청 검증 |
|
|
|
|
|
|
| `app/Http/Requests/Order/UpdateOrderRequest.php` | 수정 요청 검증 |
|
|
|
|
|
|
| `app/Http/Requests/Order/UpdateOrderStatusRequest.php` | 상태 변경 요청 검증 |
|
|
|
|
|
|
| `app/Swagger/v1/OrderApi.php` | Swagger API 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `routes/api.php` | OrderController import 및 7개 라우트 추가 |
|
|
|
|
|
|
| `lang/ko/message.php` | 수주 관련 메시지 키 추가 |
|
|
|
|
|
|
| `lang/en/message.php` | 수주 관련 메시지 키 추가 |
|
|
|
|
|
|
| `lang/ko/error.php` | 수주 에러 메시지 키 추가 |
|
|
|
|
|
|
| `lang/en/error.php` | 수주 에러 메시지 키 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 구현 내용
|
|
|
|
|
|
1. **OrderService 메서드**: index, stats, show, store, update, destroy, updateStatus
|
|
|
|
|
|
2. **상태 전환 규칙**: DRAFT → CONFIRMED → IN_PROGRESS → COMPLETED/CANCELLED
|
|
|
|
|
|
3. **수주번호 자동생성**: ORD{YYYYMMDD}{0001} 형식
|
|
|
|
|
|
4. **품목 금액 계산**: 공급가, 세액, 합계 자동 계산
|
|
|
|
|
|
5. **Swagger 스키마**: Order, OrderItem, OrderPagination, OrderStats 등
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- [x] Pint 코드 스타일 (6개 파일 자동 수정)
|
|
|
|
|
|
- [x] Swagger 문서 생성
|
|
|
|
|
|
- [x] Service-First 아키텍처 준수
|
|
|
|
|
|
- [x] i18n 메시지 키 사용
|
|
|
|
|
|
|
|
|
|
|
|
### 관련 문서
|
|
|
|
|
|
- 계획: `docs/plans/order-management-plan.md`
|
|
|
|
|
|
- 변경 요약: `docs/changes/20250108_order_management_phase1.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-02 21:06:06 +09:00
|
|
|
|
## 2026-01-02 (목) - 채권현황 동적월 지원 및 버그 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- "최근 1년" 필터 선택 시 동적 월 기간(최근 12개월) 지원
|
|
|
|
|
|
- year=0 파라미터 처리 버그 수정
|
|
|
|
|
|
- 거래처별 연체 상태 및 메모 관리 기능 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/ReceivablesController.php` | boolean 유효성 검사 수정, 디버깅 로그 추가 |
|
|
|
|
|
|
| `app/Services/ReceivablesService.php` | 동적 월 기간 지원, 이월잔액 계산 추가 |
|
|
|
|
|
|
| `app/Models/Orders/Client.php` | is_overdue, memo 필드 추가 |
|
|
|
|
|
|
| `routes/api.php` | 채권현황 라우트 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `database/migrations/2026_01_02_113722_add_is_overdue_to_clients_table.php` | clients 테이블 is_overdue 컬럼 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **Boolean 유효성 검사 수정**: `'nullable|boolean'` → `'nullable|string|in:true,false,1,0'`
|
|
|
|
|
|
- 쿼리 문자열의 `"true"` 문자열을 올바르게 처리
|
|
|
|
|
|
2. **동적 월 기간 지원**: `recent_year=true` 시 최근 12개월 동적 계산
|
|
|
|
|
|
3. **월별 레이블 동적 생성**: 예: `['25.02', '25.03', ...]`
|
|
|
|
|
|
4. **이월잔액(carry_forward_balance) 계산**: 선택 기간 이전의 누적 미수금
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `4fa38e3` feat(API): 채권현황 동적월 지원 및 year=0 파라미터 버그 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 남은 작업
|
|
|
|
|
|
- [ ] 디버깅 로그 제거 (테스트 완료 후)
|
|
|
|
|
|
- [ ] 추가 UI 개선사항 확인
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-05 15:56:46 +09:00
|
|
|
|
## 2026-01-02 (목) - 견적 BOM 산출 작업 현황 및 Item 모델 주석 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 견적 BOM 산출 관련 작업 진행 상황 문서화
|
|
|
|
|
|
- Item 모델 필드 주석 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Models/Items/Item.php` | item_category 필드 주석 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **Item 모델 필드 주석**:
|
|
|
|
|
|
- `item_category` 필드에 설명 주석 추가
|
|
|
|
|
|
- React 프론트엔드에서 필드 매핑 시 참조용
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `02e268e` docs(API): 견적 BOM 산출 작업 현황 및 Item 모델 주석 추가
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-02 21:06:06 +09:00
|
|
|
|
## 2026-01-02 (목) - Phase 1.2 다건 BOM 기반 자동산출 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- React 견적등록 화면에서 여러 품목의 자동산출을 일괄 요청할 수 있는 API 구현
|
|
|
|
|
|
- React QuoteFormItem 인터페이스 필드명(camelCase)과 API 변수명(약어) 모두 지원
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Http/Requests/Quote/QuoteBomBulkCalculateRequest.php` | 다건 BOM 산출 FormRequest (필드 변환 포함) |
|
|
|
|
|
|
| `docs/changes/20260102_1300_quote_bom_bulk_calculation.md` | 변경 내용 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Services/Quote/QuoteCalculationService.php` | calculateBomBulk() 메서드 추가 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/QuoteController.php` | calculateBomBulk 액션 추가 |
|
|
|
|
|
|
| `routes/api.php` | /calculate/bom/bulk 라우트 추가 |
|
|
|
|
|
|
| `app/Swagger/v1/QuoteApi.php` | 스키마 3개 + 엔드포인트 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **다건 BOM 기반 자동산출 API**: `POST /api/v1/quotes/calculate/bom/bulk`
|
|
|
|
|
|
2. **필드 매핑 지원**: React camelCase (openWidth, openHeight) ↔ API 약어 (W0, H0)
|
|
|
|
|
|
3. **일괄 처리**: 여러 품목 동시 계산, 성공/실패 요약 제공
|
|
|
|
|
|
4. **Swagger 문서화**: QuoteBomBulkCalculateRequest, QuoteBomBulkItemInput, QuoteBomBulkCalculationResult
|
|
|
|
|
|
|
|
|
|
|
|
### 필드 매핑 테이블
|
|
|
|
|
|
| React 필드 | API 변수 | 설명 |
|
|
|
|
|
|
|-----------|---------|------|
|
|
|
|
|
|
| openWidth | W0 | 개구부 폭 |
|
|
|
|
|
|
| openHeight | H0 | 개구부 높이 |
|
|
|
|
|
|
| quantity | QTY | 수량 |
|
|
|
|
|
|
| productCategory | PC | 제품 카테고리 |
|
|
|
|
|
|
| guideRailType | GT | 가이드레일 타입 |
|
|
|
|
|
|
| motorPower | MP | 모터 출력 |
|
|
|
|
|
|
| controller | CT | 제어반 |
|
|
|
|
|
|
| wingSize | WS | 날개 크기 |
|
|
|
|
|
|
| inspectionFee | INSP | 검사비 |
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `4e59bbf` feat: Phase 1.2 - 다건 BOM 기반 자동산출 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 관련 문서
|
|
|
|
|
|
- 계획 문서: `docs/plans/quote-calculation-api-plan.md`
|
|
|
|
|
|
- Phase 1.1: `docs/changes/20260102_quote_bom_calculation_api.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-02 11:24:22 +09:00
|
|
|
|
## 2026-01-02 (목) - Phase 1.1 견적 산출 API 엔드포인트 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- React 프론트엔드에서 BOM 기반 견적 계산 API 호출 가능하도록 구현
|
|
|
|
|
|
- MNG FormulaEvaluatorService.calculateBomWithDebug() 연결
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Http/Requests/Quote/QuoteBomCalculateRequest.php` | BOM 계산용 FormRequest |
|
|
|
|
|
|
| `docs/changes/20260102_quote_bom_calculation_api.md` | 변경 내용 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Services/Quote/QuoteCalculationService.php` | calculateBom 메서드 추가 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/QuoteController.php` | calculateBom 액션 추가 |
|
|
|
|
|
|
| `routes/api.php` | /calculate/bom 라우트 추가 |
|
|
|
|
|
|
| `app/Swagger/v1/QuoteApi.php` | 스키마 및 엔드포인트 문서 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **BOM 기반 견적 계산 API**: `POST /api/v1/quotes/calculate/bom`
|
|
|
|
|
|
2. **입력 변수**: finished_goods_code, W0, H0, QTY, PC, GT, MP, CT, WS, INSP
|
|
|
|
|
|
3. **10단계 디버깅**: debug=true 옵션으로 계산 과정 확인 가능
|
|
|
|
|
|
4. **Swagger 문서화**: QuoteBomCalculateRequest, QuoteBomCalculationResult 스키마
|
|
|
|
|
|
|
|
|
|
|
|
### 관련 문서
|
|
|
|
|
|
- 계획 문서: `docs/plans/quote-calculation-api-plan.md`
|
|
|
|
|
|
- FormulaEvaluatorService: Phase 1.1에서 구현 완료
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-30 23:45:22 +09:00
|
|
|
|
## 2025-12-30 (월) - Phase 1.1 견적 계산 MNG 로직 재구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- MNG FormulaEvaluatorService 10단계 BOM 계산 로직을 API로 이식
|
|
|
|
|
|
- React 프론트엔드에서 MNG와 동일한 견적 계산 기능 사용 가능하도록 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Models/CategoryGroup.php` | 카테고리별 단가 계산 방식 모델 (신규) |
|
|
|
|
|
|
| `docs/changes/20251230_2339_quote_calculation_mng_logic.md` | 변경 내용 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `app/Services/Quote/FormulaEvaluatorService.php` | MNG 10단계 BOM 계산 로직 추가 (537줄→1176줄) |
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 변경 내용
|
|
|
|
|
|
1. **CategoryGroup 모델**: 면적/중량/수량 기반 단가 계산 방식 관리
|
|
|
|
|
|
2. **calculateBomWithDebug()**: 10단계 BOM 계산 (디버그 모드)
|
|
|
|
|
|
3. **calculateCategoryPrice()**: 카테고리 기반 단가 계산
|
|
|
|
|
|
4. **groupItemsByProcess()**: 공정별 품목 그룹화
|
|
|
|
|
|
5. **getItemDetails()**: 품목 상세 정보 및 BOM 트리
|
|
|
|
|
|
|
|
|
|
|
|
### 관련 문서
|
|
|
|
|
|
- `docs/plans/quote-calculation-api-plan.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-30 17:25:29 +09:00
|
|
|
|
## 2025-12-30 (월) - Phase L 설정 및 기준정보 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- L-2 권한관리 API 개발
|
|
|
|
|
|
- L-3 직급관리 + L-4 직책관리 API 개발 (통합 positions 테이블)
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
|
|
|
|
|
|
#### L-2 권한관리
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `database/migrations/2025_12_30_160802_add_is_hidden_to_roles_table.php` | roles 테이블 is_hidden 컬럼 추가 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/RoleController.php` | Role CRUD API |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/RolePermissionController.php` | 권한 매트릭스 API |
|
|
|
|
|
|
| `app/Services/RoleService.php` | Role 비즈니스 로직 |
|
|
|
|
|
|
| `app/Swagger/v1/RoleApi.php` | Swagger 문서 |
|
|
|
|
|
|
| `app/Swagger/v1/RolePermissionApi.php` | Swagger 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
#### L-3/L-4 직급/직책 관리
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `database/migrations/2025_12_30_091821_create_positions_table.php` | positions 테이블 생성 |
|
|
|
|
|
|
| `database/migrations/2025_12_30_091822_add_position_type_to_common_codes.php` | position_type 코드 추가 |
|
|
|
|
|
|
| `app/Models/Tenants/Position.php` | Position 모델 |
|
|
|
|
|
|
| `app/Services/PositionService.php` | Position 비즈니스 로직 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/PositionController.php` | Position CRUD API |
|
|
|
|
|
|
| `app/Http/Requests/PositionRequest.php` | 생성/수정 요청 검증 |
|
|
|
|
|
|
| `app/Http/Requests/PositionReorderRequest.php` | 순서 변경 요청 검증 |
|
|
|
|
|
|
| `app/Swagger/v1/PositionApi.php` | Swagger 문서 |
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
|
|
|
|
|
|
#### Role API (9개)
|
|
|
|
|
|
```
|
|
|
|
|
|
GET /api/v1/roles # 역할 목록
|
|
|
|
|
|
POST /api/v1/roles # 역할 생성
|
|
|
|
|
|
GET /api/v1/roles/{id} # 역할 상세
|
|
|
|
|
|
PATCH /api/v1/roles/{id} # 역할 수정
|
|
|
|
|
|
DELETE /api/v1/roles/{id} # 역할 삭제
|
|
|
|
|
|
GET /api/v1/roles/{id}/permissions # 역할 권한 조회
|
|
|
|
|
|
POST /api/v1/roles/{id}/permissions # 권한 추가
|
|
|
|
|
|
DELETE /api/v1/roles/{id}/permissions # 권한 제거
|
|
|
|
|
|
PUT /api/v1/roles/{id}/permissions/sync # 권한 동기화
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Position API (6개)
|
|
|
|
|
|
```
|
|
|
|
|
|
GET /api/v1/positions?type=rank # 직급 목록
|
|
|
|
|
|
GET /api/v1/positions?type=title # 직책 목록
|
|
|
|
|
|
POST /api/v1/positions # 생성 (type 필수)
|
|
|
|
|
|
PUT /api/v1/positions/{id} # 수정
|
|
|
|
|
|
DELETE /api/v1/positions/{id} # 삭제
|
|
|
|
|
|
POST /api/v1/positions/reorder # 순서 변경 (bulk)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 설계 결정사항
|
|
|
|
|
|
- **통합 테이블**: 직급(rank)과 직책(title)을 `positions` 테이블로 통합
|
|
|
|
|
|
- **구분 컬럼**: `type` 컬럼으로 rank/title 구분
|
|
|
|
|
|
- **정렬 지원**: `sort_order` 컬럼 + reorder API로 드래그 앤 드롭 지원
|
|
|
|
|
|
|
|
|
|
|
|
### 참고
|
|
|
|
|
|
- 계획 문서: `docs/plans/l2-permission-management-plan.md`
|
|
|
|
|
|
- 세레나 메모리: `position-api-development`, `l2-permission-state`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-28 02:49:46 +09:00
|
|
|
|
## 2025-12-28 (토) - 시스템 게시판 tenant_id 및 custom_fields 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- POST `/api/v1/system-boards/qna/posts` 500 에러 해결
|
|
|
|
|
|
- 시스템 게시판 tenant_id 처리 로직 개선
|
|
|
|
|
|
- custom_fields field_key → field_id 매핑 지원
|
|
|
|
|
|
- 댓글 생성 시 tenant_id 누락 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 문제 원인
|
|
|
|
|
|
1. `posts.tenant_id` NOT NULL 제약조건 위반 (시스템 게시판에서 null 설정 시도)
|
|
|
|
|
|
2. `saveCustomFields()`에서 field_key(string)를 field_id(integer)로 사용
|
|
|
|
|
|
3. `createComment()`에서 tenant_id 미설정
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `app/Services/Boards/PostService.php` | tenant_id 항상 설정, custom_fields 매핑 개선, 댓글 tenant_id 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 상세 변경사항
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. HQ_TENANT_ID 상수 추가
|
|
|
|
|
|
```php
|
|
|
|
|
|
private const HQ_TENANT_ID = 1; // 본사 테넌트 ID
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. applySystemBoardScope() 헬퍼 메서드 추가
|
|
|
|
|
|
```php
|
|
|
|
|
|
private function applySystemBoardScope($query): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$query->where(function ($q) {
|
|
|
|
|
|
$q->where('tenant_id', self::HQ_TENANT_ID)
|
|
|
|
|
|
->orWhere('tenant_id', $this->tenantId());
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. createPost() 수정
|
|
|
|
|
|
- 변경 전: `$data['tenant_id'] = $isSystemBoard ? null : $this->tenantId();`
|
|
|
|
|
|
- 변경 후: `$data['tenant_id'] = $this->tenantId();` (항상 설정)
|
|
|
|
|
|
|
|
|
|
|
|
#### 4. saveCustomFields() 개선
|
|
|
|
|
|
- boardId 파라미터 추가
|
|
|
|
|
|
- field_key → field_id 매핑 로직 추가 (BoardSetting 조회)
|
|
|
|
|
|
- 모든 호출부 업데이트 (createPost, updatePost 등)
|
|
|
|
|
|
|
|
|
|
|
|
#### 5. createComment() 수정
|
|
|
|
|
|
- `$data['tenant_id'] = $this->tenantId();` 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 시스템 게시판 조회 조건
|
|
|
|
|
|
```
|
|
|
|
|
|
(tenant_id = 1) OR (tenant_id = 현재 테넌트)
|
|
|
|
|
|
```
|
|
|
|
|
|
- 본사(tenant_id=1)의 글: 모든 테넌트에서 조회 가능
|
|
|
|
|
|
- 각 테넌트 글: 해당 테넌트만 조회 가능
|
|
|
|
|
|
|
|
|
|
|
|
### 테스트 결과
|
|
|
|
|
|
- ✅ 게시글 생성 (id=7, id=8 with custom_fields)
|
|
|
|
|
|
- ✅ custom_fields 저장 (inquiry_type → field_id=2 변환)
|
|
|
|
|
|
- ✅ 댓글 생성 (id=1, tenant_id=1)
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
```
|
|
|
|
|
|
4a2c185 fix: 게시판 시스템 tenant_id 및 custom_fields 처리 개선
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-27 (금) - 결재 API 프론트엔드 호환성 개선
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 프론트엔드에서 `form_code`, `step_type`, `approver_id` 필드명 사용 지원
|
|
|
|
|
|
- 기존 `form_id`, `type`, `user_id` 필드명과 호환성 유지
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (4개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `app/Http/Requests/Approval/StoreRequest.php` | form_code, step_type, approver_id 필드 추가 |
|
|
|
|
|
|
| `app/Http/Requests/Approval/UpdateRequest.php` | form_code, steps 필드 지원 추가 |
|
|
|
|
|
|
| `app/Services/ApprovalService.php` | store()/update() - form_code→form_id 변환, createApprovalSteps() - step_type/approver_id 지원 |
|
|
|
|
|
|
| `lang/ko/error.php` | `approval.form_required` 에러 메시지 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 필드 호환성 매핑
|
|
|
|
|
|
|
|
|
|
|
|
| 프론트엔드 | API (이전) | 설명 |
|
|
|
|
|
|
|-----------|-----------|------|
|
|
|
|
|
|
| `form_code` | `form_id` | 양식 코드로 form_id 자동 조회 |
|
|
|
|
|
|
| `step_type` | `type` | 결재/참조 구분 |
|
|
|
|
|
|
| `approver_id` | `user_id` | 결재자 사용자 ID |
|
|
|
|
|
|
| `step_order` | - | 결재 순서 (자동 증가) |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-26 18:56:35 +09:00
|
|
|
|
## 2025-12-26 (목) - 휴가관리 휴직 직원 표시 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 휴가 사용현황에 휴직(leave) 상태 직원도 표시되도록 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `app/Services/LeaveService.php` | `getAllBalances()`에서 employee_status 필터를 `'active'`에서 `['active', 'leave']`로 변경 |
|
|
|
|
|
|
|
|
|
|
|
|
### 영향받는 직원
|
|
|
|
|
|
- 최준호(46), 한지민(50), 오태양(51) - 휴직 상태
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
```
|
|
|
|
|
|
defe971 fix(leave): 휴직 직원도 휴가 사용현황에 표시되도록 수정
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-24 16:16:53 +09:00
|
|
|
|
## 2025-12-24 (화) - 매입 세금계산서 수취 토글 기능 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 매입(Purchase) 테이블에 세금계산서 수취 여부(tax_invoice_received) 필드 추가
|
|
|
|
|
|
- React 프론트엔드에서 토글 API 호출 가능하도록 지원
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `2025_12_24_160000_add_tax_invoice_received_to_purchases_table.php` | purchases 테이블에 tax_invoice_received 컬럼 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (3개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `app/Models/Tenants/Purchase.php` | fillable에 tax_invoice_received 추가, casts에 boolean 타입 추가 |
|
|
|
|
|
|
| `app/Services/PurchaseService.php` | toggleTaxInvoice() 메서드 추가 |
|
|
|
|
|
|
| `app/Http/Requests/V1/Purchase/UpdatePurchaseRequest.php` | tax_invoice_received 필드 검증 규칙 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 마이그레이션 실행
|
|
|
|
|
|
```bash
|
|
|
|
|
|
php artisan migrate
|
|
|
|
|
|
# 2025_12_24_160000_add_tax_invoice_received_to_purchases_table ... DONE
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 테스트 결과
|
|
|
|
|
|
- 세금계산서 수취 토글 API 정상 동작
|
|
|
|
|
|
- React 매입 관리 페이지에서 토글 기능 정상 작동
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-22 17:42:59 +09:00
|
|
|
|
## 2025-12-22 (일) - 견적수식 시더 업데이트 (5130 연동)
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 5130 레거시 데이터 기반 견적수식 시더 업데이트
|
|
|
|
|
|
- 케이스(셔터박스) 3600mm, 6000mm 품목 및 범위 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `database/seeders/QuoteFormulaSeeder.php` | CASE_AUTO_SELECT 범위에 3600, 6000 구간 추가 |
|
|
|
|
|
|
| `database/seeders/QuoteFormulaItemSeeder.php` | PT-CASE-3600, PT-CASE-6000 품목 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### 테스트 결과
|
|
|
|
|
|
- W0=3000, H0=2500 입력 시:
|
|
|
|
|
|
- S=3270 → PT-CASE-3600 정상 선택
|
|
|
|
|
|
- H1=2770 → PT-GR-3000 정상 선택
|
|
|
|
|
|
- K=41.21kg → PT-MOTOR-150 정상 선택
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `eeca8d3` feat: 견적수식 케이스 3600/6000 품목 및 범위 추가
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 16:28:16 +09:00
|
|
|
|
## 2025-12-19 (목) - Phase 7.2 보완 - 나의 게시글 API 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- Phase 7 게시판 연동 분석 결과, 7.1/7.2 대부분 구현 완료 확인
|
|
|
|
|
|
- 누락된 `/posts/my` (나의 게시글) API 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (4개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 변경 내용 |
|
|
|
|
|
|
|--------|----------|
|
|
|
|
|
|
| `app/Services/Boards/PostService.php` | `getMyPosts()` 메서드 추가 |
|
|
|
|
|
|
| `app/Http/Controllers/Api/V1/PostController.php` | `myPosts()` 액션 추가 |
|
|
|
|
|
|
| `routes/api.php` | `GET /v1/posts/my` 라우트 추가 |
|
|
|
|
|
|
| `app/Swagger/v1/PostApi.php` | `/posts/my` Swagger 문서 추가 |
|
|
|
|
|
|
|
|
|
|
|
|
### API 라우트 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | /v1/posts/my | 나의 게시글 목록 (게시판 코드/검색/상태 필터 지원) |
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `c15a245` feat: Phase 7.2 보완 - 나의 게시글 API 추가
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 16:04:31 +09:00
|
|
|
|
## 2025-12-19 (목) - Phase 6.1 악성채권 추심관리 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/plans/erp-api-development-plan-d1.0-changes.md` Phase 6.1 악성채권 추심관리
|
|
|
|
|
|
- 악성채권 CRUD, 서류 첨부, 메모 관리 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 (3개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `2025_12_19_160001_create_bad_debts_table.php` | 악성채권 테이블 |
|
|
|
|
|
|
| `2025_12_19_160002_create_bad_debt_documents_table.php` | 악성채권 서류 테이블 |
|
|
|
|
|
|
| `2025_12_19_160003_create_bad_debt_memos_table.php` | 악성채권 메모 테이블 |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 모델 (3개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/BadDebts/BadDebt.php:**
|
|
|
|
|
|
- 악성채권 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- 상태: collecting(추심중), legal_action(법적조치), recovered(회수완료), bad_debt(대손처리)
|
|
|
|
|
|
- Relations: client(), assignedUser(), creator(), documents(), memos()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/BadDebts/BadDebtDocument.php:**
|
|
|
|
|
|
- 서류 모델 (document_type: business_license, tax_invoice, additional)
|
|
|
|
|
|
- Relations: badDebt(), file()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/BadDebts/BadDebtMemo.php:**
|
|
|
|
|
|
- 메모 모델
|
|
|
|
|
|
- Relations: badDebt(), creator()
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 서비스 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/BadDebtService.php:**
|
|
|
|
|
|
- CRUD: index, show, store, update, destroy
|
|
|
|
|
|
- 토글: toggle (is_active)
|
|
|
|
|
|
- 요약: summary (상태별 통계)
|
|
|
|
|
|
- 서류: addDocument, removeDocument
|
|
|
|
|
|
- 메모: addMemo, removeMemo
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 FormRequest (4개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `StoreBadDebtRequest.php` | 등록 (client_id, amount, status, assigned_user_id 등) |
|
|
|
|
|
|
| `UpdateBadDebtRequest.php` | 수정 (선택적 필드) |
|
|
|
|
|
|
| `StoreBadDebtDocumentRequest.php` | 서류 첨부 (document_type, file_id) |
|
|
|
|
|
|
| `StoreBadDebtMemoRequest.php` | 메모 추가 (content) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 컨트롤러 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Http/Controllers/Api/V1/BadDebtController.php:**
|
|
|
|
|
|
- index, summary, store, show, update, destroy, toggle
|
|
|
|
|
|
- addDocument, removeDocument, addMemo, removeMemo
|
|
|
|
|
|
|
|
|
|
|
|
### API 라우트 (11개)
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | /v1/bad-debts | 목록 |
|
|
|
|
|
|
| POST | /v1/bad-debts | 등록 |
|
|
|
|
|
|
| GET | /v1/bad-debts/summary | 요약 통계 |
|
|
|
|
|
|
| GET | /v1/bad-debts/{id} | 상세 |
|
|
|
|
|
|
| PUT | /v1/bad-debts/{id} | 수정 |
|
|
|
|
|
|
| DELETE | /v1/bad-debts/{id} | 삭제 |
|
|
|
|
|
|
| PATCH | /v1/bad-debts/{id}/toggle | 활성화 토글 |
|
|
|
|
|
|
| POST | /v1/bad-debts/{id}/documents | 서류 첨부 |
|
|
|
|
|
|
| DELETE | /v1/bad-debts/{id}/documents/{documentId} | 서류 삭제 |
|
|
|
|
|
|
| POST | /v1/bad-debts/{id}/memos | 메모 추가 |
|
|
|
|
|
|
| DELETE | /v1/bad-debts/{id}/memos/{memoId} | 메모 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
### Swagger 문서
|
|
|
|
|
|
|
|
|
|
|
|
**app/Swagger/v1/BadDebtApi.php:**
|
|
|
|
|
|
- BadDebt, BadDebtDocument, BadDebtMemo 스키마
|
|
|
|
|
|
- 모든 엔드포인트 문서화 완료
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `c0af888` feat: Phase 6.1 악성채권 추심관리 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-18 14:31:42 +09:00
|
|
|
|
## 2025-12-18 (수) - 가지급금 관리 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/plans/erp-api-development-plan.md` Phase 3의 3.5 가지급금 관리
|
|
|
|
|
|
- 가지급금 CRUD, 정산 처리, 인정이자 계산/리포트 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `2025_12_18_120001_create_loans_table.php` | 가지급금 테이블 (tenant_id, user_id, loan_date, amount, purpose, settlement_date, settlement_amount, status, withdrawal_id) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 모델 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/Loan.php:**
|
|
|
|
|
|
- 가지급금 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- 상태: outstanding(미정산), settled(정산완료), partial(부분정산)
|
|
|
|
|
|
- 인정이자율: 연 4.6% (2024/2025), DEFAULT_INTEREST_RATE
|
|
|
|
|
|
- 세금: 법인세 19%, 소득세 35%, 주민세 10%
|
|
|
|
|
|
- Relations: user(), withdrawal(), creator(), updater()
|
|
|
|
|
|
- Methods: calculateRecognizedInterest(), calculateTaxes(), isEditable(), isSettleable()
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 서비스 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/LoanService.php:**
|
|
|
|
|
|
- CRUD: index, show, store, update, destroy
|
|
|
|
|
|
- 요약: summary (미정산 건수/금액, 정산완료 금액)
|
|
|
|
|
|
- 정산: settle (전액/부분 정산)
|
|
|
|
|
|
- 인정이자: calculateInterest, interestReport
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 FormRequest (5개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `LoanIndexRequest.php` | 목록 조회 (user_id, status, date_from, date_to, per_page) |
|
|
|
|
|
|
| `LoanStoreRequest.php` | 등록 (user_id, loan_date, amount, purpose, withdrawal_id) |
|
|
|
|
|
|
| `LoanUpdateRequest.php` | 수정 (선택적 필드) |
|
|
|
|
|
|
| `LoanSettleRequest.php` | 정산 (settlement_date, settlement_amount) |
|
|
|
|
|
|
| `LoanCalculateInterestRequest.php` | 인정이자 계산 (year, user_id) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 컨트롤러 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Http/Controllers/Api/V1/LoanController.php:**
|
|
|
|
|
|
- index, summary, store, show, update, destroy, settle, calculateInterest, interestReport
|
|
|
|
|
|
|
|
|
|
|
|
### API 라우트 (9개)
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | /v1/loans | 목록 조회 |
|
|
|
|
|
|
| POST | /v1/loans | 등록 |
|
|
|
|
|
|
| GET | /v1/loans/summary | 요약 조회 |
|
|
|
|
|
|
| POST | /v1/loans/calculate-interest | 인정이자 계산 |
|
|
|
|
|
|
| GET | /v1/loans/interest-report/{year} | 인정이자 리포트 |
|
|
|
|
|
|
| GET | /v1/loans/{id} | 상세 조회 |
|
|
|
|
|
|
| PUT | /v1/loans/{id} | 수정 |
|
|
|
|
|
|
| DELETE | /v1/loans/{id} | 삭제 |
|
|
|
|
|
|
| POST | /v1/loans/{id}/settle | 정산 |
|
|
|
|
|
|
|
|
|
|
|
|
### i18n 키 추가
|
|
|
|
|
|
|
|
|
|
|
|
**lang/ko/message.php:**
|
|
|
|
|
|
- loan.fetched, loan.created, loan.updated, loan.deleted
|
|
|
|
|
|
- loan.settled, loan.summary_fetched
|
|
|
|
|
|
- loan.interest_calculated, loan.interest_report_fetched
|
|
|
|
|
|
|
|
|
|
|
|
**lang/ko/error.php:**
|
|
|
|
|
|
- loan.not_found, loan.not_editable, loan.not_deletable
|
|
|
|
|
|
- loan.not_settleable, loan.settlement_exceeds
|
|
|
|
|
|
- loan.invalid_withdrawal, loan.user_not_found
|
|
|
|
|
|
|
|
|
|
|
|
**lang/ko/validation.php (attributes):**
|
|
|
|
|
|
- loan_date, amount, purpose, settlement_date, settlement_amount, year
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
- `af83319` - feat: 가지급금 관리 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
feat: [approval] 전자결재 모듈 API 구현
- 마이그레이션 4개 (approval_forms, approval_lines, approvals, approval_steps)
- 모델 4개 (ApprovalForm, ApprovalLine, Approval, ApprovalStep)
- ApprovalService 비즈니스 로직 (양식/결재선 CRUD, 기안함/결재함/참조함, 결재 액션)
- 컨트롤러 3개 (ApprovalFormController, ApprovalLineController, ApprovalController)
- FormRequest 13개 (양식/결재선/문서 검증)
- Swagger 문서 3개 (26개 엔드포인트)
- i18n 메시지/에러 키 추가
- 라우트 26개 등록
2025-12-17 23:23:20 +09:00
|
|
|
|
## 2025-12-17 (화) - 전자결재 모듈 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/plans/erp-api-development-plan.md` Phase 2의 3.1 전자결재 모듈
|
|
|
|
|
|
- 결재 양식 (approval_forms), 결재선 템플릿 (approval_lines), 결재 문서 (approvals) CRUD API 구현
|
|
|
|
|
|
- 기안함, 결재함, 참조함 조회 및 결재 액션 (상신, 승인, 반려, 회수) 기능
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 (4개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `2025_12_17_200001_create_approval_forms_table.php` | 결재 양식 테이블 (name, code, category, template JSON) |
|
|
|
|
|
|
| `2025_12_17_200002_create_approval_lines_table.php` | 결재선 템플릿 테이블 (name, steps JSON, is_default) |
|
|
|
|
|
|
| `2025_12_17_200003_create_approvals_table.php` | 결재 문서 테이블 (form_id, drafter_id, title, content JSON, status) |
|
|
|
|
|
|
| `2025_12_17_200004_create_approval_steps_table.php` | 결재 단계 테이블 (approval_id, step_order, type, user_id, status) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 모델 (4개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/ApprovalForm.php:**
|
|
|
|
|
|
- 결재 양식 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- Relations: creator(), approvals()
|
|
|
|
|
|
- Scopes: active()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/ApprovalLine.php:**
|
|
|
|
|
|
- 결재선 템플릿 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- Relations: creator()
|
|
|
|
|
|
- Methods: getStepCountAttribute()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/Approval.php:**
|
|
|
|
|
|
- 결재 문서 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- 상태: draft → pending → approved/rejected/cancelled
|
|
|
|
|
|
- Relations: form(), drafter(), steps(), currentStepApprover()
|
|
|
|
|
|
- Methods: canEdit(), canDelete(), canSubmit(), canAction(), canCancel()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/ApprovalStep.php:**
|
|
|
|
|
|
- 결재 단계 모델 (SoftDeletes)
|
|
|
|
|
|
- 단계 유형: approval, agreement, reference
|
|
|
|
|
|
- Relations: approval(), user()
|
|
|
|
|
|
- Methods: isPending(), isApproved(), isRejected()
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 서비스 (1개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/ApprovalService.php:**
|
|
|
|
|
|
- Form CRUD: formIndex, formShow, formStore, formUpdate, formDestroy, formActive
|
|
|
|
|
|
- Line CRUD: lineIndex, lineShow, lineStore, lineUpdate, lineDestroy
|
|
|
|
|
|
- Approval CRUD: show, store, update, destroy
|
|
|
|
|
|
- 기안함: drafts, draftsSummary
|
|
|
|
|
|
- 결재함: inbox, inboxSummary
|
|
|
|
|
|
- 참조함: referenceList
|
|
|
|
|
|
- 액션: submit, approve, reject, cancel, markRead, markUnread
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 FormRequest (13개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `FormIndexRequest.php` | 양식 목록 조회 파라미터 |
|
|
|
|
|
|
| `FormStoreRequest.php` | 양식 생성 검증 (name, code, template) |
|
|
|
|
|
|
| `FormUpdateRequest.php` | 양식 수정 검증 |
|
|
|
|
|
|
| `LineIndexRequest.php` | 결재선 목록 조회 파라미터 |
|
|
|
|
|
|
| `LineStoreRequest.php` | 결재선 생성 검증 (name, steps) |
|
|
|
|
|
|
| `LineUpdateRequest.php` | 결재선 수정 검증 |
|
|
|
|
|
|
| `IndexRequest.php` | 기안함 조회 파라미터 |
|
|
|
|
|
|
| `InboxIndexRequest.php` | 결재함 조회 파라미터 |
|
|
|
|
|
|
| `ReferenceIndexRequest.php` | 참조함 조회 파라미터 |
|
|
|
|
|
|
| `StoreRequest.php` | 문서 생성 검증 (form_id, title) |
|
|
|
|
|
|
| `UpdateRequest.php` | 문서 수정 검증 |
|
|
|
|
|
|
| `SubmitRequest.php` | 상신 검증 (steps 필수) |
|
|
|
|
|
|
| `RejectRequest.php` | 반려 검증 (comment 필수) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 컨트롤러 (3개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 엔드포인트 |
|
|
|
|
|
|
|------|-----------|
|
|
|
|
|
|
| `ApprovalFormController.php` | index, active, show, store, update, destroy |
|
|
|
|
|
|
| `ApprovalLineController.php` | index, show, store, update, destroy |
|
|
|
|
|
|
| `ApprovalController.php` | drafts, draftsSummary, inbox, inboxSummary, reference, show, store, update, destroy, submit, approve, reject, cancel, markRead, markUnread |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**routes/api.php:**
|
|
|
|
|
|
- Approval Forms 라우트 그룹 추가 (6개 라우트)
|
|
|
|
|
|
- Approval Lines 라우트 그룹 추가 (5개 라우트)
|
|
|
|
|
|
- Approvals 라우트 그룹 추가 (15개 라우트)
|
|
|
|
|
|
|
|
|
|
|
|
**lang/ko/message.php:**
|
|
|
|
|
|
- approval 섹션 추가 (16개 키)
|
|
|
|
|
|
|
|
|
|
|
|
**lang/ko/error.php:**
|
|
|
|
|
|
- approval 섹션 추가 (15개 키)
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 Swagger 문서 (3개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `app/Swagger/v1/ApprovalFormApi.php` | 결재 양식 API 문서 (6개 엔드포인트) |
|
|
|
|
|
|
| `app/Swagger/v1/ApprovalLineApi.php` | 결재선 API 문서 (5개 엔드포인트) |
|
|
|
|
|
|
| `app/Swagger/v1/ApprovalApi.php` | 전자결재 API 문서 (15개 엔드포인트) |
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
|
|
|
|
|
|
**결재 양식 API (Approval Forms):**
|
|
|
|
|
|
- `GET /api/v1/approval-forms` - 목록 조회
|
|
|
|
|
|
- `POST /api/v1/approval-forms` - 생성
|
|
|
|
|
|
- `GET /api/v1/approval-forms/active` - 활성 양식 (셀렉트박스용)
|
|
|
|
|
|
- `GET /api/v1/approval-forms/{id}` - 상세 조회
|
|
|
|
|
|
- `PATCH /api/v1/approval-forms/{id}` - 수정
|
|
|
|
|
|
- `DELETE /api/v1/approval-forms/{id}` - 삭제
|
|
|
|
|
|
|
|
|
|
|
|
**결재선 API (Approval Lines):**
|
|
|
|
|
|
- `GET /api/v1/approval-lines` - 목록 조회
|
|
|
|
|
|
- `POST /api/v1/approval-lines` - 생성
|
|
|
|
|
|
- `GET /api/v1/approval-lines/{id}` - 상세 조회
|
|
|
|
|
|
- `PATCH /api/v1/approval-lines/{id}` - 수정
|
|
|
|
|
|
- `DELETE /api/v1/approval-lines/{id}` - 삭제
|
|
|
|
|
|
|
|
|
|
|
|
**전자결재 API (Approvals):**
|
|
|
|
|
|
- `GET /api/v1/approvals/drafts` - 기안함
|
|
|
|
|
|
- `GET /api/v1/approvals/drafts/summary` - 기안함 현황
|
|
|
|
|
|
- `GET /api/v1/approvals/inbox` - 결재함
|
|
|
|
|
|
- `GET /api/v1/approvals/inbox/summary` - 결재함 현황
|
|
|
|
|
|
- `GET /api/v1/approvals/reference` - 참조함
|
|
|
|
|
|
- `POST /api/v1/approvals` - 문서 생성
|
|
|
|
|
|
- `GET /api/v1/approvals/{id}` - 상세 조회
|
|
|
|
|
|
- `PATCH /api/v1/approvals/{id}` - 수정
|
|
|
|
|
|
- `DELETE /api/v1/approvals/{id}` - 삭제
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/submit` - 상신
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/approve` - 승인
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/reject` - 반려
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/cancel` - 회수
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/read` - 열람
|
|
|
|
|
|
- `POST /api/v1/approvals/{id}/unread` - 미열람
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- ✅ Pint 스타일 검사 통과 (19개 파일)
|
|
|
|
|
|
- ✅ 라우트 등록 확인 (26개)
|
|
|
|
|
|
- ✅ Swagger 문서 생성 완료
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
feat: 매출/매입 관리 API 구현
- 매출(Sale) 및 매입(Purchase) CRUD API 구현
- 문서번호 자동 생성 (SL/PU + YYYYMMDD + 시퀀스)
- 상태 관리 (draft → confirmed → invoiced)
- 확정(confirm) 및 요약(summary) 기능 추가
- BelongsToTenant, SoftDeletes 적용
- Swagger API 문서 작성 완료
추가된 파일:
- 마이그레이션: sales, purchases 테이블
- 모델: Sale, Purchase
- 서비스: SaleService, PurchaseService
- 컨트롤러: SaleController, PurchaseController
- FormRequest: Store/Update 4개
- Swagger: SaleApi.php, PurchaseApi.php
API 엔드포인트 (14개):
- GET/POST /v1/sales, /v1/purchases
- GET/PUT/DELETE /v1/{sales,purchases}/{id}
- POST /v1/{sales,purchases}/{id}/confirm
- GET /v1/{sales,purchases}/summary
2025-12-17 22:14:48 +09:00
|
|
|
|
## 2025-12-17 (화) - 매출/매입 관리 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/plans/erp-api-development-plan.md` Phase 1의 2.5 매출/매입 관리
|
|
|
|
|
|
- 매출(Sale) 및 매입(Purchase) CRUD API 구현
|
|
|
|
|
|
- 확정(confirm) 기능 및 요약(summary) 조회 기능 포함
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일명 | 설명 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| `2025_12_17_100001_create_sales_table.php` | 매출 테이블 (sale_number, sale_date, client_id, 금액, 상태) |
|
|
|
|
|
|
| `2025_12_17_100002_create_purchases_table.php` | 매입 테이블 (purchase_number, purchase_date, client_id, 금액, 상태) |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 모델 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/Sale.php:**
|
|
|
|
|
|
- 매출 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- 상태: draft → confirmed → invoiced
|
|
|
|
|
|
- Relations: client(), deposit(), creator()
|
|
|
|
|
|
- Methods: canConfirm(), canEdit(), canDelete()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Tenants/Purchase.php:**
|
|
|
|
|
|
- 매입 모델 (BelongsToTenant, SoftDeletes)
|
|
|
|
|
|
- 상태: draft → confirmed
|
|
|
|
|
|
- Relations: client(), withdrawal(), creator()
|
|
|
|
|
|
- Methods: canConfirm(), canEdit(), canDelete()
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 서비스 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/SaleService.php:**
|
|
|
|
|
|
- CRUD, confirm(), summary()
|
|
|
|
|
|
- 문서번호 자동 생성: SL{YYYYMMDD}{0001}
|
|
|
|
|
|
- 상태 검증 (수정/삭제는 draft만 가능)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/PurchaseService.php:**
|
|
|
|
|
|
- CRUD, confirm(), summary()
|
|
|
|
|
|
- 문서번호 자동 생성: PU{YYYYMMDD}{0001}
|
|
|
|
|
|
- 상태 검증 (수정/삭제는 draft만 가능)
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 FormRequest (4개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `app/Http/Requests/V1/Sale/StoreSaleRequest.php` | 매출 등록 검증 |
|
|
|
|
|
|
| `app/Http/Requests/V1/Sale/UpdateSaleRequest.php` | 매출 수정 검증 |
|
|
|
|
|
|
| `app/Http/Requests/V1/Purchase/StorePurchaseRequest.php` | 매입 등록 검증 |
|
|
|
|
|
|
| `app/Http/Requests/V1/Purchase/UpdatePurchaseRequest.php` | 매입 수정 검증 |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 컨트롤러 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 엔드포인트 |
|
|
|
|
|
|
|------|-----------|
|
|
|
|
|
|
| `SaleController.php` | index, store, show, update, destroy, confirm, summary |
|
|
|
|
|
|
| `PurchaseController.php` | index, store, show, update, destroy, confirm, summary |
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**routes/api.php:**
|
|
|
|
|
|
- Sales 라우트 그룹 추가 (7개 라우트)
|
|
|
|
|
|
- Purchases 라우트 그룹 추가 (7개 라우트)
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 Swagger 문서 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `app/Swagger/v1/SaleApi.php` | 매출 API 문서 (전체 엔드포인트) |
|
|
|
|
|
|
| `app/Swagger/v1/PurchaseApi.php` | 매입 API 문서 (전체 엔드포인트) |
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
|
|
|
|
|
|
**매출 API (Sales):**
|
|
|
|
|
|
- `GET /api/v1/sales` - 목록 조회
|
|
|
|
|
|
- `POST /api/v1/sales` - 등록
|
|
|
|
|
|
- `GET /api/v1/sales/{id}` - 상세 조회
|
|
|
|
|
|
- `PUT /api/v1/sales/{id}` - 수정
|
|
|
|
|
|
- `DELETE /api/v1/sales/{id}` - 삭제
|
|
|
|
|
|
- `POST /api/v1/sales/{id}/confirm` - 확정
|
|
|
|
|
|
- `GET /api/v1/sales/summary` - 요약
|
|
|
|
|
|
|
|
|
|
|
|
**매입 API (Purchases):**
|
|
|
|
|
|
- `GET /api/v1/purchases` - 목록 조회
|
|
|
|
|
|
- `POST /api/v1/purchases` - 등록
|
|
|
|
|
|
- `GET /api/v1/purchases/{id}` - 상세 조회
|
|
|
|
|
|
- `PUT /api/v1/purchases/{id}` - 수정
|
|
|
|
|
|
- `DELETE /api/v1/purchases/{id}` - 삭제
|
|
|
|
|
|
- `POST /api/v1/purchases/{id}/confirm` - 확정
|
|
|
|
|
|
- `GET /api/v1/purchases/summary` - 요약
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 완료
|
|
|
|
|
|
- ✅ Pint 스타일 검사 통과
|
|
|
|
|
|
- ✅ 라우트 등록 확인 (14개)
|
|
|
|
|
|
- ✅ 마이그레이션 실행 성공
|
|
|
|
|
|
- ✅ Swagger 문서 생성 완료
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-13 15:41:30 +09:00
|
|
|
|
## 2025-12-13 (금) - Items 테이블 통합 마이그레이션 작성
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/plans/items-table-unification-plan.md` 기반 작업
|
|
|
|
|
|
- products + materials 테이블을 items 단일 테이블로 통합
|
|
|
|
|
|
- BOM 관리 단순화 (child_item_type + child_item_id → child_item_id만)
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 마이그레이션 파일 (6개)
|
|
|
|
|
|
|
|
|
|
|
|
| 순서 | 파일명 | Phase | 설명 |
|
|
|
|
|
|
|------|--------|-------|------|
|
|
|
|
|
|
| 1 | `2025_12_13_152423_normalize_item_types_before_unification.php` | 0 | 비표준 item_type 삭제 (PRODUCT, SUBASSEMBLY, PART 등) |
|
|
|
|
|
|
| 2 | `2025_12_13_152507_create_items_table.php` | 1.1 | items 테이블 생성 |
|
|
|
|
|
|
| 3 | `2025_12_13_152553_create_item_details_table.php` | 1.2 | item_details 테이블 생성 (1:1 확장 필드) |
|
|
|
|
|
|
| 4 | `2025_12_13_152631_migrate_products_materials_to_items.php` | 1.3 | 데이터 이관 + item_id_mappings 매핑 테이블 |
|
|
|
|
|
|
| 5 | `2025_12_13_153116_update_item_pages_source_table_to_items.php` | 3 | item_pages.source_table 업데이트 |
|
|
|
|
|
|
| 6 | `2025_12_13_153544_update_reference_tables_to_items.php` | 5 | 참조 테이블 item_id 컬럼 추가 및 매핑 |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 모델 (2개)
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Items/Item.php:**
|
|
|
|
|
|
- 통합 품목 모델 (FG, PT, SM, RM, CS)
|
|
|
|
|
|
- BelongsToTenant, SoftDeletes
|
|
|
|
|
|
- 스코프: products(), materials(), type(), active()
|
|
|
|
|
|
- BOM 헬퍼: getBomChildIds(), loadBomChildren()
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/Items/ItemDetail.php:**
|
|
|
|
|
|
- 품목 상세 정보 (1:1 관계)
|
|
|
|
|
|
- Products 전용: is_sellable, is_purchasable, is_producible, 파일 필드
|
|
|
|
|
|
- Materials 전용: is_inspection, specification
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 서비스
|
|
|
|
|
|
|
|
|
|
|
|
**app/Services/ItemService.php:**
|
|
|
|
|
|
- items 단일 테이블 CRUD
|
|
|
|
|
|
- 동적 필드 → options JSON 병합
|
|
|
|
|
|
- 카테고리 트리 조회
|
|
|
|
|
|
- 활성/비활성 토글
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**app/Models/ItemMaster/ItemPage.php:**
|
|
|
|
|
|
- `getTargetModelClass()`: items 테이블 지원 추가
|
|
|
|
|
|
- `isItemPage()`, `isProductType()`, `isMaterialType()` 헬퍼 추가
|
|
|
|
|
|
|
|
|
|
|
|
### ID 매핑 전략
|
|
|
|
|
|
|
|
|
|
|
|
**item_id_mappings 테이블:**
|
|
|
|
|
|
- 기존 products/materials ID → 새 items ID 매핑
|
|
|
|
|
|
- Phase 5 참조 테이블 마이그레이션에서 활용
|
|
|
|
|
|
|
|
|
|
|
|
### 참조 테이블 업데이트 대상 (Phase 5)
|
|
|
|
|
|
|
|
|
|
|
|
| 테이블 | 기존 | 추가 컬럼 |
|
|
|
|
|
|
|--------|------|----------|
|
|
|
|
|
|
| product_components | ref_type + ref_id | item_id, parent_item_id |
|
|
|
|
|
|
| bom_template_items | ref_type + ref_id | item_id |
|
|
|
|
|
|
| orders | product_id | item_id |
|
|
|
|
|
|
| order_items | product_id | item_id |
|
|
|
|
|
|
| material_receipts | material_id | item_id |
|
|
|
|
|
|
| lots | material_id | item_id |
|
|
|
|
|
|
| price_histories | item_type + item_id | new_item_id |
|
|
|
|
|
|
| item_fields | source_table | → 'items' |
|
|
|
|
|
|
|
|
|
|
|
|
### 실행 명령어
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 마이그레이션 실행 (순서대로)
|
|
|
|
|
|
php artisan migrate
|
|
|
|
|
|
|
|
|
|
|
|
# 롤백 (전체)
|
|
|
|
|
|
php artisan migrate:rollback --step=6
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-12-13 15:45:48 +09:00
|
|
|
|
### Phase 6: 마이그레이션 실행 완료 ✅
|
|
|
|
|
|
|
|
|
|
|
|
**실행 결과:**
|
|
|
|
|
|
```
|
|
|
|
|
|
items: 362개 (FG:4, PT:4, RM:133, SM:217, CS:4)
|
|
|
|
|
|
item_details: 362개 (1:1 관계)
|
|
|
|
|
|
item_id_mappings: 362개 (ID 매핑 완료)
|
|
|
|
|
|
item_pages: 47개 → source_table='items'로 통합
|
|
|
|
|
|
product_components: 4개 중 2개 item_id 매핑 완료
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**수정 사항:**
|
|
|
|
|
|
- `migrate_products_materials_to_items.php`: null material_code 자동 생성 로직 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (Phase 7 이후)
|
2025-12-13 15:41:30 +09:00
|
|
|
|
|
|
|
|
|
|
- [ ] ItemsController → ItemService 교체
|
|
|
|
|
|
- [ ] CRUD 테스트 (전체 item_type)
|
|
|
|
|
|
- [ ] BOM 계산 테스트
|
|
|
|
|
|
- [ ] Item-Master 연동 테스트
|
|
|
|
|
|
- [ ] 기존 products/materials 테이블 삭제 (확인 후)
|
|
|
|
|
|
|
|
|
|
|
|
### 참조 문서
|
|
|
|
|
|
- `docs/plans/items-table-unification-plan.md`
|
|
|
|
|
|
- `docs/INDEX.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-09 09:40:01 +09:00
|
|
|
|
## 2025-12-09 (월) - HR API 개발 완료 (Employee, Attendance, Department Tree)
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `docs/features/HR_API_ANALYSIS.md` 기반 HR API 구현
|
|
|
|
|
|
- Employee 관리 API (tenant_user_profiles 활용)
|
|
|
|
|
|
- Attendance 근태 관리 API (attendances 테이블)
|
|
|
|
|
|
- Department 트리 조회 API
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 1: 마이그레이션 ✅
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 마이그레이션:**
|
|
|
|
|
|
- `2025_12_09_084138_add_employee_status_to_tenant_user_profiles_table.php`
|
|
|
|
|
|
- `employee_status` ENUM('active', 'leave', 'resigned') DEFAULT 'active'
|
|
|
|
|
|
- `json_extra` JSON nullable (유연한 사원 정보)
|
|
|
|
|
|
|
|
|
|
|
|
- `2025_12_09_084231_create_attendances_table.php`
|
|
|
|
|
|
- `user_id`, `base_date`, `status`, `json_details`, `remarks`
|
|
|
|
|
|
- `json_details`: check_in, check_out, gps_data, work_minutes 등
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 2: Employee API ✅
|
|
|
|
|
|
|
|
|
|
|
|
**수정된 파일:**
|
|
|
|
|
|
- `app/Models/Tenants/TenantUserProfile.php` - employee_status, json_extra 헬퍼 추가
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 파일:**
|
|
|
|
|
|
- `app/Services/EmployeeService.php` - 사원 CRUD, 통계, 계정 생성
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/EmployeeController.php`
|
|
|
|
|
|
- `app/Http/Requests/Employee/` (5개 FormRequest)
|
|
|
|
|
|
- IndexRequest, StoreRequest, UpdateRequest, BulkDeleteRequest, CreateAccountRequest
|
|
|
|
|
|
- `app/Swagger/v1/EmployeeApi.php` - 8개 엔드포인트 문서
|
|
|
|
|
|
|
|
|
|
|
|
**API 엔드포인트 (8개):**
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/v1/employees` | 사원 목록 |
|
|
|
|
|
|
| POST | `/v1/employees` | 사원 등록 |
|
|
|
|
|
|
| GET | `/v1/employees/stats` | 사원 통계 |
|
|
|
|
|
|
| GET | `/v1/employees/{id}` | 사원 상세 |
|
|
|
|
|
|
| PATCH | `/v1/employees/{id}` | 사원 수정 |
|
|
|
|
|
|
| DELETE | `/v1/employees/{id}` | 사원 삭제 |
|
|
|
|
|
|
| POST | `/v1/employees/bulk-delete` | 일괄 삭제 |
|
|
|
|
|
|
| POST | `/v1/employees/{id}/create-account` | 계정 생성 |
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 3: Department Tree API ✅
|
|
|
|
|
|
|
|
|
|
|
|
**수정된 파일:**
|
|
|
|
|
|
- `app/Services/DepartmentService.php` - getTree(), buildTreeNode() 추가
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/DepartmentController.php` - tree() 액션 추가
|
|
|
|
|
|
- `routes/api.php` - `/v1/departments/tree` 라우트 추가
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 4: Attendance API ✅
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 파일:**
|
|
|
|
|
|
- `app/Models/Tenants/Attendance.php` - 근태 모델
|
|
|
|
|
|
- BelongsToTenant, SoftDeletes
|
|
|
|
|
|
- json_details 헬퍼 (check_in, check_out, gps_data, work_minutes 등)
|
|
|
|
|
|
- 스코프: onDate, betweenDates, forUser, withStatus
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Services/AttendanceService.php` - 근태 CRUD, 출퇴근, 월간 통계
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/AttendanceController.php`
|
|
|
|
|
|
- `app/Http/Requests/Attendance/` (6개 FormRequest)
|
|
|
|
|
|
- IndexRequest, StoreRequest, UpdateRequest, CheckInRequest, CheckOutRequest, MonthlyStatsRequest
|
|
|
|
|
|
- `app/Swagger/v1/AttendanceApi.php` - 9개 엔드포인트 문서
|
|
|
|
|
|
|
|
|
|
|
|
**API 엔드포인트 (9개):**
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/v1/attendances` | 근태 목록 |
|
|
|
|
|
|
| POST | `/v1/attendances` | 근태 등록 |
|
|
|
|
|
|
| GET | `/v1/attendances/monthly-stats` | 월간 통계 |
|
|
|
|
|
|
| POST | `/v1/attendances/check-in` | 출근 기록 |
|
|
|
|
|
|
| POST | `/v1/attendances/check-out` | 퇴근 기록 |
|
|
|
|
|
|
| GET | `/v1/attendances/{id}` | 근태 상세 |
|
|
|
|
|
|
| PATCH | `/v1/attendances/{id}` | 근태 수정 |
|
|
|
|
|
|
| DELETE | `/v1/attendances/{id}` | 근태 삭제 |
|
|
|
|
|
|
| POST | `/v1/attendances/bulk-delete` | 일괄 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- ✅ Pint 코드 포맷팅 완료 (13개 파일 수정)
|
|
|
|
|
|
- ✅ 마이그레이션 실행 완료 (Batch 48)
|
|
|
|
|
|
- ✅ 라우트 등록 확인 (Employee 8개, Attendance 9개, Department Tree 1개)
|
|
|
|
|
|
- ✅ Swagger 문서 생성 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 목록
|
|
|
|
|
|
|
|
|
|
|
|
**routes/api.php:**
|
|
|
|
|
|
- EmployeeController, AttendanceController import 추가
|
|
|
|
|
|
- Employee API 라우트 그룹 (8개)
|
|
|
|
|
|
- Attendance API 라우트 그룹 (9개)
|
|
|
|
|
|
- Department /tree 라우트 추가
|
|
|
|
|
|
|
|
|
|
|
|
**버그 수정:**
|
|
|
|
|
|
- `app/Models/Tenants/Attendance.php` - BelongsToTenant 경로 수정
|
|
|
|
|
|
- `App\Models\Scopes\BelongsToTenant` → `App\Traits\BelongsToTenant`
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업
|
|
|
|
|
|
- [ ] React 프론트엔드 연동
|
|
|
|
|
|
- [ ] 휴가 관리 API 구현 (향후)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - Flow Tester Error #61 해결 (GET query 파라미터 처리)
|
|
|
|
|
|
|
|
|
|
|
|
### 문제
|
|
|
|
|
|
- `GET /pricing/cost` 요청 시 422 에러 발생
|
|
|
|
|
|
- 에러: `item_id`와 `item_type_code`가 필수 항목인데 누락
|
|
|
|
|
|
|
|
|
|
|
|
### 원인
|
|
|
|
|
|
- Flow 정의에 `query` 필드로 파라미터 정의되어 있음
|
|
|
|
|
|
- **FlowExecutor**가 `query` 필드를 처리하지 않고 `body`만 처리
|
|
|
|
|
|
- GET 요청은 query string으로 파라미터를 전달해야 하는데 누락됨
|
|
|
|
|
|
|
|
|
|
|
|
### 해결
|
|
|
|
|
|
**수정 파일**: `mng/app/Services/FlowTester/FlowExecutor.php`
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
// Line 226: query 변수 바인딩 추가
|
|
|
|
|
|
$query = $this->binder->bind($step['query'] ?? []);
|
|
|
|
|
|
|
|
|
|
|
|
// Line 230-234: HTTP 요청에 query 옵션 전달
|
|
|
|
|
|
$response = $this->httpClient->request($method, $endpoint, [
|
|
|
|
|
|
'headers' => $headers,
|
|
|
|
|
|
'body' => $body,
|
|
|
|
|
|
'query' => $query, // 추가
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// 결과 로그에도 query 정보 포함
|
|
|
|
|
|
'request' => [
|
|
|
|
|
|
'method' => $method,
|
|
|
|
|
|
'endpoint' => $endpoint,
|
|
|
|
|
|
'headers' => $headers,
|
|
|
|
|
|
'body' => $body,
|
|
|
|
|
|
'query' => $query, // 추가
|
|
|
|
|
|
],
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 검증
|
|
|
|
|
|
- PHP 문법 검사: ✅ 통과
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - Flow Tester Error #60 해결 (중복 테스트 데이터 삭제)
|
|
|
|
|
|
|
|
|
|
|
|
### 문제
|
|
|
|
|
|
- Flow Tester 재실행 시 `error.duplicate_key` 오류 발생
|
|
|
|
|
|
- 이전 테스트 실행(Error #59)이 중간에 실패하면서 테스트 데이터가 남아있음
|
|
|
|
|
|
- 동적 날짜(`{{$date}}`)가 정상 작동 중이지만, 같은 날 재실행 시 중복 발생
|
|
|
|
|
|
|
|
|
|
|
|
### 원인
|
|
|
|
|
|
- Error #59 실행 시 create_price 단계까지 진행 후 실패
|
|
|
|
|
|
- cleanup 단계(delete_price)에 도달하지 못해 테스트 데이터 잔류
|
|
|
|
|
|
- checkDuplicate() 메서드가 기존 데이터 발견
|
|
|
|
|
|
|
|
|
|
|
|
### 해결
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 잔류 테스트 데이터 삭제
|
|
|
|
|
|
docker exec -i sam-api-1 php artisan tinker --execute="
|
|
|
|
|
|
use App\Models\Products\Price;
|
|
|
|
|
|
Price::where('effective_from', '2025-12-08')->delete();
|
|
|
|
|
|
"
|
|
|
|
|
|
# 결과: 1건 삭제 완료
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 추가 권장사항
|
|
|
|
|
|
- Flow Tester 재실행 전 cleanup 또는 setup 스크립트 추가 고려
|
|
|
|
|
|
- 또는 effective_from에 `{{$uuid}}`나 `{{$timestamp}}`를 조합하여 고유성 보장
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - User 모델 경로 오류 수정 (500 에러 해결)
|
|
|
|
|
|
|
|
|
|
|
|
### 문제
|
|
|
|
|
|
- Flow Tester #59 실행 시 `GET /pricing/{id}/revisions` 에서 500 에러
|
|
|
|
|
|
- 에러: `Class "App\Models\User" not found`
|
|
|
|
|
|
|
|
|
|
|
|
### 원인
|
|
|
|
|
|
- `PriceRevision.php`, `Board.php`에서 잘못된 User 모델 경로 참조
|
|
|
|
|
|
- 실제 경로: `App\Models\Members\User`
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `app/Models/Products/PriceRevision.php` - `\App\Models\User` → `\App\Models\Members\User`
|
|
|
|
|
|
- `app/Models/Boards/Board.php` - `use App\Models\User` → `use App\Models\Members\User`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - Flow Tester 동적 날짜 변수 적용 (duplicate key 해결)
|
|
|
|
|
|
|
|
|
|
|
|
### 문제
|
|
|
|
|
|
- Flow Tester #58 실행 시 `error.duplicate_key` 에러 발생
|
|
|
|
|
|
- 원인: 하드코딩된 `effective_from: "2025-01-01"`로 인해 이전 테스트 데이터와 중복
|
|
|
|
|
|
|
|
|
|
|
|
### 해결
|
|
|
|
|
|
`{{$date}}` 동적 변수를 사용하여 매번 테스트 시 오늘 날짜 사용
|
|
|
|
|
|
|
|
|
|
|
|
### 수정 내용 (Flow ID: 8 - 단가 관리 CRUD 테스트)
|
|
|
|
|
|
|
|
|
|
|
|
| 스텝 | 필드 | 변경 전 | 변경 후 |
|
|
|
|
|
|
|------|------|---------|---------|
|
|
|
|
|
|
| create_price | effective_from | "2025-01-01" | "{{$date}}" |
|
|
|
|
|
|
| create_price | effective_to | "2025-12-31" | "2099-12-31" |
|
|
|
|
|
|
| create_price_for_finalize | effective_from | "2025-01-01" | "{{$date}}" |
|
|
|
|
|
|
| get_cost | date | "2025-06-15" | "{{$date}}" |
|
|
|
|
|
|
| by_items | date | "2025-06-15" | "{{$date}}" |
|
|
|
|
|
|
|
|
|
|
|
|
### VariableBinder 지원 변수
|
|
|
|
|
|
|
|
|
|
|
|
| 변수 | 설명 | 예시 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| `{{$date}}` | 현재 날짜 (Y-m-d) | 2025-12-08 |
|
|
|
|
|
|
| `{{$datetime}}` | 현재 날짜시간 (Y-m-d H:i:s) | 2025-12-08 14:30:00 |
|
|
|
|
|
|
| `{{$timestamp}}` | Unix 타임스탬프 | 1733637000 |
|
|
|
|
|
|
| `{{$uuid}}` | 랜덤 UUID | 550e8400-e29b-41d4-a716-... |
|
|
|
|
|
|
| `{{$random:N}}` | N자리 랜덤 숫자 | 123456 |
|
|
|
|
|
|
| `{{$faker.xxx}}` | Faker 랜덤 데이터 | 회사명, 이름 등 |
|
|
|
|
|
|
|
|
|
|
|
|
### 해결 원리
|
|
|
|
|
|
- 매번 테스트 시 오늘 날짜가 사용되어 다른 날의 중복 데이터와 충돌 없음
|
|
|
|
|
|
- 플로우 마지막에 `delete_price`와 `cleanup_finalized` 스텝이 테스트 데이터 정리
|
|
|
|
|
|
- 별도의 cleanup 스텝 없이도 반복 실행 가능
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - Flow Tester HTTP 상태 코드 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 문제
|
|
|
|
|
|
- Flow Tester `POST /pricing` 요청에서 예상 상태 코드 201, 실제 200 반환
|
|
|
|
|
|
- HTTP 표준: POST 리소스 생성 시 201 Created 반환 필요
|
|
|
|
|
|
|
|
|
|
|
|
### 수정 내용
|
|
|
|
|
|
|
|
|
|
|
|
**ApiResponse 클래스 개선:**
|
|
|
|
|
|
- `ApiResponse::success()`: `$statusCode` 파라미터 추가 (기본값 200)
|
|
|
|
|
|
- `ApiResponse::handle()`: 콜백에서 `statusCode` 키로 상태 코드 지정 가능
|
|
|
|
|
|
|
|
|
|
|
|
**PricingController 수정:**
|
|
|
|
|
|
- `store()` 메서드: `'statusCode' => 201` 반환
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `app/Helpers/ApiResponse.php` - 상태 코드 파라미터 추가
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/PricingController.php` - store 201 반환
|
|
|
|
|
|
|
|
|
|
|
|
### 사용 예시
|
|
|
|
|
|
```php
|
|
|
|
|
|
// Controller에서 201 반환
|
|
|
|
|
|
return ApiResponse::handle(function () use ($request) {
|
|
|
|
|
|
$data = $this->service->store($request->validated());
|
|
|
|
|
|
return ['data' => $data, 'message' => __('message.created'), 'statusCode' => 201];
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 필요
|
|
|
|
|
|
- [x] Flow Tester 재실행하여 201 응답 확인 ✅
|
|
|
|
|
|
- [x] duplicate key 에러 해결 (동적 날짜 변수 적용) ✅
|
|
|
|
|
|
|
|
|
|
|
|
### 남은 작업 (TODO)
|
|
|
|
|
|
다른 Controller store 메서드 일괄 수정 (27개):
|
|
|
|
|
|
- AdminController, BoardController, CategoryController, CategoryFieldController
|
|
|
|
|
|
- CategoryTemplateController, ClassificationController, ClientGroupController
|
|
|
|
|
|
- CommonController, DesignModelController, EstimateController, FolderController
|
|
|
|
|
|
- ItemsController, MaterialController, MenuController, ModelSetController
|
|
|
|
|
|
- PostController, QuoteController, RoleController, TenantController
|
|
|
|
|
|
- TenantOptionGroupController, TenantOptionValueController, TenantStatFieldController
|
|
|
|
|
|
- ItemMaster 하위: CustomTabController, ItemBomItemController, ItemFieldController
|
|
|
|
|
|
- ItemMaster 하위: ItemSectionController, UnitOptionController
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-08 (일) - 단가 관리 API 전면 재설계 (prices + price_revisions)
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- `price_histories` → `prices` + `price_revisions` 구조로 전면 재설계
|
|
|
|
|
|
- 원가 조회 시 수입검사 입고단가 우선, 표준원가 폴백 로직 구현
|
|
|
|
|
|
- 가격 확정(finalize) 기능으로 불변성 보장
|
|
|
|
|
|
- 리비전 관리로 변경 이력 추적
|
|
|
|
|
|
|
|
|
|
|
|
### 테이블 구조 변경
|
|
|
|
|
|
|
|
|
|
|
|
**prices (단가 마스터):**
|
|
|
|
|
|
| 컬럼 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| item_type_code | 품목유형 (PRODUCT/MATERIAL) |
|
|
|
|
|
|
| item_id | 품목 ID |
|
|
|
|
|
|
| client_group_id | 고객그룹 ID (NULL=기본가) |
|
|
|
|
|
|
| purchase_price | 매입단가 (표준원가) |
|
|
|
|
|
|
| processing_cost | 가공비 |
|
|
|
|
|
|
| loss_rate | LOSS율 (%) |
|
|
|
|
|
|
| margin_rate | 마진율 (%) |
|
|
|
|
|
|
| sales_price | 판매단가 |
|
|
|
|
|
|
| rounding_rule | 반올림 규칙 (round/ceil/floor) |
|
|
|
|
|
|
| rounding_unit | 반올림 단위 (1,10,100,1000) |
|
|
|
|
|
|
| effective_from/to | 적용 기간 |
|
|
|
|
|
|
| status | 상태 (draft/active/inactive/finalized) |
|
|
|
|
|
|
| is_final | 최종 확정 여부 |
|
|
|
|
|
|
|
|
|
|
|
|
**price_revisions (변경 이력):**
|
|
|
|
|
|
| 컬럼 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| price_id | 단가 FK |
|
|
|
|
|
|
| revision_number | 리비전 번호 |
|
|
|
|
|
|
| changed_at | 변경 일시 |
|
|
|
|
|
|
| changed_by | 변경자 ID |
|
|
|
|
|
|
| change_reason | 변경 사유 |
|
|
|
|
|
|
| before_snapshot | 변경 전 JSON |
|
|
|
|
|
|
| after_snapshot | 변경 후 JSON |
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**마이그레이션 (4개):**
|
|
|
|
|
|
- `2025_12_08_154633_create_prices_table.php`
|
|
|
|
|
|
- `2025_12_08_154634_create_price_revisions_table.php`
|
|
|
|
|
|
- `2025_12_08_154635_migrate_price_histories_to_prices.php`
|
|
|
|
|
|
- `2025_12_08_154636_drop_price_histories_table.php`
|
|
|
|
|
|
|
|
|
|
|
|
**모델 (2개):**
|
|
|
|
|
|
- `app/Models/Price.php` - BelongsToTenant, SoftDeletes
|
|
|
|
|
|
- `app/Models/PriceRevision.php`
|
|
|
|
|
|
|
|
|
|
|
|
**서비스 (1개):**
|
|
|
|
|
|
- `app/Services/PricingService.php`
|
|
|
|
|
|
- index, show, store, update, destroy (CRUD)
|
|
|
|
|
|
- byItems: 다중 품목 단가 조회
|
|
|
|
|
|
- revisions: 변경 이력 조회
|
|
|
|
|
|
- finalize: 가격 확정 (불변 처리)
|
|
|
|
|
|
- getCost: 원가 조회 (receipt > standard 폴백)
|
|
|
|
|
|
|
|
|
|
|
|
**FormRequest (5개):**
|
|
|
|
|
|
- `app/Http/Requests/Pricing/PriceIndexRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/Pricing/PriceStoreRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/Pricing/PriceUpdateRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/Pricing/PriceByItemsRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/Pricing/PriceCostRequest.php`
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger (1개):**
|
|
|
|
|
|
- `app/Swagger/v1/PricingApi.php` - 전면 재작성
|
|
|
|
|
|
|
|
|
|
|
|
### 삭제된 파일
|
|
|
|
|
|
- `app/Models/PriceHistory.php`
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트 (9개)
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/api/v1/pricing` | 단가 목록 (페이지네이션) |
|
|
|
|
|
|
| POST | `/api/v1/pricing` | 단가 생성 |
|
|
|
|
|
|
| GET | `/api/v1/pricing/cost` | 원가 조회 (receipt > standard) |
|
|
|
|
|
|
| POST | `/api/v1/pricing/by-items` | 다중 품목 단가 조회 |
|
|
|
|
|
|
| GET | `/api/v1/pricing/{id}` | 단가 상세 |
|
|
|
|
|
|
| PUT | `/api/v1/pricing/{id}` | 단가 수정 |
|
|
|
|
|
|
| DELETE | `/api/v1/pricing/{id}` | 단가 삭제 |
|
|
|
|
|
|
| POST | `/api/v1/pricing/{id}/finalize` | 가격 확정 |
|
|
|
|
|
|
| GET | `/api/v1/pricing/{id}/revisions` | 변경 이력 조회 |
|
|
|
|
|
|
|
|
|
|
|
|
### 원가 조회 로직 (getCost)
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1순위: 자재인 경우 → material_receipts.purchase_price_excl_vat
|
|
|
|
|
|
(수입검사 완료된 최신 입고단가)
|
|
|
|
|
|
|
|
|
|
|
|
2순위: prices.purchase_price (표준원가)
|
|
|
|
|
|
|
|
|
|
|
|
총원가 계산:
|
|
|
|
|
|
total_cost = (purchase_price + processing_cost) × (1 + loss_rate/100)
|
|
|
|
|
|
|
|
|
|
|
|
판매가 계산:
|
|
|
|
|
|
sales_price = round(total_cost × (1 + margin_rate/100), rounding_unit, rounding_rule)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 모든 파일 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 14개 파일 수정 완료
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업
|
|
|
|
|
|
- [ ] 마이그레이션 실행 (php artisan migrate)
|
|
|
|
|
|
- [ ] API 테스트 (Swagger UI)
|
|
|
|
|
|
- [ ] React 프론트엔드 연동
|
|
|
|
|
|
|
|
|
|
|
|
### 참조 문서
|
|
|
|
|
|
- `docs/front/[API-2025-12-08] pricing-api-enhancement-request.md`
|
|
|
|
|
|
- `docs/rules/pricing-policy.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
feat: [quote] 견적 API Phase 2-3 완료 (Service + Controller Layer)
Phase 2 - Service Layer:
- QuoteService: 견적 CRUD + 상태관리 (확정/전환)
- QuoteNumberService: 견적번호 채번 (KD-{PREFIX}-YYMMDD-SEQ)
- FormulaEvaluatorService: 수식 평가 엔진 (SUM, IF, ROUND 등)
- QuoteCalculationService: 자동산출 (스크린/철재 제품)
- QuoteDocumentService: PDF 생성 및 이메일/카카오 발송
Phase 3 - Controller Layer:
- QuoteController: 16개 엔드포인트
- FormRequest 7개: Index, Store, Update, BulkDelete, Calculate, SendEmail, SendKakao
- QuoteApi.php: Swagger 문서 (12개 스키마, 16개 엔드포인트)
- routes/api.php: 16개 라우트 등록
i18n 키 추가:
- error.php: quote_not_found, formula_* 등
- message.php: quote.* 성공 메시지
2025-12-04 22:03:40 +09:00
|
|
|
|
## 2025-12-04 (수) - 견적 API Phase 3: Controller + FormRequest + Routes + Swagger 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 견적 API Phase 3 Controller Layer 구현
|
|
|
|
|
|
- 16개 API 엔드포인트 구현 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**Controller (1개):**
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/QuoteController.php`
|
|
|
|
|
|
- 16개 메서드: index, show, store, update, destroy, bulkDestroy, finalize, cancelFinalize, convertToOrder, previewNumber, calculate, calculationSchema, generatePdf, sendEmail, sendKakao, sendHistory
|
|
|
|
|
|
- 4개 Service DI: QuoteService, QuoteNumberService, QuoteCalculationService, QuoteDocumentService
|
|
|
|
|
|
- ApiResponse::handle() 패턴 적용
|
|
|
|
|
|
|
|
|
|
|
|
**FormRequest (7개):**
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `QuoteIndexRequest.php` | 목록 조회 파라미터 검증 |
|
|
|
|
|
|
| `QuoteStoreRequest.php` | 견적 생성 검증 (items 배열 포함) |
|
|
|
|
|
|
| `QuoteUpdateRequest.php` | 견적 수정 검증 |
|
|
|
|
|
|
| `QuoteBulkDeleteRequest.php` | 일괄 삭제 IDs 검증 |
|
|
|
|
|
|
| `QuoteCalculateRequest.php` | 자동산출 입력값 검증 |
|
|
|
|
|
|
| `QuoteSendEmailRequest.php` | 이메일 발송 검증 |
|
|
|
|
|
|
| `QuoteSendKakaoRequest.php` | 카카오 발송 검증 |
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger (1개):**
|
|
|
|
|
|
- `app/Swagger/v1/QuoteApi.php`
|
|
|
|
|
|
- 12개 스키마: Quote, QuoteItem, QuotePagination, QuoteCreateRequest, QuoteUpdateRequest 등
|
|
|
|
|
|
- 16개 엔드포인트 문서화
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트 (16개)
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| GET | `/api/v1/quotes` | 견적 목록 (페이지네이션) |
|
|
|
|
|
|
| POST | `/api/v1/quotes` | 견적 생성 |
|
|
|
|
|
|
| GET | `/api/v1/quotes/number/preview` | 견적번호 미리보기 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/calculate` | 자동산출 |
|
|
|
|
|
|
| GET | `/api/v1/quotes/calculate/schema` | 산출 스키마 조회 |
|
|
|
|
|
|
| DELETE | `/api/v1/quotes/bulk` | 일괄 삭제 |
|
|
|
|
|
|
| GET | `/api/v1/quotes/{id}` | 견적 상세 |
|
|
|
|
|
|
| PUT | `/api/v1/quotes/{id}` | 견적 수정 |
|
|
|
|
|
|
| DELETE | `/api/v1/quotes/{id}` | 견적 삭제 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/finalize` | 확정 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/cancel-finalize` | 확정 취소 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/convert` | 주문 전환 |
|
|
|
|
|
|
| GET | `/api/v1/quotes/{id}/pdf` | PDF 생성 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/send/email` | 이메일 발송 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/send/kakao` | 카카오 발송 |
|
|
|
|
|
|
| GET | `/api/v1/quotes/{id}/send/history` | 발송 이력 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 9개 파일 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 완료
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
- 라우트 등록: ✅ 16개 라우트 확인
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (Phase 4)
|
|
|
|
|
|
- [ ] 단위 테스트 작성
|
|
|
|
|
|
- [ ] 통합 테스트 작성
|
|
|
|
|
|
- [ ] 마이그레이션 실행 및 실제 데이터 검증
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-04 (수) - 견적 API Phase 2: Service Layer 구현 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 견적 API Phase 2 Service Layer 구현
|
|
|
|
|
|
- 5개 Service 파일 생성 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 생성된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**Service Layer (5개):**
|
|
|
|
|
|
|
|
|
|
|
|
| 파일 | 설명 | 주요 기능 |
|
|
|
|
|
|
|------|------|----------|
|
|
|
|
|
|
| `QuoteService.php` | 견적 CRUD + 상태관리 | index, show, store, update, destroy, bulkDestroy, finalize, cancelFinalize, convertToOrder |
|
|
|
|
|
|
| `QuoteNumberService.php` | 견적번호 채번 | generate, preview, validate, parse, isUnique |
|
|
|
|
|
|
| `FormulaEvaluatorService.php` | 수식 평가 엔진 | validateFormula, evaluate, evaluateMultiple, evaluateRange, evaluateMapping |
|
|
|
|
|
|
| `QuoteCalculationService.php` | 견적 자동산출 | calculate, preview, recalculate, getInputSchema |
|
|
|
|
|
|
| `QuoteDocumentService.php` | 문서 생성/발송 | generatePdf, sendEmail, sendKakao, getSendHistory |
|
|
|
|
|
|
|
|
|
|
|
|
### 견적번호 형식
|
|
|
|
|
|
```
|
|
|
|
|
|
KD-{PREFIX}-{YYMMDD}-{SEQ}
|
|
|
|
|
|
예: KD-SC-251204-01 (스크린), KD-ST-251204-01 (철재)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### FormulaEvaluatorService 지원 함수
|
|
|
|
|
|
- 수학: `SUM`, `ROUND`, `CEIL`, `FLOOR`, `ABS`, `MIN`, `MAX`
|
|
|
|
|
|
- 논리: `IF`, `AND`, `OR`, `NOT`
|
|
|
|
|
|
|
|
|
|
|
|
### QuoteCalculationService 입력 스키마
|
|
|
|
|
|
|
|
|
|
|
|
**공통 입력:**
|
|
|
|
|
|
- `W0`: 개구부 폭 (mm)
|
|
|
|
|
|
- `H0`: 개구부 높이 (mm)
|
|
|
|
|
|
- `QTY`: 수량
|
|
|
|
|
|
|
|
|
|
|
|
**스크린 제품 추가:**
|
|
|
|
|
|
- `INSTALL_TYPE`: 설치 유형 (wall/ceiling/floor)
|
|
|
|
|
|
- `MOTOR_TYPE`: 모터 유형 (standard/heavy)
|
|
|
|
|
|
- `CONTROL_TYPE`: 제어 방식 (switch/remote/smart)
|
|
|
|
|
|
- `CHAIN_SIDE`: 체인 위치 (left/right)
|
|
|
|
|
|
|
|
|
|
|
|
**철재 제품 추가:**
|
|
|
|
|
|
- `MATERIAL`: 재질 (ss304/ss316/galvanized)
|
|
|
|
|
|
- `THICKNESS`: 두께 (mm)
|
|
|
|
|
|
- `FINISH`: 표면처리 (hairline/mirror/matte)
|
|
|
|
|
|
- `WELDING`: 용접 방식 (tig/mig/spot)
|
|
|
|
|
|
|
|
|
|
|
|
### i18n 키 추가
|
|
|
|
|
|
|
|
|
|
|
|
**에러 메시지 (error.php):**
|
|
|
|
|
|
- `quote_not_found`, `quote_not_editable`, `quote_not_deletable`
|
|
|
|
|
|
- `quote_not_finalizable`, `quote_not_finalized`, `quote_already_converted`
|
|
|
|
|
|
- `quote_not_convertible`, `quote_email_not_found`, `quote_phone_not_found`
|
|
|
|
|
|
- `formula_empty`, `formula_parentheses_mismatch`, `formula_unsupported_function`, `formula_calculation_error`
|
|
|
|
|
|
|
|
|
|
|
|
**성공 메시지 (message.php):**
|
|
|
|
|
|
- `quote.fetched`, `quote.created`, `quote.updated`, `quote.deleted`
|
|
|
|
|
|
- `quote.bulk_deleted`, `quote.finalized`, `quote.finalize_cancelled`
|
|
|
|
|
|
- `quote.converted`, `quote.calculated`, `quote.pdf_generated`
|
|
|
|
|
|
- `quote_email_sent`, `quote_kakao_sent`
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 5개 파일 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (Phase 3)
|
|
|
|
|
|
- [ ] QuoteController.php 생성
|
|
|
|
|
|
- [ ] FormRequest 생성 (QuoteStoreRequest, QuoteUpdateRequest 등)
|
|
|
|
|
|
- [ ] Swagger 문서 작성 (QuoteApi.php)
|
|
|
|
|
|
- [ ] 라우트 등록
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-04 (수) - 거래처 API 2차 필드 추가 및 견적 API 계획 업데이트
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 거래처 API에 2차 필드 추가 (17개 신규 필드)
|
|
|
|
|
|
- 견적 API 변경사항 분석 및 계획 문서 업데이트
|
|
|
|
|
|
|
|
|
|
|
|
### 거래처 API 2차 필드 추가
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 필드 (7개 섹션, 20개 필드):**
|
|
|
|
|
|
|
|
|
|
|
|
| 섹션 | 필드 | 설명 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| 거래처 유형 | `client_type` | 매입/매출/매입매출 |
|
|
|
|
|
|
| 연락처 | `mobile`, `fax` | 모바일, 팩스 |
|
|
|
|
|
|
| 담당자 | `manager_name`, `manager_tel`, `system_manager` | 담당자 정보 |
|
|
|
|
|
|
| 발주처 설정 | `account_id`, `account_password`, `purchase_payment_day`, `sales_payment_day` | 계정 및 결제일 |
|
|
|
|
|
|
| 약정 세금 | `tax_agreement`, `tax_amount`, `tax_start_date`, `tax_end_date` | 세금 약정 정보 |
|
|
|
|
|
|
| 악성채권 | `bad_debt`, `bad_debt_amount`, `bad_debt_receive_date`, `bad_debt_end_date`, `bad_debt_progress` | 채권 정보 |
|
|
|
|
|
|
| 기타 | `memo` | 메모 |
|
|
|
|
|
|
|
|
|
|
|
|
**수정된 파일:**
|
|
|
|
|
|
- `database/migrations/2025_12_04_205603_add_extended_fields_to_clients_table.php` (NEW)
|
|
|
|
|
|
- `app/Models/Orders/Client.php` - fillable, casts, hidden 업데이트
|
|
|
|
|
|
- `app/Http/Requests/Client/ClientStoreRequest.php` - 검증 규칙 추가
|
|
|
|
|
|
- `app/Http/Requests/Client/ClientUpdateRequest.php` - 검증 규칙 추가
|
|
|
|
|
|
- `app/Services/ClientService.php` - store/update 검증 추가
|
|
|
|
|
|
- `app/Swagger/v1/ClientApi.php` - 3개 스키마 업데이트
|
|
|
|
|
|
|
|
|
|
|
|
### 견적 API 계획 업데이트
|
|
|
|
|
|
|
|
|
|
|
|
**신규 요청 - 문서 발송 API (Section 3.5):**
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|
|
|
|
|--------|----------|------|
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/send/email` | 이메일 발송 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/send/fax` | 팩스 발송 |
|
|
|
|
|
|
| POST | `/api/v1/quotes/{id}/send/kakao` | 카카오톡 발송 |
|
|
|
|
|
|
|
|
|
|
|
|
**계획 문서 업데이트 내용:**
|
|
|
|
|
|
- Phase 2: `QuoteDocumentService` 추가
|
|
|
|
|
|
- Phase 3: `QuoteSendEmailRequest`, `QuoteSendFaxRequest`, `QuoteSendKakaoRequest` 추가
|
|
|
|
|
|
- Service 5개, FormRequest 8개로 조정
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
```
|
|
|
|
|
|
commit d164bb4
|
|
|
|
|
|
feat: [client] 거래처 API 2차 필드 추가 및 견적 계획 업데이트
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업
|
|
|
|
|
|
- 견적 API Phase 2: Service Layer 구현
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-12-04 (수) - 견적수식 시드 데이터 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- design/src/components/utils/formulaSampleData.ts의 데이터를 MNG에서 관리할 수 있도록 시드 데이터 구현
|
|
|
|
|
|
- 26개 수식 규칙, 11개 카테고리를 DB에 입력
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**Seeder (2개):**
|
|
|
|
|
|
- `database/seeders/QuoteFormulaCategorySeeder.php`
|
|
|
|
|
|
- 11개 카테고리 시드 (OPEN_SIZE, MAKE_SIZE, AREA, WEIGHT, GUIDE_RAIL, CASE, MOTOR, CONTROLLER, EDGE_WING, INSPECTION, PRICE_FORMULA)
|
|
|
|
|
|
- updateOrInsert 패턴으로 멱등성 보장
|
|
|
|
|
|
|
|
|
|
|
|
- `database/seeders/QuoteFormulaSeeder.php`
|
|
|
|
|
|
- 29개 수식 시드 (input 2개, calculation 18개, range 3개, mapping 1개, 단가수식 8개)
|
|
|
|
|
|
- 8개 범위 데이터 (quote_formula_ranges)
|
|
|
|
|
|
- 카테고리 코드 → ID 매핑으로 FK 참조
|
|
|
|
|
|
|
|
|
|
|
|
### 시드 데이터 상세
|
|
|
|
|
|
|
|
|
|
|
|
| 카테고리 | 코드 | 수식 수 | 설명 |
|
|
|
|
|
|
|----------|------|---------|------|
|
|
|
|
|
|
| 오픈사이즈 | OPEN_SIZE | 2 | W0, H0 입력 |
|
|
|
|
|
|
| 제작사이즈 | MAKE_SIZE | 4 | W1/H1 (스크린/철재) |
|
|
|
|
|
|
| 면적 | AREA | 1 | W1 × H1 / 1000000 |
|
|
|
|
|
|
| 중량 | WEIGHT | 2 | 스크린/철재 중량 계산 |
|
|
|
|
|
|
| 가이드레일 | GUIDE_RAIL | 5 | 길이, 자동선택, 설치유형별 수량 |
|
|
|
|
|
|
| 케이스 | CASE | 3 | 사이즈, 자재 자동선택 |
|
|
|
|
|
|
| 모터 | MOTOR | 1 | 중량 기반 자동선택 |
|
|
|
|
|
|
| 제어기 | CONTROLLER | 1 | 유형별 자동선택 |
|
|
|
|
|
|
| 마구리 | EDGE_WING | 1 | 날개 수량 계산 |
|
|
|
|
|
|
| 검사 | INSPECTION | 1 | 검사비 고정 |
|
|
|
|
|
|
| 단가수식 | PRICE_FORMULA | 8 | 품목별 단가 계산 |
|
|
|
|
|
|
|
|
|
|
|
|
### 실행 명령어
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 순서대로 실행
|
|
|
|
|
|
php artisan db:seed --class=QuoteFormulaCategorySeeder
|
|
|
|
|
|
php artisan db:seed --class=QuoteFormulaSeeder
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- 카테고리: 11개 생성 완료 ✅
|
|
|
|
|
|
- 수식: 29개 생성 완료 ✅
|
|
|
|
|
|
- 범위 데이터: 8개 생성 완료 ✅
|
|
|
|
|
|
|
|
|
|
|
|
### 참조 문서
|
|
|
|
|
|
- `mng/docs/QUOTE_FORMULA_SEED_PLAN.md` - 구현 계획서
|
|
|
|
|
|
- `design/src/components/utils/formulaSampleData.ts` - 소스 데이터
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-02 22:11:25 +09:00
|
|
|
|
## 2025-12-02 (월) - 메뉴 통합관리 시스템 구현 (Phase 1-2)
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 글로벌 메뉴-테넌트 메뉴 연결 시스템 구현
|
|
|
|
|
|
- Phase 1: DB 스키마 변경 및 모델 수정
|
|
|
|
|
|
- Phase 2: 서비스 및 API 엔드포인트 개발
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 1 완료 (DB 스키마 및 모델)
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 파일:**
|
|
|
|
|
|
- `database/migrations/2025_12_02_100000_add_global_menu_link_columns_to_menus_table.php`
|
|
|
|
|
|
- `global_menu_id` 컬럼: 원본 글로벌 메뉴 ID
|
|
|
|
|
|
- `is_customized` 컬럼: 테넌트 커스터마이징 여부
|
|
|
|
|
|
- 인덱스 추가
|
|
|
|
|
|
|
|
|
|
|
|
**수정된 파일:**
|
|
|
|
|
|
- `app/Models/Commons/Menu.php`
|
|
|
|
|
|
- fillable: `global_menu_id`, `is_customized` 추가
|
|
|
|
|
|
- casts: `is_customized => boolean` 등 추가
|
|
|
|
|
|
- 관계 메서드: `globalMenu()`, `tenantMenus()`
|
|
|
|
|
|
- 헬퍼 메서드: `isGlobal()`, `isClonedFromGlobal()`, `isCustomized()`
|
|
|
|
|
|
- 스코프: `scopeGlobal()`, `scopeActive()`, `scopeVisible()`, `scopeRoots()`
|
|
|
|
|
|
- `getSyncFields()`: 동기화 비교 대상 필드 목록
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Services/MenuBootstrapService.php`
|
|
|
|
|
|
- `cloneGlobalMenusForTenant()`: global_menu_id 저장 추가
|
|
|
|
|
|
- 활성 메뉴만 복제 (is_active=true)
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 2 완료 (서비스 및 API)
|
|
|
|
|
|
|
|
|
|
|
|
**추가된 파일:**
|
|
|
|
|
|
- `app/Services/GlobalMenuService.php` (신규)
|
|
|
|
|
|
- 글로벌 메뉴 CRUD (tenant_id = NULL)
|
|
|
|
|
|
- `syncToAllTenants()`: 특정 메뉴를 모든 테넌트에 동기화
|
|
|
|
|
|
- `stats()`: 글로벌 메뉴 통계
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Services/MenuSyncService.php` (신규)
|
|
|
|
|
|
- 동기화 상태 상수: NEW, UP_TO_DATE, UPDATABLE, CUSTOMIZED, DELETED
|
|
|
|
|
|
- `getSyncStatus()`: 동기화 상태 목록 조회
|
|
|
|
|
|
- `syncMenus()`: 선택 동기화 (신규/업데이트)
|
|
|
|
|
|
- `importNewMenus()`: 신규 글로벌 메뉴 일괄 가져오기
|
|
|
|
|
|
- `syncUpdates()`: 변경된 메뉴 일괄 업데이트 (커스텀 제외)
|
|
|
|
|
|
- `getAvailableGlobalMenus()`: 복제 가능한 글로벌 메뉴 목록
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Http/Controllers/Api/Admin/GlobalMenuController.php` (신규)
|
|
|
|
|
|
- 시스템 관리자용 글로벌 메뉴 관리
|
|
|
|
|
|
- index, tree, show, store, update, destroy, reorder
|
|
|
|
|
|
- syncToTenants, stats
|
|
|
|
|
|
|
|
|
|
|
|
**수정된 파일:**
|
|
|
|
|
|
- `app/Services/MenuService.php`
|
|
|
|
|
|
- `update()`: 글로벌 복제 메뉴 수정 시 is_customized=true 자동 설정
|
|
|
|
|
|
- `restore()`: 삭제된 메뉴 복원 추가
|
|
|
|
|
|
- `trashedList()`: 삭제된 메뉴 목록 조회 추가
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/MenuController.php`
|
|
|
|
|
|
- MenuSyncService DI 추가
|
|
|
|
|
|
- restore, trashed, availableGlobal, syncStatus, sync, syncNew, syncUpdates 메서드 추가
|
|
|
|
|
|
|
|
|
|
|
|
- `routes/api.php`
|
|
|
|
|
|
- GlobalMenuController use 문 추가
|
|
|
|
|
|
- 테넌트 메뉴 동기화 라우트 6개 추가 (trashed, available-global, sync-status, sync, sync-new, sync-updates, restore)
|
|
|
|
|
|
- 글로벌 메뉴 관리 라우트 9개 추가 (admin/global-menus/*)
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트
|
|
|
|
|
|
|
|
|
|
|
|
**테넌트 메뉴 동기화 (V1):**
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| GET | /v1/menus/trashed | 삭제된 메뉴 목록 |
|
|
|
|
|
|
| GET | /v1/menus/available-global | 복제 가능한 글로벌 메뉴 |
|
|
|
|
|
|
| GET | /v1/menus/sync-status | 동기화 상태 조회 |
|
|
|
|
|
|
| POST | /v1/menus/sync | 선택 동기화 |
|
|
|
|
|
|
| POST | /v1/menus/sync-new | 신규 메뉴 일괄 가져오기 |
|
|
|
|
|
|
| POST | /v1/menus/sync-updates | 변경된 메뉴 일괄 업데이트 |
|
|
|
|
|
|
| POST | /v1/menus/{id}/restore | 삭제된 메뉴 복원 |
|
|
|
|
|
|
|
|
|
|
|
|
**글로벌 메뉴 관리 (Admin):**
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| GET | /v1/admin/global-menus | 글로벌 메뉴 목록 |
|
|
|
|
|
|
| POST | /v1/admin/global-menus | 글로벌 메뉴 생성 |
|
|
|
|
|
|
| GET | /v1/admin/global-menus/tree | 글로벌 메뉴 트리 |
|
|
|
|
|
|
| GET | /v1/admin/global-menus/stats | 통계 조회 |
|
|
|
|
|
|
| POST | /v1/admin/global-menus/reorder | 순서 변경 |
|
|
|
|
|
|
| GET | /v1/admin/global-menus/{id} | 단건 조회 |
|
|
|
|
|
|
| PUT | /v1/admin/global-menus/{id} | 수정 |
|
|
|
|
|
|
| DELETE | /v1/admin/global-menus/{id} | 삭제 |
|
|
|
|
|
|
| POST | /v1/admin/global-menus/{id}/sync-to-tenants | 모든 테넌트에 동기화 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 모든 파일 통과
|
|
|
|
|
|
- 라우트 등록: ✅ 9개 글로벌 메뉴 + 7개 테넌트 동기화 라우트 확인
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (Phase 3-4)
|
|
|
|
|
|
- [ ] Phase 3: MNG 글로벌 메뉴 관리 화면
|
|
|
|
|
|
- [ ] Phase 3: MNG 동기화 센터 화면
|
|
|
|
|
|
- [ ] Phase 4: 마이그레이션 실행 및 테스트
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-01 16:17:13 +09:00
|
|
|
|
## 2025-12-01 (일) - 메뉴 통합관리 시스템 설계
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- PDF 기획서(SAM_ERP_인사관리전자결재_Storyboard)에서 메뉴 추출
|
|
|
|
|
|
- 글로벌 메뉴와 테넌트 메뉴 간의 연결(링크) 시스템 설계
|
|
|
|
|
|
- 메뉴 추가 SQL 쿼리 생성
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
- `claudedocs/MENU_INTEGRATION_SYSTEM_DESIGN.md` (신규)
|
|
|
|
|
|
- 글로벌-테넌트 메뉴 연결 시스템 설계서
|
|
|
|
|
|
- global_menu_id, is_customized 컬럼 추가 계획
|
|
|
|
|
|
- API 엔드포인트 설계 (글로벌/테넌트 메뉴 관리)
|
|
|
|
|
|
- MNG 화면 설계 (복제, 동기화 기능)
|
|
|
|
|
|
- 구현 Phase 1~4 계획
|
|
|
|
|
|
|
|
|
|
|
|
- `claudedocs/MENU_INSERT_QUERIES.sql` (신규)
|
|
|
|
|
|
- PDF 기획서 기반 신규 메뉴 23개 INSERT 쿼리
|
|
|
|
|
|
- 인사관리 (근태/휴가/급여)
|
|
|
|
|
|
- 전자결재 (기안함/결재함/참조함)
|
|
|
|
|
|
- 게시판, 보고서, 계정정보, 회사정보, 구독관리, 결제내역, 고객센터
|
|
|
|
|
|
- 기준정보 관리 하위 8개 메뉴
|
|
|
|
|
|
|
|
|
|
|
|
### 정책 결정 사항
|
|
|
|
|
|
| 항목 | 결정 내용 |
|
|
|
|
|
|
|------|----------|
|
|
|
|
|
|
| 글로벌 메뉴 삭제 시 | 테넌트 메뉴 유지 (global_menu_id = NULL) |
|
|
|
|
|
|
| 활성 메뉴 (is_active=1) | 새 테넌트 생성 시 자동 복사 |
|
|
|
|
|
|
| 비활성 메뉴 (is_active=0) | 테넌트가 수동으로 복제 가능 |
|
|
|
|
|
|
| 숨김 메뉴 (hidden=1) | 복사되지만 테넌트에서 안 보임 |
|
|
|
|
|
|
| 기존 데이터 | 신규 테넌트부터 적용 |
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (Phase별)
|
|
|
|
|
|
- [ ] Phase 1: 마이그레이션 (global_menu_id, is_customized)
|
|
|
|
|
|
- [ ] Phase 1: Menu 모델 수정
|
|
|
|
|
|
- [ ] Phase 1: MenuBootstrapService 수정
|
|
|
|
|
|
- [ ] Phase 2: GlobalMenuService 생성
|
|
|
|
|
|
- [ ] Phase 2: MenuService 메서드 추가
|
|
|
|
|
|
- [ ] Phase 2: API 엔드포인트 추가
|
|
|
|
|
|
- [ ] Phase 3: MNG 글로벌 메뉴 관리 화면
|
|
|
|
|
|
- [ ] Phase 3: MNG 테넌트 메뉴 관리 화면 개선
|
|
|
|
|
|
- [ ] Phase 4: 테스트
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
```
|
|
|
|
|
|
commit d7fdfa8
|
|
|
|
|
|
docs: 메뉴 통합관리 시스템 설계서 및 SQL 쿼리 추가
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 참고 문서
|
|
|
|
|
|
- PDF: SAM_ERP_인사관리전자결재_Storyboard_D0.6_251201.pdf
|
|
|
|
|
|
- 설계서: claudedocs/MENU_INTEGRATION_SYSTEM_DESIGN.md
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-30 21:06:22 +09:00
|
|
|
|
## 2025-11-27 (수) - 시스템 게시판 기능 확장
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 기존 boards 테이블에 시스템 게시판 지원 추가
|
|
|
|
|
|
- mng에서 시스템 게시판 생성, sam에서 테넌트 게시판 + 시스템 게시판 조회
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**Migration**:
|
|
|
|
|
|
- `database/migrations/2025_11_27_205429_add_system_fields_to_boards_table.php` (NEW)
|
|
|
|
|
|
- `tenant_id` nullable 변경
|
|
|
|
|
|
- `is_system` boolean 컬럼 추가
|
|
|
|
|
|
- `board_type` VARCHAR(50) 컬럼 추가
|
|
|
|
|
|
- `deleted_at`, `deleted_by` SoftDeletes 추가
|
|
|
|
|
|
- 인덱스 추가
|
|
|
|
|
|
|
|
|
|
|
|
**Model**:
|
|
|
|
|
|
- `app/Models/Boards/Board.php`
|
|
|
|
|
|
- SoftDeletes 추가
|
|
|
|
|
|
- fillable, casts 업데이트
|
|
|
|
|
|
- `scopeAccessible(tenantId)`, `scopeSystemOnly()`, `scopeTenantOnly(tenantId)` 스코프 추가
|
|
|
|
|
|
- 권한 헬퍼 메서드 (canRead, canWrite, canManage)
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Models/Boards/BoardSetting.php`
|
|
|
|
|
|
- casts, fillable 업데이트
|
|
|
|
|
|
- getMeta() 헬퍼 추가
|
|
|
|
|
|
|
|
|
|
|
|
**Service**:
|
|
|
|
|
|
- `app/Services/Boards/BoardService.php` (NEW)
|
|
|
|
|
|
- 시스템/테넌트 게시판 CRUD
|
|
|
|
|
|
- 필드 관리 (add, update, delete, reorder)
|
|
|
|
|
|
- 유틸리티 메서드
|
|
|
|
|
|
|
|
|
|
|
|
### DB 스키마 변경
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
-- boards 테이블 추가 컬럼
|
|
|
|
|
|
is_system TINYINT(1) DEFAULT 0 COMMENT '시스템 게시판 여부'
|
|
|
|
|
|
board_type VARCHAR(50) NULL COMMENT '게시판 유형'
|
|
|
|
|
|
deleted_at TIMESTAMP NULL
|
|
|
|
|
|
deleted_by BIGINT UNSIGNED NULL
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업
|
|
|
|
|
|
- mng 게시판 관리 화면 개발 ✅
|
|
|
|
|
|
- sam API 개발 (Swagger 포함) ✅
|
|
|
|
|
|
- 검증 및 테스트 ✅
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-11-27 (수) - sam API 게시판/게시글 API 개발
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 테넌트용 게시판/게시글 V1 API 개발
|
|
|
|
|
|
- Swagger 문서 작성
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**Service**:
|
|
|
|
|
|
- `app/Services/Boards/PostService.php` (NEW)
|
|
|
|
|
|
- 게시글 CRUD (boardCode 기반)
|
|
|
|
|
|
- 댓글 CRUD
|
|
|
|
|
|
- 커스텀 필드 관리
|
|
|
|
|
|
- 조회수 증가
|
|
|
|
|
|
|
|
|
|
|
|
**Controller**:
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/BoardController.php` (NEW)
|
|
|
|
|
|
- index: 접근 가능한 게시판 목록 (시스템 + 테넌트)
|
|
|
|
|
|
- tenantBoards: 테넌트 게시판만
|
|
|
|
|
|
- show: 게시판 상세 (코드 기반)
|
|
|
|
|
|
- store/update/destroy: 테넌트 게시판 CRUD
|
|
|
|
|
|
- fields: 게시판 필드 목록
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/PostController.php` (NEW)
|
|
|
|
|
|
- index/show/store/update/destroy: 게시글 CRUD
|
|
|
|
|
|
- comments/storeComment/updateComment/destroyComment: 댓글 CRUD
|
|
|
|
|
|
|
|
|
|
|
|
**FormRequest**:
|
|
|
|
|
|
- `app/Http/Requests/Boards/BoardStoreRequest.php` (NEW)
|
|
|
|
|
|
- `app/Http/Requests/Boards/BoardUpdateRequest.php` (NEW)
|
|
|
|
|
|
- `app/Http/Requests/Boards/PostStoreRequest.php` (NEW)
|
|
|
|
|
|
- `app/Http/Requests/Boards/PostUpdateRequest.php` (NEW)
|
|
|
|
|
|
- `app/Http/Requests/Boards/CommentStoreRequest.php` (NEW)
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger**:
|
|
|
|
|
|
- `app/Swagger/v1/BoardApi.php` (NEW)
|
|
|
|
|
|
- Board, BoardField 스키마
|
|
|
|
|
|
- BoardCreateRequest, BoardUpdateRequest 스키마
|
|
|
|
|
|
- 7개 엔드포인트 문서화
|
|
|
|
|
|
|
|
|
|
|
|
- `app/Swagger/v1/PostApi.php` (NEW)
|
|
|
|
|
|
- Post, PostPagination, Comment 스키마
|
|
|
|
|
|
- PostCreateRequest, PostUpdateRequest, CommentCreateRequest 스키마
|
|
|
|
|
|
- 9개 엔드포인트 문서화
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `routes/api.php`
|
|
|
|
|
|
- BoardController, PostController import 추가
|
|
|
|
|
|
- /v1/boards 프리픽스로 16개 라우트 등록
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트 (16개)
|
|
|
|
|
|
|
|
|
|
|
|
**게시판 관리**:
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| GET | /v1/boards | 접근 가능한 게시판 목록 |
|
|
|
|
|
|
| GET | /v1/boards/tenant | 테넌트 게시판만 |
|
|
|
|
|
|
| POST | /v1/boards | 테넌트 게시판 생성 |
|
|
|
|
|
|
| GET | /v1/boards/{code} | 게시판 상세 (코드 기반) |
|
|
|
|
|
|
| PUT | /v1/boards/{id} | 테넌트 게시판 수정 |
|
|
|
|
|
|
| DELETE | /v1/boards/{id} | 테넌트 게시판 삭제 |
|
|
|
|
|
|
| GET | /v1/boards/{code}/fields | 게시판 필드 목록 |
|
|
|
|
|
|
|
|
|
|
|
|
**게시글 관리**:
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| GET | /v1/boards/{code}/posts | 게시글 목록 |
|
|
|
|
|
|
| POST | /v1/boards/{code}/posts | 게시글 작성 |
|
|
|
|
|
|
| GET | /v1/boards/{code}/posts/{id} | 게시글 상세 |
|
|
|
|
|
|
| PUT | /v1/boards/{code}/posts/{id} | 게시글 수정 |
|
|
|
|
|
|
| DELETE | /v1/boards/{code}/posts/{id} | 게시글 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
**댓글 관리**:
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| GET | /v1/boards/{code}/posts/{postId}/comments | 댓글 목록 |
|
|
|
|
|
|
| POST | /v1/boards/{code}/posts/{postId}/comments | 댓글 작성 |
|
|
|
|
|
|
| PUT | /v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 수정 |
|
|
|
|
|
|
| DELETE | /v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 완료
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
- 라우트 등록: ✅ 16개 라우트 확인
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-27 10:29:01 +09:00
|
|
|
|
## 2025-11-27 (수) - ItemMaster API group_id(계층번호) 추가 및 Swagger 보완
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- FormRequest에 누락된 `group_id` 필드 추가
|
|
|
|
|
|
- Swagger 스키마에 `group_id` description="계층번호" 추가
|
|
|
|
|
|
- API 문서 정확도 개선
|
|
|
|
|
|
|
|
|
|
|
|
### 배경
|
|
|
|
|
|
- `POST /api/v1/item-master/pages/{pageId}/sections` Swagger 문서 점검 중 `group_id` 누락 발견
|
|
|
|
|
|
- Service에서 `$data['group_id'] ?? 1`로 사용하지만 FormRequest와 Swagger에 미정의
|
|
|
|
|
|
- `group_id`는 "계층번호"로 통일하여 주석 및 description 작성
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일 (4개)
|
|
|
|
|
|
|
|
|
|
|
|
**FormRequest (group_id 필드 추가)**:
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/ItemSectionStoreRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/ItemFieldStoreRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/ItemBomItemStoreRequest.php`
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger**:
|
|
|
|
|
|
- `app/Swagger/v1/ItemMasterApi.php`
|
|
|
|
|
|
|
|
|
|
|
|
### Swagger 스키마 업데이트 상세
|
|
|
|
|
|
|
|
|
|
|
|
**모델 스키마 (3개)** - `description="계층번호"` 추가:
|
|
|
|
|
|
- `ItemSection`
|
|
|
|
|
|
- `ItemField`
|
|
|
|
|
|
- `ItemBomItem`
|
|
|
|
|
|
|
|
|
|
|
|
**Request 스키마 (6개)** - `group_id` 추가 또는 description 추가:
|
|
|
|
|
|
- `ItemSectionStoreRequest` - group_id 신규 추가
|
|
|
|
|
|
- `ItemFieldStoreRequest` - group_id 신규 추가
|
|
|
|
|
|
- `ItemBomItemStoreRequest` - group_id 신규 추가
|
|
|
|
|
|
- `IndependentSectionStoreRequest` - description 추가
|
|
|
|
|
|
- `IndependentFieldStoreRequest` - description 추가
|
|
|
|
|
|
- `IndependentBomItemStoreRequest` - description 추가
|
|
|
|
|
|
|
|
|
|
|
|
### 12개 EntityRelationship 엔드포인트
|
|
|
|
|
|
|
|
|
|
|
|
`EntityRelationshipApi.php`에 이미 문서화 완료 확인:
|
|
|
|
|
|
- POST/DELETE `/pages/{pageId}/link-section`, `/unlink-section/{sectionId}`
|
|
|
|
|
|
- POST/DELETE `/pages/{pageId}/link-field`, `/unlink-field/{fieldId}`
|
|
|
|
|
|
- GET `/pages/{pageId}/relationships`, `/structure`
|
|
|
|
|
|
- POST/DELETE `/sections/{sectionId}/link-field`, `/unlink-field/{fieldId}`
|
|
|
|
|
|
- POST/DELETE `/sections/{sectionId}/link-bom`, `/unlink-bom/{bomId}`
|
|
|
|
|
|
- GET `/sections/{sectionId}/relationships`
|
|
|
|
|
|
- POST `/relationships/reorder`
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 통과
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
|
|
|
|
|
```
|
|
|
|
|
|
commit 4f78eed
|
|
|
|
|
|
feat: ItemMaster API group_id(계층번호) 추가 및 Swagger 보완
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-11-26 (화) - AccessService permission_overrides 테이블 사용으로 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 작업
|
|
|
|
|
|
- API AccessService가 존재하지 않는 테이블(user_permission_overrides, department_permissions)을 참조하던 문제 수정
|
|
|
|
|
|
- 실제 DB의 `permission_overrides` 테이블을 사용하도록 수정
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일:
|
|
|
|
|
|
- `app/Services/Authz/AccessService.php`
|
|
|
|
|
|
- `hasUserOverride()`: `user_permission_overrides` → `permission_overrides` (model_type='App\Models\Members\User')
|
|
|
|
|
|
- `departmentAllows()`: `department_permissions` → `permission_overrides` (model_type='App\Models\Tenants\Department')
|
|
|
|
|
|
- 필드명 변경: `is_allowed` → `effect`, `user_id` → `model_id`
|
|
|
|
|
|
|
|
|
|
|
|
### 기술 상세:
|
|
|
|
|
|
**permission_overrides 테이블 구조:**
|
|
|
|
|
|
- `model_type`: 폴리모픽 타입 (User, Department)
|
|
|
|
|
|
- `model_id`: 대상 ID
|
|
|
|
|
|
- `permission_id`: 권한 ID
|
|
|
|
|
|
- `effect`: 0=DENY, 1=ALLOW
|
|
|
|
|
|
- `effective_from`, `effective_to`: 유효 기간
|
|
|
|
|
|
|
|
|
|
|
|
### 코드 품질:
|
|
|
|
|
|
- ✅ PHP 문법 검사 통과
|
|
|
|
|
|
- ✅ Pint 포맷팅 통과
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-26 14:09:31 +09:00
|
|
|
|
## 2025-11-26 (화) - Item Master 독립 엔티티 API 추가 ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- 독립 엔티티(섹션, 필드, BOM) CRUD API 10개 추가
|
|
|
|
|
|
- `SectionTemplate` 모델 삭제 → `ItemSection.is_template` 플래그로 통합
|
|
|
|
|
|
- Swagger 문서 업데이트
|
|
|
|
|
|
|
|
|
|
|
|
### 변경 내용
|
|
|
|
|
|
|
|
|
|
|
|
**1. SectionTemplate → ItemSection 통합**
|
|
|
|
|
|
- `section_templates` 테이블 삭제
|
|
|
|
|
|
- `item_sections` 테이블에 `is_template` 컬럼 추가
|
|
|
|
|
|
- 기존 `/section-templates` API는 유지 (내부적으로 `is_template=true` 사용)
|
|
|
|
|
|
|
|
|
|
|
|
**2. 10개 독립 API 추가**
|
|
|
|
|
|
|
|
|
|
|
|
| API | 메서드 | 설명 |
|
|
|
|
|
|
|-----|--------|------|
|
|
|
|
|
|
| `/sections` | GET | 섹션 목록 (is_template 필터) |
|
|
|
|
|
|
| `/sections` | POST | 독립 섹션 생성 |
|
|
|
|
|
|
| `/sections/{id}/clone` | POST | 섹션 복제 |
|
|
|
|
|
|
| `/sections/{id}/usage` | GET | 섹션 사용처 조회 |
|
|
|
|
|
|
| `/fields` | GET | 필드 목록 |
|
|
|
|
|
|
| `/fields` | POST | 독립 필드 생성 |
|
|
|
|
|
|
| `/fields/{id}/clone` | POST | 필드 복제 |
|
|
|
|
|
|
| `/fields/{id}/usage` | GET | 필드 사용처 조회 |
|
|
|
|
|
|
| `/bom-items` | GET | BOM 항목 목록 |
|
|
|
|
|
|
| `/bom-items` | POST | 독립 BOM 생성 |
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/IndependentSectionStoreRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/IndependentFieldStoreRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/IndependentBomItemStoreRequest.php`
|
|
|
|
|
|
|
|
|
|
|
|
### 삭제된 파일
|
|
|
|
|
|
- `app/Models/ItemMaster/SectionTemplate.php`
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemSectionController.php`
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemFieldController.php`
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemBomItemController.php`
|
|
|
|
|
|
- `app/Services/ItemMaster/ItemSectionService.php`
|
|
|
|
|
|
- `app/Services/ItemMaster/ItemFieldService.php`
|
|
|
|
|
|
- `app/Services/ItemMaster/ItemBomItemService.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemSection.php` (is_template, scopeTemplates 추가)
|
|
|
|
|
|
- `routes/api.php`
|
|
|
|
|
|
- `app/Swagger/v1/ItemMasterApi.php`
|
|
|
|
|
|
|
|
|
|
|
|
### 마이그레이션
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 실행된 마이그레이션
|
|
|
|
|
|
2025_11_26_120000_add_is_template_to_item_sections_and_drop_section_templates.php
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 통과
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2025-11-26 (화) - Item Master 하이브리드 구조 전환 (독립 엔티티 + 링크 테이블) ✅ 완료
|
|
|
|
|
|
|
|
|
|
|
|
### 작업 목표
|
|
|
|
|
|
기존 CASCADE FK 기반 계층 구조를 **독립 엔티티 + 링크 테이블** 구조로 전환
|
|
|
|
|
|
|
|
|
|
|
|
### 배경
|
|
|
|
|
|
- **문제점**: 현재 구조에서 섹션 삭제 시 항목(필드)도 함께 삭제됨 (CASCADE)
|
|
|
|
|
|
- **요구사항**:
|
|
|
|
|
|
- 페이지, 섹션, 항목은 독립적으로 존재
|
|
|
|
|
|
- 관계는 링크 테이블로 관리 (Many-to-Many)
|
|
|
|
|
|
- 페이지에서 섹션/항목 모두 직접 연결 가능
|
|
|
|
|
|
- 섹션에서 항목 연결 가능
|
|
|
|
|
|
- 엔티티 삭제 시 링크만 제거, 다른 엔티티는 유지
|
|
|
|
|
|
- `group_id`로 카테고리 격리 (품목관리=1, 향후 확장)
|
|
|
|
|
|
|
|
|
|
|
|
### 변경 구조
|
|
|
|
|
|
|
|
|
|
|
|
**Before (CASCADE FK)**:
|
|
|
|
|
|
```
|
|
|
|
|
|
item_pages
|
|
|
|
|
|
↓ page_id FK (CASCADE)
|
|
|
|
|
|
item_sections
|
|
|
|
|
|
↓ section_id FK (CASCADE)
|
|
|
|
|
|
item_fields / item_bom_items
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**After (독립 + 링크)**:
|
|
|
|
|
|
```
|
|
|
|
|
|
item_pages (독립)
|
|
|
|
|
|
item_sections (독립)
|
|
|
|
|
|
item_fields (독립)
|
|
|
|
|
|
item_bom_items (독립)
|
|
|
|
|
|
⇄ entity_relationships (링크 테이블)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Phase 계획
|
|
|
|
|
|
|
|
|
|
|
|
| Phase | 작업 내용 | 상태 |
|
|
|
|
|
|
|-------|----------|------|
|
|
|
|
|
|
| 1 | 마이그레이션: FK 제거 + group_id 추가 | ✅ 완료 |
|
|
|
|
|
|
| 2 | 마이그레이션: entity_relationships 테이블 생성 | ✅ 완료 |
|
|
|
|
|
|
| 3 | 마이그레이션: 기존 데이터 이관 | ✅ 완료 |
|
|
|
|
|
|
| 4 | 모델 및 Service 수정 | ✅ 완료 |
|
|
|
|
|
|
| 5 | 새로운 API 엔드포인트 추가 | ✅ 완료 |
|
|
|
|
|
|
| 6 | Swagger 문서 업데이트 | ✅ 완료 |
|
|
|
|
|
|
| 7 | 테스트 및 검증 | ✅ 완료 |
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**마이그레이션** (Batch 26으로 실행):
|
|
|
|
|
|
- `database/migrations/2025_11_26_100001_convert_item_tables_to_independent_entities.php`
|
|
|
|
|
|
- `database/migrations/2025_11_26_100002_create_entity_relationships_table.php`
|
|
|
|
|
|
- `database/migrations/2025_11_26_100003_migrate_existing_relationships_to_entity_relationships.php`
|
|
|
|
|
|
|
|
|
|
|
|
**모델**:
|
|
|
|
|
|
- `app/Models/ItemMaster/EntityRelationship.php` (신규)
|
|
|
|
|
|
|
|
|
|
|
|
**서비스**:
|
|
|
|
|
|
- `app/Services/ItemMaster/EntityRelationshipService.php` (신규)
|
|
|
|
|
|
|
|
|
|
|
|
**컨트롤러**:
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/EntityRelationshipController.php` (신규)
|
|
|
|
|
|
|
|
|
|
|
|
**Request**:
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/LinkEntityRequest.php` (신규)
|
|
|
|
|
|
- `app/Http/Requests/ItemMaster/ReorderRelationshipsRequest.php` (신규)
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger**:
|
|
|
|
|
|
- `app/Swagger/v1/EntityRelationshipApi.php` (신규)
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**모델 (group_id 추가 + relationship 메서드)**:
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemPage.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemSection.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemField.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemBomItem.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/SectionTemplate.php`
|
|
|
|
|
|
- `app/Models/ItemMaster/ItemMasterField.php`
|
|
|
|
|
|
|
|
|
|
|
|
**라우트**:
|
|
|
|
|
|
- `routes/api.php` (새로운 엔드포인트 추가)
|
|
|
|
|
|
|
|
|
|
|
|
**언어 파일**:
|
|
|
|
|
|
- `lang/ko/message.php` (linked, unlinked 추가)
|
|
|
|
|
|
- `lang/ko/error.php` (page_not_found, section_not_found, field_not_found, bom_not_found 추가)
|
|
|
|
|
|
|
|
|
|
|
|
### 새로운 API 엔드포인트 (14개)
|
|
|
|
|
|
|
|
|
|
|
|
**페이지-섹션 연결**:
|
|
|
|
|
|
- `POST /api/v1/item-master/pages/{pageId}/link-section`
|
|
|
|
|
|
- `DELETE /api/v1/item-master/pages/{pageId}/unlink-section/{sectionId}`
|
|
|
|
|
|
|
|
|
|
|
|
**페이지-필드 직접 연결**:
|
|
|
|
|
|
- `POST /api/v1/item-master/pages/{pageId}/link-field`
|
|
|
|
|
|
- `DELETE /api/v1/item-master/pages/{pageId}/unlink-field/{fieldId}`
|
|
|
|
|
|
|
|
|
|
|
|
**페이지 관계 조회**:
|
|
|
|
|
|
- `GET /api/v1/item-master/pages/{pageId}/relationships`
|
|
|
|
|
|
- `GET /api/v1/item-master/pages/{pageId}/structure`
|
|
|
|
|
|
|
|
|
|
|
|
**섹션-필드 연결**:
|
|
|
|
|
|
- `POST /api/v1/item-master/sections/{sectionId}/link-field`
|
|
|
|
|
|
- `DELETE /api/v1/item-master/sections/{sectionId}/unlink-field/{fieldId}`
|
|
|
|
|
|
|
|
|
|
|
|
**섹션-BOM 연결**:
|
|
|
|
|
|
- `POST /api/v1/item-master/sections/{sectionId}/link-bom`
|
|
|
|
|
|
- `DELETE /api/v1/item-master/sections/{sectionId}/unlink-bom/{bomId}`
|
|
|
|
|
|
|
|
|
|
|
|
**섹션 관계 조회**:
|
|
|
|
|
|
- `GET /api/v1/item-master/sections/{sectionId}/relationships`
|
|
|
|
|
|
|
|
|
|
|
|
**관계 순서 변경**:
|
|
|
|
|
|
- `POST /api/v1/item-master/relationships/reorder`
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 검사: ✅ 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 통과 (9개 신규 파일)
|
|
|
|
|
|
- Swagger 문서 생성: ✅ 완료
|
|
|
|
|
|
- 라우트 등록: ✅ 44개 item-master 라우트 확인
|
|
|
|
|
|
|
|
|
|
|
|
### 롤백 방법
|
|
|
|
|
|
```bash
|
|
|
|
|
|
php artisan migrate:rollback --step=3
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 다음 작업 (옵션)
|
|
|
|
|
|
- 기존 API (POST /pages/{pageId}/sections 등) 내부적으로 entity_relationships 사용하도록 수정
|
|
|
|
|
|
- 독립 엔티티 CRUD API 추가 (POST /sections, POST /fields 등)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-25 09:14:33 +09:00
|
|
|
|
## 2025-11-25 (월) - API 인증 에러 처리 개선 및 요청 로그 강화
|
|
|
|
|
|
|
|
|
|
|
|
### 문제 상황
|
|
|
|
|
|
- GET /item-master/init 요청 시 `Route [login] not defined` 에러 발생
|
|
|
|
|
|
- user_id null (인증 실패 상태)
|
|
|
|
|
|
- API Request 로그에 헤더 정보 누락
|
|
|
|
|
|
|
|
|
|
|
|
### 근본 원인
|
|
|
|
|
|
1. **Handler.php**: `expectsJson()` 체크만 있어서, Accept 헤더 없는 API 요청이 기본 동작(로그인 리다이렉트)으로 처리됨
|
|
|
|
|
|
2. **ApiKeyMiddleware**: 요청 로그에 헤더 정보 (X-API-KEY, Authorization) 미포함
|
|
|
|
|
|
|
|
|
|
|
|
### 해결 방안
|
|
|
|
|
|
|
|
|
|
|
|
**Handler.php (app/Exceptions/Handler.php)**
|
|
|
|
|
|
- Line 60: API 라우트 체크 추가 (`str_starts_with($request->path(), 'api/')`)
|
|
|
|
|
|
- Line 62: `$request->expectsJson() || $isApiRoute` 조건으로 변경
|
|
|
|
|
|
- 효과: Accept 헤더 없어도 API 라우트는 무조건 JSON 응답 반환
|
|
|
|
|
|
|
|
|
|
|
|
**ApiKeyMiddleware (app/Http/Middleware/ApiKeyMiddleware.php)**
|
|
|
|
|
|
- Line 52-57: headers 필드 추가
|
|
|
|
|
|
- X-API-KEY: 마스킹 ('***')
|
|
|
|
|
|
- Authorization: Bearer 토큰 마스킹 ('Bearer ***')
|
|
|
|
|
|
- Accept, Content-Type: 원본 그대로
|
|
|
|
|
|
- 효과: 인증 문제 디버깅 용이
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `app/Exceptions/Handler.php`
|
|
|
|
|
|
- `app/Http/Middleware/ApiKeyMiddleware.php`
|
|
|
|
|
|
|
|
|
|
|
|
### 검증 결과
|
|
|
|
|
|
- PHP 문법 체크: ✅ 통과
|
|
|
|
|
|
- Pint 코드 포맷팅: ✅ 통과
|
|
|
|
|
|
|
|
|
|
|
|
### 기대 효과
|
|
|
|
|
|
1. API 요청 시 Accept 헤더 없어도 정상 JSON 응답
|
|
|
|
|
|
2. 인증 실패 시 로그인 리다이렉트 대신 401 JSON 응답
|
|
|
|
|
|
3. 요청 로그에서 헤더 정보 확인 가능 (디버깅 개선)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
## 2025-11-24 (일) - 소프트삭제 및 타임스탬프 감사 컬럼 추가
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 작업 목표
|
|
|
|
|
|
- deleted_at이 있는 테이블에 deleted_by 컬럼 추가
|
|
|
|
|
|
- created_at, updated_at이 있는 테이블에 created_by, updated_by 컬럼 추가
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
|
|
|
|
|
### 작업 내용
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**1. DB 스키마 분석 (INFORMATION_SCHEMA 쿼리)**
|
|
|
|
|
|
- deleted_at은 있지만 deleted_by가 없는 테이블: 30개
|
|
|
|
|
|
- created_at은 있지만 created_by, updated_by가 없는 테이블: 45개
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**2. 마이그레이션 생성**
|
|
|
|
|
|
- `2025_11_24_192518_add_deleted_by_to_soft_delete_tables.php`
|
|
|
|
|
|
- 30개 테이블에 deleted_by 추가
|
|
|
|
|
|
- nullable, COMMENT('삭제자 사용자 ID')
|
|
|
|
|
|
- after('deleted_at') 배치
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- `2025_11_24_192518_add_audit_columns_to_tables.php`
|
|
|
|
|
|
- 38개 비즈니스 테이블에 created_by, updated_by 추가
|
|
|
|
|
|
- 시스템 테이블 제외 (jobs, job_batches, password_reset_tokens, personal_access_tokens, taggables, tags)
|
|
|
|
|
|
- nullable, COMMENT
|
|
|
|
|
|
- after('updated_at'), after('created_by') 배치
|
2025-11-20 17:16:03 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**3. 마이그레이션 실행 및 검증**
|
|
|
|
|
|
- 실행 시간: deleted_by (429.53ms), audit_columns (1초)
|
|
|
|
|
|
- 샘플 테이블 검증: users, products, models, bom_templates, department_user 모두 정상
|
2025-11-20 17:07:40 +09:00
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- `database/migrations/2025_11_24_192518_add_deleted_by_to_soft_delete_tables.php`
|
|
|
|
|
|
- `database/migrations/2025_11_24_192518_add_audit_columns_to_tables.php`
|
2025-11-20 17:07:40 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 마이그레이션 상태
|
|
|
|
|
|
- Batch 25로 실행 완료
|
|
|
|
|
|
- 롤백 가능 (down 메서드 구현)
|
2025-11-20 17:07:40 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
## 2025-11-24 (일) - CORS Preflight 문제 해결
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 문제 상황
|
|
|
|
|
|
- React 프론트엔드(http://192.0.0.2:3001)에서 API 호출 시 CORS 에러
|
|
|
|
|
|
- 에러: `Request header field x-api-key is not allowed by Access-Control-Allow-Headers in preflight response`
|
|
|
|
|
|
- 서버 로그: OPTIONS 요청만 있고 Response 로그 없음 (401 차단)
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 근본 원인 (root-cause-analyst 스킬 활용)
|
|
|
|
|
|
1. CorsMiddleware에서 `Access-Control-Allow-Headers`에 `X-API-KEY` 누락
|
|
|
|
|
|
2. OPTIONS 요청(Preflight)이 ApiKeyMiddleware에서 401로 차단
|
|
|
|
|
|
3. 브라우저는 커스텀 헤더 사용 시 Preflight 요청을 자동 전송
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 해결 방안
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**CorsMiddleware 수정:**
|
|
|
|
|
|
- OPTIONS 요청을 미들웨어 체인 진입 전에 즉시 200 OK 처리
|
|
|
|
|
|
- `Access-Control-Allow-Headers`에 `X-API-KEY` 추가
|
|
|
|
|
|
- PATCH 메서드 추가, Max-Age 86400초 설정
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**ApiKeyMiddleware 정리:**
|
|
|
|
|
|
- 불필요한 OPTIONS 체크 제거
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
**CORS 설정 업데이트:**
|
|
|
|
|
|
- `config/cors.php`: exposed_headers, max_age 설정
|
2025-11-20 16:55:57 +09:00
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- `app/Http/Middleware/CorsMiddleware.php`
|
|
|
|
|
|
- `app/Http/Middleware/ApiKeyMiddleware.php`
|
|
|
|
|
|
- `config/cors.php`
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
### Git 커밋
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- `2e96660` - CORS preflight 요청 처리 개선 및 X-API-KEY 헤더 허용
|
|
|
|
|
|
- `8e8ab65` - CORS preflight 응답에 x-api-key 헤더 허용 추가
|
2025-11-20 16:48:23 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 다음 작업
|
|
|
|
|
|
- React에서 API 호출 테스트
|
|
|
|
|
|
- 개발 서버 로그 확인 (Request/Response 쌍 기록 여부)
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
## 2025-11-20 (수) - ItemMaster API 테스트 및 버그 수정
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
### 주요 작업
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- ItemMaster API 통합 테스트 작성 (12개 테스트, 82개 assertion)
|
|
|
|
|
|
- 누락된 마이그레이션 실행 (section_templates, tab_columns)
|
|
|
|
|
|
- API Key 미들웨어 수정 (로그인 엔드포인트 API Key 필수화)
|
|
|
|
|
|
- ReorderRequest validation 수정 (범용성 확보)
|
|
|
|
|
|
- 네임스페이스 오류 수정 (5개 Controller)
|
|
|
|
|
|
- Route 순서 수정 (specific route 우선)
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
### 테스트 결과
|
|
|
|
|
|
✅ 12/12 테스트 통과 (100%)
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
## 2025-11-19 (화) - ItemMaster API Swagger 문서 작성
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
### 주요 작업
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- ItemMaster 전체 API (32개 엔드포인트) Swagger 문서화 완료
|
|
|
|
|
|
- OpenAPI 3.0 표준 준수
|
|
|
|
|
|
- Model Schemas 8개, Request Schemas 12개 작성
|
feat: ItemMaster 데이터베이스 구조 구축 (9개 테이블)
- 마이그레이션 9개 생성 (unit_options, section_templates, item_master_fields, item_pages, item_sections, item_fields, item_bom_items, custom_tabs, tab_columns)
- Eloquent 모델 9개 구현 (ItemMaster 네임스페이스)
- ItemMasterSeeder 작성 및 테스트 데이터 생성
주요 특징:
- Multi-tenant 지원 (BelongsToTenant trait)
- Soft Delete 적용 (deleted_at, deleted_by)
- 감사 로그 지원 (created_by, updated_by)
- JSON 필드로 동적 속성 지원 (display_condition, validation_rules, options, properties)
- FK 제약조건 및 Composite Index 설정
- 계층 구조 (ItemPage → ItemSection → ItemField/ItemBomItem)
SAM API Development Rules 준수
2025-11-20 16:36:55 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-11-24 19:30:23 +09:00
|
|
|
|
## 2025-11-18 (월) - Category API 테스트 및 개선
|
2025-11-17 14:08:42 +09:00
|
|
|
|
|
|
|
|
|
|
### 주요 작업
|
2025-11-24 19:30:23 +09:00
|
|
|
|
- Category CRUD 테스트 작성 (9개 테스트, 98개 assertion)
|
|
|
|
|
|
- 계층 구조 및 필드 관리 테스트
|
|
|
|
|
|
- Validation 로직 개선
|
2025-11-17 14:08:42 +09:00
|
|
|
|
|
2025-12-19 16:14:04 +09:00
|
|
|
|
---
|
|
|
|
|
|
## 2025-12-19 (목) - Phase 6.2 팝업관리 API 구현
|
|
|
|
|
|
|
|
|
|
|
|
### 주요 작업
|
|
|
|
|
|
- Phase 6.2 팝업관리 기능 구현 완료
|
|
|
|
|
|
- PROJECT_DEVELOPMENT_POLICY.md 정책 준수 (string 타입, options JSON 가변 컬럼)
|
|
|
|
|
|
|
|
|
|
|
|
### 추가된 파일
|
|
|
|
|
|
|
|
|
|
|
|
**마이그레이션:**
|
|
|
|
|
|
- `database/migrations/2025_12_19_170001_create_popups_table.php`
|
|
|
|
|
|
|
|
|
|
|
|
**모델:**
|
|
|
|
|
|
- `app/Models/Popups/Popup.php`
|
|
|
|
|
|
- BelongsToTenant, SoftDeletes 적용
|
|
|
|
|
|
- target_type: all(전사), department(부서)
|
|
|
|
|
|
- status: active(사용), inactive(사용안함)
|
|
|
|
|
|
- 스코프: active(), status(), targetType(), forUser()
|
|
|
|
|
|
- 관계: department(), creator(), updater()
|
|
|
|
|
|
|
|
|
|
|
|
**서비스:**
|
|
|
|
|
|
- `app/Services/PopupService.php`
|
|
|
|
|
|
- index(): 관리자용 목록 (페이지네이션)
|
|
|
|
|
|
- getActivePopups(): 사용자용 활성 팝업
|
|
|
|
|
|
- show(): 상세 조회
|
|
|
|
|
|
- store(): 등록
|
|
|
|
|
|
- update(): 수정
|
|
|
|
|
|
- destroy(): 삭제 (Soft Delete)
|
|
|
|
|
|
|
|
|
|
|
|
**FormRequest:**
|
|
|
|
|
|
- `app/Http/Requests/V1/Popup/StorePopupRequest.php`
|
|
|
|
|
|
- `app/Http/Requests/V1/Popup/UpdatePopupRequest.php`
|
|
|
|
|
|
|
|
|
|
|
|
**컨트롤러:**
|
|
|
|
|
|
- `app/Http/Controllers/Api/V1/PopupController.php`
|
|
|
|
|
|
|
|
|
|
|
|
**Swagger:**
|
|
|
|
|
|
- `app/Swagger/v1/PopupApi.php`
|
|
|
|
|
|
|
|
|
|
|
|
### 수정된 파일
|
|
|
|
|
|
- `routes/api.php`: Popup 라우트 추가 (6개 엔드포인트)
|
|
|
|
|
|
|
|
|
|
|
|
### API 엔드포인트 (6개)
|
|
|
|
|
|
| Method | Path | Description |
|
|
|
|
|
|
|--------|------|-------------|
|
|
|
|
|
|
| GET | /api/v1/popups | 팝업 목록 (관리자용) |
|
|
|
|
|
|
| POST | /api/v1/popups | 팝업 등록 |
|
|
|
|
|
|
| GET | /api/v1/popups/active | 활성 팝업 (사용자용) |
|
|
|
|
|
|
| GET | /api/v1/popups/{id} | 팝업 상세 |
|
|
|
|
|
|
| PUT | /api/v1/popups/{id} | 팝업 수정 |
|
|
|
|
|
|
| DELETE | /api/v1/popups/{id} | 팝업 삭제 |
|
|
|
|
|
|
|
|
|
|
|
|
### 정책 준수 사항
|
|
|
|
|
|
- ✅ 기존 테이블 확인 후 신규 생성
|
|
|
|
|
|
- ✅ string 타입 사용 (enum 대신)
|
|
|
|
|
|
- ✅ options JSON 가변 컬럼
|
|
|
|
|
|
- ✅ BelongsToTenant, SoftDeletes 적용
|
|
|
|
|
|
- ✅ Service-First 아키텍처
|
|
|
|
|
|
- ✅ FormRequest 검증
|
|
|
|
|
|
|
|
|
|
|
|
---
|