# ADR-MONGO-001 — MongoDB platform boundary - **Status:** Accepted - **Date:** 2026-08-13 - **Design source:** `mongodb-superpowers-package/.../2026-08-11-mongodb-document-persistence-platform-design.md` §1, §2 (D-01, D-04, D-05), §5, §6 ## Context Two failure modes are common when a team wraps MongoDB. The first is flattening: a shared `CommonMongoRepository` and a generic CRUD facade, which forces every collection to share an id strategy, a consistency profile and a query surface. MongoDB's single-document atomicity, aggregation model and change streams stop being reachable, and the first collection that needs something different gets a cast or a leaky generic. The second is unrestricted exposure: the driver and `runCommand` available everywhere. Then any service can drop a collection, run an unbounded pipeline, or issue an admin command from a request thread, and no review catches it because there is nothing structural to catch. ## Decision The domain owns its documents; the platform owns the cross-cutting decisions. Four exposure planes: | Plane | Contents | Client | |---|---|---| | D1 Standard document persistence | Spring Data repositories, typed queries, mapping manifest, atomic update primitives, optimistic revision | Stable API V1, `apiStrict=true` | | D2 Advanced document operations | `MongoTemplate`, transactions/sessions, bulk, aggregation, keyset cursors, change streams | Stable API V1, `apiStrict=true` | | D3 Explicit Mongo capability | Native BSON, time series, search/vector, CSFLE/QE, shard-aware operations | Separate capability client | | D4 Admin plane | Collection, validator, index, migration, shard, repair | Separate admin client and credential | Specifically: 1. **No `CommonMongoRepository`.** Each aggregate declares its own repository. 2. **D1/D2 run on Stable API V1 with `apiStrict=true`,** so a command outside the versioned API fails at development time instead of on the next server upgrade. 3. **D3 is not a raw-client escape.** Every call passes a fixed admission order: capability registered → database profile → collection allowlist → operation name → timeout → consistency profile → result limit → trace → redaction → command category → admin-command refusal → execute. 4. **D4 is a separate client with a separate credential.** No application-plane path reaches it; `PolicyAwareMongoNativeGateway` refuses admin-category commands regardless of capability. 5. **Advanced and Experimental capabilities are opt-in modules**, never transitive dependencies of the Stable surface. ## Consequences **Positive.** MongoDB's semantics stay reachable. Misuse is refused structurally rather than reviewed for. A server upgrade cannot silently change D1/D2 behaviour. Admin operations have their own audit trail and credential. **Negative.** Every operation needs a registered name and profile, so a new query is a small amount of configuration rather than zero. A genuinely new capability requires a registration before it can be used. Both are deliberate: the cost is paid once per operation, at review time. **Rejected alternative — "expose the driver, rely on code review."** Review does not scale to every query in every service, and the operations that matter (unbounded pipeline, `dropCollection`, unanchored regex on user input) look unremarkable in a diff. ## Repository adaptation The design assumes 19 Gradle modules under `modules/mongodb/`. This repository's fail-closed registry declares exactly 19 leaf identities, so the modules became package boundaries inside `:adapter:outbound:persistence-mongo`, enforced by ArchUnit. See [docs/mongodb/repository-adaptation.md](../mongodb/repository-adaptation.md).