
기간: 2026.04.06 - 2026.04.12
커리큘럼: 최종 프로젝트 (HR 인사시스템 SaaS 플랫폼) - 목표·성과 관리 도메인 설계 및 구현
< 목표·성과 관리 모듈 도메인 설계 및 핵심 로직 구현 >
kpi_template → goal → goal_approval_bundle 흐름을 실제 Spring Boot 엔티티와 서비스로 구현했다.KpiTemplate에 KPI 정의 목록(kpis_json)을 JSON 배열로 저장하고, 이를 Java 값 객체 KpiDefinition과 KpiDefinitionListConverter로 타입 안전하게 변환하는 구조를 설계했다.Goal 엔티티에 parent_goal_id 자기 참조, rollup_policy, rollup_source, achievement_pct, rolled_achievement_pct를 설계해 계층 구조 목표와 하위 → 상위 달성률 롤업 계산이 자동으로 이루어지도록 구현했다.DRAFT → ACTIVE → COMPLETED / CANCELLED로 정의하고, 활성화·완료 단계에 선택적 승인 워크플로를 붙이는 GoalApprovalBundle 구조를 설계했다. 단일 목표뿐 아니라 KPI 일괄 생성 시 여러 목표를 하나의 번들로 묶어 배치 승인이 가능하도록 만들었다.GoalApprovalPolicy enum(NONE / ACTIVATION_ONLY / COMPLETION_ONLY / BOTH)으로 템플릿 단위 승인 정책을 세분화해, 활성화와 완료 각각에 대해 독립적으로 승인 여부를 제어할 수 있게 설계했다.GoalActivity로 목표 생성·수정·승인·진행률 변경 등 모든 변경 이력을 감사 로그로 추적하고, GoalComment에 이모지 리액션 기능까지 구현했다.MeasureType(HIGHER_BETTER / LOWER_BETTER / TARGET_MATCH)에 따라 actualValue를 입력하면 달성률이 자동 계산되는 수식을 Goal.updateActualValue()에 구현했다.rollup_policy처럼 집계 방식을 데이터로 관리하는 구조를 보면서, 단순히 조회 로직을 짜는 것과 비즈니스 규칙 자체를 시스템이 이해하는 것 사이의 차이를 느꼈다.parent_goal_id로 트리를 구성하면 조회가 간단하지만, 깊이(depth)를 계산할 때 부모를 거슬러 올라가며 반복 쿼리가 발생하는 N+1 문제가 생긴다. Materialized Path나 depth 컬럼을 엔티티에 직접 저장하는 방식이 성능상 더 적합함을 알게 됐다.HIGHER_BETTER), 낮을수록 좋은 지표(LOWER_BETTER), 특정 목표값에 근접할수록 좋은 지표(TARGET_MATCH) 각각에 다른 공식이 필요했고, 이를 MeasureType enum으로 분기 처리하는 구조를 배웠다.requireApproval(boolean)과 goalApprovalPolicy(enum)처럼 같은 개념을 두 필드로 관리하면, 하나를 변경할 때 다른 하나와 동기화가 깨지는 버그가 발생할 수 있다. 마이그레이션을 빠르게 완료하고 레거시 필드를 제거하는 것이 중요하다.activate(), complete(), cancel()처럼 상태 변경 메서드를 엔티티에 캡슐화하고, 부수 효과는 서비스 계층에서 일관되게 처리하는 패턴이 유지보수에 유리했다.KpiDefinition처럼 전용 값 객체 클래스와 JPA AttributeConverter를 함께 사용하면 직렬화·역직렬화를 중앙에서 관리할 수 있고, 컴파일 타임에 오류를 잡을 수 있다.computeDepth()의 N+1 쿼리 문제를 해결하기 위해 Goal 엔티티에 depth 컬럼을 추가하고, 목표 생성·부모 변경 시 자동으로 갱신되도록 개선할 계획이다.requireApproval(boolean) 레거시 필드를 DB 마이그레이션으로 제거하고, goalApprovalPolicy만으로 단일 관리하도록 정리할 예정이다.goalSnapshotJson이 평가자에게 맥락 정보를 보여주는 용도로만 쓰이는데, 목표 달성률(achievementPct)이 평가 점수 계산에 직접 반영되는 구조로 개선해야 한다.EvaluationDesign의 섹션에 SectionType(MANUAL / KPI_SCORE / PEER_FEEDBACK)을 도입해, KPI 섹션은 achievementPct를 자동으로 집계하고 수동 섹션은 평가자가 직접 입력하는 혼합 채점 구조를 설계할 계획이다.GoalVisibility, ownerType별 접근 제어가 실제 멀티테넌시 환경에서도 올바르게 동작하는지 검증할 예정이다."목표를 만드는 것보다 목표가 어떤 상태로, 누구에게, 어떻게 연결되는지를 설계하는 게 진짜 성과관리 시스템이었다."