# SAM API 작업 현황 ## 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 (월) - 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 (일) - 소프트삭제 및 타임스탬프 감사 컬럼 추가 ### 작업 목표 - deleted_at이 있는 테이블에 deleted_by 컬럼 추가 - created_at, updated_at이 있는 테이블에 created_by, updated_by 컬럼 추가 ### 작업 내용 **1. DB 스키마 분석 (INFORMATION_SCHEMA 쿼리)** - deleted_at은 있지만 deleted_by가 없는 테이블: 30개 - created_at은 있지만 created_by, updated_by가 없는 테이블: 45개 **2. 마이그레이션 생성** - `2025_11_24_192518_add_deleted_by_to_soft_delete_tables.php` - 30개 테이블에 deleted_by 추가 - nullable, COMMENT('삭제자 사용자 ID') - after('deleted_at') 배치 - `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') 배치 **3. 마이그레이션 실행 및 검증** - 실행 시간: deleted_by (429.53ms), audit_columns (1초) - 샘플 테이블 검증: users, products, models, bom_templates, department_user 모두 정상 ### 추가된 파일 - `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` ### 마이그레이션 상태 - Batch 25로 실행 완료 - 롤백 가능 (down 메서드 구현) --- ## 2025-11-24 (일) - CORS Preflight 문제 해결 ### 문제 상황 - 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 차단) ### 근본 원인 (root-cause-analyst 스킬 활용) 1. CorsMiddleware에서 `Access-Control-Allow-Headers`에 `X-API-KEY` 누락 2. OPTIONS 요청(Preflight)이 ApiKeyMiddleware에서 401로 차단 3. 브라우저는 커스텀 헤더 사용 시 Preflight 요청을 자동 전송 ### 해결 방안 **CorsMiddleware 수정:** - OPTIONS 요청을 미들웨어 체인 진입 전에 즉시 200 OK 처리 - `Access-Control-Allow-Headers`에 `X-API-KEY` 추가 - PATCH 메서드 추가, Max-Age 86400초 설정 **ApiKeyMiddleware 정리:** - 불필요한 OPTIONS 체크 제거 **CORS 설정 업데이트:** - `config/cors.php`: exposed_headers, max_age 설정 ### 수정된 파일 - `app/Http/Middleware/CorsMiddleware.php` - `app/Http/Middleware/ApiKeyMiddleware.php` - `config/cors.php` ### Git 커밋 - `2e96660` - CORS preflight 요청 처리 개선 및 X-API-KEY 헤더 허용 - `8e8ab65` - CORS preflight 응답에 x-api-key 헤더 허용 추가 ### 다음 작업 - React에서 API 호출 테스트 - 개발 서버 로그 확인 (Request/Response 쌍 기록 여부) --- ## 2025-11-20 (수) - ItemMaster API 테스트 및 버그 수정 ### 주요 작업 - ItemMaster API 통합 테스트 작성 (12개 테스트, 82개 assertion) - 누락된 마이그레이션 실행 (section_templates, tab_columns) - API Key 미들웨어 수정 (로그인 엔드포인트 API Key 필수화) - ReorderRequest validation 수정 (범용성 확보) - 네임스페이스 오류 수정 (5개 Controller) - Route 순서 수정 (specific route 우선) ### 테스트 결과 ✅ 12/12 테스트 통과 (100%) --- ## 2025-11-19 (화) - ItemMaster API Swagger 문서 작성 ### 주요 작업 - ItemMaster 전체 API (32개 엔드포인트) Swagger 문서화 완료 - OpenAPI 3.0 표준 준수 - Model Schemas 8개, Request Schemas 12개 작성 --- ## 2025-11-18 (월) - Category API 테스트 및 개선 ### 주요 작업 - Category CRUD 테스트 작성 (9개 테스트, 98개 assertion) - 계층 구조 및 필드 관리 테스트 - Validation 로직 개선 ---