Files
frontend/apps/as/docs/spec/approval-line-management/SPEC.md
T

26 KiB

화면설계서: 결재선 관리

1. 기본 정보

항목 내용
버전 0.3
프로세스명 UI설계
화면명 결재선 관리
화면 유형 [v] 조회 [v] 입력 [v] 수정 [v] 삭제 [ ] 출력
메뉴 경로 디지털행정지원 > 시스템관리 > 결재선 관리

2. 화면 목적

전자결재 처리에 사용할 결재서식(템플릿)을 등록·관리하고, 각 서식별로 결재선(결재구분·결재자·순서)을 구성한다. 상단의 결재서식 목록에서 하나를 선택하면 하단 영역에 해당 서식의 결재선이 표시되며, 사용자는 그리드 인라인 폼으로 결재자를 등록·수정한다. 행 추가 또는 한 행 수정 중에는 다른 행을 편집할 수 없다(단일 행 편집 잠금). 드래그로 순서를 변경한 뒤 [결재선 저장] 으로 서버에 반영한다.


3. 화면 구성

3-1. 전체 레이아웃

┌───────────────────────────────────────────────────────────────────────────────────────────────┐
│  페이지 타이틀: 결재선 관리                                 브레드크럼: 디지털행정지원 > … >  │
├───────────────────────────────────────────────────────────────────────────────────────────────┤
│  [영역 A] 전자결재선 관리 목록                              [서식 등록]                       │
│  ┌──────────────────────────────────────────────────────────────────────┐                     │
│  │ 전자결재서식아이디 | 결재서식명 | 문서구분 | 등록일시 | 관리         │                     │
│  ├──────────────────────────────────────────────────────────────────────┤                     │
│  │  TMPL-0001 (선택 행 강조)  …                            [수정][삭제] │                     │
│  └──────────────────────────────────────────────────────────────────────┘                     │
├───────────────────────────────────────────────────────────────────────────────────────────────┤
│  [영역 B] 결재선 관리                                선택된 서식: TMPL-0001  [결재선 저장]    │
│  ┌─────────────────────────────────────────────────────────────────────────────────────────┐  │
│  │ [영역 B-2] 결재선 그리드 (인라인 편집 + 행 드래그 — @dnd-kit)                           │  │
│  │ ⋮⋮ | 결재선아이디 | 결재순서 | 결재구분 ▼  | 결재자 [선택]    | 등록일시 | 관리         │  │
│  │ ⋮⋮ | APLN-0001    | [ 1 ]    | [검토자 ▼]  | [김민수  ][선택] | …        | [저장][삭제] │  │
│  │ ⋮⋮ | (신규)       | [ 2 ]    | [승인자 ▼]  | [       ][선택]  | —        | [저장][취소] │  │
│  └─────────────────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  [행 추가]    │
│  ※ 결재자 등록·수정은 그리드 셀에서 직접 입력. 검토인력만 [선택] 팝업/다이얼로그              │
│  ※ 행 추가·수정 중: 해당 행만 편집 가능, 나머지 행·[행 추가]·드래그 비활성                    │
└───────────────────────────────────────────────────────────────────────────────────────────────┘

3-2. 화면 데이터 흐름

