5240 ↔ 구글 캘린더 연동 — 기능정의서
버전 0.1 (2026-08-12) · 상태 개발 착수용 초안 전제 이 문서의 규칙은 대부분 google.insapien.co.kr 콘솔에서 이미 화면으로 구현해 확인한 것이다. 글로만 있는 규칙과 화면으로 확인한 규칙을 섞지 않기 위해, 각 항목에 근거를 함께 적는다.
0. 이 연동이 하는 일
5240 근태에 쌓인 휴가·출장·교육 일정을 구글 캘린더로 내보낸다. 단방향이다 — 구글 캘린더의 일정을 5240으로 들여오지 않고, 직원 개인 일정을 읽지도 않는다.
받는 쪽은 회사가 만든 공유 캘린더 하나이고, 직원은 그것을 각자 구독한다.
범위 밖 (명시적으로 제외)
| 제외 대상 | 이유 |
|---|---|
| 근무일정(근무유형) | 기본근무·유일·휴무까지 매일 값이 있어 직원 수 × 365일이 쌓인다. 휴가가 그 속에 묻혀 캘린더가 못 쓰게 된다 — 연동량 과다이지 구현 난도가 아니다 |
교육계획신청(EDUT_PLAN_REQ/PLAN_REQ2) | 수강예정 년월만 있고 날짜가 없다. 확정 일정이 아니라 수요조사다 |
| 구글 → 5240 역방향 | 하지 않는다 |
| 직원 개인 캘린더 직접 쓰기(도메인 전체 위임) | 기능은 설계에 있으나 이번 범위에서 잠근다. Workspace 최고관리자 승인과 보안 검토가 선행 |
근무일정을 되살릴 일이 생기면 UNION 하나를 더하는 일이 아니다. 근무일정조회 화면은 신청 테이블의 합집합이 아니라 일자별 우선순위를 적용한 결과 1건을 보여준다(조직 근무계획과 개인 신청이 겹치면 개인 신청 우선, 변경은 변경일자 이후만 반영). 근거: 근태 매뉴얼 「근무일정조회/근무일정표/근무시간표」.
1. 용어
| 용어 | 뜻 |
|---|---|
| 연동함(tenant) | 고객사 하나. 서비스영역 ID(SERVAREA_ID) 하나에 연동 설정 한 벌이 붙는다 |
| 연동 계정 | 5240에서 자료를 읽어 갈 때 쓰는 직원 계정. 이 계정의 조직조회권한이 곧 동기화 범위 |
| 갈래(branch) | 내보낼 일정의 종류 — 휴가 / 출장 / 교육 |
| 기간 창(window) | 내보낼 기간. 오늘 기준 과거 N개월 ~ 미래 M개월로 매 실행 시 다시 계산 |
| 대조(reconcile) | 기간 창 전체를 다시 읽어 캘린더와 맞추는 것. 없어진 것은 지우고 달라진 것은 고친다 |
2. 기능 목록
| # | 기능 | 주체 | 비고 |
|---|---|---|---|
| F-01 | 연동함 등록·전환 | 5240 운영 | 서비스영역 ID 단위 |
| F-02 | 구글 계정 종류 판별 및 연동 방식 선택 | 고객사 인사담당 | 콘솔 1단계 |
| F-03 | 구글 OAuth 연결(클라이언트 등록·동의) | 고객사 인사담당 | 콘솔 2단계 ① |
| F-04 | 내보낼 범위·갈래·기간·상태 설정 | 고객사 인사담당 | 콘솔 2단계 ② |
| F-05 | 내보내기 미리보기 | 고객사 인사담당 | 콘솔 3단계 |
| F-06 | 직원 안내문·공지문 생성 | 고객사 인사담당 | 콘솔 4단계 |
| F-07 | 5240 일정 조회 API | 5240 제품 | 신규 개발 — api-proposal/ 참조 구현 있음 |
| F-08 | 캘린더 동기화(생성·수정·삭제) | 연동 서버 | 신규 개발 — 미구현 |
| F-09 | 동기화 결과 통지 | 연동 서버 | 실패·중단 시 담당자 메일 |
| F-10 | 준비 상태 점검(무엇이 막고 있나) | 콘솔 | 구현됨 |
F-01~F-06, F-10은 콘솔에 이미 구현되어 동작한다. 신규 개발은 F-07·F-08·F-09다.
3. 대상 데이터
3.1 휴가 — TAAT_LEAV_REQ
이 테이블에는 휴가신청만 있는 것이 아니다. EAPT_RULE 기준 이 테이블을 쓰는 신청서는 셋이다.
| APPL_CD | 신청서 | 캘린더 |
|---|---|---|
| 1022 | 휴가신청 | 내보낸다 |
| 1122 | 조퇴/외출 신청 | 내보낸다 |
| 1123 | 경조휴가신청 | 내보낸다 |
조퇴/외출도 시스템 구조상 휴가다. 무엇을 감출지는 오로지 옵션 1426이 정한다 — 신청서 종류로 거르지 않는다. 따라서 EAPT_REQ 조인이 필요 없고, 테이블을 통째로 읽는다.
3.2 출장 — TAAT_BSTRIP_REQ
단일 테이블. 시작·종료 일시가 모두 있다.
3.3 교육 — EDUT_REQ + EDUT_HST2 (둘)
| 테이블 | 무엇 | 기간을 어디서 얻나 |
|---|---|---|
EDUT_REQ | 개설된 차수에 신청 | 이 테이블에 없다 → EDUT_COURSN(과정·시작일·차수)에서 종료일, EDUT_COURS에서 과정명 |
EDUT_HST2 | 과정명 직접입력(외부 교육) | 자체 보유(STA_YMD/END_YMD) |
교육 과정명은 공통코드가 아니라 자유 문자열이라 CMMF_CODE_ML로 뽑을 수 없다. 갈래마다 TYPE_NM_RAW에 이름을 담아 올리고 NVL(TYPE_NM_RAW, CMMF_CODE_ML(...))로 받는다.
교육에는 최종수정일시 컬럼이 없다.
CHG_DATE가 NULL이므로 증분 비교가 교육에는 듣지 않는다. 대조로만 맞춘다.
4. 업무 규칙
R-01 · 조회 범위는 연동 계정의 조직조회권한이 정한다
AUTT_SRCH_BASE(AUTH_TYPE_CD='111') + ORGF_LINE. 제품 홈 화면과 같은 패턴이다. 화면에서 전사를 골라도 권한 밖 직원은 나가지 않는다. 요청의 orgCd는 그 안에서 더 좁히기만 한다.
이유 — 인터페이스 키가 새더라도 전사 인사정보가 통째로 나가지 않게 하려는 것이다. 키는 "누구로서 조회하는가"까지만 정하고, 무엇이 보이는가는 제품의 권한 설정이 정한다.
R-02 · 조직은 하위조직을 포함하지 않는다
부서를 고르면 그 부서에 직접 속한 직원만 나간다. 하위 부서는 들어가지 않는다. inclOrgYn 같은 파라미터를 두지 않는다 — 받아 두면 언젠가 'Y'가 들어와 범위가 조용히 넓어진다.
⚠ 하위 불포함이라고
ORGF_LINE을 빼면 안 된다. 그 함수는 "요청 조직의 하위"가 아니라 "연동 계정에게 권한이 있는 조직의 하위" 를 계산하는 권한 경계다. 없애면 권한 밖 인사정보가 샌다. 이름이 닮아 혼동하기 쉬운 자리라 못박는다.
R-03 · 캘린더에 실리는 상태는 결재완료(30)가 기본
| 상태 | 캘린더 |
|---|---|
| 10 임시저장 | 나가지 않음 |
| 20 결재중 | 설정에서 「결재중도 포함」을 켠 경우에만. 제목 앞에 [진행중] |
| 30 결재완료 | 나감 |
| 40 반려 | 나가지 않음 |
API의 reqStatusCds 기본값은 30 이다. 기본을 20,30으로 두면 연동이 값을 빠뜨렸을 때 결재도 안 끝난 휴가가 조용히 나간다 — 빠뜨린 쪽이 안전한 값이어야 한다.
R-04 · 취소는 「응답에서 사라짐」으로 나타난다
5240에는 삭제도 변경도 없다. 취소만 있고, 취소 후에는 새로 결재를 받는다. 부분 취소는 없다 — 한 신청건은 통째로 살아 있거나 통째로 없다. 그래서 신청건 하나 = 캘린더 일정 하나가 성립한다.
- 취소는 휴가 테이블이 아니라
EAPT_CANCL_REQ(결재취소 신청서) 에 따로 쌓인다.
→ 취소신청이 결재를 도는 동안 휴가 테이블에는 아무것도 늘지 않는다.
- 취소승인이 나면 원건
REQ_STATUS_CD가 40(반려)으로 바뀐다. → R-03 필터에서 저절로 빠진다. - 취소는 승인된 것만 반영한다. 취소신청이 결재중인 동안 원건은 30이므로 캘린더에 그대로 남는다.
별도 표시를 붙이지 않는다.
근거(데모 데이터 대조, 2026-08-12)
| 취소신청서 | 상태 | 원건 | 원건 상태 |
|---|---|---|---|
| 1578 | 30 승인 | 1572 | 40 |
| 101255 | 30 승인 | 101254 | 40 |
| 101246 | 20 결재중 | 101022 | 30 유지 |
이미 나간 일정의 날짜·종류는 뒤에서 바뀌지 않는다. 유일한 변화는 20 → 30 전이이고, 그때 제목의
[진행중]만 뗀다.
R-05 · 무엇을 감출지는 옵션 1426(HIDE_LEAV_CDS)이 정한다
| 값 | 뜻 | 처리 |
|---|---|---|
CNFG_VAL01 | 미표시 코드 | 응답에 아예 넣지 않는다 — 연동 쪽에서 거를 기회를 주지 않는 편이 안전하다 |
CNFG_VAL02 | 마스킹 코드 | MASK_YN='Y'로 표시해 내보낸다 |
CNFG_VAL03 | 마스킹 표시명 | MASK_NM으로 함께 내보낸다 |
규칙을 연동 쪽에 복사해 두지 않는다 — 복사하면 제품과 기준이 갈린다.
- 표시명도 응답에 실어야 한다. 연동은 API로 옮기고 나면
CFGT_VAL을 직접 읽지 못한다.
MASK_YN만 받고 무엇으로 바꿔 쓸지 모르면 마스킹이 반쪽이 된다.
- 표시명이 비어 있을 때 무엇으로 내보낼지는 정해야 한다(데모 서비스영역은 현재 비어 있음).
- 출장·교육에는 가림 규칙을 두지 않는다.
R-06 · 기간은 겹치면 뽑는다
STA_YMD <= endYmd AND END_YMD >= staYmd. 시작일만 보면 달을 걸친 휴가가 빠진다.
기간 창은 오늘 기준으로 매 실행 시 다시 계산된다(고정 날짜가 아니다). 상한 400일.
R-07 · 조회 실패와 빈 결과를 구분한다
retCode가 0이 아니면 연동은 캘린더를 건드리지 않는다. 빈 배열을 "휴가가 없다"로 읽으면 이미 등록한 일정을 몽땅 지운다.
5. 동기화 규칙 (F-08)
취소·미표시 전환이 모두 "응답에서 사라짐"으로 나타나므로, 동기화는 기간 창 스냅샷 대조다. 훅도 변경분 조회도 필요 없다.
대조 절차
- 기간 창 전체를 API로 읽는다
- 캘린더에서 이 연동이 만든 일정만 골라 온다
- 응답에 있고 캘린더에 없다 → 생성
- 양쪽에 있고 내용이 다르다 → 수정 (사실상 20→30 전이뿐)
- 캘린더에 있고 응답에 없다 → 삭제
안전장치 (필수)
| # | 규칙 | 이유 |
|---|---|---|
| S-01 | 이 연동이 만든 일정만 지운다. 이벤트마다 표식(신청번호·갈래·직원ID)을 남긴다 | 사람이 손으로 넣은 일정을 지우면 안 된다 |
| S-02 | 조회 실패 시 아무것도 지우지 않는다 | R-07 |
| S-03 | 정상 응답 0건·급감도 의심한다. 삭제 예정 건수가 임계를 넘으면 중단하고 담당자에게 알린다 | 권한 축소·조직 개편이면 오류 없이 0건이 온다 → 전 직원 일정 일괄 삭제 사고 |
| S-04 | 기간 창 안만 대조한다 | 창이 하루씩 움직이므로, 창 밖까지 대조하면 멀쩡한 과거 일정을 "응답에 없다"고 지운다 |
| S-05 | 삭제 후 재생성이 아니라 수정한다 | 직원이 걸어 둔 알림 설정이 사라지지 않는다. 단 교육은 CHG_DATE가 없어 증분 비교 불가 |
6. 고객사 설정 항목 (F-02~F-04)
| 항목 | 값 | 비고 |
|---|---|---|
| 계정 종류 | 워크스페이스 / 개인 지메일 | 방식보다 먼저 정한다. 관리 콘솔 유무로 판별 |
| 연동 방식 | 공유 캘린더 / 담당자 확인용 / 도메인 위임(잠금) | 기본은 공유 캘린더 |
| 공유 방법 | 주소를 받아 초대 / 링크 공개 | 개인 지메일 조직에서만. 유출 위험을 고객사가 고른다 |
| 범위 | 본인 / 부서 / 전사 | 하위조직 불포함(R-02) |
| 갈래 | 휴가 / 출장 / 교육 | 근무일정 없음 |
| 기간 창 | 과거 N개월 / 미래 M개월 | 오늘 기준 재계산 |
| 결재중 포함 | 예 / 아니오 | R-03 |
| 캘린더 ID | …@group.calendar.google.com |
계정 종류가 가르는 것
| 워크스페이스 | 개인 지메일 | |
|---|---|---|
| OAuth 동의화면 | 내부 앱 — 게시·검증·테스터 한도·7일 만료 전부 없음 | 외부 앱 강제 — 프로덕션 게시 필요 |
| 캘린더 공유 대상 | 도메인·그룹에 한 번에 | 주소를 받아 초대하거나 링크 공개 |
| 직원↔구글 계정 매핑 | 회사 메일이 곧 구글 계정 | 회사가 모르는 개인 주소 — 직원에게 받아야 함 |
| 도메인 전체 위임 | 가능(잠금 상태) | 불가 |
OAuth 클라이언트는 고객사가 소유한다(2026-08-12 결정). 따라서 워크스페이스 고객사는 동의화면을 「내부」로 두어 게시·검증이 아예 필요 없다.
7. 인터페이스 요약
POST /getTaaCalendarApiList.do — 서버 간 호출. 기존 JSON API 24개와 같은 형식.
- 인증: 옵션
TAA_CAL_INF_YN의 사이트ID·인터페이스 키 + 연동 계정 직원번호 - 갈래는
kindCds로 고른다(LEAV,BSTRIP,EDU) - 호출 기록은
CMMT_MSG_LOG에 남긴다 — "캘린더에 왜 저 일정이 있느냐"를 되짚는 근거
상세와 참조 구현(SQL·컨트롤러·서비스·요청/응답 샘플)은 docs/api-proposal/ 에 있다. 이 폴더는 제품 소스에 반영하지 않았고 실행해 본 적도 없다 — 컴파일·쿼리 실행 모두 미검증이다.
8. 열려 있는 결정
| # | 항목 | 누가 |
|---|---|---|
| O-01 | 마스킹 표시명이 비어 있을 때 캘린더에 무엇으로 내보낼지 | 5240 |
| O-02 | 삭제 임계(S-03)를 몇 %로 둘지 | 5240 |
| O-03 | 동기화 실행 주기와 실패 통지 방법 | 5240 |
| O-04 | 초대 방식에서 직원 지메일 주소를 어디에 보관할지 | 고객사·5240 |
| O-05 | SERVAREA_ID 파라미터화(현재 콘솔 조회는 데모 300 고정) | 5240 |
부록 · 근거 자료
| 자료 | 위치 |
|---|---|
| 준비사항 9항목(결정과 이유) | 콘솔 /prep · app/lib/prep.ts |
| API 참조 구현 | docs/api-proposal/ |
| 콘솔 설계 문서 | docs/superpowers/specs/2026-08-11-google-console-redesign-design.md |
| 초기 검토(일부 무효 — 상단 정정 주석 참조) | docs/2026-08-10-google-calendar-sync-plan.md |
| 제품 리버스 문서 | kiwibox_eGov4.2/spec-docs, spec-db/Table/* |
| 근태 매뉴얼 | tna-docs/ |