5240구글 캘린더 연동
관리
← 개발기획문서초안↓ 내려받기

휴가·출장·교육 조회 API — 별도 구현(2026-08-11, 근무일정 제외·교육 추가 2026-08-12)

이 폴더의 것은 제품 소스에 반영하지 않았고, 개발서버에도 올리지 않았다. ~/5240lab/kiwibox_eGov4.2 아래는 한 줄도 건드리지 않았다. 무엇을 만들면 되는지 보이기 위한 산출물이다.

왜 새로 만드는가

제품의 JSON API(SYS/API/json) 컨트롤러 URL 24개를 전수 확인했다. 근태 쪽은 근태기 적재와 PC-OFF 처리뿐이고, 조회 계열은 조직·직원·SSO·발령·결재다. 휴가·출장·교육을 기간으로 뽑는 엔드포인트는 없다.

가장 가까운 결재 3종(getApprovalData / getApprovalApplData / getApprovalReqData)도 못 쓴다. SQL을 직접 읽고 확인한 이유다.

안에 있다. 파싱해서 쓸 물건이 아니다.

만든 것

파일무엇
TaaCalendarApi_SQL.xml신규 매퍼 SQL 3개 — 권한 확인, 일정 조회(휴가·출장·교육), 호출 기록
TaaCalendarController.javaPOST /getTaaCalendarApiList.do
TaaCalendarServiceImpl.java입력 확인 → 키 확인 → 조회 → 기록
TaaCalendarMapper.java매퍼 인터페이스
sample-request.json / sample-response.json요청·응답 형태
option-TAA_CAL_INF_YN.md가정한 신규 옵션의 정의

엔드포인트는 하나로 묶었다. 갈래를 따로 두면 호출도 그만큼, 키 확인도 그만큼이고 기간·조직 조건을 여러 곳에 똑같이 유지해야 한다. kindCds로 고르게 했다.

판단한 것들

조회 범위는 연동 계정의 조직조회권한이 정한다. AUTT_SRCH_BASE(AUTH_TYPE_CD='111') + ORGF_LINE — 제품 홈 화면(Home_SQL.xml L744-L761)이 쓰는 바로 그 패턴을 옮겼다. 요청의 orgCd는 그 안에서 더 좁히기만 한다. 키가 새더라도 전사 인사정보가 통째로 나가지 않게 하려는 것이다.

조직은 하위조직을 포함하지 않는다. ← 구현 전에 반드시 읽을 것 부서를 고르면 그 부서에 직접 속한 직원만 나간다. 하위 부서 직원은 나가지 않는다. 그래서 inclOrgYn 파라미터를 아예 없앴다 — 받아 두면 언젠가 'Y'가 들어와 조용히 범위가 넓어진다. 조직 필터는 K.ORG_CD = orgCd 한 줄이다.

그렇다고 ORGF_LINE을 빼면 안 된다. orgScope의 ORGF_LINE/ORG_LINE LIKE는 "요청 조직의 하위"가 아니라 "연동 계정에게 권한이 있는 조직의 하위"를 계산하는 자리다. 이건 권한 경계라, 없애면 권한 밖 조직의 인사정보가 새어 나간다. 하위조직 불포함과는 다른 이야기다. 아래 성능 항목도 이 때문에 그대로 남아 있다.

근무일정은 연동하지 않는다.(2026-08-12 결정) 매일 값이 있어(기본근무·유일·휴무 포함) 직원 수 × 365일이 그대로 캘린더에 쌓인다. 휴가가 그 속에 묻혀 캘린더가 못 쓰게 된다 — 연동량 과다가 이유이지 구현 난도가 아니다. WKTYPE 분기를 SQL·서비스·샘플요청에서 모두 뺐다.