BEGIN

  // 최초 진입
  CALL GET /as-elapr-service/api/v1/elapr-tmplt
  DISPLAY 결재서식 그리드 (영역 A)
  DISPLAY 빈 상태 안내 (영역 B)            // 서식 미선택 시 그리드·툴바 비활성

  // 영역 A: 서식 행 선택
  ON 영역 A 행 CLICK DO
      SET 선택된 서식 = 행.elaprTmpltId
      CALL GET /as-elapr-service/api/v1/elapr-apln?elaprTmpltId={id}
      DISPLAY 결재선 그리드 (영역 B-2) — 조회 모드
  END ON

  // 영역 A: 신규 서식 등록
  ON [서식 등록] 버튼 CLICK DO
      OPEN 결재서식 등록 다이얼로그
      ON 확인 DO
          CALL POST /as-elapr-service/api/v1/elapr-tmplt
          CALL GET /as-elapr-service/api/v1/elapr-tmplt
      END ON
  END ON

  // 영역 A: 서식 수정·삭제 (다이얼로그 유지)
  ON 영역 A [수정] / [삭제] DO
      (기존과 동일 — PUT / DELETE elapr-tmplt)
  END ON

  // 영역 B: 행 추가 (인라인 신규 행)
  ON [행 추가] 버튼 CLICK DO
      VALIDATE 서식 선택됨
      VALIDATE 편집 중인 행 없음 (editingRowKey == null)
      ADD 영역 B-2 그리드 맨 아래 편집 가능 행
          SET editingRowKey = rowKey (draft-{timestamp})
          SET 편집상태 = 신규
          SET aplnId = 미설정 (POST 저장 시 서버 fn_gen_apln_id 발급)
          SET atrzSeqNo = 현재 행 수 + 1
          SET atrzSeComCd, aprvrUuid = 빈 값
      DISABLE 나머지 행 편집 · [행 추가] · 드래그 · [결재선 저장](정책에 따라)
  END ON

  // 영역 B-2: 기존 행 수정 진입
  ON 행별 [수정] CLICK DO
      VALIDATE 편집 중인 행 없음
      SET editingRowId = 행.aplnId
      SET 해당 행만 편집 모드
      DISABLE 나머지 행 편집 · [행 추가] · 드래그
  END ON

  // 영역 B-2: 인라인 편집
  ON 그리드 셀 변경 DO
      VALIDATE 변경 대상 행 == editingRowId
      SET 해당 행 dirty = true
  END ON

  ON 셀 [선택] (검토인력) CLICK DO
      OPEN 검토인력 선택 다이얼로그 (단일 선택)
      ON 선택 DO
          SET 행.aprvrUuid = 선택인력.uuid
          SET 행.aprvrNm = 선택인력.성명   // UI 표시용 (응답 DTO에 없음 — 로컬 보조 필드)
      END ON
  END ON

  // 영역 B-2: 행별 저장
  ON 행별 [저장] CLICK DO
      VALIDATE atrzSeComCd, aprvrUuid, atrzSeqNo
      IF 편집상태 = 신규 THEN
          CALL POST /as-elapr-service/api/v1/elapr-apln
      ELSE
          CALL PUT /as-elapr-service/api/v1/elapr-apln/{aplnId}
      END IF
      CALL GET /as-elapr-service/api/v1/elapr-apln?elaprTmpltId={id}
      CLEAR editingRowId
      ENABLE 전체 행 조회 모드 · [행 추가] · 드래그
  END ON

  // 영역 B: 결재선 저장 (드래그 순서 일괄 반영)
  ON [결재선 저장] 버튼 CLICK DO
      VALIDATE 서식 선택됨
      VALIDATE 편집 중인 행 없음
      REORDER atrzSeqNo = 그리드 행 순서 (1..n)
      FOR EACH dirty 또는 순서 변경된 행 DO
          CALL PUT /as-elapr-service/api/v1/elapr-apln/{aplnId}  // atrzSeqNo 등 반영
      END FOR
      FOR EACH 신규 미저장 행 DO
          CALL POST /as-elapr-service/api/v1/elapr-apln
      END FOR
      CALL GET /as-elapr-service/api/v1/elapr-apln?elaprTmpltId={id}
      TOAST "결재선이 저장되었습니다."
  END ON

  // 영역 B-2: 행 드래그
  ON 영역 B-2 행 DRAG END DO
      VALIDATE 편집 중인 행 없음
      REORDER 그리드 행
      SET 각 행 atrzSeqNo = 행 인덱스 + 1 (UI 즉시 반영, 서버는 [결재선 저장] 또는 행별 [저장])
  END ON

  // 영역 B-2: 행 삭제
  ON 행별 [삭제] CLICK DO
      CONFIRM "선택한 결재선을 삭제하시겠습니까?"
      IF 서버 저장된 행 THEN
          CALL DELETE /as-elapr-service/api/v1/elapr-apln/{aplnId}
      END IF
      REMOVE 그리드 행 (신규 미저장 행은 API 호출 없이 제거)
      CALL GET /as-elapr-service/api/v1/elapr-apln?elaprTmpltId={id}
  END ON

  ON 행별 [취소] CLICK DO   // 신규·수정 공통
      IF 편집상태 = 신규 THEN REMOVE 임시 행
      ELSE RESTORE 행 스냅샷 (수정 취소)
      CLEAR editingRowId
      ENABLE 전체 행 조회 모드 · [행 추가] · 드래그
  END ON

