이 글은 2026-06-18 하루 동안
artifact-transformer와 그 산하 문서 저장소들에서 다이어그램을 둘러싼 길을 정리한 작업 기록이다..puml에서 사람이 보는.png로 가는 렌더, 그 결과를 산출물 관리 대장에 등록하는 일, 새 다이어그램을 일관되게 작성하는 규약 — 세 갈래를 하나로 꿰었다.
배경
artifact-transformer는 Jira 이슈와 PlantUML 다이어그램을 입력으로 받아 요구사항·유스케이스·기능·시퀀스 명세서와 데이터 정의서/명세서 등을 docx/xlsx로 자동 생성·역파싱하는 도구다 (#4 참조).
이 저장소에서 .puml은 단순한 그림이 아니라 **구조 필드의 원천(source of truth)**이다. 작성한 .puml을 parse.py로 역추출하면 그 구성요소가 그대로 입력 JSON(business/usecase/participant/sequence)이 된다.
#16까지는 시선이 도구 안쪽을 향해 있었다 — 설정을 실행 코드에서 떼어내고, 생성↔파싱 가역성 점검을 roundtrip.py 일급 명령으로 끌어올린 날이었다.
오늘은 같은 “원천에서 산출물로” 사고를 다이어그램 바깥으로 끌어냈다. .puml을 원천으로 둔다는 결정은 내려져 있었지만, 정작 거기서 갈라져 나가는 세 길은 아직 손으로 메우고 있었다 — png 렌더, 시트 등록, 작성 규약. 셋 다 “원천은 분명한데 거기서 나가는 길이 사람 손에 달린” 것들이었다.
문제
손대기 전, 다이어그램을 둘러싸고 보이던 것들.
- puml→png 렌더가 수작업이었다 — 누가 언제 변경된
.puml을.png로 바꿔 커밋하는지 규약이 없었다. 사람이 빠뜨리면 시트가 가리키는 그림이 옛것으로 남는다. - 시트의 버전·링크가 실제 산출물과 어긋났다 —
upload.py로 산출물 관리 대장에 올릴 때, 일부 버전 정보가 실제 버전(1.2.0 등)이 아니라 기존 이력으로 기록되고 있었다. - 작성 규약이 사람 머릿속에만 있었다 — 종류별 표기·식별자·버전 주석이 제각각이라, 새로 그린 다이어그램이 라운드트립을 깨뜨릴 위험이 있었다.
- LORAS는 Jira와 문서가 벌어져 있었다 — 군집·AI 서비스 요구가 Jira 이슈엔 반영됐는데 문서엔 아직 내려오지 않았다.
결정 1 — 렌더를 CI로 끌어올리다
가장 먼저, “변경된 puml을 사람이 png로 바꿔 커밋한다”는 손작업을 파이프라인으로 옮겼다.
- Bitbucket 파이프라인을 신설했다 —
diagrams/*.puml이 바뀌면 동일 경로에 PNG를 렌더해 커밋백한다. 원천이 바뀌면 그림은 따라온다는 보증을, 사람 기억이 아니라 CI에 맡겼다. - 처음엔 png를
out/같은 별도 디렉터리로 분리할까 했지만, puml과 같은 위치에 두기로 했다. 시트가 가리키는 경로와 사람이 저장소에서 찾는 경로를 하나로 모으는 게, 디렉터리를 가르는 명분보다 먼저였다. - 로컬 변환 도구(
render.py)도 다양한 옵션을 받도록 정리하고, CI의 렌더 대상 grep을@startuml에서@start*로 확대했다 — mindmap 등 다른 다이어그램 종류까지render.py가 처리하는 범위와 CI가 처리하는 범위를 같게 맞췄다. 로컬에서 렌더되는 것과 CI에서 렌더되는 것이 어긋나면, “내 화면엔 있는데 저장소엔 옛 그림”이 생긴다. - 같은 파이프라인을 6개 저장소(
artifact-transformer+iam·sdsp·fdsp·padx·loras)에 적용하고, 로컬 전용 3개 저장소는 grep 변경만 반영했다.
원천이 바뀌면 그림이 따라온다는 보증을 사람 손에 두면, 바쁜 날 가장 먼저 빠진다. CI가 같은 자리에 png를 떨궈 주면, 렌더는 “돌렸나 안 돌렸나”의 문제가 아니라 push의 부산물이 된다.
결정 2 — 시트의 버전·링크를 실제 산출물과 맞추다
산출물 관리 대장은 “지금 무엇이 몇 버전인지”를 보는 단일 창이다. 그 창이 실제와 어긋나면, 맞다고 믿는 사람이 틀린 걸 본다.
upload.py가 시트에 기록하는 버전을 산출물·다이어그램의 실제 버전으로 잡도록 고쳤다. 산출물이 1.2.0으로 올랐는데도 기존 이력으로 기록되던 버그를, 시트가 진짜 버전을 읽게 정리했다.- 다이어그램에도 같은 결의 버그가 있었다 — 시트의 PNG 링크를
@startuml이름(파일명 규약) 기준으로 산출하도록 고쳤다. 결정 1에서 png 위치를 puml 옆으로 고정해 뒀으니, 링크도 그 규약을 그대로 따라가게 했다.
렌더 위치·시트 링크·시트 버전이 같은 규약 하나(@startuml 이름 = 파일명 = png 경로)로 묶이자, 세 곳이 따로 노는 일이 사라졌다.
결정 3 — 다이어그램 작성을 규약으로: author-diagram 스킬
render.py는 이미 그려진 .puml을 png로 바꾼다. 정작 그 .puml을 어떤 규칙으로 작성하느냐는 사람 머릿속에 있었다. 그래서 작성 자체를 위한 공용 스킬을 새로 만들었다.
- 목표를 분명히 했다 — “보기 좋은 그림”이 아니라 “파싱하면 의도한 JSON이 그대로 나오는 라운드트립 안전”. 이 저장소에서 다이어그램은 구조 필드의 원천이므로, 작성의 성공 기준은 미관이 아니라 가역성이다.
- 규약의 단일 출처는 어디까지나 **파서 코드(
parse_*.pydocstring)와common/diagram_paths.py**로 두고, 스킬은 그것을 사람이 따라 쓰기 좋게 정리한 계층으로 한정했다. 결정적 검증은 여전히 루트 CLI(parse.py diagram --diff,check.py)가 한다. - Sequence·BCDG·UCDG·C4(CDG)·ERD 5종을 실제로 작성해 시연·검증했다. 규약을 글로만 두지 않고, 종류마다 한 장씩 그려 라운드트립이 도는지 눈으로 확인했다.
- 표기도 표준화했다 —
@version주석을 머리 주석 블록 최상단으로 일관 배치하고 스킬에 반영했다. 더불어@startuml식별자를 파일명 규약(하이픈형)으로 정합시켜, 5개 문서 저장소 전체의 다이어그램 머리말을 같은 모양으로 맞췄다.
작성 규약을 사람 머릿속에 두면, 다음 다이어그램은 그 사람의 그날 컨디션을 닮는다. 규약을 스킬로 외화하고 검증을 CLI에 맡기면, 누가 그려도 라운드트립이 도는 그림이 나온다.
결정 4 — LORAS: 군집·AI 서비스를 C4에 정식 편입
마지막은 도구가 아니라 도구가 다루는 도메인 쪽 빚이었다. LORAS의 군집·AI 서비스 요구가 Jira엔 있는데 문서엔 없었다.
- 먼저
system.env의 API 토큰으로 Jira REST를 직접 조회해 실제 요구를 확인하고, 그 절차를init-source스킬에 규약으로 남겼다. 다음에 같은 확인이 필요할 때 다시 헤매지 않도록. - AI 서비스·군집 컴포넌트를 C4에 정식 편입(v1.2.0)하고, AI 서비스 데이터 6종(AIS-003~008)을 ERD에 반영해 재생성했다.
- participant를 복원해 **댕글링 참조 17건을 해소(WARN 0)**했다. 컴포넌트를 들이면 그걸 가리키던 끊긴 참조도 함께 메워야 한다.
- 상태 흐름 다이어그램(사용자 계정·세션·위험도 평가)을 추가하고, 업무 구성도(BCDG)의 글자·선 겹침과 동선 꼬임을 풀어 가독성을 손봤다. 파서 쪽에서는 CDG가
System_Ext를externalSystems로 분리하도록 고쳐, 외부 시스템이 내부 컴포넌트와 한 덩어리로 섞이지 않게 했다.
의도치 않은 함정
- 로컬 렌더는 Docker에 묶여 있었다 —
render.py로 puml을 png로 돌리려는데dockerDesktopLinuxEngine파이프를 못 찾는 에러가 났다. Docker Desktop이 떠 있어야 도는 구조라, 렌더의 1차 경로는 CI(결정 1)이고 로컬은 보조라는 게 분명해졌다. - png가 원본 옆에 안 떨어졌다 — 생성된다고 믿었는데 어디에도 없었다. 변환 코드가 실제로 만든 파일의 경로를 로그에 찍게 고치자, 어느 폴더로 떨어지는지가 드러나면서 경로 가정이 틀렸다는 게 보였다. “안 생긴다”의 절반은 “엉뚱한 데 생긴다”였다.
- 표준화와 의미 변경을 한 커밋에 섞지 않았다 — 머리 주석·식별자 정합 작업은 변경 줄이 많다. 버전 정규화(2자리→3자리 semver)만 따로 떼어 커밋하고,
@startuml잔존 변경은 별도 커밋으로 갈랐다. 나중에 “왜 이 줄이 바뀌었나”를 되짚을 때, 표기 정리와 내용 변경이 한 덩어리면 둘 다 못 읽는다.
마무리
오늘 관통한 결은 하나였다 — .puml이라는 원천에서 갈라지는 세 길(렌더·등록·작성)을 같은 규약으로 묶은 것.
- 렌더를 CI로 — puml이 바뀌면 같은 자리에 png가 따라오고(6개 저장소), 로컬과 CI가 같은
@start*범위를 본다. - 시트를 실제와 맞추고 — 버전과 PNG 링크를 산출물의 진짜 버전·파일명 규약 기준으로 잡았다.
- 작성을 규약으로 —
author-diagram스킬과 머리 주석 표준으로, 누가 그려도 라운드트립이 도는 그림을 목표로 했다. - LORAS 도메인을 메우고 — 군집·AI 서비스를 C4에 정식 편입하고 댕글링을 0으로 내렸다.
#16이 도구 안쪽의 가역성을 일급 명령으로 만든 날이라면, 오늘은 그 “원천→산출물” 사고를 다이어그램 바깥으로 끌어낸 날이다. 원천이 바뀌면 그림·시트·작성 규약이 함께 따라오도록 길을 깔아 두면, 다음 변경은 더 적은 손질 위에서 시작한다.
다음에 할 것: