Files
clean-architecture-backend-…/docs/superpowers/plans/2026-08-11-mongodb-advanced-capabilities-expansion-plan.md
T

1140 lines
59 KiB
Markdown

# MongoDB Advanced Capabilities Expansion Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Stable MongoDB 문서 영속성 플랫폼의 공개 계약을 변경하지 않고 Sharding, Time Series, CSFLE, Queryable Encryption, Search, Vector Search, Multi-tenancy, Change Stream Messaging Bridge와 GridFS migration compatibility를 선택 모듈로 구현한다.
**Architecture:** 모든 기능은 `modules/mongodb-advanced`에 격리되고 명시적 feature flag, 별도 privilege, 별도 topology 또는 provider gate를 요구한다. Stable Starter는 이 모듈을 자동 의존하지 않는다. Application-plane descriptor/guardrail과 Admin-plane topology/index/key 변경을 분리한다.
**Tech Stack:** Stable MongoDB platform, Java 21, Spring Boot 4.1 BOM, Spring Data MongoDB 5.1, MongoDB 8.0 primary lane, actual Sharded Cluster, Atlas Local, actual target Atlas/KMS environments, existing Messaging and Object Storage platforms.
## Global Constraints
- Stable Task 1~50과 Stable Release Gate가 먼저 통과해야 한다.
- Advanced module root는 `modules/mongodb-advanced`이다.
- 모든 기능은 `backend.mongodb.advanced.<capability>.enabled=true`를 요구한다.
- Advanced 모듈은 Stable Starter의 transitive dependency가 아니다.
- Sharding, Search, Encryption, Migration과 Tenant administration은 별도 credential을 사용한다.
- Time Series는 일반 Collection capability를 상속하지 않는다.
- CSFLE와 Queryable Encryption을 같은 Collection에 동시에 적용하지 않는다.
- MongoDB 8.0 Stable에서 QE prefix/suffix/substring query를 지원하지 않는다.
- Search/Vector index creation과 READY 상태를 분리한다.
- Shared Collection tenancy는 tenant context 누락 시 fail-closed다.
- Database-per-tenant는 client/migration concurrency를 제한한다.
- Change Stream 원본을 Messaging 외부 계약으로 직접 발행하지 않는다.
- GridFS는 legacy read/migration compatibility 전용이다.
- 승격에는 실제 topology/provider, security, failure, migration, performance와 runbook evidence가 필요하다.
---
### Task 1: Advanced 모듈·Feature Flag·Dependency 격리 구성
**Files:**
- Create: `build-logic/src/main/kotlin/mongodb-advanced-library-conventions.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-sharding/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-timeseries/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-csfle/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-queryable-encryption/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-search/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-vector-search/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-tenancy-shared/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-tenancy-database/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-gridfs-compat/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-testkit-sharded/build.gradle.kts`
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/build.gradle.kts`
- Modify: `settings.gradle.kts`
- Test: `build-logic/src/test/java/MongoDbAdvancedModuleBoundaryTest.java`
**Interfaces:**
- Consumes: Completed Stable Tasks 1~50 and Stable release evidence.
- Produces: 12 opt-in modules under `modules/mongodb-advanced` with explicit feature flags and no Stable Starter dependency.
**Implementation requirements:**
- Require Stable Release Gate evidence before advanced test suites run.
- Every capability requires `backend.mongodb.advanced.<capability>.enabled=true`.
- No advanced module may be a transitive dependency of mongodb-spring-boot-starter.
- Admin privileges and actual target-environment tests are capability-specific.
- Promotion to Stable requires a separate ADR and evidence package.
- [ ] **Step 1: Write the failing test**
```java
class MongoDbAdvancedModuleBoundaryTest {
@org.junit.jupiter.api.Test
void stableStarterHasNoAdvancedDependency() {
org.assertj.core.api.Assertions.assertThat(
MongoAdvancedBuildModel.dependenciesOf("mongodb-spring-boot-starter"))
.noneMatch(it -> it.startsWith("mongodb-advanced"));
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew build-logic:test --tests 'MongoDbAdvancedModuleBoundaryTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public final class MongoAdvancedBuildModel {
public static boolean enabled(String capability, java.util.Map<String,Boolean> flags) {
return Boolean.TRUE.equals(flags.get(capability));
}
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew build-logic:test --tests 'MongoDbAdvancedModuleBoundaryTest'
./gradlew :modules:mongodb-advanced:mongodb-sharding:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'build-logic/src/main/kotlin/mongodb-advanced-library-conventions.gradle.kts' 'modules/mongodb-advanced/mongodb-sharding/build.gradle.kts' 'modules/mongodb-advanced/mongodb-timeseries/build.gradle.kts' 'modules/mongodb-advanced/mongodb-csfle/build.gradle.kts' 'modules/mongodb-advanced/mongodb-queryable-encryption/build.gradle.kts' 'modules/mongodb-advanced/mongodb-search/build.gradle.kts' 'modules/mongodb-advanced/mongodb-vector-search/build.gradle.kts' 'modules/mongodb-advanced/mongodb-tenancy-shared/build.gradle.kts' 'modules/mongodb-advanced/mongodb-tenancy-database/build.gradle.kts' 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/build.gradle.kts' 'modules/mongodb-advanced/mongodb-gridfs-compat/build.gradle.kts' 'modules/mongodb-advanced/mongodb-testkit-sharded/build.gradle.kts' 'modules/mongodb-advanced/mongodb-testkit-atlas/build.gradle.kts' 'settings.gradle.kts' 'build-logic/src/test/java/MongoDbAdvancedModuleBoundaryTest.java'
git commit -m "build: add isolated mongodb advanced modules"
```
### Task 2: Shard Key Descriptor와 Targeted Query Validator 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardKeyDescriptor.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardKeyPart.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardStrategy.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardAwareQueryValidator.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/MongoRoutingClassification.java`
- Test: `modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/sharding/ShardAwareQueryValidatorTest.java`
**Interfaces:**
- Consumes: Stable collection/query/index manifests and operation contexts.
- Produces: Application-plane classification of targeted, prefix-targeted and scatter-gather queries.
**Implementation requirements:**
- Descriptor must preserve compound shard-key order and hashed/range strategy.
- Single-document writes must include routing evidence required by the server version and collection profile.
- Unique indexes must be checked for shard-key compatibility.
- Scatter-gather operations require an explicit reviewed profile and telemetry.
- Do not execute shardCollection, refine or reshard through this module.
- [ ] **Step 1: Write the failing test**
```java
class ShardAwareQueryValidatorTest {
@org.junit.jupiter.api.Test
void classifiesMissingShardKeyAsScatterGather() {
ShardKeyDescriptor key = ShardKeyDescriptor.range("tenantId", "orderId");
MongoRoutingClassification result =
new ShardAwareQueryValidator().classify(key, java.util.Set.of("status"));
org.assertj.core.api.Assertions.assertThat(result)
.isEqualTo(MongoRoutingClassification.SCATTER_GATHER);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-sharding:test --tests 'io.backend.skeleton.mongodb.advanced.sharding.ShardAwareQueryValidatorTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public enum MongoRoutingClassification {
TARGETED, PREFIX_TARGETED, SCATTER_GATHER, REJECTED
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-sharding:test --tests 'io.backend.skeleton.mongodb.advanced.sharding.ShardAwareQueryValidatorTest'
./gradlew :modules:mongodb-advanced:mongodb-sharding:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardKeyDescriptor.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardKeyPart.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardStrategy.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/ShardAwareQueryValidator.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/MongoRoutingClassification.java' 'modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/sharding/ShardAwareQueryValidatorTest.java'
git commit -m "feat: add mongodb shard aware query validation"
```
### Task 3: analyzeShardKey Readiness Report와 D4 Sharding Admin 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyReadinessReport.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyAnalyzer.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/MongoShardingAdminGateway.java`
- Create: `modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ReshardApproval.java`
- Test: `modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyAnalyzerTest.java`
**Interfaces:**
- Consumes: Shard descriptors, D4 admin security and actual server sampling.
- Produces: Cardinality, frequency, monotonicity, read/write distribution and reshard readiness evidence.
**Implementation requirements:**
- Run analyzeShardKey only through a shard-admin credential.
- Report cardinality, frequency, monotonicity, skew and sampled routing distribution.
- Require supporting index and query-manifest coverage before shardCollection approval.
- Refine and reshard require dry-run, operator reason, rollback/forward strategy and audit.
- Balancer, zones and shard add/remove remain explicit Admin operations.
- [ ] **Step 1: Write the failing test**
```java
class ShardKeyAnalyzerTest {
@org.junit.jupiter.api.Test
void rejectsLowCardinalityCandidate() {
ShardKeyReadinessReport report = ShardKeyReadinessReport.lowCardinality("status");
org.assertj.core.api.Assertions.assertThat(report.approved()).isFalse();
org.assertj.core.api.Assertions.assertThat(report.reasons())
.contains("LOW_CARDINALITY");
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-sharding:test --tests 'io.backend.skeleton.mongodb.advanced.sharding.admin.ShardKeyAnalyzerTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public record ShardKeyReadinessReport(
boolean approved,
java.util.Set<String> reasons,
double monotonicity,
double readTargetingRatio,
double writeTargetingRatio) {
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-sharding:test --tests 'io.backend.skeleton.mongodb.advanced.sharding.admin.ShardKeyAnalyzerTest'
./gradlew :modules:mongodb-advanced:mongodb-sharding:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyReadinessReport.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyAnalyzer.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/MongoShardingAdminGateway.java' 'modules/mongodb-advanced/mongodb-sharding/src/main/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ReshardApproval.java' 'modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/sharding/admin/ShardKeyAnalyzerTest.java'
git commit -m "feat: add mongodb shard key readiness and admin gate"
```
### Task 4: 실제 Sharded Cluster Testkit과 Chunk Migration 계약 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardedCluster.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoChunkMigrationController.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardingContractSuite.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-sharded/src/test/resources/mongodb/init-sharded-cluster.js`
- Test: `modules/mongodb-advanced/mongodb-testkit-sharded/src/test/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardingContractSuiteTest.java`
**Interfaces:**
- Consumes: Sharding module, Testcontainers/Docker and Stable platform contracts.
- Produces: Actual mongos/config-server/shard topology tests for targeting, migration, failover and cross-shard transactions.
**Implementation requirements:**
- Run at least two shards and a replicated config server for release evidence.
- Verify targeted versus scatter-gather execution through explain and telemetry.
- Move chunks while reads, writes and change streams are active.
- Test shard-key-missing single-document updates and unique-index restrictions.
- Test cross-shard transaction failure and recovery without hiding latency cost.
- [ ] **Step 1: Write the failing test**
```java
class MongoShardingContractSuiteTest {
@org.junit.jupiter.api.Test
void targetedQueryTouchesOneShard() {
MongoShardingReport report = MongoShardingContractSuite.runTargetedQuery();
org.assertj.core.api.Assertions.assertThat(report.shardsExamined()).isEqualTo(1);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-testkit-sharded:test --tests 'io.backend.skeleton.mongodb.advanced.testkit.sharded.MongoShardingContractSuiteTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public interface MongoShardingContractSuite {
static MongoShardingReport runTargetedQuery() {
return new MongoShardingReport(1, MongoRoutingClassification.TARGETED);
}
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-testkit-sharded:test --tests 'io.backend.skeleton.mongodb.advanced.testkit.sharded.MongoShardingContractSuiteTest'
./gradlew :modules:mongodb-advanced:mongodb-testkit-sharded:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardedCluster.java' 'modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoChunkMigrationController.java' 'modules/mongodb-advanced/mongodb-testkit-sharded/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardingContractSuite.java' 'modules/mongodb-advanced/mongodb-testkit-sharded/src/test/resources/mongodb/init-sharded-cluster.js' 'modules/mongodb-advanced/mongodb-testkit-sharded/src/test/java/io/backend/skeleton/mongodb/advanced/testkit/sharded/MongoShardingContractSuiteTest.java'
git commit -m "test: add mongodb sharded cluster contract suite"
```
### Task 5: Time Series 전용 Collection·Write·Query 계약 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesDescriptor.java`
- Create: `modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesGranularity.java`
- Create: `modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesOperations.java`
- Create: `modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesCapabilityValidator.java`
- Test: `modules/mongodb-advanced/mongodb-timeseries/src/test/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesCapabilityValidatorTest.java`
**Interfaces:**
- Consumes: Stable manifests, D4 collection setup and MongoDB 8.0 capability reports.
- Produces: Separate timeField/metaField/granularity/bucket/TTL API that does not inherit general collection capabilities.
**Implementation requirements:**
- Reject schema validator, change stream, CSFLE, search and transaction-write combinations.
- Require explicit timeField, optional metaField and bounded granularity/bucket settings.
- Validate server-version-specific sharding restrictions.
- Expose TTL as time-series retention, not an exact scheduler.
- Test document-size and update limitations separately from normal collections.
- [ ] **Step 1: Write the failing test**
```java
class MongoTimeSeriesCapabilityValidatorTest {
@org.junit.jupiter.api.Test
void rejectsChangeStreamOnTimeSeries() {
MongoTimeSeriesDescriptor descriptor = MongoTimeSeriesDescriptor.standard("observedAt", "sensor");
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
new MongoTimeSeriesCapabilityValidator().requireChangeStream(descriptor))
.isInstanceOf(UnsupportedOperationException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-timeseries:test --tests 'io.backend.skeleton.mongodb.advanced.timeseries.MongoTimeSeriesCapabilityValidatorTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public record MongoTimeSeriesDescriptor(
String timeField,
String metaField,
MongoTimeSeriesGranularity granularity,
java.time.Duration retention) {
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-timeseries:test --tests 'io.backend.skeleton.mongodb.advanced.timeseries.MongoTimeSeriesCapabilityValidatorTest'
./gradlew :modules:mongodb-advanced:mongodb-timeseries:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesDescriptor.java' 'modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesGranularity.java' 'modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesOperations.java' 'modules/mongodb-advanced/mongodb-timeseries/src/main/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesCapabilityValidator.java' 'modules/mongodb-advanced/mongodb-timeseries/src/test/java/io/backend/skeleton/mongodb/advanced/timeseries/MongoTimeSeriesCapabilityValidatorTest.java'
git commit -m "feat: add mongodb time series capability"
```
### Task 6: CSFLE Automatic·Explicit Encryption 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleProfile.java`
- Create: `modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleFieldPolicy.java`
- Create: `modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoDataKeyResolver.java`
- Create: `modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleClientFactory.java`
- Test: `modules/mongodb-advanced/mongodb-csfle/src/test/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleFieldPolicyTest.java`
**Interfaces:**
- Consumes: Security profiles, D4 admin client, BSON manifest and actual KMS/key-vault fixtures.
- Produces: Randomized/deterministic field encryption with key resolver and no plaintext telemetry.
**Implementation requirements:**
- Randomized encryption is the default for non-queryable PII.
- Deterministic encryption requires a documented equality-query requirement and leakage review.
- Key-vault access uses a dedicated principal.
- Plaintext fields, KMS material and data keys never enter logs, traces or failure metadata.
- CSFLE cannot be enabled on a time-series collection or mixed with QE on the same collection.
- [ ] **Step 1: Write the failing test**
```java
class MongoCsfleFieldPolicyTest {
@org.junit.jupiter.api.Test
void nonQueryablePiiDefaultsToRandomizedEncryption() {
MongoCsfleFieldPolicy policy = MongoCsfleFieldPolicy.forPii("ssn", false);
org.assertj.core.api.Assertions.assertThat(policy.mode())
.isEqualTo(MongoCsfleMode.RANDOMIZED);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-csfle:test --tests 'io.backend.skeleton.mongodb.advanced.encryption.csfle.MongoCsfleFieldPolicyTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public record MongoCsfleFieldPolicy(
String fieldPath,
MongoCsfleMode mode,
String keyAlias) {
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-csfle:test --tests 'io.backend.skeleton.mongodb.advanced.encryption.csfle.MongoCsfleFieldPolicyTest'
./gradlew :modules:mongodb-advanced:mongodb-csfle:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleProfile.java' 'modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleFieldPolicy.java' 'modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoDataKeyResolver.java' 'modules/mongodb-advanced/mongodb-csfle/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleClientFactory.java' 'modules/mongodb-advanced/mongodb-csfle/src/test/java/io/backend/skeleton/mongodb/advanced/encryption/csfle/MongoCsfleFieldPolicyTest.java'
git commit -m "feat: add mongodb csfle capability"
```
### Task 7: Queryable Encryption Equality·Range 계약 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionProfile.java`
- Create: `modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoEncryptedFieldDescriptor.java`
- Create: `modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionCollectionManager.java`
- Create: `modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoEncryptionMetadataOwnership.java`
- Test: `modules/mongodb-advanced/mongodb-queryable-encryption/src/test/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionProfileTest.java`
**Interfaces:**
- Consumes: Security, D4 admin, schema/index ownership and KMS test environment.
- Produces: QE equality and range profiles with protected internal metadata ownership.
**Implementation requirements:**
- MongoDB 8.0 Stable supports equality and range only.
- Prefix, suffix and substring query profiles are rejected.
- Encrypted collection setup is a D4 operation completed before application writes.
- Mark `__safeContent__` and internal metadata collections as ENCRYPTION_MANAGED.
- Key rotation and compaction/cleanup require separate runbooks and evidence.
- [ ] **Step 1: Write the failing test**
```java
class MongoQueryableEncryptionProfileTest {
@org.junit.jupiter.api.Test
void mongoEightRejectsSubstringQueryableEncryption() {
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
MongoQueryableEncryptionProfile.substring("name"))
.isInstanceOf(UnsupportedOperationException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-queryable-encryption:test --tests 'io.backend.skeleton.mongodb.advanced.encryption.qe.MongoQueryableEncryptionProfileTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public enum MongoQueryableEncryptionQueryType { EQUALITY, RANGE }
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-queryable-encryption:test --tests 'io.backend.skeleton.mongodb.advanced.encryption.qe.MongoQueryableEncryptionProfileTest'
./gradlew :modules:mongodb-advanced:mongodb-queryable-encryption:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionProfile.java' 'modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoEncryptedFieldDescriptor.java' 'modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionCollectionManager.java' 'modules/mongodb-advanced/mongodb-queryable-encryption/src/main/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoEncryptionMetadataOwnership.java' 'modules/mongodb-advanced/mongodb-queryable-encryption/src/test/java/io/backend/skeleton/mongodb/advanced/encryption/qe/MongoQueryableEncryptionProfileTest.java'
git commit -m "feat: add mongodb queryable encryption equality and range"
```
### Task 8: MongoDB Search Query·Index Readiness 계약 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchIndexDescriptor.java`
- Create: `modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchIndexState.java`
- Create: `modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchQuery.java`
- Create: `modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchOperations.java`
- Create: `modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchReadinessGate.java`
- Test: `modules/mongodb-advanced/mongodb-search/src/test/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchReadinessGateTest.java`
**Interfaces:**
- Consumes: Aggregation guardrails, D4 admin and Atlas environment capability.
- Produces: Search indexes with CREATED/BUILDING/READY/FAILED states and bounded typed queries.
**Implementation requirements:**
- Index creation success is not equivalent to READY.
- Application search queries run only against an index proven READY.
- Search query paths and operators are allowlisted.
- Actual target deployment validates analyzers, relevance and latency.
- Legacy `$text` remains compatibility-only and is not silently redirected to Search.
- [ ] **Step 1: Write the failing test**
```java
class MongoSearchReadinessGateTest {
@org.junit.jupiter.api.Test
void buildingIndexCannotServeTraffic() {
MongoSearchReadinessGate gate = new MongoSearchReadinessGate();
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
gate.requireReady(MongoSearchIndexState.BUILDING))
.isInstanceOf(MongoOperationRejectedException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-search:test --tests 'io.backend.skeleton.mongodb.advanced.search.MongoSearchReadinessGateTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public enum MongoSearchIndexState { CREATED, BUILDING, READY, FAILED, DELETING }
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-search:test --tests 'io.backend.skeleton.mongodb.advanced.search.MongoSearchReadinessGateTest'
./gradlew :modules:mongodb-advanced:mongodb-search:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchIndexDescriptor.java' 'modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchIndexState.java' 'modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchQuery.java' 'modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchOperations.java' 'modules/mongodb-advanced/mongodb-search/src/main/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchReadinessGate.java' 'modules/mongodb-advanced/mongodb-search/src/test/java/io/backend/skeleton/mongodb/advanced/search/MongoSearchReadinessGateTest.java'
git commit -m "feat: add mongodb search readiness contract"
```
### Task 9: Vector Search와 Embedding·Score 계약 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorIndexDescriptor.java`
- Create: `modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoEmbedding.java`
- Create: `modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorQuery.java`
- Create: `modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorSearchOperations.java`
- Create: `modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorSearchBenchmarkGate.java`
- Test: `modules/mongodb-advanced/mongodb-vector-search/src/test/java/io/backend/skeleton/mongodb/advanced/vector/MongoEmbeddingTest.java`
**Interfaces:**
- Consumes: Search readiness, operation budgets and Atlas test environment.
- Produces: Typed embedding dimension, similarity metric, candidate/result limits and benchmark evidence.
**Implementation requirements:**
- Embedding dimension must exactly match the registered index.
- Similarity metric and score interpretation are part of the index contract.
- Bound numCandidates, result count, filter fields and timeout.
- Do not return raw provider score without a named score contract.
- Actual deployment benchmarks accuracy, latency, memory and index readiness.
- [ ] **Step 1: Write the failing test**
```java
class MongoEmbeddingTest {
@org.junit.jupiter.api.Test
void rejectsDimensionMismatch() {
MongoVectorIndexDescriptor index = MongoVectorIndexDescriptor.cosine("embedding", 3);
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
MongoEmbedding.forIndex(index, new float[]{1f, 2f}))
.isInstanceOf(IllegalArgumentException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-vector-search:test --tests 'io.backend.skeleton.mongodb.advanced.vector.MongoEmbeddingTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public record MongoEmbedding(float[] values) {
public MongoEmbedding { values = values.clone(); }
@Override public float[] values() { return values.clone(); }
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-vector-search:test --tests 'io.backend.skeleton.mongodb.advanced.vector.MongoEmbeddingTest'
./gradlew :modules:mongodb-advanced:mongodb-vector-search:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorIndexDescriptor.java' 'modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoEmbedding.java' 'modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorQuery.java' 'modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorSearchOperations.java' 'modules/mongodb-advanced/mongodb-vector-search/src/main/java/io/backend/skeleton/mongodb/advanced/vector/MongoVectorSearchBenchmarkGate.java' 'modules/mongodb-advanced/mongodb-vector-search/src/test/java/io/backend/skeleton/mongodb/advanced/vector/MongoEmbeddingTest.java'
git commit -m "feat: add mongodb vector search contract"
```
### Task 10: Shared Collection Multi-tenancy Guardrail 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantContext.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/TenantScopedMongoOperations.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantPredicateInjector.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantManifestValidator.java`
- Test: `modules/mongodb-advanced/mongodb-tenancy-shared/src/test/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantPredicateInjectorTest.java`
**Interfaces:**
- Consumes: Stable query/aggregation/index/change-stream modules and security context.
- Produces: Fail-closed tenant predicate injection for find, update, delete, aggregation and change-stream projection.
**Implementation requirements:**
- Missing tenant context rejects all tenant-scoped operations.
- Inject tenant predicate into find/update/delete and require a bounded first-stage match for aggregation.
- Validate tenant participation in unique indexes when uniqueness is tenant-scoped.
- Do not assume tenantId is always the correct shard key; use shard-key analysis.
- Never expose raw tenant IDs in metrics or general logs.
- [ ] **Step 1: Write the failing test**
```java
class MongoTenantPredicateInjectorTest {
@org.junit.jupiter.api.Test
void missingTenantContextFailsClosed() {
MongoTenantPredicateInjector injector = new MongoTenantPredicateInjector();
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
injector.apply(java.util.Optional.empty(), AtomicFilter.id("o-1")))
.isInstanceOf(MongoOperationRejectedException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-tenancy-shared:test --tests 'io.backend.skeleton.mongodb.advanced.tenancy.shared.MongoTenantPredicateInjectorTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public record MongoTenantContext(String opaqueTenantKey) {
public MongoTenantContext {
if (opaqueTenantKey == null || opaqueTenantKey.isBlank()) {
throw new IllegalArgumentException("tenant context required");
}
}
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-tenancy-shared:test --tests 'io.backend.skeleton.mongodb.advanced.tenancy.shared.MongoTenantPredicateInjectorTest'
./gradlew :modules:mongodb-advanced:mongodb-tenancy-shared:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantContext.java' 'modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/TenantScopedMongoOperations.java' 'modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantPredicateInjector.java' 'modules/mongodb-advanced/mongodb-tenancy-shared/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantManifestValidator.java' 'modules/mongodb-advanced/mongodb-tenancy-shared/src/test/java/io/backend/skeleton/mongodb/advanced/tenancy/shared/MongoTenantPredicateInjectorTest.java'
git commit -m "feat: add shared collection mongodb tenancy guardrails"
```
### Task 11: Database-per-tenant Routing·Migration·Client Lifecycle 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantDatabaseResolver.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantClientRegistry.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantMigrationCoordinator.java`
- Create: `modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantLifecyclePolicy.java`
- Test: `modules/mongodb-advanced/mongodb-tenancy-database/src/test/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantClientRegistryTest.java`
**Interfaces:**
- Consumes: Stable profile/client generation, migration core and security modules.
- Produces: Bounded tenant database routing, client caching, migration fan-out and offboarding lifecycle.
**Implementation requirements:**
- Tenant-to-database mapping comes from a trusted registry, never request input.
- Bound cached clients and close idle generations.
- Migration fan-out uses concurrency and rate limits with per-tenant checkpoints.
- A tenant database cannot become active before schema/index validation succeeds.
- Offboarding requires retention, export and delete evidence.
- [ ] **Step 1: Write the failing test**
```java
class MongoTenantClientRegistryTest {
@org.junit.jupiter.api.Test
void registryEnforcesMaximumActiveClients() {
MongoTenantClientRegistry registry = new MongoTenantClientRegistry(2);
registry.acquire("t1");
registry.acquire("t2");
org.assertj.core.api.Assertions.assertThatThrownBy(() -> registry.acquire("t3"))
.isInstanceOf(MongoOperationRejectedException.class);
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-tenancy-database:test --tests 'io.backend.skeleton.mongodb.advanced.tenancy.database.MongoTenantClientRegistryTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public interface MongoTenantDatabaseResolver {
DatabaseProfileName resolve(MongoTenantContext tenant);
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-tenancy-database:test --tests 'io.backend.skeleton.mongodb.advanced.tenancy.database.MongoTenantClientRegistryTest'
./gradlew :modules:mongodb-advanced:mongodb-tenancy-database:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantDatabaseResolver.java' 'modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantClientRegistry.java' 'modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantMigrationCoordinator.java' 'modules/mongodb-advanced/mongodb-tenancy-database/src/main/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantLifecyclePolicy.java' 'modules/mongodb-advanced/mongodb-tenancy-database/src/test/java/io/backend/skeleton/mongodb/advanced/tenancy/database/MongoTenantClientRegistryTest.java'
git commit -m "feat: add database per tenant mongodb lifecycle"
```
### Task 12: Change Stream → Messaging 안정 Bridge 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeToIntegrationEventMapper.java`
- Create: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeMessagingBridge.java`
- Create: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoBridgeOutboxPolicy.java`
- Create: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoBridgeCheckpointPolicy.java`
- Test: `modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/test/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeMessagingBridgeTest.java`
**Interfaces:**
- Consumes: Stable Change Stream projector and the existing Messaging Platform typed publisher.
- Produces: Mapping of physical changes to versioned integration events with idempotent publish/checkpoint semantics.
**Implementation requirements:**
- Never publish raw MongoDB change events as external contracts.
- Integration event type, schema version and message ID are mapper-owned stable values.
- Publish and checkpoint ambiguity must preserve duplicate-safe message identity.
- Document where Change Stream bridge is insufficient and Transactional Outbox is required.
- Messaging failures must not silently advance the MongoDB checkpoint.
- [ ] **Step 1: Write the failing test**
```java
class MongoChangeMessagingBridgeTest {
@org.junit.jupiter.api.Test
void failedPublishDoesNotAdvanceMongoCheckpoint() {
MongoBridgeProbe probe = MongoBridgeProbe.publishFails();
probe.bridge().handle(probe.change()).block();
org.assertj.core.api.Assertions.assertThat(probe.checkpointWrites()).isZero();
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-change-stream-messaging-bridge:test --tests 'io.backend.skeleton.mongodb.advanced.bridge.MongoChangeMessagingBridgeTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public interface MongoChangeToIntegrationEventMapper {
MessagingEnvelope map(MongoChangeEventIdentity identity, org.bson.BsonDocument change);
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-change-stream-messaging-bridge:test --tests 'io.backend.skeleton.mongodb.advanced.bridge.MongoChangeMessagingBridgeTest'
./gradlew :modules:mongodb-advanced:mongodb-change-stream-messaging-bridge:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeToIntegrationEventMapper.java' 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeMessagingBridge.java' 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoBridgeOutboxPolicy.java' 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/main/java/io/backend/skeleton/mongodb/advanced/bridge/MongoBridgeCheckpointPolicy.java' 'modules/mongodb-advanced/mongodb-change-stream-messaging-bridge/src/test/java/io/backend/skeleton/mongodb/advanced/bridge/MongoChangeMessagingBridgeTest.java'
git commit -m "feat: add mongodb change stream messaging bridge"
```
### Task 13: GridFS Legacy Compatibility와 Object Storage Migration Adapter 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsCompatibilityReader.java`
- Create: `modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationJob.java`
- Create: `modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationCheckpoint.java`
- Create: `modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsObjectReference.java`
- Test: `modules/mongodb-advanced/mongodb-gridfs-compat/src/test/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationJobTest.java`
**Interfaces:**
- Consumes: Fileserver/Object Storage ContentStore contract and migration core.
- Produces: Read-only legacy GridFS compatibility plus resumable migration to the single file source of truth.
**Implementation requirements:**
- Do not expose new upload APIs backed by GridFS.
- Read GridFS metadata and bytes without creating a second domain file lifecycle.
- Migrate bytes to ContentStore, verify size/checksum, then write the new FileId/ContentKey reference.
- Checkpoint migration and preserve retry-safe deterministic identities.
- Delete legacy GridFS content only through a separate audited cleanup phase.
- [ ] **Step 1: Write the failing test**
```java
class MongoGridFsMigrationJobTest {
@org.junit.jupiter.api.Test
void sourceIsRetainedUntilTargetChecksumIsVerified() {
MongoGridFsMigrationProbe probe = MongoGridFsMigrationProbe.checksumMismatch();
probe.job().migrate(probe.sourceId());
org.assertj.core.api.Assertions.assertThat(probe.sourceDeleted()).isFalse();
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-gridfs-compat:test --tests 'io.backend.skeleton.mongodb.advanced.gridfs.MongoGridFsMigrationJobTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public interface MongoGridFsCompatibilityReader {
GridFsLegacyContent open(String legacyId);
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-gridfs-compat:test --tests 'io.backend.skeleton.mongodb.advanced.gridfs.MongoGridFsMigrationJobTest'
./gradlew :modules:mongodb-advanced:mongodb-gridfs-compat:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsCompatibilityReader.java' 'modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationJob.java' 'modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationCheckpoint.java' 'modules/mongodb-advanced/mongodb-gridfs-compat/src/main/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsObjectReference.java' 'modules/mongodb-advanced/mongodb-gridfs-compat/src/test/java/io/backend/skeleton/mongodb/advanced/gridfs/MongoGridFsMigrationJobTest.java'
git commit -m "feat: add gridfs compatibility migration adapter"
```
### Task 14: Atlas Local·실제 Atlas Search·Vector·Encryption Testkit 구현
**Files:**
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasLocalContainer.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasCapabilityContractSuite.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoActualAtlasReleaseGate.java`
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/src/test/resources/atlas/search-index.json`
- Create: `modules/mongodb-advanced/mongodb-testkit-atlas/src/test/resources/atlas/vector-index.json`
- Test: `modules/mongodb-advanced/mongodb-testkit-atlas/src/test/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasCapabilityContractSuiteTest.java`
**Interfaces:**
- Consumes: Search, vector, CSFLE/QE modules and Testcontainers Atlas Local.
- Produces: Fast local contracts plus credentialed actual-target release gates for readiness, query, KMS and rotation.
**Implementation requirements:**
- Atlas Local is PR/nightly evidence, not the sole production compatibility proof.
- Actual target tests are opt-in secret-backed release jobs.
- Wait for Search/Vector index READY before queries.
- Test wrong KMS key, key-vault permission and credential rotation without plaintext diagnostics.
- Persist only bounded capability reports and never provider credentials.
- [ ] **Step 1: Write the failing test**
```java
class MongoAtlasCapabilityContractSuiteTest {
@org.junit.jupiter.api.Test
void vectorQueriesWaitForReadyIndex() {
MongoAtlasCapabilityReport report = MongoAtlasCapabilityContractSuite.vectorReadiness();
org.assertj.core.api.Assertions.assertThat(report.queriedBeforeReady()).isFalse();
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-testkit-atlas:test --tests 'io.backend.skeleton.mongodb.advanced.testkit.atlas.MongoAtlasCapabilityContractSuiteTest'
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public interface MongoAtlasCapabilityContractSuite {
static MongoAtlasCapabilityReport vectorReadiness() {
return new MongoAtlasCapabilityReport(false, true);
}
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
./gradlew :modules:mongodb-advanced:mongodb-testkit-atlas:test --tests 'io.backend.skeleton.mongodb.advanced.testkit.atlas.MongoAtlasCapabilityContractSuiteTest'
./gradlew :modules:mongodb-advanced:mongodb-testkit-atlas:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasLocalContainer.java' 'modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasCapabilityContractSuite.java' 'modules/mongodb-advanced/mongodb-testkit-atlas/src/main/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoActualAtlasReleaseGate.java' 'modules/mongodb-advanced/mongodb-testkit-atlas/src/test/resources/atlas/search-index.json' 'modules/mongodb-advanced/mongodb-testkit-atlas/src/test/resources/atlas/vector-index.json' 'modules/mongodb-advanced/mongodb-testkit-atlas/src/test/java/io/backend/skeleton/mongodb/advanced/testkit/atlas/MongoAtlasCapabilityContractSuiteTest.java'
git commit -m "test: add atlas local and actual target capability gates"
```
### Task 15: Advanced Capability 문서·승격 ADR·최종 Promotion Gate
**Files:**
- Create: `docs/mongodb/advanced/sharding.md`
- Create: `docs/mongodb/advanced/time-series.md`
- Create: `docs/mongodb/advanced/encryption.md`
- Create: `docs/mongodb/advanced/search-vector.md`
- Create: `docs/mongodb/advanced/multi-tenancy.md`
- Create: `docs/mongodb/advanced/gridfs-migration.md`
- Create: `docs/adr/ADR-MONGO-ADV-001-capability-promotion.md`
- Create: `scripts/verify-mongodb-advanced.sh`
- Test: `modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/MongoAdvancedPromotionGateTest.java`
**Interfaces:**
- Consumes: Every previous Advanced task and Stable release evidence.
- Produces: Capability-specific support matrix, runbooks, promotion ADR and reproducible advanced verification command.
**Implementation requirements:**
- Each capability documents topology, server version, privilege, unsupported combinations and failure recovery.
- Promotion requires actual topology/environment evidence, security review and migration/runbook coverage.
- A capability promoted to Stable still remains an opt-in module unless a later starter ADR changes the dependency boundary.
- Search/Vector promotion requires relevance and performance evidence, not only functional success.
- Database-per-tenant and reshard orchestration remain Experimental until operational scale evidence exists.
- [ ] **Step 1: Write the failing test**
```java
class MongoAdvancedPromotionGateTest {
@org.junit.jupiter.api.Test
void everyPromotionRequiresActualEnvironmentEvidence() {
MongoAdvancedPromotionEvidence evidence = MongoAdvancedPromotionEvidence.fixture();
org.assertj.core.api.Assertions.assertThat(evidence.requiredCategories())
.contains("actual-topology", "security", "migration", "failure", "runbook");
}
}
```
- [ ] **Step 2: Run the focused test and verify the failure**
Run:
```bash
bash scripts/verify-mongodb-advanced.sh
```
Expected: FAIL because the advanced capability or its gate is not implemented yet.
- [ ] **Step 3: Implement the smallest complete production contract**
```java
public final class MongoAdvancedPromotionGate {
public void verify(MongoAdvancedPromotionEvidence evidence) {
evidence.require("stable-platform");
evidence.require("actual-topology");
evidence.require("security");
evidence.require("failure");
evidence.require("runbook");
}
}
```
Implement every invariant listed under **Implementation requirements**. The snippet fixes public names and the central safety contract.
- [ ] **Step 4: Run the focused test and module suite**
Run:
```bash
bash scripts/verify-mongodb-advanced.sh
./gradlew :modules:mongodb-advanced:mongodb-sharding:test
```
Expected: PASS with the focused assertion and module suite green.
- [ ] **Step 5: Commit the independently reviewable change**
```bash
git add 'docs/mongodb/advanced/sharding.md' 'docs/mongodb/advanced/time-series.md' 'docs/mongodb/advanced/encryption.md' 'docs/mongodb/advanced/search-vector.md' 'docs/mongodb/advanced/multi-tenancy.md' 'docs/mongodb/advanced/gridfs-migration.md' 'docs/adr/ADR-MONGO-ADV-001-capability-promotion.md' 'scripts/verify-mongodb-advanced.sh' 'modules/mongodb-advanced/mongodb-sharding/src/test/java/io/backend/skeleton/mongodb/advanced/MongoAdvancedPromotionGateTest.java'
git commit -m "docs: add mongodb advanced promotion gate"
```