END

4. 영역 A: 전자결재선 관리 목록

선택된 결재서식이 영역 B의 작업 대상이 된다. 행 클릭으로 선택 상태를 표시(좌측 컬러 바·배경 강조)한다.

4-1. 헤더 / 툴바

항목 내용
섹션 타이틀 전자결재선 관리 목록
우측 버튼 [서식 등록] — 결재서식 등록 다이얼로그 오픈

4-2. 그리드 컬럼

컬럼명 Field 타입 비고
전자결재서식아이디 elaprTmpltId string 등록 시 서버(DB 함수) 자동 발급
결재서식명 elaprTmpltNm string
문서구분 docSeComNm string 코드 docSeComCd, 상위코드 ASDOCSECD
등록일시 regDt string yyyy-MM-dd HH:mm:ss
관리 — — 행별 [수정] · [삭제] 버튼
  • 행 클릭 시: elaprTmpltId 선택 → 영역 B 라벨·B-2 그리드 갱신.
  • 페이지네이션: Spring Pageable (page, size, sort).

4-3. 버튼

버튼명 위치 동작
서식 등록 섹션 우측 상단 결재서식 등록 다이얼로그 오픈
수정 행별 결재서식 수정 다이얼로그 (기존 값 초기화)
삭제 행별 확인 후 삭제. 선택 중인 서식이면 영역 B 초기화.

4-4. 다이얼로그(개요)

다이얼로그명 트리거 입력 항목 비고
결재서식 등록 [서식 등록] elaprTmpltNm, docSeComCd elaprTmpltExpln 선택, ID는 저장 후 응답
결재서식 수정 행별 [수정] elaprTmpltNm, docSeComCd, elaprTmpltExpln ID는 변경 불가
결재서식 삭제 확인 행별 [삭제] (확인/취소)

5. 영역 B: 결재선 관리

영역 A에서 선택된 elaprTmpltId 기준으로 결재선을 관리한다. 등록·수정은 B-2 그리드 인라인 폼으로 수행하며, 검토인력 지정만 [선택] 보조 다이얼로그를 사용한다.

5-1. 헤더 / 툴바

항목 내용
섹션 타이틀 결재선 관리
우측 라벨 선택된 서식: {elaprTmpltId} — 미선택 시 영역 B 비활성
우측 버튼 [행 추가] — 편집 중인 행이 없을 때만 활성 · [결재선 저장] — 편집 중인 행이 없을 때만 활성(순서·미저장 행 일괄 반영)

5-2. 영역 B-2: 결재선 그리드 (인라인 편집)

그리드 컬럼

컬럼명 Field 입력 UI (편집 모드) 비고
(드래그 핸들) — — useSortable 연동
결재선아이디 aplnId 읽기 전용 신규 행: —, 저장 후 서버 aplnId 표시
결재순서번호 atrzSeqNo 읽기 전용 (그리드 행 순서 1부터 표시) 저장 시 행 순서 기준 자동 채번
결재구분 atrzSeComCd Select (ATRZSECD 공통코드) 표시명 atrzSeComNm (조회 행)
결재자 aprvrUuid 읽기 전용 이름 + [선택] 버튼 응답에 성명 없음 — 선택 시 로컬 aprvrNm 유지
등록일시 regDt 읽기 전용 신규 행은 —
관리 — 편집 중인 행: [저장] [취소] · 조회 행: [수정] [삭제] (다른 행 편집 중이면 비활성)

인라인 편집 정책