되살릴 일이 생기면 UNION 하나를 더하는 일이 아니다. 근무일정조회 화면은 신청 테이블의 합집합이 아니라 일자별로 우선순위를 적용해 해결한 결과 1건을 보여준다 — 조직 근무계획과 개인 신청이 겹치면 개인 신청이 우선하고, 변경은 변경일자 이후만 반영된다(근태 매뉴얼 「근무일정조회/근무일정표/근무시간표」). 신청 테이블을 그대로 합치면 화면에는 1건인 날이 캘린더에는 2건으로 뜬다. 그 우선순위 규칙을 SQL에 재구현하면 제품과 갈린다 — 옵션 1426을 연동 쪽에 복사하지 않기로 한 것과 같은 이유다.

교육은 신청 마스터가 둘이다 — 계획은 뺐다.(2026-08-12) 「무엇을 실을지부터 정해야 한다」로 남아 있던 항목이다. 리버스 문서(spec-db/Table/*)로 확인해 다음과 같이 정했다.

테이블무엇캘린더왜
EDUT_REQ개설된 차수에 신청싣는다기간이 이 테이블에 없다 — EDUT_COURSN(과정·시작일·차수)에서 종료일을, EDUT_COURS에서 과정명을 가져온다
EDUT_HST2과정명을 직접 적어 신청(외부 교육)싣는다STA_YMD·END_YMD가 자체에 있어 그대로 쓴다
EDUT_PLAN_REQ / PLAN_REQ2교육계획신청(수요조사)뺀다수강예정 년월(EDU_YM)만 있고 날짜가 없다. 확정 일정이 아니라 수요조사다

데모 서비스영역 건수: EDUT_REQ 2, EDUT_HST2 10, EDUT_PLAN_REQ 3, EDUT_COURSN 149.

교육 과정명은 공통코드가 아니라 자유 문자열이라 CMMF_CODE_ML로 못 뽑는다. 그래서 갈래마다 TYPE_NM_RAW에 이름을 담아 올리고, 바깥에서 NVL(TYPE_NM_RAW, CMMF_CODE_ML(...))로 받는다 — 휴가·출장은 지금까지처럼 공통코드를 쓰고 교육만 자기 이름을 쓴다.

EDUT_REQ·EDUT_HST2에는 최종수정일시 컬럼이 없다. CHG_DATE를 NULL로 내보내므로 증분 비교가 교육에는 듣지 않는다. 대조로만 맞춰야 한다.

취소는 "응답에서 사라짐"으로 나타난다. 5240에는 삭제도 변경도 없다. 취소만 있고, 취소한 뒤에는 새로 결재를 받는다 — 원래 건을 끝내고 새 신청건이 생기는 구조다. 취소에는 휴가취소 결재 프로세스가 따로 있어서, 취소승인이 나야 결재완료됐던 원래 건이 원복된다. 그리고 캘린더에 실리는 것은 결재완료(30)가 기본이고, 결재중(20)은 콘솔에서 「결재중도 포함」을 켰을 때만 더해진다. 임시저장(10)·반려(40)는 어느 경우에도 나가지 않고, 원복된 건도 이 필터에서 빠진다.

이 구조가 연동을 단순하게 만든다.

바뀌는 일이 없다 — 고치려면 취소하고 새로 신청하므로, 그것은 다른 신청번호의 새 일정이다.

캘린더와 대조하고, 없어진 것을 지운다. 사라지는 시점은 취소를 낸 때가 아니라 취소승인이 난 때다 — 그 사이에는 원래 일정이 캘린더에 남아 있다.

그 건이 응답에서 빠지기 때문이다. 따로 찾아 지우는 코드가 필요 없다.

확인 완료(2026-08-12, 데이터 대조). ⑴ 취소는 EAPT_CANCL_REQ(결재취소 신청서)에 따로 쌓인다 — 휴가 테이블에는 취소신청이 늘지 않으므로 "취소했더니 일정이 하나 더" 문제는 없다. ⑵ 취소승인이 나면 원건 REQ_STATUS_CD가 40(반려) 으로 바뀐다(취소신청서 1578→원건 1572, 101255→101254 모두 40). 상태 필터만으로 빠지므로 SQL에 조건을 더할 필요가 없다. 취소신청이 결재중인 건의 원건은 30 그대로였다(101246→101022) — 취소는 승인된 것만 반영한다는 규칙과 맞다.

이 테이블에는 휴가신청만 있는 것이 아니다. EAPT_RULE 기준 TAAT_LEAV_REQ를 쓰는 신청서는 셋이다 — 휴가신청(1022)·조퇴/외출(1122)·경조휴가(1123). 셋 다 내보낸다(2026-08-12 결정). 조퇴/외출도 시스템 구조상 휴가이고, 무엇을 감출지는 오로지 옵션 1426이 정한다. 그래서 신청서 종류로 거르는 조건도, EAPT_REQ 조인도 두지 않는다 — 통째로 읽는 지금 구조가 맞다.

대조할 때의 규칙은 준비사항 change 항목에 적었다. 가장 중요한 것 — 정상 응답으로 0건이 올 수 있다. 연동 계정의 조직조회권한이 좁아지거나 조직이 개편되면 오류 없이 빈 결과가 온다. 그대로 대조하면 전 직원 일정이 한꺼번에 지워진다. 삭제 쪽에 안전장치가 필요하다.

옵션 1426(HIDE_LEAV_CDS)은 API에서 적용한다. 미표시 코드(CNFG_VAL01)는 응답에 아예 넣지 않고, 마스킹 코드(CNFG_VAL02)는 MASK_YN='Y'로 표시해 내보낸다. 연동 쪽에 규칙을 복사해 두면 제품과 기준이 갈린다.

마스킹 표시명(CNFG_VAL03)도 응답에 싣는다(MASK_NM). 연동은 API로 옮기고 나면 CFGT_VAL을 직접 읽지 못한다. MASK_YN='Y'만 받고 무엇으로 바꿔 쓸지 모르면 마스킹이 반쪽이 된다 — 지금 콘솔은 DB를 직접 읽어 이 값을 얻고 있어서 드러나지 않던 구멍이다. 값이 비어 있을 때 무엇으로 내보낼지는 연동이 정해야 한다(데모 서비스영역은 지금 비어 있다).

기간은 겹치면 뽑는다. STA_YMD <= endYmd AND END_YMD >= staYmd. 지금 콘솔의 데모 조회는 STA_YMD만 봐서 달을 걸친 휴가가 빠진다. 이 API에서는 고쳤다.

상태 기본값은 30(결재완료)뿐이다. 결재중(20)은 연동이 콘솔 설정(「결재중도 포함」)에 따라 reqStatusCds에 더해 보낼 때만 나간다 — 기본값을 20,30으로 두면 연동이 값을 빠뜨렸을 때 결재도 안 끝난 휴가가 조용히 캘린더로 나간다. 임시저장(10)·반려(40)는 어느 경우에도 안 된다.

조회 실패와 빈 결과를 구분한다. retCode가 0이 아니면 연동 쪽은 캘린더를 건드리지 않아야 한다. 빈 배열을 "휴가가 없다"로 읽으면 이미 등록한 일정을 몽땅 지운다.

기간 상한 400일. 넓힐수록 응답이 커지고 느려진다.

확인하지 못한 것

검증하려면 kiwibox 빌드 환경과 WAS가 필요하다.

CMMF_CODE_ML로 이름을 뽑게 해 두었으므로 코드표가 있으면 그대로 나온다.

이 다음

이 상태로는 제품에 넣을 수 없다. 넣으려면 브랜치·릴리스·WAS 재기동, 그리고 고객사 설치본 반영 시점이 정해져야 한다. 그 전에 SQL 실행 계획과 ORGF_LINE 호출 비용을 실데이터에서 재 보는 것이 먼저다 — 조직 범위 계산이 행마다 함수를 부르는 구조라 직원 수가 많으면 여기서 느려진다. 하위조직을 안 쓰기로 했다고 이 비용이 사라지지 않는다. ORGF_LINE은 권한 범위를 계산하는 쪽에 남아 있고, 줄어든 것은 요청 조직 쪽 LIKE 하나뿐이다.