# MongoDB Document Persistence Platform — Repository Adaptation Contract **Design source:** `mongodb-superpowers-package/docs/superpowers/specs/2026-08-11-mongodb-document-persistence-platform-design.md` **Stable plan:** `mongodb-superpowers-package/docs/superpowers/plans/2026-08-11-mongodb-document-persistence-platform-implementation-plan.md` **Advanced plan:** `mongodb-superpowers-package/docs/superpowers/plans/2026-08-11-mongodb-advanced-capabilities-expansion-plan.md` The design package declares its own module root (`modules/mongodb`) and root package (`io.backend.skeleton.mongodb`) as *implementation assumptions*, not as contract. This file is the single record of how that assumed layout was mapped onto this repository. Only paths, build DSL, and composition-root ownership changed. Public contracts, policy order, and error semantics are implemented exactly as specified. ## 1. Why the module layout differs The design assumes 19 Stable Gradle projects under `modules/mongodb/` and 12 Advanced projects under `modules/mongodb-advanced/`. This repository is a Clean Architecture template whose **fail-closed registry** (`src/config/architecture/modules.json`, enforced by `src/settings.gradle` and `verifyCleanArchitectureDependencies`) declares **exactly 19 leaf identities**. Creating 31 more Gradle projects would violate HARD-STOP #5 in `AGENTS.md`. Therefore the design's 31 modules become **package boundaries inside the registered leaf** `:adapter:outbound:persistence-mongo`, following the precedent already set by [docs/httpclient/repository-adaptation.md](../httpclient/repository-adaptation.md). The design's module dependency table (§6.3) is reproduced as ten ArchUnit rules in `MongoModuleBoundaryTest`, so a forbidden edge fails the build the same way a missing Gradle dependency would. ## 2. Package mapping Root package: `io.backend.skeleton.mongodb` → `dev.caskeleton.adapter.outbound.mongo`. ### 2.1 Stable modules | Design module | Repository package | |---|---| | `mongodb-core-api` | `…outbound.mongo.api` (+ `.capability`, `.consistency`, `.error`, `.mapping`, `.observation`, `.profile`, `.schema`) | | `mongodb-spring-data` | `…outbound.mongo.mapping` (+ `.type`), `…outbound.mongo.failure` | | `mongodb-imperative` | `…outbound.mongo.imperative` (+ `.atomic`, `.bulk`, `.revision`) | | `mongodb-reactive` | `…outbound.mongo.reactive` (+ `.cursor`) | | `mongodb-query` | `…outbound.mongo.query` (+ `.budget`, `.pagination`) | | `mongodb-aggregation` | `…outbound.mongo.aggregation` | | `mongodb-transaction` | `…outbound.mongo.transaction` (+ `.retry`, `.session`) | | `mongodb-index-schema` | `…outbound.mongo.schema` (+ `.index`, `.manifest`, `.model`, `.ttl`, `.validation`) | | `mongodb-change-stream` | `…outbound.mongo.changestream` (+ `.projector`, `.recovery`) | | `mongodb-geospatial` | `…outbound.mongo.geo` | | `mongodb-migration-core` | `…outbound.mongo.migration` | | `mongodb-migration-flamingock` | `…outbound.mongo.migration.flamingock` | | `mongodb-observability` | `…outbound.mongo.observation` | | `mongodb-security` | `…outbound.mongo.security` (+ `.admin`), `…outbound.mongo.nativecap` | | `mongodb-spring-boot-starter` | `…outbound.mongo.autoconfigure` | | `mongodb-testkit-core` | `…outbound.mongo.testkit.mapping`, `.compat`, `.performance` (`testkit` source set) | | `mongodb-testkit-replicaset` | `…outbound.mongo.testkit.rs` (`testkit` source set) | | `mongodb-testkit-failover` | `…outbound.mongo.testkit.failover` (`testkit` source set) | | `mongodb-testkit-migration` | `…outbound.mongo.testkit.migration` (`testkit` source set) | `…outbound.mongo.architecture` has no design counterpart: it holds the `@MongoOperation` marker and the reusable ArchUnit rule set a fork applies to its own document/repository code. ### 2.2 Advanced modules | Design module | Repository package | |---|---| | `mongodb-sharding` | `…outbound.mongo.advanced.sharding` (+ `.admin` for the D4 shard plane) | | `mongodb-timeseries` | `…outbound.mongo.advanced.timeseries` | | `mongodb-csfle` | `…outbound.mongo.advanced.encryption.csfle` | | `mongodb-queryable-encryption` | `…outbound.mongo.advanced.encryption.qe` | | `mongodb-search` | `…outbound.mongo.advanced.search` | | `mongodb-vector-search` | `…outbound.mongo.advanced.vector` | | `mongodb-tenancy-shared` | `…outbound.mongo.advanced.tenancy.shared` | | `mongodb-tenancy-database` | `…outbound.mongo.advanced.tenancy.database` | | `mongodb-change-stream-messaging-bridge` | `…outbound.mongo.advanced.bridge` | | `mongodb-gridfs-compat` | `…outbound.mongo.advanced.gridfs` | | `mongodb-testkit-sharded` | `…outbound.mongo.testkit.sharded` (`testkit` source set) | | `mongodb-testkit-atlas` | `…outbound.mongo.testkit.atlas` (`testkit` source set) | The design's rule that a Stable module never depends on an Advanced one survives as an ArchUnit rule (`stableNeverDependsOnAdvanced`) plus the opt-in flag: every Advanced entry point requires `MongoAdvancedCapabilityFlags` to have the matching capability enabled and refuses construction otherwise. Being on the classpath is not being enabled. ## 3. Other deliberate substitutions | Design assumption | Repository reality | Adaptation | |---|---|---| | Gradle Kotlin DSL under `modules/mongodb*` | Groovy DSL, root `build.gradle` conventions, `LockMode.STRICT` locking | Dependencies declared in `src/adapter/outbound/persistence-mongo/build.gradle`; `gradle.lockfile` regenerated. | | `mongodb-spring-boot-starter` is a separate module the app depends on | `modules.json` gives `adapter-outbound-persistence-mongo` `runtime_memberships: []` and does **not** list it among `app-bootstrap`'s allowed dependencies | The `autoconfigure` package stays inside the leaf and registers through the leaf's own `META-INF/spring/…AutoConfiguration.imports`. This differs from the httpclient precedent, where the starter moved to `:app-bootstrap`; here the registry forbids that edge. | | Spring Boot 4.1 / Spring Data MongoDB 5.1 baseline | Repository baseline is Spring Boot 4.0.0 / Spring Data MongoDB 5.0.0 | The platform targets the Spring Data MongoDB **API surface** common to both; no 5.1-only type is referenced. The support matrix records the actual pinned versions. | | `MongoRetryScope` lives in `mongodb-transaction` | The `mongodb-spring-data` failure translator must classify retry scope, and it cannot depend on `mongodb-transaction` | `MongoRetryScope` lives in `…api.error` (core-api), which both packages already depend on. Same values, same meaning, one legal position in the DAG. | | `mongodb-migration-flamingock` depends on Flamingock | Adding an unvetted external dependency is out of scope for this task, and the design itself requires the public contract not to depend on Flamingock types | The adapter is provider-neutral: it consumes a platform-owned `FlamingockChangeUnitView`. Wiring an actual Flamingock distribution is a one-file change behind that view. | | Testkit as its own Gradle module | The design forbids production modules depending on the testkit | A dedicated `testkit` source set whose output is on the test compile/runtime classpaths only. ArchUnit rule `productionNeverDependsOnTestkit` enforces the direction. | | Per-task `git commit` | `AGENTS.md`: commit policy is `human-only` | Implementation is delivered unstaged; commits are the human's action. This is the only plan step intentionally not executed, and it is recorded here. | | `docs/mongodb/**`, `scripts/verify-mongodb-*.sh` | Repository already owns `docs/` and `scripts/` | Created at the same repository-relative paths. | ## 4. What is unchanged from the design - D1 / D2 / D3 / D4 exposure planes and the ordered D3 admission sequence (§5). - Stable API V1 with `apiStrict=true` on the D1/D2 client generation; D3/D4 on separate generations. - `MongoExecutionOutcome`, including both ambiguous outcomes (`WRITE_RESULT_UNKNOWN`, `TRANSACTION_COMMIT_UNKNOWN`), and `MongoFailureContext`'s permitted-field list. - The complete stable exception hierarchy and the label-before-code classification order. - The BSON representation manifest (UUID `STANDARD`, `Decimal128`, UTC instants, alias type metadata) and the document-size budget. - Update-operator-first writes, and optimistic revision as the precondition for whole-document replacement. - Transaction body retry and commit retry as separate loops: a new session per body attempt, and commit-only retry on unknown commit. The body is never replayed after a commit ambiguity. - Registered operation names and manifests for query, aggregation and index; no free-form JSON query and no unbounded pipeline. - Keyset pagination with an authenticated cursor and a unique tie-breaker requirement. - Change stream as an at-least-once projector with resume-token checkpointing and explicit history-lost handling. - TTL as physical cleanup only, never the sole basis for access denial or business scheduling. - Manifest-owned index/validator state with an apply policy that never drops what it does not own. - Low-cardinality observation tags, command redaction, and the credential reference indirection. - The Stable release gate's evidence categories, and the Advanced promotion gate's requirement for actual-topology evidence. ## 5. Verification ```bash bash scripts/verify-mongodb-platform.sh # Stable gate bash scripts/verify-mongodb-advanced.sh # Advanced gate (opt-in lanes) ``` Both scripts run from the repository root and delegate to `src/gradlew`.