항목 내용
단일 행 편집 행 추가 또는 한 행 수정 중에는 다른 행을 편집할 수 없다. editingRowId 로 현재 편집 행 1건만 허용.
편집 잠금 시 비활성 다른 행: 셀·[수정]·[삭제] 비활성 · [행 추가] 비활성 · 행 드래그 비활성 · (선택) [결재선 저장] 비활성
편집 해제 행별 [저장] 성공 또는 [취소] 시 editingRowId 초기화 후 전체 조회 모드 복귀
조회 행 편집 중이 아닐 때 읽기 전용. [수정] 클릭 시 해당 행만 편집 모드 진입
신규 행 [행 추가] 시 맨 아래 편집 행 1건 생성 (editingRowId = 임시 키)
필수값 atrzSeComCd, aprvrUuid
순서 중복 저장 시 행 순서로 자동 채번하므로 중복 없음
결재구분 코드 ATRZSECD — 예: ATRZ01 검토자, ATRZ02 승인자, ATRZ03 최종승인자
순서 제약 ATRZ01은 최상단 블록, ATRZ03은 최하단 블록. 드래그 종료·저장 시 validateAtrzOrder로 검증, 위반 시 적용/저장 불가 (결재구분 변경 시에는 미검증)
저장 단위 행별 [저장] (단건 POST/PUT) 또는 툴바 [결재선 저장] (일괄)

행 드래그 정렬 (@dnd-kit + useSortable)

항목 내용
목적 결재 단계 순서를 그리드에서 직접 변경
라이브러리 @dnd-kit/core, @dnd-kit/sortable — 테이블 행 POC 후 확정
저장 시점 드래그는 클라이언트 상태만 변경 → [결재선 저장] 또는 행별 [저장] 시 atrzSeqNo PUT
편집 중 editingRowKey != null 이면 드래그 불가
순서 제약 드래그 종료 시 validateAtrzOrder — 실패하면 순서 변경 미적용 + 안내. 결재구분 미선택 행은 드래그 불가

5-3. 보조 다이얼로그 (검토인력만)

다이얼로그명 트리거 결과
검토인력 선택 그리드 결재자 셀 [선택] aprvrUuid 및 UI용 aprvrNm 반영

결재자 등록·수정 다이얼로그는 사용하지 않음 (v0.2 변경).


6. API/DTO 명세

6-1. 공통

항목 내용
서비스 as-elapr-service
Base prefix /as-elapr-service/api/v1 (프록시 경유)
인증 JWT (Authorization 헤더)
페이징 Spring Pageable: page, size, sort → PageResponse<T>
엔티티 @/entities/elapr (elaprTmpltService, elaprAplnService)

6-2. 전자결재서식 (영역 A) — elapr-tmplt

기능 Method URL Request / Query Response 클라이언트
목록 조회 GET /elapr-tmplt Query: ElaprTmpltSearchParams + Pageable Page<ElaprTmplt> elaprTmpltService.findPage
단건 조회 GET /elapr-tmplt/{elaprTmpltId} — ElaprTmplt elaprTmpltService.findById
등록 POST /elapr-tmplt ElaprTmpltSaveRequest ElaprTmplt (201) elaprTmpltService.create
수정 PUT /elapr-tmplt/{elaprTmpltId} ElaprTmpltUpdateRequest ElaprTmplt elaprTmpltService.update
삭제 DELETE /elapr-tmplt/{elaprTmpltId} — 204 elaprTmpltService.remove

ElaprTmplt (응답)

Field 타입 설명
elaprTmpltId string 전자결재서식아이디
elaprTmpltNm string 결재서식명
elaprTmpltExpln string? 서식 설명
docSeComCd string? 문서구분 코드
docSeComNm string? 문서구분명
regDt string? 등록일시

ElaprTmpltSaveRequest: elaprTmpltNm_, elaprTmpltExpln?, docSeComCd?

ElaprTmpltUpdateRequest: elaprTmpltNm*, elaprTmpltExpln?, docSeComCd?

ElaprTmpltSearchParams: elaprTmpltNm?, docSeComCd?, regDtStart?, regDtEnd? + page, size, sort

6-3. 결재선 (영역 B) — elapr-apln

기능 Method URL Request / Query Response 클라이언트
목록 조회 GET /elapr-apln Query: elaprTmpltId, Pageable Page<ElaprApln> elaprAplnService.findPage
단건 조회 GET /elapr-apln/{aplnId} — ElaprApln elaprAplnService.findById
등록 POST /elapr-apln ElaprAplnSaveRequest ElaprApln (201) elaprAplnService.create
수정 PUT /elapr-apln/{aplnId} ElaprAplnUpdateRequest ElaprApln elaprAplnService.update
삭제 DELETE /elapr-apln/{aplnId} — 204 elaprAplnService.remove

