c350ebe86a
- 마이그레이션 V022/RUN_088: DEPT_MANAGERS 신규 (role: approval/dept/org_leader, PK 3-tuple, FK CASCADE) - StartupSchemaMigrator 에 V022 idempotent CREATE 추가 → 테넌트 DB 자동 동기화 - mapper.xml: SELECT 에 3 json_agg ::TEXT 컬럼 추가, insertDeptManagers + deleteDeptManagersByDeptAndRole 신규 - service: parseManagersJson + syncManagers (delete-all + insert-all, 최대 10명, 역할 한글 메시지) - frontend: types 3 필드, DeptDetailDraft 확장, ManagerChipsField (chip+UserSearchModal 재사용), 조직장 Row 신규 기존 DEPT_INFO.APPROVAL_MANAGER / DEPT_MANAGER 단일 컬럼은 호환을 위해 유지.
5.5 KiB
5.5 KiB
088 마이그레이션 — DEPT_MANAGERS 테이블 추가 (다중 관리자 + 조직장)
작성일: 2026-05-14 작성자: johngreen 관련: RPS 더존 ERP UJA1040 레퍼런스 대비 누락 기능 (A 단계 — 다중 관리자 + 조직장)
목적
부서별로 결재 관리자 / 부서 관리자 / 조직장을 각각 다중 등록 (최대 10명) 할 수 있도록 매핑 테이블 신설.
- 기존
DEPT_INFO.APPROVAL_MANAGER/DEPT_INFO.DEPT_MANAGER컬럼은 단일user_id만 저장 가능 - 신규
DEPT_MANAGERS매핑 테이블이 SoT(source of truth).ROLE컬럼으로 3 종류 구분approval= 결재 관리자 (자동 결재라인 등록 시 호출)dept= 부서 관리자 (행정 책임자)org_leader= 조직장 (본인 부서 + 하위 부서의 경비/근태 조회·승인 권한)
- 기존 단일 컬럼은 호환 위해 일단 유지. 향후 cleanup PR 에서 제거 예정
스키마
DEPT_MANAGERS (신규)
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
DEPT_CODE |
VARCHAR(1024) | NOT NULL, FK → DEPT_INFO ON DELETE CASCADE | 부서 코드 |
USER_ID |
VARCHAR(50) | NOT NULL | 사용자 ID |
ROLE |
VARCHAR(20) | NOT NULL, CHECK | approval | dept | org_leader |
SORT_ORDER |
INTEGER | NOT NULL DEFAULT 1 | 표시 순서 |
CREATED_AT |
TIMESTAMP | NOT NULL DEFAULT NOW() | 등록 시각 |
PK: (DEPT_CODE, USER_ID, ROLE) — 같은 사용자가 같은 부서에 같은 role 로 중복 등록 차단.
인덱스: (DEPT_CODE, ROLE, SORT_ORDER) — 부서별 role 조회 + 정렬 가속.
SQL
-- =================================================================
-- 088: DEPT_MANAGERS 테이블 (idempotent)
-- =================================================================
CREATE TABLE IF NOT EXISTS DEPT_MANAGERS (
DEPT_CODE VARCHAR(1024) NOT NULL,
USER_ID VARCHAR(50) NOT NULL,
ROLE VARCHAR(20) NOT NULL,
SORT_ORDER INTEGER NOT NULL DEFAULT 1,
CREATED_AT TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (DEPT_CODE, USER_ID, ROLE),
CONSTRAINT chk_dept_managers_role
CHECK (ROLE IN ('approval', 'dept', 'org_leader')),
CONSTRAINT fk_dept_managers_dept
FOREIGN KEY (DEPT_CODE) REFERENCES DEPT_INFO(DEPT_CODE) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_dept_managers_role
ON DEPT_MANAGERS (DEPT_CODE, ROLE, SORT_ORDER);
부팅 시 StartupSchemaMigrator 가 메타 DB + 모든 활성 테넌트 DB 에 동일 DDL 을 IF NOT EXISTS 로 적용하므로 일반적으로는 별도 수동 실행이 필요 없음.
사전 점검
-- A. 테이블 사전 상태
SELECT table_name FROM information_schema.tables WHERE table_name = 'dept_managers';
-- 빈 결과여야 정상. 이미 있으면 CREATE 의 IF NOT EXISTS 가 안전.
-- B. DEPT_INFO 행수 (FK 영향 범위)
SELECT COUNT(*) FROM DEPT_INFO;
사후 검증
-- C. 테이블 추가 확인
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_name = 'dept_managers'
ORDER BY ordinal_position;
-- 기대: 5 행 (DEPT_CODE/USER_ID/ROLE/SORT_ORDER/CREATED_AT)
-- D. CHECK 제약 확인
SELECT constraint_name, check_clause FROM information_schema.check_constraints
WHERE constraint_name = 'chk_dept_managers_role';
-- 기대: ROLE IN ('approval', 'dept', 'org_leader')
-- E. FK 동작 확인 (테스트)
BEGIN;
INSERT INTO DEPT_MANAGERS (DEPT_CODE, USER_ID, ROLE)
VALUES ('NON_EXISTENT_DEPT', 'tester', 'approval');
-- 기대: FK 위반 에러 (foreign key constraint "fk_dept_managers_dept")
ROLLBACK;
실행
# 1) 메타 DB
psql -h <host> -U postgres -d invyone -f RUN_088.sql
# 2) 각 테넌트 DB (StartupSchemaMigrator 가 부팅 시 자동 적용하므로 통상 생략 가능)
for db in $(psql -tA -d invyone -c "SELECT db_name FROM company_mng WHERE db_status='active'"); do
echo "=== $db ==="
psql -h <host> -U postgres -d "$db" -f RUN_088.sql
done
롤백
-- DEPT_MANAGERS 테이블 제거 (저장된 다중 관리자 매핑 함께 삭제됨)
DROP INDEX IF EXISTS idx_dept_managers_role;
DROP TABLE IF EXISTS DEPT_MANAGERS;
롤백 후엔 백엔드/프론트가 단일 APPROVAL_MANAGER / DEPT_MANAGER 컬럼만 사용하는 이전 동작으로 자연스럽게 복귀 (호환 컬럼 유지하기 때문).
적용 환경 체크리스트
- 로컬 docker
naengangi-pg(관련 없음 — invyone DB 는 wace/운영에만 존재) - wace 개발서버 PostgreSQL
- 운영 메타 DB (
invyone) - 운영 각 테넌트 DB (loop or 부팅 시 자동)
관련 코드
- Flyway:
backend-spring/src/main/resources/db/migration/V022__create_dept_managers.sql - StartupSchemaMigrator:
backend-spring/src/main/java/com/erp/migration/StartupSchemaMigrator.java(마지막 항목으로 추가) - Mapper:
backend-spring/src/main/resources/mapper/department.xmlselectDepartments/selectDepartmentByCode의 SELECT 절에APPROVAL_MANAGERS/DEPT_MANAGERS/ORG_LEADERSjson_agg 컬럼 추가- 신규 query:
insertDeptManagers,deleteDeptManagersByDept
- Service:
DepartmentService.javacreateDepartment/updateDepartment가 body 의approval_managers[]/dept_managers[]/org_leaders[]배열을DEPT_MANAGERS에 sync (트랜잭션, 최대 10명 검증)
- Frontend:
frontend/app/(main)/admin/userMng/deptMngList/page.tsx- BasicInfoForm 에 다중 chip UI + ManagerPicker 모달