Skip to Content

Hive

한 줄 소개: 인사(HR) backend. 조직도 · 휴가 · 성과 평가 · 급여 · 보상을 한 곳에서 다루고, 사람은 화면으로 AI 에이전트는 MCP 83개 도구로 같은 데이터를 본다. 한국 근로기준법과 개인정보보호법이 요구하는 경계를 애플리케이션 규칙이 아니라 데이터베이스 제약으로 걸어 둔 것이 특징이다.

주소

용도주소
MCP 엔드포인트https://<workspace>.axelabs.ai/hive/mcp
스키마 목록 (공개 규격)https://<workspace>.axelabs.ai/hive/schemas
livenesshttps://<workspace>.axelabs.ai/hive/health
readiness (DB 포함)https://<workspace>.axelabs.ai/hive/health/ready — 본문 function 은 부팅 후 실제 도구 호출 결과(성공·서버 오류 수, 마지막 성공 시각)와 state(idle 아직 호출 없음 · ok · degraded 성공 없이 서버 오류만 5건 이상, 또는 최근 20건이 전부 서버 오류)를 싣는다. 인증·권한 거부와 입력 오류는 세지 않는다. HTTP 상태는 종전대로 DB 준비 여부만 따른다
로그인 경로 점검https://<workspace>.axelabs.ai/hive/health/sso — 플랫폼 로그인의 토큰 교환·서명키 조회를 실제 로그인과 같은 코드로 시험, 막히면 503 (D-ops-120)

<workspace> 는 조직에 배정된 워크스페이스 이름이다.

다루는 도메인

도메인무엇상태
조직조직 트리, 임직원 마스터, 직무·직급, 발령 이력운영 중
휴가정책·신청·결재·잔여·팀 캘린더. 연차는 근로기준법 §60 자동운영 중
성과성과 근거 적재 → 월간 문답 → 분기 평가 → 이의제기 → 설명팩운영 중
급여월 산정, 명세서, 송금 명세, 발송, 퇴사 정산운영 중
보상정책 ↔ 개인 약정 ↔ 실제 이벤트 3단 모델 (스톡옵션 포함)운영 중
KPI / OKR목표 관리미구현

설계에서 고집한 것

조직마다 데이터가 물리적으로 갈린다

법인·조직마다 별도 스키마를 쓴다. 한 조직의 조회가 다른 조직의 데이터에 닿는 경로가 애초에 없다. 조직 간 참조가 필요한 자리(예: 다른 법인을 위해 한 기여)는 교차 조인이 아니라 명시적인 소속·귀속 필드로 표현하고, 권한이 있는 스키마만 골라 합친다.

발령 이력은 두 개의 시간축을 갖는다

“언제부터 유효했나”(업무 시간)와 “언제 그렇게 기록됐나”(기록 시간)를 따로 들고 있다. 그래서 과거 시점의 조직도를 그 시점에 알고 있던 그대로 재현할 수 있고, 소급 발령을 이력 조작 없이 기록할 수 있다.

모든 쓰기는 감사 로그에 남는다

변경 추적은 애플리케이션 코드가 아니라 데이터베이스 트리거가 한다. 거부된 시도도 기록된다 — 누가 무엇에 어떤 동작을 시도해 막혔는지가 보안 모니터링의 1차 자료다.

민감정보는 열별로 암호화된다

주민등록번호·주소·계좌번호는 조직별 키로 암호화해 저장한다. 급여 송금 명세를 뽑는 그 순간에만 평문이 되고, 감사 로그에는 값이 아니라 내용 해시만 남는다. 계좌번호 전체를 보유하는 서비스는 Hive 하나뿐이고, 다른 서비스로 나가는 이벤트에는 매칭용 뒤 4자리만 실린다.

본인 정보는 본인이 넣는다

입사자의 민감정보는 관리자가 대신 입력하지 않고 본인이 나눠서 채운다(개인정보보호법의 정보주체 본인 입력 원칙). 통장 사본·신분증을 올리면 문서에서 읽은 값과 신고한 값을 대조하고, 예금주 이름이 본인과 다르면 거부한다. 원본 문서는 저장하지 않는다.

권한 — 동사 × 자원

권한이 read < write < admin 같은 한 줄짜리 등급이 아니다. 동사(verb) 와 자원(resource) 의 조합이다.

축값
동사read · write · approve · configure · grant · audit (+ 평가 사이클 전용 close · reopen)
자원점으로 구분한 경로 — hive.employee · hive.payroll.period · hive.payroll.* · *
효과allow / deny

판정 규칙: 가장 구체적인 매칭이 이긴다 → 같은 구체성이면 거부가 이긴다 → 매칭이 없으면 거부(default deny). 조회 권한이 있다고 승인 권한이 따라오지 않고, 급여를 계산할 수 있다고 발송까지 할 수 있는 것이 아니다.

권한에는 조건을 붙일 수 있다. 조건은 실행 가능한 표현식이 아니라 닫힌 문법의 선언형 JSON이다 — 허용된 연산자와 허용된 이름공간만 쓸 수 있고, 코드 평가가 없다. 판단에 필요한 값이 없으면 조건은 충족될 수 없다(fail-closed). 본인 명세서만 조회하게 하는 조건은 이렇게 생겼다.

{"eq": [{"var": "actor.email"}, {"var": "resource.employee_email"}]}

기본 역할

조직마다 아래 역할이 시드된다. 필요하면 조직이 직접 조합해 새 역할을 만든다.

역할권한용도
owner모든 자원에 모든 동사전권. 최소 2명 유지 강제 — 마지막 한 명은 해지되지 않는다
member조회 + 본인 정보 수정 + 휴가 신청 + 본인 명세서일반 구성원
hr_manager임직원 CRUD · 조직/직무 설정 · 휴가 승인·정책인사 운영
payroll_operator급여 기간·명세서·송금·발송 · 알림 템플릿급여 운영
auditor전 자원 조회 + 감사 로그감사 — 수정 권한 없음

owner 최소 2명 규칙은 계정 하나가 사라져 조직 전체가 잠기는 것을 막는 안전망이다.

사람이 아닌 행위자

cron·이벤트 리스너 같은 자동화 주체는 사람 역할을 빌리지 않는다. 별도 테이블에 필요한 권한만 명시적으로 부여받고, 명시 부여가 없으면 거부된다.