일괄 저장 API 없음 — UI의 [결재선 저장]은 변경된 행에 대해 POST/PUT을 순차(또는 병렬) 호출하는 클라이언트 오케스트레이션으로 구현.

ElaprApln (응답)

Field 타입 설명
aplnId string 결재선아이디
elaprTmpltId string 전자결재서식아이디
aprvrUuid string? 결재자 UUID
atrzSeComCd string? 결재구분 코드
atrzSeComNm string? 결재구분명
atrzSeqNo number? 결재순서번호
regDt string? 등록일시

ElaprAplnSaveRequest: elaprTmpltId_, aprvrUuid?, atrzSeComCd?, atrzSeqNo?

ElaprAplnUpdateRequest: elaprTmpltId*, aprvrUuid?, atrzSeComCd?, atrzSeqNo?

6-4. 검토인력 (보조)

기능 Method URL 비고
검토인력 목록 조회 TBD TBD 사용자 서비스 또는 별도 API

6-5. Backend ↔ 화면 필드 매핑 (구 SPEC 대비)

구 SPEC 필드 백엔드 필드
elctAtrzTmpltId elaprTmpltId
atrzTmpltNm elaprTmpltNm
docSeNm docSeComNm
atrzLineId aplnId
atrzSeNm atrzSeComNm
atrzUserNm (없음) aprvrUuid + 사용자 조회/선택 시 로컬 표시명

7. UI 구현 가이드

7-1. 기술 스택·원칙

  • 공통 컴포넌트: @common/components
  • 테이블: @tanstack/react-table + 인라인 편집 셀 (Select, Input, Button)
  • 드래그: @dnd-kit — B-2 행 정렬 (POC 필수)
  • 데이터: React Query — @/entities/elapr hooks
  • 상태: 선택된 elaprTmpltId, editingRowId (단일 행 편집 잠금), B-2 행 배열(dirty·신규·aprvrNm·수정 전 스냅샷)
  • 모의 데이터: API 연동 전 @faker-js/faker

7-2. 모듈·파일 배치(제안)

구분 경로
라우트 apps/as/app/(with-base-layout)/approval-line-management/page.tsx
페이지 apps/as/src/pages/approval-line-management/ (Public API: page만 export)
UI .../ui/elapr-tmplt-list.tsx, elapr-tmplt-form-dialog.tsx, elapr-apln-grid.tsx 등
model .../model/columns.tsx, apln-row-types.ts, mock-reviewers.ts
lib .../lib/use-apln-rows.ts, validators.ts, use-dnd-sensors.ts
엔티티 apps/as/src/entities/elapr/

7-3. 영역별 UI 매핑

영역 주요 UI
A DataTable + 행 선택 + 서식 등록/수정 다이얼로그
B 헤더 상태 라벨 + 행 추가, 결재선 저장
B-2 인라인 편집 DataTable + editingRowId 단일 행 잠금 + 드래그 핸들 + 행별 수정/저장/삭제/취소
공통 서식 Dialog, 검토인력 선택 Dialog만

7-4. 데이터 흐름(요약)

  • 진입: useElaprTmpltPage → 영역 A. B 비활성.
  • 서식 선택: useElaprAplnPage({ elaprTmpltId }) → B-2.
  • 행 추가: editingRowId 없을 때만 가능 → 신규 행 1건 편집 잠금 → 저장/취소 후 해제.
  • 인라인 수정: [수정]으로 editingRowId 설정 → 해당 행만 편집 → useUpdateElaprApln 후 해제.
  • 드래그: editingRowId == null 일 때만 가능 → 로컬 atrzSeqNo 재부여 → 일괄 PUT.
  • 삭제: useDeleteElaprApln 또는 신규 행 로컬 제거.

7-5. 미확정 / 검증 필요

  • 검토인력 API 경로·DTO.
  • @dnd-kit + react-table 행 인라인 Input 동시 적용 POC.
  • 결재자 성명 표시: aprvrUuid → 사용자명 조회 API.
  • 영역 A·B 페이지네이션·검색 UI 노출 여부.
  • 권한(역할별 CRUD).