{ "schema_version": "1.0", "document": "/home/donghyeon/workspace/chat-gpt-container/document-haness/docs/clean-architecture-backend-template/final/document.md", "document_sha256": "8071fe71b3359d9cf60b95909c26c7b50653ce2f22bbc5fcf6988719bb91236d", "line_count": 47035, "line_number_space": "canonical-source-with-managed-blocks-collapsed", "anchor": { "kind": "line", "value": 29172, "line": 29172 }, "current_section": { "heading": { "line": 29172, "level": 4, "text": "2. 의존성과 런타임 배선" }, "start_line": 29172, "end_line": 29196, "text": "#### 2. 의존성과 런타임 배선\n\n들어오는 것(project): `messaging-core-api`, `messaging-policy`, `messaging-transport-spi`, `messaging-kafka` — 넷 다 `api`.\n\n들어오는 것(vendor): `org.apache.kafka:kafka-clients`(`implementation`) — **어떤 소스도 import하지 않는다**(§12.4).\n\n나가는 것: **없다.** 어떤 leaf의 `allowed_dependencies`에도 이 leaf가 없고 starter 목록에도 없다.\n\n런타임 배선: 없음. `runtime_memberships: []`. bean 없음(Spring 주석 0개).\n\n**소비자 없음·membership 없음·조립 없음의 삼중 정합**이다 — `messaging-schema-avro`·`messaging-schema-protobuf`와 같은 형태이고, incubating leaf의 올바른 상태다.\n\n**`messaging-policy`와 `messaging-kafka` 의존이 실제로 쓰이는가.**\n\n| 의존 | 사용 |\n|---|---|\n| `messaging-core-api` | `OrderingScope`, `DestinationName`, `MessagingCapabilities`, `MessagingCapabilityUnavailableException` — **사용** |\n| `messaging-transport-spi` | `TransportConsumerRegistration`, `TransportConsumerSpec` — **사용** |\n| `messaging-policy` | 어떤 타입도 import하지 않음 — **미사용** |\n| `messaging-kafka` | 어떤 타입도 import하지 않음 — **미사용** |\n\n네 project 의존 중 둘, 벤더 의존 하나가 미사용이다. §17.\n\n---\n" }, "previous_section": { "heading": { "line": 29142, "level": 4, "text": "1. 모듈의 정체와 경계" }, "start_line": 29142, "end_line": 29171, "text": "#### 1. 모듈의 정체와 경계\n\nKafka **Share Group**(KIP-932, 경쟁 소비자 work queue)을 실험적 어댑터로 감싼다. `runtime_memberships: []`이고 이름 자체가 `-experimental`이다.\n\n이 leaf의 실질은 **거절**이다. 190줄 중 실제 동작을 하는 코드는 거의 없고, 세 가지를 거절한다.\n\n| 거절 | 코드 | 이유 |\n|---|---|---|\n| 비활성 상태의 사용 | `KAFKA_SHARE_DISABLED` | experimental이 기본 켜지지 않게 |\n| 순서 보장 목적지 | `IllegalArgumentException` | share group이 순서를 줄 수 없음 |\n| pause/resume | `KAFKA_SHARE_NO_PAUSE`/`_NO_RESUME` | 일시정지할 파티션 할당이 없음 |\n\n핵심 진술이 validator javadoc에 있다.\n\n```java\n// KafkaShareProfileValidator.java:10-17\n *
A share group hands individual records to competing consumers and acknowledges them\n * individually. That is a work queue, and it is fundamentally incompatible with partition ordering:\n * two consumers in the same share group can process records from one partition concurrently and\n * finish in either order. Configuring an ordered destination on a share group would therefore\n * advertise a guarantee the broker is not providing, so it is refused rather than degraded.\n *\n *
The adapter is also off unless explicitly enabled, so an Experimental capability cannot drift\n * into a Stable deployment by default.\n```\n\n두 번째 문단이 이 저장소의 experimental 정책을 한 문장으로 담는다 — **기본 꺼짐이 drift 방지 수단이다.**\n\n---\n" }, "next_section": { "heading": { "line": 29197, "level": 4, "text": "3. 패키지/컴포넌트 지도" }, "start_line": 29197, "end_line": 29218, "text": "#### 3. 패키지/컴포넌트 지도\n\n```\nKafkaShareProfile (record)\n destination · shareGroup · orderingScope · enabled · maxDeliveryCount\n ↓\nKafkaShareProfileValidator.validate(profile)\n ├── !enabled → MessagingCapabilityUnavailableException(KAFKA_SHARE_DISABLED)\n └── orderingScope != NONE → IllegalArgumentException\n ↓\nKafkaShareGroupRegistrar.register(profile, spec)\n └── ShareRegistration implements TransportConsumerRegistration\n ├── pause(scope) → failedFuture(KAFKA_SHARE_NO_PAUSE)\n ├── resume(scope) → failedFuture(KAFKA_SHARE_NO_RESUME)\n ├── isActive() → true until close()\n └── close() → active = false\n\nKafkaShareWorkQueueCapability.capabilities() → MessagingCapabilities(12 booleans)\n```\n\n---\n" }, "context_range": { "start_line": 29142, "end_line": 29218 }, "context_lines": [ { "line": 29142, "text": "#### 1. 모듈의 정체와 경계" }, { "line": 29143, "text": "" }, { "line": 29144, "text": "Kafka **Share Group**(KIP-932, 경쟁 소비자 work queue)을 실험적 어댑터로 감싼다. `runtime_memberships: []`이고 이름 자체가 `-experimental`이다." }, { "line": 29145, "text": "" }, { "line": 29146, "text": "이 leaf의 실질은 **거절**이다. 190줄 중 실제 동작을 하는 코드는 거의 없고, 세 가지를 거절한다." }, { "line": 29147, "text": "" }, { "line": 29148, "text": "| 거절 | 코드 | 이유 |" }, { "line": 29149, "text": "|---|---|---|" }, { "line": 29150, "text": "| 비활성 상태의 사용 | `KAFKA_SHARE_DISABLED` | experimental이 기본 켜지지 않게 |" }, { "line": 29151, "text": "| 순서 보장 목적지 | `IllegalArgumentException` | share group이 순서를 줄 수 없음 |" }, { "line": 29152, "text": "| pause/resume | `KAFKA_SHARE_NO_PAUSE`/`_NO_RESUME` | 일시정지할 파티션 할당이 없음 |" }, { "line": 29153, "text": "" }, { "line": 29154, "text": "핵심 진술이 validator javadoc에 있다." }, { "line": 29155, "text": "" }, { "line": 29156, "text": "```java" }, { "line": 29157, "text": "// KafkaShareProfileValidator.java:10-17" }, { "line": 29158, "text": " *
A share group hands individual records to competing consumers and acknowledges them" }, { "line": 29159, "text": " * individually. That is a work queue, and it is fundamentally incompatible with partition ordering:" }, { "line": 29160, "text": " * two consumers in the same share group can process records from one partition concurrently and" }, { "line": 29161, "text": " * finish in either order. Configuring an ordered destination on a share group would therefore" }, { "line": 29162, "text": " * advertise a guarantee the broker is not providing, so it is refused rather than degraded." }, { "line": 29163, "text": " *" }, { "line": 29164, "text": " *
The adapter is also off unless explicitly enabled, so an Experimental capability cannot drift" }, { "line": 29165, "text": " * into a Stable deployment by default." }, { "line": 29166, "text": "```" }, { "line": 29167, "text": "" }, { "line": 29168, "text": "두 번째 문단이 이 저장소의 experimental 정책을 한 문장으로 담는다 — **기본 꺼짐이 drift 방지 수단이다.**" }, { "line": 29169, "text": "" }, { "line": 29170, "text": "---" }, { "line": 29171, "text": "" }, { "line": 29172, "text": "#### 2. 의존성과 런타임 배선" }, { "line": 29173, "text": "" }, { "line": 29174, "text": "들어오는 것(project): `messaging-core-api`, `messaging-policy`, `messaging-transport-spi`, `messaging-kafka` — 넷 다 `api`." }, { "line": 29175, "text": "" }, { "line": 29176, "text": "들어오는 것(vendor): `org.apache.kafka:kafka-clients`(`implementation`) — **어떤 소스도 import하지 않는다**(§12.4)." }, { "line": 29177, "text": "" }, { "line": 29178, "text": "나가는 것: **없다.** 어떤 leaf의 `allowed_dependencies`에도 이 leaf가 없고 starter 목록에도 없다." }, { "line": 29179, "text": "" }, { "line": 29180, "text": "런타임 배선: 없음. `runtime_memberships: []`. bean 없음(Spring 주석 0개)." }, { "line": 29181, "text": "" }, { "line": 29182, "text": "**소비자 없음·membership 없음·조립 없음의 삼중 정합**이다 — `messaging-schema-avro`·`messaging-schema-protobuf`와 같은 형태이고, incubating leaf의 올바른 상태다." }, { "line": 29183, "text": "" }, { "line": 29184, "text": "**`messaging-policy`와 `messaging-kafka` 의존이 실제로 쓰이는가.**" }, { "line": 29185, "text": "" }, { "line": 29186, "text": "| 의존 | 사용 |" }, { "line": 29187, "text": "|---|---|" }, { "line": 29188, "text": "| `messaging-core-api` | `OrderingScope`, `DestinationName`, `MessagingCapabilities`, `MessagingCapabilityUnavailableException` — **사용** |" }, { "line": 29189, "text": "| `messaging-transport-spi` | `TransportConsumerRegistration`, `TransportConsumerSpec` — **사용** |" }, { "line": 29190, "text": "| `messaging-policy` | 어떤 타입도 import하지 않음 — **미사용** |" }, { "line": 29191, "text": "| `messaging-kafka` | 어떤 타입도 import하지 않음 — **미사용** |" }, { "line": 29192, "text": "" }, { "line": 29193, "text": "네 project 의존 중 둘, 벤더 의존 하나가 미사용이다. §17." }, { "line": 29194, "text": "" }, { "line": 29195, "text": "---" }, { "line": 29196, "text": "" }, { "line": 29197, "text": "#### 3. 패키지/컴포넌트 지도" }, { "line": 29198, "text": "" }, { "line": 29199, "text": "```" }, { "line": 29200, "text": "KafkaShareProfile (record)" }, { "line": 29201, "text": " destination · shareGroup · orderingScope · enabled · maxDeliveryCount" }, { "line": 29202, "text": " ↓" }, { "line": 29203, "text": "KafkaShareProfileValidator.validate(profile)" }, { "line": 29204, "text": " ├── !enabled → MessagingCapabilityUnavailableException(KAFKA_SHARE_DISABLED)" }, { "line": 29205, "text": " └── orderingScope != NONE → IllegalArgumentException" }, { "line": 29206, "text": " ↓" }, { "line": 29207, "text": "KafkaShareGroupRegistrar.register(profile, spec)" }, { "line": 29208, "text": " └── ShareRegistration implements TransportConsumerRegistration" }, { "line": 29209, "text": " ├── pause(scope) → failedFuture(KAFKA_SHARE_NO_PAUSE)" }, { "line": 29210, "text": " ├── resume(scope) → failedFuture(KAFKA_SHARE_NO_RESUME)" }, { "line": 29211, "text": " ├── isActive() → true until close()" }, { "line": 29212, "text": " └── close() → active = false" }, { "line": 29213, "text": "" }, { "line": 29214, "text": "KafkaShareWorkQueueCapability.capabilities() → MessagingCapabilities(12 booleans)" }, { "line": 29215, "text": "```" }, { "line": 29216, "text": "" }, { "line": 29217, "text": "---" }, { "line": 29218, "text": "" } ], "numbered_context": "29142 | #### 1. 모듈의 정체와 경계\n29143 | \n29144 | Kafka **Share Group**(KIP-932, 경쟁 소비자 work queue)을 실험적 어댑터로 감싼다. `runtime_memberships: []`이고 이름 자체가 `-experimental`이다.\n29145 | \n29146 | 이 leaf의 실질은 **거절**이다. 190줄 중 실제 동작을 하는 코드는 거의 없고, 세 가지를 거절한다.\n29147 | \n29148 | | 거절 | 코드 | 이유 |\n29149 | |---|---|---|\n29150 | | 비활성 상태의 사용 | `KAFKA_SHARE_DISABLED` | experimental이 기본 켜지지 않게 |\n29151 | | 순서 보장 목적지 | `IllegalArgumentException` | share group이 순서를 줄 수 없음 |\n29152 | | pause/resume | `KAFKA_SHARE_NO_PAUSE`/`_NO_RESUME` | 일시정지할 파티션 할당이 없음 |\n29153 | \n29154 | 핵심 진술이 validator javadoc에 있다.\n29155 | \n29156 | ```java\n29157 | // KafkaShareProfileValidator.java:10-17\n29158 | *
A share group hands individual records to competing consumers and acknowledges them\n29159 | * individually. That is a work queue, and it is fundamentally incompatible with partition ordering:\n29160 | * two consumers in the same share group can process records from one partition concurrently and\n29161 | * finish in either order. Configuring an ordered destination on a share group would therefore\n29162 | * advertise a guarantee the broker is not providing, so it is refused rather than degraded.\n29163 | *\n29164 | *
The adapter is also off unless explicitly enabled, so an Experimental capability cannot drift\n29165 | * into a Stable deployment by default.\n29166 | ```\n29167 | \n29168 | 두 번째 문단이 이 저장소의 experimental 정책을 한 문장으로 담는다 — **기본 꺼짐이 drift 방지 수단이다.**\n29169 | \n29170 | ---\n29171 | \n29172 | #### 2. 의존성과 런타임 배선\n29173 | \n29174 | 들어오는 것(project): `messaging-core-api`, `messaging-policy`, `messaging-transport-spi`, `messaging-kafka` — 넷 다 `api`.\n29175 | \n29176 | 들어오는 것(vendor): `org.apache.kafka:kafka-clients`(`implementation`) — **어떤 소스도 import하지 않는다**(§12.4).\n29177 | \n29178 | 나가는 것: **없다.** 어떤 leaf의 `allowed_dependencies`에도 이 leaf가 없고 starter 목록에도 없다.\n29179 | \n29180 | 런타임 배선: 없음. `runtime_memberships: []`. bean 없음(Spring 주석 0개).\n29181 | \n29182 | **소비자 없음·membership 없음·조립 없음의 삼중 정합**이다 — `messaging-schema-avro`·`messaging-schema-protobuf`와 같은 형태이고, incubating leaf의 올바른 상태다.\n29183 | \n29184 | **`messaging-policy`와 `messaging-kafka` 의존이 실제로 쓰이는가.**\n29185 | \n29186 | | 의존 | 사용 |\n29187 | |---|---|\n29188 | | `messaging-core-api` | `OrderingScope`, `DestinationName`, `MessagingCapabilities`, `MessagingCapabilityUnavailableException` — **사용** |\n29189 | | `messaging-transport-spi` | `TransportConsumerRegistration`, `TransportConsumerSpec` — **사용** |\n29190 | | `messaging-policy` | 어떤 타입도 import하지 않음 — **미사용** |\n29191 | | `messaging-kafka` | 어떤 타입도 import하지 않음 — **미사용** |\n29192 | \n29193 | 네 project 의존 중 둘, 벤더 의존 하나가 미사용이다. §17.\n29194 | \n29195 | ---\n29196 | \n29197 | #### 3. 패키지/컴포넌트 지도\n29198 | \n29199 | ```\n29200 | KafkaShareProfile (record)\n29201 | destination · shareGroup · orderingScope · enabled · maxDeliveryCount\n29202 | ↓\n29203 | KafkaShareProfileValidator.validate(profile)\n29204 | ├── !enabled → MessagingCapabilityUnavailableException(KAFKA_SHARE_DISABLED)\n29205 | └── orderingScope != NONE → IllegalArgumentException\n29206 | ↓\n29207 | KafkaShareGroupRegistrar.register(profile, spec)\n29208 | └── ShareRegistration implements TransportConsumerRegistration\n29209 | ├── pause(scope) → failedFuture(KAFKA_SHARE_NO_PAUSE)\n29210 | ├── resume(scope) → failedFuture(KAFKA_SHARE_NO_RESUME)\n29211 | ├── isActive() → true until close()\n29212 | └── close() → active = false\n29213 | \n29214 | KafkaShareWorkQueueCapability.capabilities() → MessagingCapabilities(12 booleans)\n29215 | ```\n29216 | \n29217 | ---\n29218 | ",
"headings": [
{
"line": 1,
"level": 1,
"text": "clean-architecture-backend-template — 상세 분석 (통합 정본)"
},
{
"line": 40,
"level": 2,
"text": "0. 이 문서를 읽는 법"
},
{
"line": 60,
"level": 2,
"text": "1. Project map — 숫자로 먼저"
},
{
"line": 62,
"level": 3,
"text": "1.1 빌드와 레지스트리"
},
{
"line": 81,
"level": 3,
"text": "1.2 가족별 분모와 출하 여부"
},
{
"line": 94,
"level": 3,
"text": "1.3 leaf별 규모 (main Java 기준 상위)"
},
{
"line": 119,
"level": 3,
"text": "1.4 이 표에서 읽어야 할 것"
},
{
"line": 168,
"level": 2,
"text": "2. Architectural boundaries — 무엇이 경계를 강제하는가"
},
{
"line": 173,
"level": 3,
"text": "2.1 강제 장치 목록"
},
{
"line": 189,
"level": 3,
"text": "2.2 `CleanArchitectureTest`의 규칙 14종"
},
{
"line": 212,
"level": 3,
"text": "2.3 검증된 경계 — 실제로 성립하는 것"
},
{
"line": 266,
"level": 3,
"text": "2.4 경계가 열려 있는 지점"
},
{
"line": 300,
"level": 2,
"text": "3. Representative execution paths"
},
{
"line": 302,
"level": 3,
"text": "3.1 HTTP 요청 — 출하 경로"
},
{
"line": 364,
"level": 3,
"text": "3.2 트랜잭션 — `application-core` 포트에서 PostgreSQL local timeout까지"
},
{
"line": 453,
"level": 3,
"text": "3.3 메시지 발행 — messaging 플랫폼"
},
{
"line": 494,
"level": 3,
"text": "3.4 gRPC — 채택 시점 경로"
},
{
"line": 518,
"level": 3,
"text": "3.5 알림 발송 — 논리적 수락과 provider 불확실성"
},
{
"line": 539,
"level": 2,
"text": "4. Data and state"
},
{
"line": 541,
"level": 3,
"text": "4.1 관계형 — `persistence-jpa` (605 파일 / main 350 / 27,744 LOC)"
},
{
"line": 654,
"level": 3,
"text": "4.2 문서형 — `persistence-mongo` (497 파일 / main 351 / 22,924 LOC)"
},
{
"line": 705,
"level": 3,
"text": "4.3 messaging 신뢰성 저장소 (`19` §7)"
},
{
"line": 757,
"level": 3,
"text": "4.4 fileserver / objectstorage / cache-redis"
},
{
"line": 788,
"level": 2,
"text": "5. Failure and operational behavior"
},
{
"line": 790,
"level": 3,
"text": "5.1 실패 분류 — 세 개의 계층"
},
{
"line": 824,
"level": 3,
"text": "5.2 관측 — 태그를 유한하게, 그리고 그 대가"
},
{
"line": 854,
"level": 3,
"text": "5.3 시작 검증기 — 법칙과 그 예외"
},
{
"line": 903,
"level": 3,
"text": "5.4 admin plane — 가장 잘 조립된 게이트"
},
{
"line": 939,
"level": 3,
"text": "5.5 gRPC 구현 층의 원자성 (`20` §7)"
},
{
"line": 1011,
"level": 2,
"text": "6. Tests and verification coverage"
},
{
"line": 1013,
"level": 3,
"text": "6.1 실행한 것"
},
{
"line": 1025,
"level": 3,
"text": "6.2 실행하지 않은 것과 그 이유"
},
{
"line": 1047,
"level": 3,
"text": "6.3 fail-closed 레인 규약"
},
{
"line": 1071,
"level": 3,
"text": "6.4 완전히 닫힌 게이트 하나 — messaging 인증 체인"
},
{
"line": 1111,
"level": 3,
"text": "6.5 evidence manifest — JPA의 R1/R2 분리"
},
{
"line": 1125,
"level": 3,
"text": "6.6 게이트가 통과하면서 아무것도 증명하지 않는 경우 — 14건"
},
{
"line": 1156,
"level": 2,
"text": "7. 이 저장소에서 반복된 네 가지 형태"
},
{
"line": 1160,
"level": 3,
"text": "7.1 형태 A — 판정하는 코드는 있고, 부르는 코드가 없다"
},
{
"line": 1203,
"level": 3,
"text": "7.2 형태 B — 게이트가 통과하면서 아무것도 증명하지 않는다"
},
{
"line": 1214,
"level": 3,
"text": "7.3 형태 C — 중복 장치에서 조립된 쪽이 약한 쪽이다"
},
{
"line": 1239,
"level": 3,
"text": "7.4 형태 D — 문서 드리프트, 그리고 그 방향"
},
{
"line": 1274,
"level": 3,
"text": "7.5 공시 스펙트럼 — 자기 미완성을 얼마나 말했는가"
},
{
"line": 1289,
"level": 3,
"text": "7.6 학습 전이 — messaging → grpc"
},
{
"line": 1308,
"level": 2,
"text": "8. Confirmed problems"
},
{
"line": 1310,
"level": 3,
"text": "8.1 P1 — 지금 출하되는 아티팩트에서 틀린 동작"
},
{
"line": 1349,
"level": 3,
"text": "8.2 P2 — 명확한 실패 시나리오를 가진 실질적 공백"
},
{
"line": 1392,
"level": 3,
"text": "8.3 심각도가 등급 때문에 낮아진 것"
},
{
"line": 1403,
"level": 2,
"text": "9. Reusable criteria and rules"
},
{
"line": 1452,
"level": 2,
"text": "10. Explicit project decisions"
},
{
"line": 1457,
"level": 3,
"text": "10.1 계약과 경계"
},
{
"line": 1468,
"level": 3,
"text": "10.2 실패와 불확실성"
},
{
"line": 1480,
"level": 3,
"text": "10.3 조립과 활성화"
},
{
"line": 1492,
"level": 3,
"text": "10.4 데이터와 경계값"
},
{
"line": 1506,
"level": 3,
"text": "10.5 증거와 게이트"
},
{
"line": 1523,
"level": 2,
"text": "11. Unresolved questions"
},
{
"line": 1564,
"level": 2,
"text": "12. Evidence index"
},
{
"line": 1581,
"level": 2,
"text": "13. Limits of this analysis"
},
{
"line": 1632,
"level": 2,
"text": "14. 사이클 2 — 18개 리프 재검증과 23개 리프 전수 통독"
},
{
"line": 1634,
"level": 3,
"text": "14.1 18개 리프 재검증"
},
{
"line": 1668,
"level": 3,
"text": "14.2 23개 리프 전수 통독"
},
{
"line": 1747,
"level": 2,
"text": "부록 A. 모듈 문서 지도"
},
{
"line": 1779,
"level": 2,
"text": "부록 B. 자주 쓸 명령"
},
{
"line": 1825,
"level": 2,
"text": "부록 C. 다시 읽는다면 이 순서"
},
{
"line": 1839,
"level": 1,
"text": "제2부 — 모듈 분석 전문"
},
{
"line": 1845,
"level": 2,
"text": "A00. project-overview"
},
{
"line": 1849,
"level": 3,
"text": "Project Overview"
},
{
"line": 1856,
"level": 4,
"text": "분석 기준 revision"
},
{
"line": 1867,
"level": 4,
"text": "최종 커버리지"
},
{
"line": 1884,
"level": 4,
"text": "Build and module map"
},
{
"line": 1939,
"level": 4,
"text": "Dependency direction"
},
{
"line": 1945,
"level": 4,
"text": "Runtime entry points"
},
{
"line": 1951,
"level": 4,
"text": "Persistence / messaging / external systems"
},
{
"line": 1955,
"level": 4,
"text": "Test topology"
},
{
"line": 1960,
"level": 4,
"text": "Configuration and operational surfaces"
},
{
"line": 1964,
"level": 4,
"text": "분석할 bounded scopes (계획 — 실제 문서 배치는 위 \"최종 커버리지\" 참조)"
},
{
"line": 1977,
"level": 4,
"text": "아직 단정하지 않는 것 (분석 시작 시점의 목록)"
},
{
"line": 1993,
"level": 2,
"text": "A01. domain-core"
},
{
"line": 1997,
"level": 3,
"text": "domain-core 상세 분석"
},
{
"line": 2000,
"level": 4,
"text": "SSOT identity — 2026-08-31 재검증"
},
{
"line": 2015,
"level": 4,
"text": "분석 범위와 결론 상태"
},
{
"line": 2026,
"level": 4,
"text": "1. Quantified scope map"
},
{
"line": 2028,
"level": 5,
"text": "Owned source"
},
{
"line": 2042,
"level": 4,
"text": "2. Coverage ledger"
},
{
"line": 2062,
"level": 4,
"text": "3. 이 모듈이 실제로 소유하는 것"
},
{
"line": 2064,
"level": 5,
"text": "관찰: 재사용 가능한 도메인 “내용”보다 도메인 모델링 계약을 소유한다"
},
{
"line": 2073,
"level": 4,
"text": "4. Identifier contract"
},
{
"line": 2075,
"level": 5,
"text": "`ResourceId