AI 에이전트 프로필

AI 에이전트도 사람 역할을 빌리지 않는다. ai_agent 는 이름이 붙은 최소권한 묶음 하나 — 프로필 — 만 갖는다. 프로필은 코드에 선언돼 있다. INSERT 한 줄로 조용히 넓힐 수 없는 것이 요점이다. 어느 프로필을 쓰는지는 법인마다 그 법인의 직원 행이 정한다 — 토큰 하나가 여러 법인을 스코프에 담아도 프로필은 법인별로 따로 배정돼야 한다. 누가 어느 프로필로 발급됐는지는 임직원 행의 ai_agent_profile 컬럼에 남는다.

프로필조회쓰기
ai_operator임직원 · 조직 · 직무 · 휴가 · 휴가 정책 · 알림 템플릿 · 성과 근거 · 성과 문답성과 근거 · 성과 문답 둘뿐
ai_cfo임직원 · 조직 · 급여 명세서 · 발송·송금 대장 · 휴가 · 알림 템플릿없음 — 조회 전용

ai_operator 는 조직·휴가·템플릿을 읽어 질문에 답하고 성과 문답 루프만 기록한다. 채용·인사 필드·조직 개편은 인사 담당자의 일이라 임직원 레코드는 읽기 전용이다. ai_cfo 는 급여 결과를 읽어 대사·보고만 한다. 산정·확정·송금 명세·발송이라는 비가역 경로에 에이전트를 들이지 않는 것이 이 프로필의 핵심이라 쓰기가 하나도 없다.

어느 프로필도 approve · close · reopen · configure · grant · audit 를 갖지 않는다. 승인·종료·재개·설정·권한 부여는 사람의 결정이고 감사는 사람의 기록이다. 평가 확정의 인간 게이트가 하는 말을 권한 층이 한 단계 앞에서 똑같이 하는 셈이다.

인가에 쓰이는 프로필은 요청한 법인의 employees.ai_agent_profile 행에서 읽는다 — 토큰의 extra.ai_agent_profile 클레임(extra.actor_kind 옆자리)은 비교·로그용일 뿐이고 어긋나면 행이 이긴다. 토큰 스코프에 그 법인이 없거나, 그 법인에 actor_kind='ai_agent'·status='active' 인 행이 없으면 권한 0줄이다. 프로필이 없거나 이 빌드가 모르는 이름이면 권한이 0줄이다. 역할도, 레거시 등급 폴백도 없다. 행위자 종류 자체도 토큰이 아니라 임직원 원장이 정한다 — 요청한 법인의 직원 행 actor_kind 가 ai_agent 면 토큰이 그 클레임을 담았든 빠뜨렸든 프로필 번들로만 인가되고(레거시 최고 등급이라도 여기서 아무것도 사지 못한다, 판정 출처 ai_agent_profile), 그 행이 더 이상 살아 있지 않으면(비활성이거나 소프트 삭제) 번들을 잃는 데서 그치지 않고 사람 경로로도 내려가지 않은 채 곧장 거부된다(판정 출처 ai_agent_inactive) — 원장은 종류를 상태로 걸러내지 않고 상태와 함께 읽으므로 퇴사한 에이전트도 여전히 에이전트다. 반대로 토큰만 ai_agent 를 주장하는데 원장 행이 그렇지 않거나 아예 없으면 사람 경로로 내려가지 않고 곧장 거부된다(판정 출처 actor_kind_mismatch). 프로필은 인가 때마다 원장에서 새로 읽는다 — 캐시가 없으므로 퇴사·비활성 처리는 다음 호출부터 즉시 반영된다.

행이 사라져도 종류는 남는다 — 각 법인의 직원 표에 걸린 트리거가 에이전트 주체(소문자 이메일)를 shared.agent_subject 에 등록하고, 이름이 바뀌거나 종류가 바뀌거나 행이 지워지면 지우는 대신 툼스톤을 남긴다. 그 레지스트리에 한 번이라도 오른 주체는 요청한 법인에 자기 행이 없으면 사람 경로로 내려가지 않고 곧장 거부된다(판정 출처 ai_agent_unmapped · ai_agent_tombstoned). 레거시 스코프는 신원이 아니라 직원 행 위의 덧칠이다 — 요청한 법인에 활성 직원 행이 있어야만 적용되고(없으면 legacy_requires_ledger_row), 유일한 예외는 아직 직원이 0명인 법인의 최초 채용(경고로 기록되는 부트스트랩 예외)이다. 그 법인의 제 행이 경로를 정한다 — 레지스트리 적중이 살아 있는 지역 행을 뒤집지 못하고 충돌은 경고로만 남지만, 레지스트리가 한 번이라도 에이전트로 본 주체는 그 법인에 사람 행이 있어도 레거시 덧칠을 받지 못한다(legacy_refused_agent_subject) — 발급 시 admin 으로 실린 스코프가 재분류나 동명 고용으로 되살아나지 않게 하려는 것이고, 그 법인이 직접 부여한 롤은 그대로 유효하다. 같은 주체에 대소문자만 다른 행이 둘이면 어느 쪽도 고르지 않고 거부한다(ledger_ambiguous) — 직원 이메일은 법인 안에서 대소문자를 접어 유일해야 하며, 마이그레이션이 충돌을 발견하면 주소를 나열하며 멈춘다.

데이터베이스 제약 두 개가 이 표를 지킨다. 알려진 프로필 이름만 허용하고(ck_employee_ai_agent_profile), 프로필은 actor_kind 가 ai_agent 인 행에만 붙는다(ck_employee_ai_agent_profile_actor_kind). 두 번째 제약은 사람 행에 프로필이 붙어 조용히 에이전트 번들을 얻는 경로를 막는다. 조직 스키마 마이그레이션 0015_entity 가 컬럼과 두 제약을 함께 올린다.

