- 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>
5.9 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | assets | evidence | source | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CONCEPT | independent-flyway-streams | 독립 Flyway 스트림과 baseline version 0 | schema-ownership-and-capability-streams | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | concept:independent-flyway-streams | 2026-09-01 |
|
|
|
독립 Flyway 스트림과 baseline version 0
능력마다 자기 마이그레이션 위치와 자기 히스토리 테이블을 갖는다. 그래야 각 능력의 버전 계열이 독립적이고, 켜지 않은 능력은 테이블도 히스토리도 남기지 않는다.
관계
- 두 트리가 다 V1부터 번호를 매겨 공유 history가 하나를 건너뛸 수 있었다 이 구조가 필요해진 사례다.
- 마이그레이션 스트림은 자기 history 테이블을 갖는다 이 개념을 규칙으로 옮긴 것이다.
- capability_schema_registry — 스키마 적용과 사용 승인의 분리 스트림이 설치되었다는 사실을 기록하는 쪽이다.
본문
이 저장소에 Flyway 스트림이 여덟 개이고 각각 자기 history 테이블을 갖는 이유의 설명이다. 뻔한 해법(디렉터리를 primary location 목록에 추가)이 틀린 이유는 두 트리가 다 V1부터 번호를 매기고 공유 history가 두 V1을 같은 버전으로 만들어 하나를 거부하거나 resolution 순서에 따라 건너뛰기 때문이다.
뻔한 해법이 틀린 이유
:::evidence key="independent-flyway-streams" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true" :::
baselineOnMigrate 가 필요한 이유
core가 이미 채운 스키마 위에 자기 history를 만들어야 하므로, 없으면 Flyway가 "history 없는 비어있지 않은 스키마"라며 거부한다.
baseline이 0이어야 하는 이유
더 높은 baseline은 그 스트림의 마이그레이션을 건너뛴다 — 이 설정이 보통 두려워하는 실패 모드다.
:::note
마이그레이션 레인 미실행
:::
왜 위치만 더하면 안 되는가
/**
* The notification schema as its own Flyway stream, with its own history table.
*
* <p>The migrations live in {@code db/migration/jpa/notification-platform} while the primary Flyway
* location is {@code db/migration/postgresql}, so nothing applied them. The obvious fix — adding
* the directory to the primary location list — is the wrong one: both trees number from V1, and a
* shared history table would make {@code V1__notification_platform_core} and {@code
* V1__initial_schema} the same version. Flyway would either refuse the second or, worse, record one
* and skip the other depending on resolution order.
*/
두 트리가 각자 V1 부터 번호를 매긴다. 히스토리를 공유하면 두 개의 V1 이 같은 버전이 된다.
Flyway 의 반응이 두 가지인 것이 문제다. 거절하면 발견되지만, 해석 순서에 따라 하나를 기록하고 다른 하나를 건너뛰면 발견되지 않는다.
별도 스트림이 만드는 것
/**
* <p>A separate stream with {@code flyway_jpa_notification_history} keeps the two version series
* independent, which is what makes the capability genuinely optional: a deployment that never
* enables notifications has no notification history table and no notification tables, and a
* deployment that enables it later applies a stream that starts at its own V1.
*/
public static final String LOCATION = "classpath:db/migration/jpa/notification-platform";
public static final String HISTORY_TABLE = "flyway_jpa_notification_history";
능력을 켜지 않은 배포에는 그 능력의 히스토리 테이블도 없다. 나중에 켜면 자기 V1 부터 적용한다.
선택 가능성이 스키마 수준에서 성립한다
능력이 선택적이라는 말이 코드 수준에서만 참이면, 스키마에는 쓰지 않는 테이블이 남는다. 스트림이 독립적이면 그 테이블도 생기지 않는다.
:::tip
이 구조에서 "이 능력을 쓰지 않는다"는 것과 "이 능력의 스키마가 없다"는 것이 같은 사실이 된다. 두 사실이 갈라지면 나중에 어느 쪽이 진실인지 알 수 없다.
:::
버전 공간을 공유하는 경우
같은 Flyway 위치 목록에 병합되는 트리들은 하나의 버전 공간을 공유한다. 샘플 컴포지션이 두 위치를 병합하므로, 한쪽이 이미 쓴 번호를 다른 쪽이 쓸 수 없다.
-- Numbered V9, not V8 or V7. `db/migration/postgresql` and `db/sample-migration` are merged into
-- one Flyway location list by the sample composition root, so the two trees share a single version
-- space: the sample already owns V2, V7 and V8. A duplicate version is not a merge conflict Flyway
-- resolves — it refuses to start at all.
번호를 고를 때 다른 트리를 봐야 한다는 뜻이고, 그 사실이 마이그레이션 헤더에 적혀 있다.
두 위치가 같은 테이블을 만들 때
-- Both locations create capability_schema_registry, so both have to grow the column. A deployment
-- that migrated through only one of them would otherwise still reject a stream path over 32
-- characters, and the error would name the column rather than the reason.
한쪽만 고치면 그 경로로만 마이그레이션한 배포가 옛 제약을 유지한다. 그리고 그때의 오류 메시지는 컬럼 이름을 부르지 이유를 말하지 않는다.