- Published on
ISO 14817-2 기반 7단계 워크플로우 — 기록부터 배포까지 상태 설계
- Authors

- Name
- Hyo814
ISO 14817-2 기반 7단계 워크플로우 — 기록부터 배포까지 상태 설계
표준데이터 등록 시스템(SDMS)을 설계하면서 가장 먼저 맞닥뜨린 질문은 "등록 요청을 어떤 상태들로 쪼갤 것인가" 였습니다. 승인 한 번, 반려 한 번만 있으면 될 것 같았지만, 실제 운영에서는 **관리자(Steward)**와 **위원회(Registra)**가 서로 다른 역할로 끼어들고, 각 단계마다 "사전 검토 → 본 심의" 가 반복되는 구조였습니다.
임의로 상태를 잡지 않고 ISO 14817-2(Intelligent transport systems — ITS central data dictionaries — Part 2: Governance of the Central ITS Data Concept Registry) 가 제시하는 데이터 개념 라이프사이클을 그대로 차용했습니다. 그 결과가 아래의 7단계 상태 머신입니다.
1. ISO 14817-2 개요 — 왜 이 표준인가
ISO 14817-2는 지능형 교통 시스템(ITS)에서 사용되는 데이터 개념(Data Concept)을 중앙 레지스트리(CIDCR, Central ITS Data Concept Registry) 에 등록·관리하는 절차를 규정한 국제표준입니다. 상위 표준인 ISO/IEC 11179(메타데이터 레지스트리) 프레임워크를 ITS 도메인에 맞춰 특화한 문서이고, 핵심은 다음 세 가지입니다.
- 데이터 개념을 등록 상태(registration status) 로 분류하고, 상태 간 이동을 거버넌스 절차로 통제한다.
- 각 상태 이동은 역할(Role) 이 부여된 주체가 승인(Approve) 하거나 반려(Deny) 하는 방식으로만 일어난다.
- 반려 시에는 특정 이전 상태로 되돌아가며, 모든 이력은 감사 추적(audit trail)이 가능해야 한다.
SDMS는 표준데이터 등록뿐 아니라 OID 등록, 메타데이터 등록을 같은 엔진 위에 올려야 했기 때문에, 도메인별 커스텀 상태를 매번 새로 설계하는 대신 국제표준이 이미 검증한 상태 모델을 뼈대로 삼는 게 맞다고 판단했습니다.
2. 7단계 상태 — 기록에서 배포까지
상태 이름은 표준의 영문 용어를 한국어 운영 용어로 매핑했습니다. 코드 상에서는 workflow/iso14817_factory.py의 StateType 상수로 정의돼 있습니다.
# workflow/iso14817_factory.py
class StateType:
"""Constants for workflow state names"""
RECORD = "기록단계"
SUBMIT = "제출단계"
PRE_VERIFY = "사전검증단계"
VERIFY = "검증단계"
PRE_CERTIFY = "사전인증단계"
CERTIFY = "인증단계"
DEPLOY = "배포단계"
각 단계의 의미와 담당 역할은 다음 표와 같습니다.
| # | 상태 | 역할에서 보면 | 다음 단계로 가는 조건 |
|---|---|---|---|
| 1 | 기록단계 (RECORD) | 제출자가 폼 작성 중 — 아직 심사 대상 아님 | 제출자가 "제출" |
| 2 | 제출단계 (SUBMIT) | 관리자 1차 검토 대기열 | 관리자(Steward) 승인 |
| 3 | 사전검증단계 (PRE_VERIFY) | 위원회 검증 대기열 | 위원회(Registra) 승인 |
| 4 | 검증단계 (VERIFY) | 관리자 2차 검토 대기열 | 관리자(Steward) 승인 |
| 5 | 사전인증단계 (PRE_CERTIFY) | 위원회 인증 대기열 | 위원회(Registra) 승인 |
| 6 | 인증단계 (CERTIFY) | 관리자 최종 승인 대기열 | 관리자(Steward) 승인 |
| 7 | 배포단계 (DEPLOY) | 최종 상태 — 공식 등록 완료 | — (완료) |
핵심은 "사전(Pre-) 단계 - 본(Main-) 단계" 가 쌍을 이루며 관리자 ↔ 위원회 가 번갈아 검토한다는 점입니다. 사전검증/사전인증은 위원회가 바로 보기 전에 관리자가 한 번 걸러주는 게이트 역할을 합니다.
3. 3개 역할 — Submitter / Steward / Registra
ISO 14817-2는 상태 이동 권한을 역할에 귀속시킵니다. SDMS에서는 아래 세 역할로 정리했습니다.
class RoleType(Enum):
"""Role types for workflow participants"""
SUBMITTER = "submitter" # 제출자 (관계자그룹)
STEWARD = "steward" # 관리자 (관리자그룹)
REGISTRA = "registra" # 위원회 (위원회그룹)
ETC = "etc"
그룹 이름 역시 한국어 운영 용어와 매핑합니다.
class GroupType:
STAKEHOLDER_GROUP = "관계자그룹" # Submitter
STEWARD_GROUP = "관리자그룹" # Steward
REGISTRA_GROUP = "위원회그룹" # Registra
어떤 역할이 어떤 단계를 봐야 하는지는 리스트 필터로 관리합니다. 예컨대 위원회 사용자가 로그인하면 "내가 할 일"은 사전검증과 사전인증 두 개, "내가 끝낸 일"은 검증·인증·배포 세 개입니다.
STATE_FILTERS = {
RoleType.REGISTRA.value: {
ListType.TODO.value: [StateType.PRE_VERIFY, StateType.PRE_CERTIFY],
ListType.DONE.value: [StateType.VERIFY, StateType.CERTIFY, StateType.DEPLOY]
},
RoleType.STEWARD.value: {
ListType.TODO.value: [StateType.SUBMIT, StateType.VERIFY, StateType.CERTIFY],
ListType.DONE.value: [StateType.PRE_VERIFY, StateType.PRE_CERTIFY, StateType.DEPLOY]
}
}
이 필터가 있으면 화면단에서는 "내 대기열" 을 뽑을 때 역할만 주면 끝이고, 상태 추가 시 코드가 퍼지지 않습니다.
4. 상태 전이 — 승인 경로와 반려 경로
전이(transition)는 9개로 정의됩니다. 7개 상태를 잇는 전이 6개 + 반려 전이 3개입니다.
workflow_stages = [
# 기록 -> 제출 (제출자가 제출 버튼)
{'current': RECORD, 'next': SUBMIT, 'role': SUBMITTER, 'is_start': True},
# 제출 -> 사전검증 (관리자 승인) / 제출 -> 기록 (관리자 반려)
{'current': SUBMIT, 'next': PRE_VERIFY, 'role': STEWARD},
{'current': SUBMIT, 'next': RECORD, 'role': STEWARD, 'is_denial': True},
# 사전검증 -> 검증 (위원회 승인) / 사전검증 -> 기록 (위원회 반려)
{'current': PRE_VERIFY, 'next': VERIFY, 'role': REGISTRA},
{'current': PRE_VERIFY, 'next': RECORD, 'role': REGISTRA, 'is_denial': True},
# 검증 -> 사전인증 (관리자 승인)
{'current': VERIFY, 'next': PRE_CERTIFY, 'role': STEWARD},
# 사전인증 -> 인증 (위원회 승인) / 사전인증 -> 검증 (위원회 반려)
{'current': PRE_CERTIFY, 'next': CERTIFY, 'role': REGISTRA},
{'current': PRE_CERTIFY, 'next': VERIFY, 'role': REGISTRA, 'is_denial': True},
# 인증 -> 배포 (관리자 최종 승인, 완료)
{'current': CERTIFY, 'next': DEPLOY, 'role': STEWARD, 'is_complete': True},
]
반려 경로의 설계 포인트는 "얼마나 멀리 되돌리느냐" 입니다.
- 제출단계·사전검증단계 반려 → 기록단계까지 되돌림 (작성 자체를 다시 해야 할 수준의 문제)
- 사전인증단계 반려 → 검증단계로만 되돌림 (이미 위원회 검증을 통과했으므로 앞 단계 성과는 보존)
이 비대칭이 처음에는 어색했는데, 실제로 위원회 논의를 보면 "인증 단계에서 발견된 이슈는 대부분 표기 문제" 여서 검증 결과까지 뒤집을 필요는 없더군요. 표준 자체도 이런 단계별 되돌림 깊이 차이를 허용합니다.
5. 팩토리 패턴으로 구성한 이유
9개 전이 × 각 전이마다 (상태, 액션, 액션 타깃, 액티비티, 트랜지션 액션·액티비티) 를 일일이 만들면 금방 수백 줄이 됩니다. 그래서 ISO14817Factory 로 한 덩어리를 만들고, 각 전이를 create_process_line 한 번 호출로 압축했습니다.
def create_process_line(self,
process,
current_state_name: str,
next_state_name: str,
role_type: RoleType = RoleType.ETC,
is_denial: bool = False,
is_start: bool = False,
is_complete: bool = False) -> None:
"""Create a complete process line with states, transition, actions, and activities"""
transition = self.create_state_transition(
process, current_state_name, next_state_name,
is_start, is_complete
)
self.create_transition_action_lines(process, transition, role_type, is_denial)
self.create_transition_activity_lines(process, transition)
캐싱도 같이 들어갔습니다. 같은 프로세스의 같은 그룹·액션을 반복 생성하지 않도록 _process_group_cache, _action_cache, _activity_cache 를 두었습니다.
def create_process_group_cached(self, process, name: str):
cache_key = f"{process.id}_{name}"
if cache_key not in self._process_group_cache:
self._process_group_cache[cache_key] = self.create_process_group(process, name)
return self._process_group_cache[cache_key]
전이가 9개인데 그룹이 3개뿐이면 같은 그룹을 27번 조회하게 되므로, 이 캐시가 마이그레이션/초기화 속도를 눈에 띄게 줄여줬습니다.
6. Simple Factory — 5단계 간소화 버전
모든 데이터가 7단계를 거칠 필요는 없습니다. OID 같은 식별자 등록은 "인증" 개념 자체가 약하고, 빠른 반영이 중요합니다. 그래서 ISO14817SimpleFactory 에 5단계(RECORD → SUBMIT → PRE_VERIFY → VERIFY → DEPLOY) 변형을 만들었습니다.
class ISO14817SimpleFactory(ISO14817Factory):
def create(self, process_type: str, process_name: str):
process = self.create_process(process_type, process_name)
self.create_process_group_line(process)
workflow_stages = [
{'current': RECORD, 'next': SUBMIT, 'role': SUBMITTER, 'is_start': True},
{'current': SUBMIT, 'next': PRE_VERIFY, 'role': STEWARD},
{'current': SUBMIT, 'next': RECORD, 'role': STEWARD, 'is_denial': True},
{'current': PRE_VERIFY, 'next': VERIFY, 'role': REGISTRA},
{'current': PRE_VERIFY, 'next': RECORD, 'role': REGISTRA, 'is_denial': True},
{'current': VERIFY, 'next': DEPLOY, 'role': STEWARD, 'is_complete': True},
]
...
핵심은 7단계를 상속하고 create() 만 오버라이드했다는 점입니다. 상태 상수·역할·그룹·캐시 로직은 그대로 재사용하고, "어떤 전이를 포함할지" 만 다시 쓰면 됩니다. 덕분에 OID용으로 별도 엔진을 깎지 않아도 됐습니다.
7. 정리
- ISO 14817-2는 "정해진 절차대로 데이터 개념을 등록하라" 는 거버넌스 표준이다. 상태 이름만 빌려오는 게 아니라, 역할·승인·반려 구조까지 통째로 가져오는 게 이득이다.
- 7단계(기록·제출·사전검증·검증·사전인증·인증·배포) 는 "사전(Pre-) ↔ 본(Main-)" 쌍으로 읽으면 훨씬 이해가 쉽다. 관리자 게이트가 위원회 앞에 한 번씩 붙는 구조다.
- 반려는 일괄적으로 처음으로 되돌리지 않는다. 단계마다 되돌림 깊이를 다르게 설계해야 실제 검토 흐름과 맞는다.
- 팩토리 + 캐싱으로 전이 선언을 데이터처럼 다루면, 5단계 간소화 버전이나 OID 전용 변형을 선언만 바꿔서 만들 수 있다.
- 역할별 TODO/DONE 필터를 팩토리 상수로 묶어두면 화면단에서 상태를 하드코딩할 일이 사라진다.
표준이 이미 다듬어 놓은 상태 모델을 그대로 따를 수 있다면, 팀 내부에서 "왜 이 단계가 필요한가" 를 매번 재논의할 필요가 없다는 점이 가장 큰 장점이었습니다. 커스텀 상태는 자주 "어느 팀이 더 목소리가 큰가"에 따라 흔들리는데, 국제표준을 기준선으로 두면 그 논의 자체가 줄어듭니다.