프로필을 배정하고 회수하는 경로는 운영자 CLI 하나뿐이다 — hive set-agent-profile --entity <법인> --email <주소> --profile ai_operator|ai_cfo|none. MCP 도구로는 열지 않는다. 에이전트가 자기 묶음을 넓히는 경로를 만들지 않기 위해서이고, 임직원 생성·수정 도구(employee_create · employee_update)도 이 컬럼을 받지 않는다. 명령은 그 법인에 이미 있는 에이전트 행 하나에만 쓰고 행을 만들지 않는다 — 그 주소의 행이 없거나 에이전트 행이 아니면 EMPLOYEE_NOT_FOUND 로 거부하고 아무것도 바꾸지 않는다. 주소는 대소문자를 접어 찾고, 그렇게 맞는 행이 둘 이상이면(위의 ledger_ambiguous 상태) 역시 아무것도 쓰지 않고 거부한다. 행을 세기 전에 그 법인의 직원 표에 쓰기 잠금을 잡으므로, 세는 것과 쓰는 것 사이에 대소문자만 다른 행이 끼어들 수 없다 — 그 짧은 동안 그 법인의 직원 표 쓰기는 기다리고, 인가를 위한 조회는 막히지 않는다. none 은 회수다 — 그 에이전트는 다시 모든 자원에서 거부된다(판정 출처 ai_agent_profile). 비활성이거나 소프트 삭제된 에이전트 행(status 가 active 가 아니거나 deleted_at 이 찍힌 행 — pending_start 포함)에는 none(회수)만 쓸 수 있고, 다른 프로필은 AI_AGENT_INACTIVE 로 거부하며 아무것도 바꾸지 않는다. 행을 비활성으로 만드는 쓰기(employee_update 의 상태 변경 · 퇴사 처리의 소프트 삭제 · 퇴직정산)는 같은 UPDATE 에서 에이전트 프로필을 지운다(같은 감사 기록). 비활성이던 행이 다시 active 가 되어도 프로필은 돌아오지 않는다 — 그 에이전트는 운영자가 이 명령으로 다시 배정할 때까지 ai_agent_profile 로 거부된다. 이 규칙 이전부터 비활성 행에 남아 있던 프로필도 재활성화 순간 지워진다. 그래서 입사 전(pending_start) 행에는 미리 배정할 수 없고, active 가 된 뒤 배정한다. 소프트 삭제된 행은 임직원 도구로 되살릴 수 없다(deleted_at 은 수정할 수 없는 필드). 출력의 status · deleted 가 어느 쪽 행이었는지 알려 준다. 쓰기는 같은 트랜잭션에 행위자 cli:set-agent-profile 를 걸어 감사 로그에 남고, 프로필은 캐시 없이 읽으므로 다음 호출부터 반영된다. 새 에이전트 행을 만들 때는 같은 변경에서 프로필도 배정한다 — 빠뜨리면 그 주체의 요청은 전부 거부된다. 프로필이 붙은 에이전트 행을 다른 종류로 바꾸려면 먼저 --profile none 으로 회수한다 — 그러지 않으면 위의 두 번째 제약이 그 변경을 거부한다. (hive 다음 ship, 2026-10)

프로필은 자신을 재원할 수 있는 보상 정책 종류(api_budget · compute_subscription)도 함께 지정한다. AI 에이전트는 급여·주식보상 위에 올라가지 않는다는 보상 3단 모델의 규칙을 권한 쪽에서 되풀이한 것이고, 실제로 막히는 지점은 개인 약정 부여(compensation_award_create)다.

아직 actor_kind 를 ai_agent 로 발급하는 경로는 없다. 먼저 잠그고 나중에 여는 순서다. (hive 다음 ship, 2026-09)

원장을 떠난 주소의 토큰

토큰 주체는 이메일이고 이메일은 바뀔 수 있다 — 직원 행의 이메일이 바뀌거나(대소문자만 바뀐 것은 같은 주체라 해당하지 않는다) 행이 삭제·TRUNCATE 되면 그 주소는 그 법인에서 ‘떠난 주소’ 가 되고, 그 주소의 토큰은 발급 시각과 무관하게 거부된다(판정 출처 subject_revoked). 발급된 토큰에는 하나씩 회수할 식별자가 없고 발급은 데이터베이스를 거치지 않아서, 이탈과 발급의 선후를 시각으로 가릴 수 없기 때문이다. 주소가 다른 트랜잭션에서 원장에 다시 들어오면(재사용·재입사) 복귀 이후에 발급된 토큰만 통과한다 — 초 단위라 복귀와 같은 초에 발급된 토큰과 발급 시각이 없는 토큰은 거부된다. 한 트랜잭션 안에서 떠난 주소를 같은 트랜잭션에서 다시 쓰는 인계(이메일 맞바꾸기·되돌리기·삭제 후 재생성)는 트랜잭션째 거부되므로 두 트랜잭션으로 나눈다. 이 기록은 법인 스키마 안에 있어, 한 법인의 원장 변경은 그 법인에서만 옛 토큰을 끈다. 배포 때 조직 스키마 마이그레이션 0018_entity 가 직원 표의 감사 로그로 과거 이탈을 채운다: 지금 원장에 없는 주소는 떠난 주소로 남고, 지금 원장에 있으면서 감사 이력에 이탈이 있거나 두 번 이상 들어온 주소는 마이그레이션 시각에 돌아온 것으로 적힌다 — 그 주소의 보유자는 배포 뒤 토큰을 새로 받아야 한다. 한 번 들어와 그대로인 주소와 감사 이력에 없는 주소(원장 행 없이 역할만 가진 주체 등)는 영향이 없다. 알려진 한계: 복귀 표식은 트리거가 도는 시각에 찍히고, 트리거는 보통 커밋 때 돌지만 SET CONSTRAINTS … IMMEDIATE 로 문장 시각에 앞당길 수 있다. 옛 보유자의 이탈이 커밋된 뒤 주소를 새 사람에게 주는 트랜잭션이 그렇게 표식을 앞당긴 채 오래 열려 있으면, 주소가 비어 보이는 그 사이에 발급된 토큰도 커밋 뒤 새 보유자의 것으로 통과한다. 원장 시각으로는 닫을 수 없고, 토큰에 불변 직원 식별자를 서명해 싣는 작업이 닫는다.

사람 · AI · 계약직을 한 테이블에서

임직원 테이블은 행위자 종류(actor_kind)를 들고 있다. 도메인 규칙은 이 값으로 갈린다.

종류적용되는 것
human휴가, 4대보험, 근로기준법 §60, 급여·주식보상, 민감정보 컬럼
ai_agentAPI 예산 · 컴퓨트 구독, 성과 평가, 감사 통합 (근로법 프레임 미적용)
service_account자동화 주체 — 감사 기록만
contractor_external외부 계약직 — 수수료·프로젝트 피, 민감정보 없음

