Skip to content

근로계약 백엔드 핸드오프

범위와 소유권

근로계약 생성, 검토 요청, 승인·반려는 Human Capital 단독 핵심 흐름이다. 정본 forward migration은 supabase/migrations/20260717160116_workforce_local_decision_ledgers.sql이며 기존 migration은 배포 이력으로 유지한다.

Approval은 후속 선택 adapter다. Human Capital RPC·RLS·trigger는 Approval 테이블·함수·private outbox를 직접 참조하지 않는다.

데이터 모델

public.workforce_employment_contracts

  • 상태는 호환상 draft | approval_pending | approved | rejected | cancelled를 유지한다. approval_pending의 사용자 의미는 인사 검토 중이다.
  • 신규 생성에는 office_id가 필수이며 해당 Office의 human-capital entitlement를 검사한다.
  • 과거 Office-null 초안은 최초 검토 요청에서 Office를 한 번 확정할 수 있다.

public.workforce_employment_contract_revisions

  • 검토 요청 시 계약 조건 snapshot을 보존한다.
  • approval_document_id는 nullable이고 provider FK가 없다.
  • 기존 UUID는 감사용 opaque legacy reference일 뿐 상태 전이 권위가 아니다.

public.workforce_employment_contract_decisions

Human Capital 소유 append-only decision ledger다.

  • (contract_id, contract_revision, event_sequence) 유일
  • sequence 1: review_requested
  • sequence 2: approved | rejected
  • actor, opinion, subject snapshot, request key, occurred time 보존
  • integration_status: not_connected | legacy_linked | pending | linked | failed
  • update/delete는 workforce_local_decision_history_append_only로 거부

기존 revision은 review event로 backfill하고, 기존 terminal 상태는 두 번째 event로 backfill한다. provider 테이블을 조회하지 않는다.

상태와 RPC

text
draft --request_workforce_employment_contract_review--> approval_pending(검토 중)
approval_pending --decide_workforce_employment_contract(approve)--> approved
approval_pending --decide_workforce_employment_contract(reject)--> rejected
  • create_workforce_employment_contract_draft: actor, HR 관리자, Office, human-capital entitlement, 직원·계약조건·멱등키를 검증한다.
  • request_workforce_employment_contract_review: expected_revision을 검증하고 revision snapshot과 review event를 같은 트랜잭션에 저장한다.
  • decide_workforce_employment_contract: pending revision을 잠그고 local terminal event, revision 상태, 계약 상태, 감사를 한 트랜잭션에 저장한다.

private.workforce_local_decision_commands는 subject/command/request key별 입력과 응답을 보존한다. 같은 키의 동일 payload는 기존 응답을 반환하고 다른 payload는 충돌로 거부한다.

권한과 RLS

  • public RPC는 authenticated/service role만 실행한다.
  • 내부 SECURITY DEFINER는 private schema, search_path='', auth.uid() 확인, 정확한 signature grant를 사용한다.
  • 모든 mutation은 private.require_office_product(..., 'human-capital')을 통과한다.
  • authenticated direct insert/update/delete는 없다.
  • 계약 당사자 또는 HR 관리자만 읽으며 RLS에서도 entitlement를 확인한다.
  • decision ledger는 부모 계약 read helper를 재사용한다.

감사 이벤트

  • workforce.employment_contract_created
  • workforce.employment_contract_review_requested
  • workforce.employment_contract_approved
  • workforce.employment_contract_rejected

선택 Approval seam

신규 review event는 integration_status='not_connected'와 opaque adapter metadata만 기록한다. 후속 adapter는 로컬 커밋 뒤 outbox로 전달해야 하며, unavailable/실패가 계약 상태를 롤백해서는 안 된다. 양쪽 product table에는 FK를 추가하지 않는다.

검증

  • JS: employmentContractMigration.spec.js, employmentContractRepo.spec.js, employmentContractUiContract.spec.js
  • SQL rollback: supabase/tests/workforce_local_decision_ledgers_smoke.sql
  • 경계: strict audit에서 신규 human-capital -> approval 참조 0

초안 수정·새 Revision 재검토, 계약 원문·전자서명·교부, optional Approval adapter는 후속 범위다.