- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다 - 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5 (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를 techviz 로 만들었다 - 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs 돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다. Concept 이 인용한 코드가 SSOT 에 없어 뺐다 - candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
94 lines
4.4 KiB
Markdown
94 lines
4.4 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: messaging-migrations-collide-at-v2
|
|
title: messaging 마이그레이션 두 leaf가 같은 디렉터리에서 V2를 둘 만들었다
|
|
topic: schema-ownership-and-capability-streams
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:messaging-migrations-collide-at-v2
|
|
evidenceCapturedOn: 2026-09-01
|
|
assets:
|
|
- key: messaging-migrations-collide-at-v2
|
|
file: ../../../final/evidence/rendered/messaging-migrations-collide-at-v2.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/messaging-migrations-collide-at-v2.txt
|
|
source:
|
|
- 원본 분석 절은 final/document.md#4-3 · final/document.md#a19 §7.2 이다.
|
|
---
|
|
|
|
# messaging 마이그레이션 두 leaf가 같은 디렉터리에서 V2를 둘 만들었다
|
|
|
|
인박스 리프와 아웃박스 리프가 각자 자기 자원 경로에 같은 마이그레이션 디렉터리 이름을 쓰고, 둘 다 V2 를 만든다. 두 리프가 함께 클래스패스에 있으면 같은 위치에 같은 버전이 둘이다.
|
|
|
|
## 관계
|
|
|
|
- **마이그레이션 스트림은 자기 history 테이블을 갖는다**
|
|
이 사례가 그 규칙을 요구하는 형태다.
|
|
- **두 트리가 다 V1부터 번호를 매겨 공유 history가 하나를 건너뛸 수 있었다**
|
|
같은 형태가 JPA 리프에서 나타난 사례다.
|
|
- **lease가 만료 시각만 기록하고 소유자를 기록하지 않아 terminal state가 되돌려졌다**
|
|
충돌하는 두 V2 중 하나가 그 수정이다.
|
|
|
|
## 문제
|
|
|
|
메시징 인박스 리프와 아웃박스 리프는 각자 별도의 Gradle 리프다.
|
|
|
|
두 리프 모두 자기 자원에 같은 이름의 마이그레이션 디렉터리를 둔다.
|
|
|
|
그리고 둘 다 V2 를 갖는다. 하나는 인박스 테이블을 만들고 다른 하나는 아웃박스 리스 펜싱을 추가한다.
|
|
|
|
## 결론
|
|
|
|
두 리프가 함께 클래스패스에 있으면 같은 마이그레이션 위치에 같은 버전이 둘이 된다.
|
|
|
|
Flyway 에서 중복 버전은 병합해 해결하는 충돌이 아니다. 기동을 거부한다.
|
|
|
|
리프가 독립적이라는 것이 이 문제를 만든다. 각 리프는 자기만 보고 번호를 매기며, 다른 리프가 같은 디렉터리 이름을 쓴다는 사실을 알 방법이 없다.
|
|
|
|
그리고 두 리프는 레지스트리에서 같은 런타임 컴포지션에 속한다. 즉 함께 배포되는 것이 정상 구성이다.
|
|
|
|
이 계열의 해법은 JPA 쪽이 이미 보여 준다. 스트림마다 자기 위치와 자기 히스토리 테이블을 갖게 하는 것이다. 그러면 각 리프가 자기 버전 계열을 갖고 번호가 충돌하지 않는다.
|
|
|
|
## 검증 환경
|
|
|
|
데이터베이스 : PostgreSQL
|
|
마이그레이션 도구 : Flyway
|
|
확인 방식 : 두 리프의 자원 경로와 파일명 대조
|
|
소스 수정 : x
|
|
|
|
## 재현 조건
|
|
|
|
원문은 final/evidence/raw/259-messaging-flyway-migration-namespace.txt 에 있다.
|
|
|
|
1. 두 리프의 마이그레이션 디렉터리 경로를 확인한다. 리프 경로는 다르고 디렉터리 이름은 같다.
|
|
2. 각 디렉터리의 파일 목록을 확인한다. 둘 다 V2 를 갖는다.
|
|
3. 레지스트리에서 두 리프의 런타임 멤버십을 확인한다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
두 leaf가 같은 classpath 리소스 디렉터리 `db/migration/messaging/`에 각자 번호를 매겨 `V2`가 둘이다. 그 위치를 Flyway에 주는 순간 duplicate version으로 부팅이 실패한다.
|
|
|
|
## 같은 디렉터리에 붙은 두 V2
|
|
|
|
:::evidence key="messaging-migrations-collide-at-v2" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true"
|
|
:::
|
|
|
|
## 지금 실패하지 않는 유일한 이유
|
|
|
|
**그 위치를 아무도 Flyway에 주지 않기 때문**이다(main 코드에서 `db/migration/messaging`을 부르는 곳 0건). 각 leaf의 IT는 자기 jar 리소스만 보므로 재현하지 못한다.
|
|
|
|
## 원 계획은 달랐다
|
|
|
|
원 구현 계획서는 분리된 위치를 지정했었다.
|
|
|
|
## 확인하지 못한 것
|
|
|
|
두 리프를 함께 클래스패스에 두고 Flyway 를 실행해 기동 거부를 재현하지 않았다. 이 기록은 파일 배치 대조에 근거한다.
|
|
|
|
실제로 그 위치를 Flyway에 추가해 duplicate version 실패를 관측하지 않았다
|
|
|
|
<!-- body:end -->
|