조직도·감사 로그·접근 제어는 종류와 무관하게 공통이다. AI 에이전트를 인사 시스템에 올리되 인간 노동법 프레임을 그대로 이식하지 않는 것이 여기서의 원칙이다.

연차 — 근로기준법 §60

연차 정책을 만들 때 규칙을 비우면 법정 기준이 적용된다.

rules: first_year_monthly: { grant_per_month: 1, max_first_year: 11 } after_first_year: { base: 15, bonus_every_n_years: 2, max: 25 } expiry: { kind: "1_year_from_grant" } carry_over: { allowed: false, payout_on_expiry: true }

회사별 변형은 같은 구조에 값만 바꾼다 — 코드를 고치지 않는다.

성과 평가 — AI 는 초안까지, 확정은 사람

Hive 는 평가 점수를 스스로 매기지 않는다. 초안은 외부 평가 에이전트가 만들고, Hive 는 그것을 기록하고 검증한다. 이 경계는 규범이 아니라 구조다.

  • 인간 확정 게이트 — 평가가 confirmed 상태가 되려면 확정자(사람)가 채워져 있어야 한다는 제약이 데이터베이스에 걸려 있다. 사람의 확정 없이는 어떤 등급도 보상 단계로 넘어가지 못한다. 자동인 것은 근거 수집·초안 서술·인용·재현성 로그·설명팩 조립까지고, 사람인 것은 개시·확정·종료·이의 재검토다. 그래서 개인정보보호법 제37조의2 가 말하는 “완전히 자동화된 결정” 에 해당하지 않는다.
  • 인용 없는 등급 금지 — 각 차원의 등급은 근거 인용 없이 부여할 수 없고, 인용한 문장이 실제 원문에 있는지 서버가 대조한다(있지도 않은 문장을 인용하는 것을 차단).
  • 근거 동결 — 사이클 시작 시 인용 가능한 근거의 마감선을 못 박는다. 평가 직전에 근거를 몰아 만드는 패턴이 구조적으로 불가능하다.
  • 채점 기준 잠금 — 루브릭은 버전과 지문(해시)으로 잠긴다. 나중에 기준을 바꿔도 과거 평가는 그때의 기준으로 재현된다.
  • 이의제기 — 정정 요구 · 설명 요구 · 자동결정 거부 세 갈래가 모두 경로로 존재한다. review_explanation_pack 은 설명 요구에 답할 자료(인용 원문 · 적용 기준 · 사람의 개입 내역 · 이의 이력 · 재현성 지표)를 한 번에 조립한다.
  • 평가 대상이 AI 인 경우 — 다른 계열 모델로 구성한 교차 심사를 강제한다(모델이 자기 계열을 후하게 보는 편향 방어). 감정·태도·인성 차원은 배제한다.
  • 보상과의 결합은 참조까지 — 확정 등급은 보상 약정에 참조로만 기록된다. 등급에서 금액이 자동으로 튀어나오는 산식은 없다.
  • 처우 규정의 값도 잠근다 — 평가를 처우에 쓰는 기준 가운데 회사가 고르는 값(시행일 · 승진 검토를 여는 신호 · 보상밴드 구조 · AI 심사 계열 · 루브릭 운용 등)은 취업규칙 별첨의 파라미터로 두고, 루브릭처럼 버전과 지문으로 잠근다. 법령이 정하는 사항은 파라미터가 아니라서 잠금이 받지 않는다. 잠근 값은 데이터베이스가 고치지 못하게 막고, 바꾸려면 새 버전을 잠근다. (hive 다음 ship, 2026-10)

보상 — 3단 모델

보상의 종류·시점·산정 방식·통화·세무·성과연동·거버넌스가 제각각이라, 하나의 급여 테이블로는 표현되지 않는다. 그래서 세 층으로 나눈다.

compensation_plans 회사 정책 (예: 2026 기본급 체계, 2025 스톡옵션 플랜) │ 1:N compensation_awards 개인 약정 (누구에게, 얼마를, 언제부터 언제까지) │ 1:N compensation_events 실제 이벤트 (월 지급, 베스팅 tick, 행사, API 과금)
  • 정책이 바뀌어도 이미 부여된 약정은 당시 조건 그대로 얼어 있다.
  • 산정 방식은 고정액 · 수식 · 구간별 · 풀 분배 · 재량 다섯 가지를 조합한다.
  • 베스팅 스케줄(4년 클리프 · 월 단위 · 마일스톤 · 가속)은 스키마 변경 없이 표현된다.
  • 임원 보상은 이사회 결의와의 연결을 요구하도록 걸 수 있다.
  • 급여 확정 이벤트는 회계 서비스(Frame)로 신호가 나가 인건비 분개가 자동으로 만들어진다.

보상 종류는 급여·상여·수당·초과근로·주식보상·퇴직금·복리후생·실비정산·이익배분·리텐션·이전지원 외에 AI 에이전트용 API 예산 · 컴퓨트 구독을 1급으로 포함한다.

스키마 공개 — GET /hive/schemas

Hive 가 생산하는 사실(fact)의 타입 규격을 엔드포인트로 노출한다. 소비하는 쪽이 필드 이름을 추측하지 않게 하기 위한 것이다.

curl -H "Authorization: Bearer $TOKEN" \ https://<workspace>.axelabs.ai/hive/schemas

응답 봉투는 { version, service, schemas, citation_arg_contract } 형태다.

  • schemas — 임직원 · 온보딩 · 조직도 · 직무 · 휴가(잔여/캘린더/신청/정책/사용집계) · 급여(기간/명세서/송금/발송로그/디스패치로그) · 알림 템플릿 · 감사 로그. 버전은 스키마 id 의 @버전 접미사로 구분한다.
  • citation_arg_contract — “이 사실을 다시 조회하려면 어느 도구의 어느 인자에 무엇을 넣어야 하는가” 의 매핑. 인용 필드 이름과 도구 인자 이름이 항상 같지는 않아서(예: 명세서의 기간 식별자, 조직도의 루트 지정), 그 변환을 규격으로 못 박았다. 결과 payload 전용 필드는 인자로 넘기면 안 되는 것으로 따로 표시된다.

이 계약은 라이브 서버의 함수 시그니처에 고정돼 있고, 어긋나면 테스트가 깨진다.

