이번주 프로젝트 진행하면서 내가 진행한 부분에 대한 정리
직원 계정 관리(관리자)
[직원 목록 조회] (GET) /admin/employees
@승혁 조
Parameter
이 API는 별도의 Body 없이 아래의 쿼리 파라미터들을 조합하여 필터링된 결과를 반환합니다.
- 호출 예시
- GET /admin/employees?page=0&size=10&dept_id=2&status=ACTIVE&keyword=홍길동
key type 위치 설명
| page | integer | query | 페이지 번호 (0부터 시작) |
| size | integer | query | 한 페이지에 표시할 데이터 개수 (기본 10) |
| dept_id | integer | query | 부서 ID 필터링 |
| job_role_id | integer | query | 직무/권한 ID 필터링 (예: 1-상담사, 2-관리자) |
| status | string | query | 계정 상태 필터링 (ACTIVE, INACTIVE) |
| keyword | string | query | 이름 또는 이메일 포함 검색어 |
Request
{
}
Response
{
"content": [
{
"empId": 0,
"loginId": "string",
"name": "string",
"email": "string",
"phone": "string",
"isActive": true,
"deptName": "string",
"roleName": "string",
"joinedAt": "string",
"createdAt": "2026-03-08T17:10:22.495Z"
}
],
"totalElements": 0,
"totalPages": 0,
"page": 0,
"size": 0
}
Error
error number error code 설명
| 403 | Forbidden | 권한없음 |
[직원 상세 조회] (GET) /admin/employees/{id}
담당자 : @승혁 조
Parameter
- 호출 예시
- /api/admin/employees/1
key type 위치 설명
| id | int | path | 직원 고유 ID (empId) |
Request
{
}
Response
{
"empId": 0,
"loginId": "string",
"name": "string",
"email": "string",
"phone": "string",
"birth": "string",
"gender": "string",
"isActive": true,
"createdAt": "2026-03-08T17:17:26.012Z",
"deptId": 0,
"deptName": "string",
"jobRoleId": 0,
"roleName": "string",
"joinedAt": "string"
}
Error
error number error code 설명
| 403 | Forbidden | 권한없음 |
매뉴얼 관리(관리자)
[매뉴얼 신규 작성/교체] (POST) /api/admin/manuals
담당자 : 조승혁


Parameter
- 호출 예시
- /api/admin/manuals
Request
{
"categoryCode": "string",
"title": "string",
"content": "string"
}
Response
{
}
Error
error number error code 설명
| 403 | Forbidden | 관리자 권한이 없는 경우 |
| 404 | CATEGORY_POLICY_NOT_FOUND | 존재하지 않는 카테고리 정책 |
| 404 | MANUAL_NOT_FOUND | 존재하지 않는 매뉴얼 |
| 400 | INVALID_INPUT | 제목/내용이 비어있거나 100자 초과 시 |
[매뉴얼 내용 수정] (PUT) /api/admin/manuals/{manualId}
담당자 : 조승혁


Parameter
- 호출 예시
- /api/admin/manuals/1
key type 위치 설명
| manualId | integer | path | 수정할 매뉴얼의 고유 ID |
Request
{
"title": "string",
"content": "string"
}
Response
{
}
Error
error number error code 설명
| 400 | INVALID_INPUT | 수정할 제목/내용이 비어있는 경우 또는 제목 100자 이상 |
| 404 | MANUAL_NOT_FOUND | 해당 ID의 매뉴얼이 존재하지 않는 경 |
[매뉴얼 이력 및 목록 조회] (GET) /api/admin/manuals/history
담당자 : 조승혁




Parameter
- 호출 예시
- http://localhost:8080/api/admin/manuals/history?categoryCode= //카테고리 코드 1만 조회
- http://localhost:8080/api/admin/manuals/history //메뉴얼 목록 전체 조회
key type 위치 설명
| categoryCode | string | query | (선택) 특정 카테고리만 필터링 |
Request
{
}
Response
[
{
"manualId": 0,
"categoryCode": "string",
"categoryName": "string",
"title": "string",
"content": "string",
"isActive": true,
"empName": "string",
"updatedAt": "2026-03-08T17:43:39.033Z"
}
]
Error
error number error code 설명
| 404 | CATEGORY_POLICY_NOT_FOUND | 입력한 categoryCode가 시스템에 등록되지 않은 코드인 경우 |
[매뉴얼 수동 비활성화] (PATCH) /api/admin/manuals/{manualId}/deactivate
담당자 : 조승혁


Parameter
- 호출 예시
- /api/admin/manuals/1/deactivate
key type 위치 설명
| manualId | integer | path | 활성화할 매뉴얼 ID |
Request
{
}
Response
// 200 OK (Body 없음)
[매뉴얼 수동 활성화] (PATCH) /api/admin/manuals/{manualId}/activate
담당자 : 조승혁


Parameter
- 호출 예시
- /api/admin/manuals/1/activate
key type 위치 설명
| manualId | integer | path | 활성화할 매뉴얼 ID |
Request
{
}
Response
{
// 200 OK (Body 없음)
}
error number error code 설명
| 404 | NOT_FOUND | 없음 |
| 404 | NOT_FOUND | 데이터 없음 |
| 500 | INTERNAL_SERVER_ERROR | 서버 오류 |
그외에 내가 개발한 핵심 기능 및 개발할 기능
[Project] Gemini AI를 활용한 상담 분석 시스템 고도화 기록
LG U+ 프로젝트에서 고객 상담 데이터를 효율적으로 관리하기 위해 Gemini AI를 도입했다. 단순한 텍스트 저장을 넘어 AI가 상담의 맥락을 이해하고, 정해진 비즈니스 로직에 따라 데이터를 추출하며, 관리자의 채점 기준에 맞춰 상담 품질을 평가하는 시스템을 구축한 과정을 정리한다.
1. AI 핵심 데이터 추출 및 상담 요약 (기존 구현)
첫 번째 단계는 방대한 상담 원문에서 비즈니스에 필요한 핵심 지표를 뽑아내고, 이를 한 줄로 요약하는 엔진을 만드는 것이었다.
핵심 기능 및 로직
- 해지 의도 및 방어 데이터 추출: 상담 카테고리가 '해지(CHN)' 관련일 경우, AI가 상담원의 방어 시도 여부, 방어 성공 여부, 구체적인 방어 액션 리스트를 JSON 형태로 정밀하게 추출함.
- 상담 흐름 요약: 상담의 전체 흐름을 상황 → 조치 → 결과 형태의 화살표(→) 구문으로 연결하여 단 한 문장으로 요약함. 상담원이 나중에 기록을 확인할 때 가독성을 극대화함.
- 기술 스택: * Model: Gemini 2.5 Flash Lite (비용 효율 및 속도 최적화)
- Interface: Spring RestClient를 활용한 비동기 API 통신 및 @Retryable을 이용한 장애 복구 로직.
배치(Batch) 처리 전략
- 상태 관리: result_event_status 테이블을 두어 REQUESTED → PROCESSING → COMPLETED/FAILED의 생명 주기를 관리함.
- 트랜잭션 분리: Propagation.REQUIRES_NEW를 사용하여 개별 상담 분석 실패가 전체 배치 작업에 영향을 주지 않도록 설계함.
- 안정성: AI 응답의 불확실성을 고려하여 cleanJsonString 로직을 통해 정형화된 JSON 데이터만 파싱하도록 구현함.
2. AI 활용 우수 상담 자동 채점 및 선정 (신규 개발)
두 번째 단계는 관리자가 설정한 매뉴얼(채점 기준)을 바탕으로 AI가 상담 품질을 직접 평가하고 우수 사례 후보를 선별하는 시스템이다.
핵심 설계 및 프로세스
- 동적 매뉴얼 주입 (Dynamic Prompting): DB에 저장된 '활성화된 매뉴얼' 내용을 AI 프롬프트에 실시간으로 주입함. 관리자가 관리자 페이지에서 매뉴얼을 수정하면 배치가 돌아갈 때 즉시 새로운 기준이 적용됨.
- 정밀 채점 로직: 단순히 점수만 매기는 것이 아니라, 매뉴얼 준수 여부에 따른 구체적인 채점 근거(evaluation_reason)를 함께 생성함.
- 우수 사례 후보 분류: AI 점수가 90점 이상일 경우 is_candidate 플래그를 true로 설정하여 관리자가 수만 건의 상담 중 검토해야 할 대상을 좁혀줌.
3단 테이블 구조 (DB Architecture)
데이터 정합성과 확장성을 위해 기능을 분리하여 설계함.
- 이벤트 테이블 (excellent_event_status): AI 채점 작업의 스케줄링 및 상태(성공/실패/재시도)를 관리.
- 결과 테이블 (consultation_evaluations): AI가 산출한 실제 점수와 사유를 저장. 상담 결과서(consult_id)와 직결하여 데이터 추적성 확보.
- 스냅샷 테이블 (weekly_excellent_cases): 관리자가 최종 선정한 우수 사례를 연도/주차별로 저장. 관리자의 선정 사유(admin_reason)를 포함하여 명예의 전당 형태로 운영.