# MongoDB 문서 영속성 플랫폼 설계서 - 문서 상태: 구현 기준 설계 - 기준일: 2026-08-11 - 대상 프로젝트: Java 21 / Spring Boot 4.1 기반 Backend Skeleton - 모듈 루트: `modules/mongodb` - 루트 패키지: `io.backend.skeleton.mongodb` - 요구사항 원본: `MongoDB 문서 영속성 플랫폼 심층 리서치` ## 1. 설계 목적 이 설계의 목적은 Spring Data MongoDB를 다시 감싼 공통 CRUD 라이브러리를 만드는 것이 아니다. 도메인 모듈이 MongoDB의 Document, Repository, Query 의미와 Index 요구를 직접 소유하면서도, 다음 기술 결정은 모든 서비스가 같은 기준으로 재사용하도록 만드는 것이다. ```text Document Modeling → BSON Mapping → Atomic Write → Consistency Profile → Session / Transaction → Retry / Ambiguous Outcome → Query / Aggregation Guardrail → Schema / Index Manifest → Pagination / Bulk → Change Stream → Security / Observability → Topology / Release Gate ``` 플랫폼은 MongoDB를 관계형 저장소처럼 평탄화하지 않는다. 반대로 Native Driver와 `runCommand()`를 일반 애플리케이션에 무제한 노출하지도 않는다. MongoDB의 단일 문서 원자성, BSON 표현, Aggregation, Replica Set, Change Stream, Sharding, Encryption 의미론을 유지하면서 잘못된 사용을 사전에 차단한다. ## 2. 최상위 설계 결정 | 번호 | 결정 | 구현 결과 | |---:|---|---| | D-01 | 도메인이 `@Document`, Repository, Query, Index Requirement, Schema Version을 소유한다. | 플랫폼에는 범용 `CommonMongoRepository`를 만들지 않는다. | | D-02 | Local 기본 토폴로지는 Single-node Replica Set이다. | Transaction, Retryable Write, Change Stream을 Local에서 동일하게 검증한다. | | D-03 | Standalone은 smoke test만 지원한다. | 운영 Profile이나 Stable Release Gate로 인정하지 않는다. | | D-04 | D1/D2 Runtime Client는 Stable API V1과 `apiStrict=true`를 기본으로 한다. | 일반 CRUD·Query·Transaction·Change Stream 경로의 호환성을 제한한다. | | D-05 | D3 Capability Client와 D4 Admin Client를 분리한다. | Stable API 밖 기능과 관리 명령을 일반 Runtime에서 우회하지 못한다. | | D-06 | UUID·Decimal·시간·type metadata 표현을 Manifest로 고정한다. | 배포나 라이브러리 변경으로 BSON 표현이 암묵적으로 바뀌지 않는다. | | D-07 | 부분 변경은 Update Operator를 우선한다. | `save()` 기반 전체 Document 교체로 인한 Lost Update를 줄인다. | | D-08 | 전체 Document 교체에는 optimistic revision을 요구한다. | `@Version` 또는 expected revision predicate를 사용한다. | | D-09 | Transaction보다 단일 Document 원자 연산을 우선한다. | Multi-document invariant에만 Transaction을 사용한다. | | D-10 | Transaction 본문 Retry와 Commit Retry를 분리한다. | `TransientTransactionError`는 전체 본문, `UnknownTransactionCommitResult`는 Commit만 재시도한다. | | D-11 | Query·Aggregation·Index는 등록된 operation/manifest를 요구한다. | 자유형 JSON Query와 무제한 Pipeline을 차단한다. | | D-12 | Change Stream은 at-least-once projector다. | physical change event를 업무 Integration Event로 직접 공개하지 않는다. | | D-13 | TTL은 물리 cleanup이다. | 정확한 업무 Scheduler 또는 접근 차단의 유일한 근거로 사용하지 않는다. | | D-14 | GridFS는 compatibility adapter다. | 신규 파일 Source of Truth는 기존 Fileserver/Object Storage를 사용한다. | | D-15 | Sharding·Time Series·Encryption·Search·Vector·Multi-tenancy는 선택 모듈이다. | Stable Starter의 기본 dependency와 권한에 포함하지 않는다. | ## 3. 범위와 비범위 ### 3.1 Stable 범위 ```text Mapping Manifest Repository / MongoTemplate 통합 Imperative / Reactive 실행 경로 단일 Document 원자 Update Optimistic Lock Replica Set Transaction Consistency Profile Retry / Error Translation Query Guardrail Aggregation Guardrail Schema / Index Manifest Keyset Pagination Bulk Partial Result Change Stream TTL Cleanup Contract GeoJSON / 2dsphere Security Observability Replica Set Testkit ``` ### 3.2 Advanced 범위 ```text Sharding-aware Query Time Series CSFLE Queryable Encryption Equality / Range Change Stream → Messaging Bridge Shared Collection Multi-tenancy ``` ### 3.3 Experimental 범위 ```text MongoDB Search Vector Search Hybrid Search Database-per-tenant Collection-per-tenant Reshard orchestration Atlas/provider 고유 기능 ``` ### 3.4 명시적 비지원 ```text CommonMongoRepository Runtime arbitrary runCommand 운영 auto-index creation Standalone 운영 계약 TTL 기반 정확한 Scheduler Change Stream 원본의 외부 업무 이벤트 공개 신규 GridFS 파일 플랫폼 Java FQCN을 장수 BSON schema로 강제 무제한 skip pagination 무제한 aggregation / regex / result ``` ## 4. 지원 기준 | 구성 | Stable 기준 | 정책 | |---|---|---| | Java | 21 | 프로젝트 Runtime 기준 | | Spring Boot | 4.1.x BOM | 개별 Driver 버전 override 금지 | | Spring Data MongoDB | 5.1.x | Repository·Template 통합 | | MongoDB Java Driver | Boot BOM 관리 | 직접 버전 고정 금지 | | MongoDB Server | 8.0 최신 패치 | Primary Certification Lane | | MongoDB 7.0 | 최신 7.0 패치 | Compatibility Lane | | Stable API | V1 | D1/D2 strict 기본 | | Local | Single-node Replica Set | 기본 개발 환경 | | 운영 Stable Gate | 3-node Replica Set | Failover 검증 필수 | | Sharding | 실제 Sharded Cluster | Advanced Gate | | Search/Vector | Atlas Local + 실제 목표 배포 | 기능별 Gate | | Encryption | 실제 KMS·Key Vault 환경 | 기능별 Gate | MongoDB 8.0/7.0 Stable 계약에서는 `validationAction=errorAndLog`를 사용하지 않는다. Stable Validation Action은 `error`와 `warn`이다. ## 5. 공개 계층 ```text D1 Standard Document Persistence ├─ Spring Data Repository ├─ Typed Query / Projection ├─ Mapping Manifest ├─ Atomic Update Primitive └─ Optimistic Revision D2 Advanced Document Operations ├─ MongoTemplate ├─ Transaction / Session ├─ Bulk ├─ Aggregation ├─ Keyset / Cursor └─ Change Stream D3 Explicit Mongo Capability ├─ Native BSON ├─ Time Series ├─ Search / Vector ├─ CSFLE / QE └─ Sharding-aware Operations D4 Admin Plane ├─ Collection ├─ Validator ├─ Index ├─ Migration ├─ Shard / Refine / Reshard └─ Repair / Verification ``` D3도 raw client escape가 아니다. 모든 D3 호출은 다음 순서를 통과한다. ```text Capability 등록 확인 → Database Profile 확인 → Collection allowlist → Operation Name 필수 → Timeout / maxTimeMS → Consistency Profile → Result / Batch Limit → Trace → Log Redaction → Command Category 검증 → D4 Command 차단 → 실행 ``` ## 6. 모듈 구조 ### 6.1 Stable 모듈 ```text modules/mongodb/ ├── mongodb-core-api ├── mongodb-spring-data ├── mongodb-imperative ├── mongodb-reactive ├── mongodb-query ├── mongodb-aggregation ├── mongodb-transaction ├── mongodb-index-schema ├── mongodb-change-stream ├── mongodb-geospatial ├── mongodb-migration-core ├── mongodb-migration-flamingock ├── mongodb-observability ├── mongodb-security ├── mongodb-spring-boot-starter ├── mongodb-testkit-core ├── mongodb-testkit-replicaset ├── mongodb-testkit-failover └── mongodb-testkit-migration ``` ### 6.2 Advanced·Experimental 모듈 ```text modules/mongodb-advanced/ ├── mongodb-sharding ├── mongodb-timeseries ├── mongodb-csfle ├── mongodb-queryable-encryption ├── mongodb-search ├── mongodb-vector-search ├── mongodb-tenancy-shared ├── mongodb-tenancy-database ├── mongodb-change-stream-messaging-bridge ├── mongodb-gridfs-compat ├── mongodb-testkit-sharded └── mongodb-testkit-atlas ``` ### 6.3 Dependency 규칙 ```text mongodb-core-api → Java 표준 라이브러리만 mongodb-spring-data → core-api mongodb-imperative / mongodb-reactive → core-api → spring-data mongodb-query → core-api → spring-data mongodb-aggregation → core-api → query mongodb-transaction → core-api → spring-data mongodb-index-schema → core-api → spring-data mongodb-change-stream → core-api → reactive mongodb-geospatial → core-api → spring-data mongodb-migration-flamingock → migration-core → index-schema mongodb-spring-boot-starter → Stable 모듈만 Advanced 모듈 → Starter에 자동 포함하지 않음 ``` ## 7. 핵심 타입 ### 7.1 Operation·Profile ```java public record MongoOperationName(String value) { public MongoOperationName { if (value == null || !value.matches("[a-z][a-z0-9.-]{2,95}")) { throw new IllegalArgumentException("invalid MongoDB operation name"); } } } public record DatabaseProfileName(String value) {} public record CollectionProfileName(String value) {} public record MongoOperationContext( MongoOperationName operationName, DatabaseProfileName databaseProfile, CollectionProfileName collectionProfile, MongoConsistencyProfile consistency, Duration timeout) { } ``` Operation name은 metric·trace·policy key로 사용하므로 사용자 ID나 동적 값이 들어갈 수 없다. ### 7.2 Consistency Profile ```java public enum MongoConsistencyProfile { PRIMARY_LOCAL, PRIMARY_MAJORITY, CAUSAL_MAJORITY, STALE_READ_ALLOWED, SNAPSHOT_TRANSACTION, MONGO_SHORT_WRITE } ``` | Profile | Read Preference | Read Concern | Write Concern | 용도 | |---|---|---|---|---| | PRIMARY_LOCAL | primary | local | acknowledged | 일반 저지연 작업 | | PRIMARY_MAJORITY | primary | majority | majority | rollback 저항·내구성 | | CAUSAL_MAJORITY | primary 기본 | majority | majority | read-your-writes | | STALE_READ_ALLOWED | secondaryPreferred | local/majority | 없음 | 명시적 stale read | | SNAPSHOT_TRANSACTION | primary | snapshot | majority | multi-document snapshot | | MONGO_SHORT_WRITE | primary | profile 값 | profile 값 | 짧은 write transaction | `STALE_READ_ALLOWED`는 이름으로 위험을 드러낸다. `readOnly=true`를 자동으로 secondary routing 조건으로 사용하지 않는다. ### 7.3 실행 결과 ```java public enum MongoExecutionOutcome { NOT_SENT, NO_WRITE_PERFORMED, WRITE_CONFIRMED, PARTIAL_BULK_WRITE, WRITE_RESULT_UNKNOWN, TRANSACTION_COMMIT_UNKNOWN } ``` `WRITE_RESULT_UNKNOWN`과 `TRANSACTION_COMMIT_UNKNOWN`은 명백한 실패가 아니다. 동일 업무 본문을 무조건 재실행하지 않고 version, unique key, idempotency record, transaction record를 조회해 복구한다. ### 7.4 Capability ```java public enum MongoSupportLevel { STABLE, ADVANCED, EXPERIMENTAL, UNSUPPORTED } public record MongoCapabilitySupport( String capability, MongoSupportLevel level, Map constraints) { } ``` Capability는 `boolean`만 반환하지 않는다. Time Series, Sharding, Encryption, Search처럼 제약이 큰 기능은 토폴로지·버전·권한·비지원 조합을 함께 반환한다. ## 8. Client와 권한 경계 ```text Runtime Strict Client ├─ Stable API V1 ├─ apiStrict=true ├─ App read/write credential └─ D1/D2 Capability Client ├─ capability allowlist ├─ Stable API strict 여부 기능별 결정 ├─ capability credential └─ D3 Admin Client ├─ Runtime Starter에서 기본 미등록 ├─ migration/deployment job 전용 ├─ admin credential └─ D4 ``` 일반 Runtime에서 `MongoClient`, `MongoDatabase`, `MongoCollection` Bean을 이름 없이 전역 공개하지 않는다. Spring Data가 내부적으로 사용하는 Bean은 존재하지만 애플리케이션이 직접 주입하지 않도록 ArchUnit·Bean visibility·문서 규칙을 적용한다. ## 9. Document 모델링 계약 ### 9.1 Embed와 Reference ```text 같이 읽음 AND 같이 변경함 AND 크기가 bounded → Embed 독립 lifecycle OR unbounded growth OR 여러 Aggregate에서 공유 OR 독립 sharding 필요 → Manual Reference ``` | 특성 | Embed | Manual Reference | |---|---:|---:| | 항상 함께 조회 | 권장 | 가능 | | 같은 명령에서 변경 | 권장 | 신중 | | bounded | 필수 | 불필요 | | 무한 배열 | 금지 | 권장 | | 공유 데이터 | 신중 | 권장 | | 독립 보안·보존 | 신중 | 권장 | | hot write | 신중 | 권장 | ### 9.2 Document Modeling Manifest 도메인별로 다음 Manifest를 제공한다. ```yaml collections: orders: document-type: order schema-version: 3 max-estimated-document-bytes: 2097152 embedded-collections: lineItems: max-elements: 200 stateHistory: max-elements: 100 references: customerId: target-collection: customers required: true ``` 플랫폼은 16 MiB 한계에 가까운 설정을 허용하지 않고 안전 여유가 포함된 프로젝트 상한을 요구한다. 실제 serialized BSON 크기를 contract test로 측정한다. ### 9.3 GridFS 경계 ```text 신규 파일 저장 → Fileserver Application → Filesystem / Object Storage Adapter MongoDB Document → FileId / ContentKey Reference GridFS → Legacy read / migration compatibility only ``` ## 10. BSON 표현 Manifest ```yaml mongodb: mapping: uuid-representation: STANDARD big-decimal-representation: DECIMAL128 big-integer-representation: STRING instant-representation: BSON_DATE local-date-time: REJECT_UNLESS_CONVERTER_REGISTERED enum-representation: STRING type-metadata: ALIAS_FOR_LONG_LIVED_COLLECTIONS ``` | Java/Domain 타입 | BSON | 정책 | |---|---|---| | ObjectId | ObjectId | Mongo 전용 내부 ID에 허용 | | UUID/UUIDv7 | Binary UUID | STANDARD 고정 | | String Domain ID | String | ObjectId 자동 변환 차단 | | BigDecimal | Decimal128 | 정밀도·범위 검사 | | BigInteger | 명시적 | 컬렉션별 고정 | | Instant | BSON Date | Stable | | LocalDateTime | 암묵 저장 금지 | 명시 Converter 요구 | | Enum | String | rename은 migration | | Money | Document | amount/currency 고정 | | Encrypted field | BinData | Encryption 모듈 소유 | 다음 차이는 모두 schema 차이다. ```text absent != null [] != absent "1" != 1 String decimal != Decimal128 String object id != ObjectId ``` ### 10.1 Golden BSON Gate 모든 지원 타입은 다음 흐름을 통과한다. ```text Java object → MappingMongoConverter → BSON snapshot → 실제 Replica Set 저장 → raw BSON read-back → Java object round-trip ``` ## 11. Type Metadata | Collection | 정책 | |---|---| | 내부 단기 | 기본 `_class` 허용 가능 | | 장수·다중 버전 | `@TypeAlias` 필수 | | 외부 공유 | 명시적 `documentType` | | package refactoring 가능 | FQCN 금지 | `_class` 제거는 모든 다형성 Mapping에 동일하게 적용하지 않는다. Collection별 `TypeMetadataPolicy`를 사용한다. ## 12. Schema Validation·Versioning·Migration ### 12.1 Validation 계층 ```text Bean Validation → 입력·Java 객체 조기 실패 MongoDB JSON Schema → 저장 BSON type/required/range 최종 방어 Domain Invariant → 업무 규칙 ``` | 단계 | validationLevel | validationAction | |---|---|---| | 신규 Collection | strict | error | | Legacy 정비 시작 | moderate | warn | | Backfill | migration profile | warn 또는 error | | 정비 완료 | strict | error | ### 12.2 Schema Version ```java public record DocumentSchemaVersion(int value) { public DocumentSchemaVersion { if (value < 0) throw new IllegalArgumentException("negative schema version"); } } ``` ```text schemaVersion 없음 → Legacy V0 신규 Write → Current Version만 지원 범위 밖 Version → MongoDataSchemaUnsupportedException ``` ### 12.3 변경 절차 ```text Dual Reader → New Writer → Rate-limited Backfill → Version 잔존량 검증 → Legacy Index 제거 → Legacy Reader 제거 ``` ### 12.4 Migration SPI ```java public interface MongoMigration { MigrationId id(); MigrationChecksum checksum(); MigrationPrecondition precondition(); MigrationResult execute(MigrationContext context); MigrationPostcondition postcondition(); } ``` 필수 기능: ```text Ledger Distributed Lock Dry Run Batch Checkpoint Resume Rate Limit maxTimeMS Precondition Postcondition Forward Fix Operator Metadata ``` 신규 기본 Adapter는 `mongodb-migration-flamingock`으로 두되, 플랫폼 공개 계약은 Flamingock 타입에 의존하지 않는다. Mongock 신규 채택은 금지한다. Liquibase MongoDB는 후속 D4 Adapter로 추가할 수 있다. ## 13. 쓰기 모델 | 상황 | 기본 연산 | |---|---| | 신규 Document | insert | | 전체 재계산 | versioned save/replace | | 일부 필드 | updateOne + operator | | Counter | `$inc` | | 상태 전이 | expected state + `$set` | | bounded Set | `$addToSet` | | 배열 원소 | positional / arrayFilters | | 변경 결과 반환 | findAndModify | | 경쟁 생성 | unique index + upsert | | 독립 다건 | bulk | | 하나의 multi-document invariant | transaction | ### 13.1 Atomic Update API ```java public interface MongoAtomicOperations { AtomicUpdateResult updateOne( MongoOperationContext context, Class documentType, AtomicFilter filter, AtomicUpdate update, ReturnDocumentMode returnMode); } ``` 자유형 BSON filter/update를 받지 않고 등록된 field descriptor와 operator allowlist를 사용한다. ### 13.2 Optimistic Revision 전체 Document 교체와 custom update는 다음 predicate를 사용한다. ```text filter: _id = id version = expected update: business fields version = version + 1 ``` Conflict Retry는 stale object 재저장이 아니다. ```text 최신 Document 재조회 → 전체 Use Case 재계산 → 외부 side effect 부재 확인 → 제한 재시도 ``` ## 14. Session·Transaction ### 14.1 선택 기준 ```text 단일 Document invariant → atomic update 여러 Document invariant → transaction MongoDB + HTTP → transaction 밖 MongoDB + Object Storage → saga/state machine MongoDB + Messaging → outbox 또는 change-stream bridge ``` ### 14.2 Transaction API ```java public interface MongoTransactionExecutor { T execute(MongoTransactionProfile profile, Supplier work); } public interface ReactiveMongoTransactionExecutor { Publisher execute( MongoTransactionProfile profile, Supplier> work); } ``` ### 14.3 Retry 분리 ```text TransientTransactionError → 새 Session → Transaction 본문 전체 재실행 UnknownTransactionCommitResult → 본문 재실행 금지 → Commit만 재시도 → 최종 불명 시 reconciliation ``` 모든 Retry는 max attempts, max elapsed time, jitter, deadline을 가진다. ## 15. 오류 모델 ```text MongoPersistenceException ├─ MongoDuplicateKeyException ├─ MongoSchemaValidationException ├─ MongoOptimisticConflictException ├─ MongoWriteConflictException ├─ MongoTransactionTransientException ├─ MongoTransactionCommitUnknownException ├─ MongoWriteConcernException ├─ MongoReadConcernException ├─ MongoServerSelectionException ├─ MongoConnectionException ├─ MongoTimeoutException ├─ MongoCursorException ├─ MongoDocumentTooLargeException ├─ MongoBulkPartialFailureException ├─ MongoShardRoutingException ├─ MongoResumeException ├─ MongoEncryptionException └─ MongoOperationRejectedException ``` 오류에는 다음만 보존한다. ```text operationName databaseProfile collectionProfile operationType consistencyProfile retryable ambiguous errorLabels serverCode attempt elapsed traceId ``` Document, Query parameter, credential, plaintext encrypted field, resume token, shard key 실제 값은 저장하지 않는다. ## 16. Query Guardrail ### 16.1 Query 등급 | 등급 | API | 사용 위치 | |---|---|---| | Q1 | Derived Query, Projection | 일반 Domain | | Q2 | Criteria, Custom Repository, Querydsl | 동적 Query | | Q3 | Aggregation, Search/Vector, 제한 Native BSON | Advanced | | Q4 | Collection/Index/Admin command | D4 | ### 16.2 정책 ```text Sort field allowlist Projection field allowlist Field path allowlist Operator allowlist Collation profile Hint allowlist maxTimeMS Result limit Regex 길이·문자 클래스 제한 Dynamic collection 차단 ``` 다음 API는 제공하지 않는다. ```java Document executeUserBson(String json); Document runCommand(Map input); ``` ## 17. Aggregation Guardrail | 등급 | Stage | 정책 | |---|---|---| | A1 | match/project/set/unset/bounded limit | Stable | | A2 | sort/group/unwind/lookup/bucket | Resource Budget 필수 | | A3 | facet/graphLookup/large window/union | Advanced Review | | A4 | out/merge/admin write stage | D4 | 기본 설정: ```text strictMapping=true maxTimeMS=profile-defined resultLimit=bounded allowDiskUse=explicit resource profile writeStage=false lookupCollection=allowlist operationName=required ``` ## 18. Schema·Index Manifest ```yaml collections: orders: owner: order-domain validator: classpath:/mongodb/orders-schema-v3.json validation-level: strict validation-action: error indexes: - name: uq_order_number keys: orderNumber: 1 unique: true expected-usage: order.find-by-number - name: ix_customer_created_id keys: customerId: 1 createdAt: -1 _id: -1 expected-usage: order.find-recent ``` Index Manifest 필드: ```text name key order unique partialFilter sparse collation expireAfterSeconds hidden wildcardProjection geo options shardKeySupport expectedUsage owner metadataOwnership ``` `metadataOwnership` 값: ```text APPLICATION MONGODB_MANAGED ENCRYPTION_MANAGED SEARCH_MANAGED ``` 운영에서는 자동 Index 생성이 아니라 diff·approval·D4 apply를 사용한다. ```text Local/Test: apply 허용 Dev: apply + diff Staging: diff + 승인 apply Prod: D4만 생성·삭제·collMod ``` Index 삭제: ```text deprecated 표시 → usage 확인 → hidden → 관측 → explain regression → 승인 drop ``` ## 19. Pagination·Cursor·Bulk ### 19.1 Pagination ```text 작은 Admin 목록 → Page 일반 목록 → Slice 대규모 목록 → Keyset Batch 처리 → Cursor + batchSize 무한 변경 구독 → Change Stream ``` Keyset은 항상 유일한 tie-breaker를 포함한다. ```text sort: createdAt DESC, _id DESC cursor: createdAt + _id + sortVersion ``` ### 19.2 Bulk ```java public record MongoBulkResult( int requested, int inserted, int modified, int deleted, int upserted, List failures, boolean partial) { } ``` Ordered·Unordered Bulk 모두 부분 성공을 보존한다. 성공 항목을 다시 실행하지 않는다. ## 20. Change Stream ### 20.1 상태 ```text STARTING RUNNING RESUMING HISTORY_LOST FAILED STOPPED ``` ### 20.2 Checkpoint 계약 ```text Event 처리 → idempotent projector 완료 → checkpoint 저장 ``` 이 순서는 duplicate 가능성을 허용하지만 event loss를 방지한다. Projector는 stable event identity와 idempotency key를 사용한다. ### 20.3 Resume ```text resumeAfter → 일반 resume token startAfter → invalidate 이후 재개 oplog history 부족 → HISTORY_LOST → 자동으로 최신부터 시작하지 않음 → 운영 복구 정책 필요 ``` ### 20.4 Messaging 경계 ```text MongoDB Physical Change → Internal Projector → Stable Integration Event → Messaging Platform ``` DB 변경과 Event가 반드시 같은 commit에 있어야 하면 Outbox를 사용한다. ## 21. TTL·Geo·특수 Collection 경계 ### 21.1 TTL ```text Query 접근 조건: expiresAt > applicationNow TTL Index: physical cleanup ``` TTL 삭제 지연을 정상으로 취급한다. 정확한 업무 상태 전이는 별도 Scheduler가 담당한다. ### 21.2 Geospatial Stable 기본: ```text GeoJSON 2dsphere longitude, latitude 순서 거리 단위 명시 bounded near/within query ``` ### 21.3 Time Series Time Series는 일반 Collection 계약을 상속하지 않는다. | 기능 | 일반 | Time Series | |---|---:|---:| | Validator | O | X | | Change Stream | O | X | | CSFLE | O | X | | Transaction Write | O | X | | Search | 조건부 | X | | TTL | O | O | | Document limit | 16 MiB | 별도 제한 | ## 22. Sharding 경계 Application Plane: ```text ShardKeyDescriptor ShardAwareQueryValidator CollectionRoutingProfile Targeted/Scatter Classification Telemetry ``` Admin Plane: ```text shardCollection analyzeShardKey refineCollectionShardKey reshardCollection zone balancer shard add/remove ``` 모든 shard-aware write는 shard key 또는 routing evidence를 요구한다. `@Sharded` 하나로 충분하다고 간주하지 않는다. ## 23. Encryption 경계 ```text mongodb-csfle mongodb-queryable-encryption ``` | 요구 | Capability | |---|---| | Query 불필요 PII | randomized 또는 unindexed | | equality | deterministic 또는 QE equality | | range | QE range | | prefix/suffix/substring | MongoDB 8.0 Stable 비지원 | | tenant key | explicit resolver | | collection setup | D4 | | rotation | D4 + runbook | CSFLE와 QE를 같은 Collection에 동시에 적용하지 않는다. QE 내부 metadata collection과 `__safeContent__`는 ENCRYPTION_MANAGED ownership으로 보호한다. ## 24. Search·Vector 경계 ```text GeoJSON / 2dsphere → Stable Legacy $text → Compatibility only MongoDB Search → Advanced Vector Search → Advanced Hybrid Search → Advanced Search Index Admin → D4 ``` Index 생성 완료와 `READY` 상태를 구분한다. Atlas Local은 빠른 CI, 실제 목표 배포는 Release Gate다. ## 25. Multi-tenancy 경계 | 모델 | 등급 | |---|---| | Single DB | Stable | | Shared Collection + tenantId | Advanced | | Database per Tenant | Experimental | | Collection per Tenant | 제한 Experimental | | Cluster per Tenant | Infra Profile | Shared Collection은 모든 find/update/delete, aggregation, change stream에 tenant predicate를 적용하고 unique index·shard key에 tenant 의미를 검증한다. raw tenant ID는 log·metric에 남기지 않는다. ## 26. Security Principal 분리: ```text mongo-app-read mongo-app-write mongo-change-stream mongo-migration mongo-search-admin mongo-shard-admin mongo-encryption-admin mongo-dba ``` Production 기본 금지: ```text auth disabled TLS disabled admin credential 공유 connection string credential source 저장 raw user BSON 실행 arbitrary runCommand Document 전체 logging plaintext encrypted field logging ``` Query 입력은 allowlist로 변환하고 Regex는 길이·패턴·timeout을 제한한다. ## 27. Observability Driver native ObservabilitySettings를 기준으로 한다. | 영역 | Signal | |---|---| | Pool | size, checked-out, wait, failure | | SDAM | topology, primary, heartbeat | | Operation | count, latency, result, timeout | | Write | inserted, modified, deleted, upsert, concern failure | | Retry | driver/app retry, labels | | Transaction | duration, abort, body retry, commit retry, unknown | | Aggregation | duration, disk use, result count | | Query Efficiency | examined/returned, index, spill | | Sharding | targeted/scatter | | Change Stream | lag, resume, history lost | | TTL | cleanup lag | | Migration | progress, checkpoint | | Search | index readiness | 허용 Tag: ```text mongoProfile databaseProfile collectionProfile operationName operationType result failureCategory consistencyProfile ``` 금지 Tag: ```text documentId rawTenantId dynamicCollectionName queryParameter fullBson resumeToken shardKeyValue plaintextPII credential ``` ## 28. Spring Boot 설정 ```yaml backend: mongodb: profiles: default: uri-secret: secret://mongodb/default-uri topology: REPLICA_SET stable-api: version: V1 strict: true deprecation-errors: true consistency-default: PRIMARY_MAJORITY timeout: server-selection: 3s connect: 2s socket-read: 5s operation: 3s pool: min-size: 2 max-size: 40 max-wait-time: 500ms mapping: uuid-representation: STANDARD big-decimal-representation: DECIMAL128 index: runtime-auto-create: false security: tls-required: true authentication-required: true ``` Startup 실패 조건: ```text Production에서 Standalone Production에서 auth/TLS 비활성 Runtime auto-index 활성 UUID/Decimal 표현 미설정 Stable D1/D2에서 apiStrict 미설정 Required Replica Set인데 topology 불일치 Transaction 활성인데 Replica Set 아님 Change Stream 활성인데 watch capability 없음 Admin Client가 일반 Runtime credential과 동일 Unsupported schema version Dynamic collection profile ``` ## 29. 테스트 아키텍처 ```text Unit → Manifest / Policy / Classifier Repository Slice → Converter / Repository / Query Single-node Replica Set → Mapping / Atomic / Transaction / Change Stream 3-node Replica Set → Failover / Retry / Commit Unknown / Resume Sharded Cluster → Routing / Chunk Migration / Cross-shard / Reshard Atlas Local → Search / Vector quick CI Actual Target Deployment → Search / Vector / Encryption Release Gate ``` 필수 장애 테스트: ```text Primary kill Network partition Server selection timeout Write response loss TransientTransactionError UnknownTransactionCommitResult Bulk partial failure Change Stream process kill Resume token loss Oplog history loss Index drift Schema validation mismatch Credential rotation ``` ## 30. Release Gate Stable 릴리스 조건: ```text Java 21 / Boot 4.1 BOM 확인 MongoDB 7.0 compatibility MongoDB 8.0 primary certification Single-node RS contract 3-node RS failover Golden BSON snapshot Atomic update race Optimistic conflict Transaction body/commit retry 분리 Index/Schema manifest drift Keyset pagination Bulk partial result Change Stream resume/history loss TLS/RBAC/redaction Driver native observability ``` Advanced 기능은 해당 모듈과 실제 환경 Gate를 통과하기 전 Starter에 포함하지 않는다. ## 31. 구현 단계 | 단계 | 범위 | 완료 조건 | |---|---|---| | 1 Foundation | BOM, modules, profiles, topology, stable API | Context startup·topology gate | | 2 Document Core | BSON manifest, converter, type metadata, modeling | Golden BSON·size guard | | 3 Write·Consistency | atomic update, revision, profile, transaction, retry | race·failover·commit ambiguity | | 4 Schema·Query | validator, migration, query, aggregation, index | strictMapping·diff·explain | | 5 Scale·Stream | keyset, cursor, bulk, TTL, change stream | partial result·resume·kill | | 6 Operations | security, observability, starter, runbook | least privilege·redaction | | 7 Advanced | sharding, time series, encryption, search/vector, tenancy | capability-specific gate | ## 32. 완료 정의 다음 질문에 모두 구현과 테스트로 답할 수 있어야 한다. ```text Document가 bounded라는 증거가 있는가? BSON 타입 표현이 배포 간 고정되는가? 부분 Update가 전체 Document를 덮지 않는가? Read/Write Concern의 실제 보장을 호출자가 아는가? Transaction body retry와 commit retry가 분리되는가? Bulk 일부 성공이 보존되는가? Query와 Index가 Release 전에 연결되는가? Change Stream checkpoint 경계가 명확한가? TTL을 Scheduler로 오해하지 않는가? Shard Key 없는 Query를 감지하는가? 암호화 metadata를 drift cleanup이 삭제하지 않는가? 실제 Replica Set·Sharded·Atlas 환경에서 검증되는가? ``` ## 33. 요구사항 추적표 | 리서치 영역 | 설계 절 | 구현 계획 영역 | |---|---|---| | 기준선·Topology | 4, 8, 28 | Task 1~5, 45~48 | | D1~D4 경계 | 5, 6 | Task 1, 38, 39 | | Document Modeling | 9 | Task 10 | | BSON 표현 | 10, 11 | Task 6~9 | | Schema·Migration | 12 | Task 11, 18~22, 46 | | Atomic Write·Optimistic | 13 | Task 13~14 | | Consistency·Transaction | 14 | Task 23~28 | | 오류·Retry | 15 | Task 4~5, 27~28 | | Query·Aggregation | 16~17 | Task 15~17 | | Index | 18 | Task 18~20 | | Pagination·Bulk | 19 | Task 29~31 | | Change Stream | 20 | Task 33~35 | | TTL·Geo | 21 | Task 32, 36 | | Security·Observability | 26~27 | Task 37~40, 47 | | Starter·Gate | 28~30 | Task 41~50 | | Advanced | 22~25 | 별도 Advanced 계획 |