diff --git a/_pipeline/knowledge/incident-history.json b/_pipeline/knowledge/incident-history.json
index 27573814..eed37706 100644
--- a/_pipeline/knowledge/incident-history.json
+++ b/_pipeline/knowledge/incident-history.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "lastUpdated": "2026-03-27T10:23:39.377Z",
+ "lastUpdated": "2026-03-27T13:27:38.390Z",
"incidents": [
{
"type": "out-of-scope-change",
@@ -154,6 +154,168 @@
"action": "rolled-back",
"id": "inc-mn8r77n5-o99a",
"timestamp": "2026-03-27T10:23:39.377Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/java/com/erp/security/JwtAuthenticationFilter.java",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-7yy5",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/AdminMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-rm91",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ApprovalMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-vsx5",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ButtonDataflowMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-1b5w",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ComponentStandardMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-ojib",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/DigitalTwinMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-4ccn",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/DynamicFormMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-k3c3",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/EntityReferenceMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-19of",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ExternalRestApiConnectionMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-bvd6",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/MailSentHistoryMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-xjfu",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/RoleMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-p4y3",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ScreenEmbeddingMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-6fkp",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ScreenGroupMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-zlq8",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/ShippingPlanMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-qg0w",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/TableCategoryValueMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-kjk0",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/TemplateStandardMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-i2bw",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "backend-spring/src/main/resources/mapper/TodoMapper.xml",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-r9wr",
+ "timestamp": "2026-03-27T13:27:38.389Z"
+ },
+ {
+ "type": "out-of-scope-change",
+ "pipelineId": "pipe-20260327131904-jedw",
+ "file": "frontend/components/admin/dashboard/DashboardSaveModal.tsx",
+ "description": "범위 밖 파일 변경 → 자동 롤백",
+ "action": "rolled-back",
+ "id": "inc-mn8xrted-i8kd",
+ "timestamp": "2026-03-27T13:27:38.389Z"
}
]
}
\ No newline at end of file
diff --git a/_pipeline/pipeline-state.json b/_pipeline/pipeline-state.json
index 88c8fcbc..b1c2c841 100644
--- a/_pipeline/pipeline-state.json
+++ b/_pipeline/pipeline-state.json
@@ -158,10 +158,39 @@
"backend-node/src/services/authService.ts"
],
"taskContext": "AuthMapper.xml의 selectUserInfo 쿼리를 Node authService.ts 138~143행과 동일하게 수정.\n\n반드시 포함할 컬럼:\nSELECT sabun, user_id, user_name, user_name_eng, user_name_cn,\n dept_code, dept_name, position_code, position_name,\n email, tel, cell_phone, user_type, user_type_name,\n partner_objid, company_code, locale, photo\nFROM user_info\nWHERE UPPER(user_id) = UPPER(#{userId})\n\n추가 쿼리:",
- "status": "pending",
- "attempts": 0,
+ "status": "success",
+ "attempts": 1,
"maxRetries": 5,
- "logs": []
+ "logs": [
+ {
+ "timestamp": "2026-03-27T13:29:11.170Z",
+ "type": "info",
+ "message": "PM 지시: [task-22] Round 1에서 이미 실행 완료, L1+L2 통과 확인됨\n[task-4] selectUserInfo 쿼리가 Node.js 버전과 동일한 필드를 반환하도록 구현하라. Node.js 기존 코드에서 selectUserInfo가 반환하는 필드 목록을 먼저 확인하고, Spring MyBatis XML에서 동일한 SELECT 컬럼을 매핑하라.\n[task-6] task-5에서 JWT 페이로드가 Node와 동일하게 완료되었다. /api/auth/login API 응답 전체가 Node.js와 동일한 구조(필드명, 값 형식)를 반환하도록 AuthController와 AuthService를 수정하라. Node.js의 login 라우터 응답 구조를 참조하라.\n[task-7] task-2에서 BaseService(sqlSession 주입)가 완료되었다. AdminService, RoleService, DepartmentService, CompanyManagementService, SystemNoticeService, AuditLogService, ApprovalService가 BaseService를 상속하여 sqlSession.selectList/selectOne 등을 직접 사용하도록 변환하라. 기존 Mapper 인터페이스 호출을 sqlSession 호출로 교체하라.\n[task-17] src/main/java/com/erp/mapper/ 디렉토리 내의 모든 Mapper 인터페이스 파일을 삭제하라. 디렉토리 자체도 삭제하라. 단, src/main/resources/mapper/ (XML 파일들)는 유지해야 한다.\n[task-18] 모든 MyBatis XML의 namespace를 소문자 형식으로 변경하라 (예: com.erp.mapper.AdminMapper → admin). 모든 도 새로운 namespace에 맞게 업데이트하라. sqlSession.selectList('admin.getMenuList') 형태로 호출될 수 있도록 namespace를 맞춰라.\n[task-19] 모든 MyBatis XML에서 companyCode 필터 조건에 OR company_code = '*' 를 포함하라. 기존 WHERE company_code = #{companyCode} 패턴을 WHERE (company_code = #{companyCode} OR company_code = '*') 로 변경하라.\n[task-23] GlobalExceptionHandler 또는 에러 응답 구조에 path 필드를 추가하라. Spring의 request URI를 에러 응답 JSON에 포함시켜라. Node.js 에러 응답과 동일한 구조를 유지하라."
+ },
+ {
+ "timestamp": "2026-03-27T13:29:11.174Z",
+ "type": "info",
+ "message": "Agent(backend) 호출 시작 (시도 1)"
+ },
+ {
+ "timestamp": "2026-03-27T13:38:41.304Z",
+ "type": "agent",
+ "message": "Agent 응답 수신 (716자)"
+ },
+ {
+ "timestamp": "2026-03-27T13:38:47.245Z",
+ "type": "test",
+ "message": "L1 통과: cd backend-spring && ./gradlew compileJava 2>&1 | tail -20"
+ },
+ {
+ "timestamp": "2026-03-27T13:38:47.245Z",
+ "type": "test",
+ "message": "L2 통과: cd /Users/gbpark/TEST-VEX/backend-spring && ./gradlew bootJa"
+ }
+ ],
+ "startedAt": "2026-03-27T13:29:11.170Z",
+ "agentOutput": "완료했습니다.\n\n**변경 내용 요약:**\n\n### AuthMapper.xml\n- `namespace=\"com.erp.mapper.AuthMapper\"` → `namespace=\"auth\"` (Duckil 스타일)\n- `selectUserInfo` WHERE절: `WHERE user_id = #{userId}` → `WHERE UPPER(user_id) = UPPER(#{userId})` (Node.js와 동일)\n\n### AuthMapper.java\n- 삭제 — namespace가 `auth`로 바뀌면서 `@Mapper` 인터페이스 바인딩이 끊기기 때문\n\n### AuthService.java\n- `extends BaseService` 추가 → `sqlSession` (SqlSessionTemplate) 상속\n- `private final AuthMapper authMapper` 제거\n- 모든 `authMapper.xxx()` → `sqlSession.xxx(\"auth.xxx\", params)` 패턴으로 교체:\n - `selectOne(\"auth.selectUserInfo\", ...)`, `selectList(\"auth.selectUserAuth\", ...)`, `insert(\"auth.insertLoginLog\", ...)` 등\n- 로그인 시 `selectCompanyName` 쿼리 추가 → JWT에 `companyName` 정확히 포함 (Node.js와 동일)",
+ "completedAt": "2026-03-27T13:38:47.245Z"
},
{
"id": "task-5",
@@ -255,9 +284,26 @@
],
"taskContext": "모든 Service를 BaseService 상속으로 변경하고, Mapper Interface 주입을 제거.\nsqlSession으로 직접 XML 호출하는 Duckil 스타일로 변환.\n\n변경 전:\n@Service\n@RequiredArgsConstructor\npublic class AdminService {\n private final AdminMapper adminMapper;\n public List