운영자 경보 메일 — POST /hive/ops/operator-alert

Blueprint 의 운영자 경보 워처가 원격 운영자에게 메일을 보낼 때 부르는 엔드포인트다(D-ops-51). 메일은 Hive 의 앱 전용 메일러(Blueprint 와 별개의 Azure 앱, client credentials 방식)로 나간다. 경보가 보고하는 장애가 대개 Blueprint 의 위임 권한(delegated consent) 회수이기 때문에, 같은 권한에 기대는 채널로는 그 장애를 알릴 수 없다.

curl -X POST https://<workspace>.axelabs.ai/hive/ops/operator-alert \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"subject": "⚠ Blueprint operator alert — graphTokenHealth", "body": "..."}'
  • 토큰은 용도 토큰만 받는다. 서명 검증은 MCP 경로와 같은 미들웨어가 하고, 라우트는 그중 이 용도로 발급된 토큰(python -m hive.cli operator-alert-token, 기본 365일)만 통과시킨다. 사람 로그인 토큰이나 MCP 서비스 토큰은 403 이다. 이 토큰에는 법인 권한이 없어서 MCP 도구로는 아무것도 할 수 없다. 폐기하려면 Hive 서비스 토큰 서명 키를 회전한다(모든 Hive 서비스 토큰이 함께 무효가 된다).
  • 수신자는 서버가 정한다. 환경 변수 OPERATOR_ALERT_EMAIL(쉼표 구분, 비우면 기본 운영 수신자)이 정본이고, 본문에 to 를 넣어도 무시한다. 토큰이 새어도 임의 주소로는 보낼 수 없다.
  • 본문은 subject(200자 이하)와 body(2만 자 이하)뿐이다.
  • 상한: 프로세스당 10분에 20통. 넘으면 429 와 Retry-After 를 준다. 이 메일박스는 급여 명세 메일과 같은 것이라 경보 폭주가 발송 한도를 다 쓰면 급여 메일이 막힌다.
  • 응답: 성공 200 {sent, to_count, http_status} · 메일러 실패 502 {error: {code: "MAIL_SEND_FAILED", stage}}. 메일러의 원문 오류는 응답에 싣지 않고 서버 로그에만 남긴다.

MCP 도구 83개

https://<workspace>.axelabs.ai/hive/mcp 를 MCP 커넥터로 등록하면 아래 도구가 그대로 잡힌다. AXE CLI 를 쓰면 axe hive tools / axe hive call <도구> 로 같은 것을 호출한다.

조직 (9)

도구설명
employee_get단일 임직원 조회 (id · 이메일 · 사번)
employee_search이름·이메일·사번 부분일치 + 상태·조직 필터
employee_create신규 등록 + 초기 발령
employee_update필드 수정 (본인 가능 필드와 인사 전용 필드 분리)
org_get_chart조직 트리 — 부분 트리 · 특정 시점 조회
org_get_team조직 + 소속 인원 (하위 조직 포함 옵션)
org_create조직 신설
org_move_employee인사 발령 (소속 변경 + 이력 기록)
org_set_manager조직장 지정·해제

직무 · 온보딩 (5)

도구설명
position_list · position_create직무·직급·직책 조회 / 신설
employee_onboarding_status본인(또는 관리자가 타인)의 미입력 필수 항목
employee_complete_onboarding본인 민감정보 입력 — 일부만 나눠 입력 가능
employee_verify_document통장 사본·신분증 대조 검증. 명의 불일치는 거부

휴가 (9)

도구설명
leave_request신청 — 중복·잔여 자동 검증
leave_approve승인·반려 (다단계 결재)
leave_cancel취소 (신청 철회 / 승인분 취소)
leave_get_balance잔여 (부여·사용·대기·잔여)
leave_get_calendar팀 캘린더 — 겹치는 신청 표시
leave_get_request단일 신청 상세
leave_policy_create · leave_policy_list정책 등록 / 목록
leave_usage_report기간별 사용 집계

급여 · 보상 (20)

도구설명
payroll_compute_period월 급여 산정 — 전 재직자 대상 전체 재실행. 산정 전 프리플라이트(쓰기 전): KR 7-category 세율 — 빠진 category 는 전부 한 번에 TAX_RATE_NOT_FOUND, 작년 행이 올해를 덮고 있으면 금액에 쓰는 6개 category 만 TAX_RATE_STALE 로 차단(local_income_tax 는 소득세의 10% 로 계산돼 차단하지 않고 결과의 stale_rate_rows 에만 표시) · 그 해 간이세액표에 부양가족 1~11 열이 없으면 SIMPLIFIED_TAX_BAND_NOT_FOUND. 세율은 검증된 값으로 넣는다 — hive seed-tax-kr-<year> 는 placeholder 라 운영 DB 금지 (allow_stale_rates=True 는 해당 연도 요율 무변경을 운영자가 확인했을 때만)
payroll_get_my_payslip본인 명세서
payroll_get_payslip · payroll_list_payslips타인 명세서 / 기간별 목록 (목록은 부작용 없는 조회 전용)
payroll_payslip_void확정 전 명세서 무효화
payroll_termination_settlement퇴사 정산 — 미사용 연차 수당 · 보험 정산 · 연말정산 소급
payroll_export_remittance일괄 송금 명세 내보내기
payroll_mark_paid송금 완료 처리 → 회계 자동 분개 신호 발행
payroll_send_payslip · payroll_send_all_payslips명세서 메일 발송 (단건 / 일괄, 미리보기 모드 지원)
payroll_preview_payslip_pdfPDF 미리보기 (발송 없음)
payroll_list_send_log · payroll_list_dispatch_log발송 감사 / 송금 스냅샷 조회
compensation_plan_list · compensation_award_create보상 정책 목록 / 개인 약정 부여
compensation_event_adjustment_create · _list · _update · _delete명세서 사후 정정 라인 (soft-delete). 직원이 이미 받은 명세서의 정정 라인을 수정·삭제하면 커밋 직후 최신 명세서를 [정정] 표지와 PDF 첨부로 직원에게 자동 재발송한다(한 번도 전달되지 않은 명세서는 정정 메일 대신 정상 발송 경로로) — 결과의 correction_delivery 에 발송 여부가 남고, 같은 값으로 다시 부른 수정은 unchanged 로 끝나 메일을 다시 보내지 않는다
payroll_retry_adjustment_corrections정정 명세서 재발송 재시도 — 수정·삭제 직후 자동 발송이 메일·PDF·템플릿 오류로 실패해 남은 건을 오래된 순서로 최대 limit(1~100)건 다시 보낸다. 이미 성공한 정정은 건너뛰고, 그사이 같은 명세서의 정정이 다시 수정·삭제됐으면 옛 건은 보내지 않고 닫는다(superseded — 최신본은 새 건이 보낸다). 전송 도중 끊겨 나갔는지 모르는 건은 자동으로 다시 보내지 않고 따로 보고하며, 발신함을 확인한 사람이 ‘나갔음’(재발송 없이 닫기) 또는 ‘다시 보내기’로 처분한다

알림 템플릿 (7)

notify_template_list · notify_template_get_active · notify_template_create · notify_template_update · notify_template_clone_from_shared · notify_template_preview · notify_template_activate

메일 문안은 공통 기본값과 조직별 재정의로 나뉜다. 활성 템플릿은 수정 불가(불변) 이고, 고치려면 새 초안을 만들어 활성화한다.

성과 근거 (12)

도구설명
performance_source_ingest성과 원문 1건 + 원자 기여 N건을 한 트랜잭션으로 적재. 원문은 불멸 보존, 정정은 새 버전으로
performance_get_contributions임직원·기간별 기여 조회 — 평가 에이전트의 1급 진입점
performance_get_source원문 재조회 (정정 이력 추적 포함)
performance_list_sources어떤 근거가 존재하는지 메타만 스캔
performance_inquiry_create · _list확인 질의 생성 / 목록 — 수신자는 구성원(사번) 또는 비직원 주주·고문({type,name,email}). 비직원에게는 평가·등급과 무관한 참고 기록임을 밝힌 외부 전용 문안으로 나간다
performance_inquiry_send구성원별 1통 메일 발송 (미리보기 모드 · 중복 발송 방지 대장)
performance_inquiry_remindD+3 리마인더 — 회신 없이 목표(3일)를 초과한 발송분을 원 수신자에게 같은 회신 토큰으로 재발송(72시간 정각은 아직 목표 안이라 리포트의 sla_breach 도, 재알림도 켜지지 않고 — 초과한 순간부터 둘이 같이 켜진다). 하루 1통은 발송 전에 행을 원자적으로 클레임해서 보장한다: attributes 에 last_reminded_on·reminder_state=pending 을 조건부 병합(jsonb `
performance_inquiry_record_reply회신을 근거로 환류
performance_inquiry_poll_replies회신 자동 수집 — 발신자가 원 수신자와 일치할 때만 기록
performance_inquiry_cancel구버전·중복 질의 철회 — 사유 필수. 회신이 온 질의는 거부한다(회신은 이미 근거다 — 정정은 원문 대체 경로). 이미 철회된 id 는 원 사유를 지킨 채 보고만 하고, 없는 id 는 오류다. 행에 철회 시각·행위자·사유·직전 상태가 남고 감사 로그에도 같이 남는다. 메일은 나가지 않는다. 문답 자원(hive.performance.inquiry) 쓰기 (hive 다음 ship, 2026-09)
performance_inquiry_list_send_log발송 대장 조회

응답지연은 별도 리포트 도구가 아니라 performance_inquiry_list 에 얹혀 있다 (hive 다음 ship, 2026-09). 응답에 조회 기준시각(as_of)과 집계 블록(sla — 목표 시간 · 대기 건수 · 대기 중 목표 초과 · 최장 대기 시간 · 회신 건수 · 회신 중 목표 초과 · 평균 회신 시간)이 함께 오고, 행마다 경과 시간(age_hours)과 그 기준(age_basis — 회신 완료면 확정 지연, 대기 중이면 진행 지연, 둘 다 아니면 없음) · 목표 시간 · 초과 여부가 붙는다. 미발송(draft) · 철회(cancelled) · 만료(expired)는 지연 개념이 없어 집계에서 빠진다 — 구버전 질의가 sent 로 남아 대기시간을 무한정 부풀리던 왜곡이 performance_inquiry_cancel 로 걷힌다.

리마인더는 발송 대장에 쓰지 않는다. 그 대장은 실제 원 발송의 중복 방지 키라서, 재알림이 거기 섞이면 다음 발송이 “이미 보냈다” 로 오판해 진짜 질의가 안 나간다. 재알림의 멱등은 질의 행 attributes 의 하루 단위 클레임 표식(last_reminded_on · reminder_state · reminder_claimed_at · reminder_claim_token · reminder_count)이 따로 맡고, 철회(performance_inquiry_cancel)도 같은 attributes 를 병합으로만 써서 서로의 키를 지우지 않는다. 클레임을 커밋한 직후 발송 전에 죽은 행은 최대 30분 pending 으로 머문 뒤 회수되지만, 발송을 시작한 뒤(sending)의 행은 회수 대상이 아니라 화해 대상이다. 실제 발송은 그 행들을 잠근 채(SELECT … FOR UPDATE) 한 트랜잭션 안에서 돈다 — 잠금 아래에서 자격을 다시 검증하고, 살아남은 행으로만 본문을 짓고, 보내고, 결과를 같은 트랜잭션에 적는다. 그래서 발송 중에 들어온 회신·철회는 그 잠금 앞에서 기다렸다가 발송이 끝난 뒤 그대로 성립하고, 잠금보다 먼저 커밋된 회신·철회의 질의는 메일에 아예 실리지 않는다(superseded_ids) — 닫힌 질의로 메일이 나가는 창도, 그것을 사후에 적던 고아 발송 기록도 없다. 표식 쓰기만 실패해 트랜잭션이 롤백된 행은 sending 에 남아 재발송되지 않고 화해 대상이 된다. 화해는 사람이 한다: 발신함에서 그 회신 토큰이 든 제목의 메일이 실제로 나갔는지 확인하고, 안 나갔으면 그 행의 reminder_state 를 failed 로 되돌려 다음 호출의 대상으로 만든다(자동 화해 도구는 아직 없다).

평가 사이클 (17)

도구설명
review_rubric_lock · review_rubric_get채점 기준 잠금 / 조회
review_regulation_lock · review_regulation_get처우 규정(취업규칙 별첨) 파라미터 잠금 / 조회 — 버전·지문으로 잠그고, 잠근 값은 데이터베이스가 고정한다. dry_run 으로 검증만 할 수 있다
review_cycle_open사이클 개시
review_cycle_freeze_evidence근거 마감선 동결
review_cycle_list사이클 목록
review_cycle_close · review_cycle_reopen종료 / 재개 (권한이 서로 분리돼 있다)
evaluation_draft외부 평가 에이전트의 초안을 기록 + 검증 (AI 는 여기까지)
evaluation_get상세 + 인용 원문 링크 (피평가자 본인 열람 가능)
evaluation_confirm사람의 확정 — 이 호출 없이는 어떤 등급도 보상으로 가지 않는다
evaluation_supersede재판정 새 버전 (원본은 남는다)
review_appeal_file · review_appeal_resolve · review_appeal_list이의제기 접수 / 재검토 / 목록
review_explanation_pack설명 요구권 대응 자료 자동 조립

권한 · 감사 (4)

role_assign · role_revoke · role_list · audit_log_list

배포 — 조직 스키마가 전부 최신이어야 마이그레이션이 끝난다

배포는 새 버전으로 트래픽을 넘기기 전에, 후보 컨테이너 안에서 hive.cli migrate 를 돌린다. 이 명령은 공용 스키마와 레지스트리(shared.entity)에 등록된 조직 스키마를 최신 리비전으로 올린다. 약점은 “등록된” 이다 — 레지스트리가 비었거나 일부만 남아 있으면, 실제로 존재하는 스키마를 건너뛰고도 성공으로 끝난다. 2026-09-06 에 정확히 그렇게 됐다. 배포는 마이그레이션을 정상적으로 실행했지만 레지스트리가 0행이라 어떤 조직 스키마도 올리지 않았고, 종료 코드는 0 이었다.

그래서 업그레이드가 끝난 뒤 레지스트리가 아니라 실제 스키마를 다시 확인한다. 확인 대상은 두 부류의 합집합이다.

  • 레지스트리가 이름을 대는 스키마
  • 레지스트리와 무관하게, 조직 스키마의 기본 테이블 다섯 개(organizations · positions · employees · organization_memberships · employment_records)를 전부 가진 스키마 (공용 스키마 제외)

각 스키마는 자기 alembic_version 표에 조직 스키마 head 리비전 하나만 찍혀 있어야 한다. 표가 없거나, 비었거나, 이 이미지가 모르는 리비전이거나, 더 오래됐거나 더 새로우면 전부 미달이다. 하나라도 미달이면 migrate 는 ENTITY_SCHEMA_NOT_AT_HEAD 로 실패하고 배포는 거기서 멈춘다 — 후보의 헬스 확인과 트래픽 전환보다 앞이므로, 검사 시점에 존재하는 스키마 중 뒤처진 것이 있으면 새 코드는 트래픽을 받지 못한다. 검사 뒤에 생긴 스키마는 이 검사가 보지 못한다 — 조직 스키마를 새로 만드는 것은 운영자의 hive register-entity 명령뿐이고(요청 처리 경로에는 스키마를 만드는 곳이 없다) 등록과 배포 사이에 잠금은 없으므로, 배포가 도는 동안 옛 이미지로 조직을 등록하면 그 스키마는 옛 리비전으로 남은 채 전환될 수 있다. 조직 등록은 배포 창 밖에서 한다. 오류에는 스키마마다 찍힌 리비전(또는 표 없음), head 리비전, 고치는 법이 함께 나온다.

원인고치는 법
살아 있는 조직이 레지스트리에서 빠졌다레지스트리 행을 복원하거나 hive register-entity 로 다시 등록한 뒤 hive migrate 재실행
등록된 스키마에 alembic_version 이 없다 (프로비저닝 실패)hive migrate 재실행. 테이블을 손으로 만들었다면 먼저 그 테이블이 맞는 리비전으로 alembic stamp
찍힌 리비전을 이 이미지가 모른다이미지가 데이터베이스보다 오래됐다 — 그 리비전을 가진 이미지를 배포
살아 있는 조직이 아닌 스키마 (버려진 것 · 백업 사본 · 다른 애플리케이션의 것)의도적으로 지우거나 hive 데이터베이스 밖으로 옮긴다

검사를 우회하는 선택지는 없다.

판정을 테이블 모양으로 하는 이유: 이 검사보다 오래된 스키마에는 hive 전용 표식이 없고, 새 마이그레이션으로 표식을 달아도 뒤처진 스키마에는 바로 그 마이그레이션이 없다. 리비전 번호로 가리는 것도 안 된다 — 이미지가 더 새 리비전을 모를 수 있고, 흔한 번호는 다른 애플리케이션과 겹칠 수 있다. 그래서 같은 모양을 가진 남의 스키마도 배포를 멈춘다(열린 채로 실패하지 않는다). 거꾸로, 레지스트리에도 없고 기본 테이블 다섯 개 중 하나라도 빠진 스키마는 조직 스키마로 보지 않아 이 검사 밖이다. 조직 스키마의 첫 리비전이 다섯 개를 모두 만들고 이후 리비전은 그중 어느 것도 지우지 않으므로, hive 가 프로비저닝해 어떤 리비전에 있든 조직 스키마는 이 모양을 갖는다 — 빠지는 것은 누가 기본 테이블을 손으로 지운, 이미 망가진 스키마다. 후보 목록은 pg_catalog 에서 읽는다 — information_schema 는 접속 롤이 읽을 수 없는 테이블을 숨겨, 뒤처진 스키마를 못 본 채 통과시킬 수 있다. 리비전은 후보 스키마에서만 읽으므로 다른 애플리케이션의 alembic_version 은 조회하지 않고, 후보의 리비전을 읽지 못하면 통과가 아니라 오류다.

이 검사의 통합 테스트는 실제 Postgres 가 필요하고, 아래 절의 다른 파괴적 테스트와 같은 계약으로만 돈다.

개발 — 데이터베이스를 건드리는 테스트에는 기본값이 없다

Hive 테스트는 대부분 데이터베이스 없이 돈다. 실제로 쓰는 것은 네 갈래뿐이다 — 공용 스키마를 지우고 다시 만드는 권한 테스트, 자기 데이터베이스를 만들었다 지우는 급여 정정 테스트, 특정 월 급여를 지우고 다시 계산하는 골든 테스트, 그리고 전용 데이터베이스에 자기 스키마와 매번 이름이 다른 일회용 롤을 만들었다 지우는 조직 스키마 head 검사 테스트(위 배포 절). 이 넷은 기본 접속 주소를 갖지 않는다. 예전에는 기본값이 있었고 그 값이 하필 라이브 클러스터였다. 환경변수를 깜빡한 것만으로 파괴적 테스트가 운영 데이터를 향했다는 뜻이다.

지금의 계약은 세 줄이다.

  1. HIVE_ALLOW_DB_MUTATING_TESTS=1 — 의도적 옵트인.
  2. 접속 주소를 환경변수로 명시 — 권한·정정 테스트는 HIVE_RBAC_TEST_DB_URL 과 HIVE_TEST_ADMIN_URL, 골든 테스트는 HIVE_DB_*, head 검사 테스트는 전용 주소 변수 하나(이름은 그 테스트 파일이 건너뛸 때 알려 준다).
  3. 그 주소가 라이브 클러스터가 아닐 것.

1·2 가 없으면 무엇을 설정해야 하는지 알려주고 건너뛴다. 데이터베이스가 없는 환경에서도 나머지 스위트는 그대로 초록이다. 3 을 어기면 조용히 넘어가지 않고 import 시점에 LiveClusterRefusedError 로 큰 소리로 실패한다 — 접속은 시도조차 하지 않는다. 파괴적 스위트를 라이브에 겨눈 설정은 “데이터베이스가 없음” 이 아니라 사고이므로, 그 둘의 반응이 같아서는 안 된다.

라이브 판정은 라이브 hive-postgres 가 공개하는 그 포트이거나, 호스트 이름을 실제로 해석해 그 엔드포인트에 닿는 경우다. loopback 별칭으로 우회되지 않는다.

일회용 클러스터를 띄우는 한 줄(볼륨 없는 postgres:16-alpine 을 호스트 loopback 의 임시 포트에 묶고 일회용 자격증명을 주는 docker run)은 tests/db_guard.py 의 docstring 에 붙어 있다 — 이 공개 페이지에는 주소·자격증명 리터럴을 싣지 않는다.

볼륨을 붙이지 않았으므로 docker rm -f 가 데이터까지 가져간다. 골든 테스트만은 빈 클러스터로 되지 않는다 — 실제 급여 데이터를 대조하므로 복원한 사본이 필요하고, 라이브는 이 게이트가 애초에 거부한다.

거부·건너뛰기 문구는 host:port/dbname 만 찍는다. 그 문구가 CI 로그에 그대로 남기 때문에 사용자명과 비밀번호는 어떤 경로로도 출력되지 않는다. (hive 다음 ship, 2026-09)

로그아웃 — 플랫폼 단위 (D-ops-120 ⑤)

hive 웹 화면에서 로그아웃하면 hive 세션만이 아니라 플랫폼 로그인(Blueprint)과 다른 서비스의 세션도 함께 끝난다. hive 는 자기 쿠키를 지운 뒤 플랫폼 로그아웃 페이지로 넘기고, 끝나면 hive 로그인 화면으로 돌아온다 — 그 화면의 로그인 버튼은 계정 선택 창을 띄워 다른 계정으로 바꿔 들어갈 수 있다. 다른 서비스에서 로그아웃한 경우에는 플랫폼이 hive 의 /hive/auth/frontchannel-logout 을 불러 hive 세션을 끝낸다. 이 요청은 플랫폼이 서명한 일회용 로그아웃 토큰(수명 1분, hive 앞으로 발급된 것만)이 있고, 그 토큰의 사용자가 이 브라우저의 hive 세션 사용자와 같고, 플랫폼 페이지가 보낸 요청일 때만 효과가 있다. 그 밖의 요청에는 아무것도 바꾸지 않는 같은 응답을 돌려준다. 이 기능이 들어가기 전에 로그인한 세션은 플랫폼 로그아웃으로 끊기지 않고 최대 24시간 수명이 끝날 때 사라진다. 운영자는 서비스 설정의 롤백 스위치로 종전 동작(hive 세션만 종료)으로 되돌릴 수 있다.

통합 워크스페이스 셸 (준비 중, 기본 꺼짐)

플랫폼 공통 셸(좌측 레일·계정 메뉴·세션 패널·프롬프트)을 hive 웹 화면에 싣는 첫 단계가 들어가 있다. 환경 변수 AXE_SHELL 이 스위치다 — 비밀이 아닌 화면 모양 스위치이고 기본은 0 이다.

값동작
0 (기본 · 미설정 · 빈 값 · 읽을 수 없는 값)종전 hive 화면 그대로. HTML 은 이 기능 이전과 같다.
1로그인한 화면이 공통 셸 골격 위에 선다. 메뉴는 보는 사람의 권한으로 걸러 싣고, 세션 패널과 프롬프트는 플랫폼 위젯이 채운다. 공개 메뉴 색인 https://<workspace>.axelabs.ai/hive/axe-shell.json 이 열린다 — 인증 없이 읽히며 사용자·법인·레코드 데이터는 담지 않는다(메뉴 이름·경로와 필요한 역할만, 5분 공개 캐시·ETag). 계정 메뉴의 로그아웃은 확인 화면을 거쳐 위의 플랫폼 로그아웃으로 이어진다.

값을 못 읽으면 꺼진 것으로 본다 — 스위치 오타가 서비스 기동을 막지 않는다. 되돌릴 때는 줄을 지우거나 0 으로 둔다. (hive 다음 ship, 2026-09)

다른 서비스와의 관계

  • Frame (회계) — 급여가 확정되면 신호가 나가 인건비 분개가 자동으로 만들어진다. 법인 기본 정보의 정본은 Frame 이고 Hive 는 사본만 갖는다. 반대로 인원 명부의 정본은 Hive 다.
  • Blueprint (워크스페이스) — 입·퇴사 결정이 계정 생성·정지로 이어진다. 역방향은 없다 — 워크스페이스에 계정이 생겼다고 임직원으로 자동 등록되지 않는다.
  • AXE CLI — axe hive tools · axe hive call <도구> 로 커넥터 없이 같은 도구를 호출한다.

서비스 사이의 데이터 이동은 명시적인 신호 채널로만 한다. 남의 데이터베이스를 직접 읽는 경로는 없다.