# The mongodb profile **Status (source review 2026-10-21): adapter and migration assets, not a selectable app profile.** `kit template:prune --profile mongodb` is still refused; its error incorrectly says no adapter exists, although `@conusai-kit/data-mongo` is implemented. The web/worker composition is unfinished. The tables and generated- app steps below describe the target design; repository/transaction and migration tests do not establish a generated application deployment. The persistence profile for an app whose primary store is MongoDB instead of Postgres (spec §5.1): the same procedures, the same modules, the same migrations discipline, on the official `mongodb` driver (`@conusai-kit/data-mongo`) with jobs on BullMQ over Valkey (`@conusai-kit/jobs-bullmq`). | | postgres (default) | mongodb (this profile) | |---|---|---| | Primary store | Postgres 18 | MongoDB 8.0, **single-node replica set** (below) | | Data adapter | `@conusai-kit/data-kysely` | `@conusai-kit/data-mongo` | | Jobs | pg-boss (Postgres) | BullMQ on Valkey (`@conusai-kit/jobs-bullmq`) | | Tenant wall | repository predicate + RLS (three roles, AT-D20) | repository predicate + compound indexes leading with `org_id` — MongoDB has no RLS | | Links | `postgres`, `identity` | `mongodb`, `redis`, `identity` | | Process env | `POSTGRES_URL`, `POSTGRES_READER_URL`, `POSTGRES_MIGRATE_URL` | `MONGODB_URL`, `REDIS_URL` | ## The replica_set requirement (AT-D15) **Create the MongoDB service with `replica_set` set.** A managed MongoDB is a standalone server unless `replica_set` is given at creation (the console's create form offers it and states it cannot be changed afterwards), and a standalone server has no multi-document transactions — a `unitOfWork.run` on it would be silently non-atomic. `@conusai-kit/data-mongo` therefore asks the server what it is at boot (`hello`'s `setName`) and refuses to start against a standalone mongod with a `MongoTopologyError` that names this setting. A single-node replica set is enough: with `replica_set` set, the platform starts mongod with `--replSet` and `rs.initiate()`, and the injected `MONGODB_URL` carries `directConnection=true`. The `conusai.json` in this folder links `mongodb` — that link is only valid for an app whose MongoDB service was created this way. ## What this folder carries - `conusai.json` — the profile's deployment contract: the same three services, links `mongodb` + `redis` + `identity`. There is no `mongodb.migrate` flag: the three-role split the postgres profile declares (data-services DS21) exists to make row-level security bind, and MongoDB has none, so every process holds the one `MONGODB_URL` and ordering is compose's `service_completed_successfully` alone (AT-D14). - `compose.yaml`, `compose.dev.yaml` — the profile's compose files. The dev overlay runs `mongo:8.0` as a single-node replica set (`--replSet` plus a one-shot `mongo-init` that runs `rs.initiate()`) and `valkey/valkey:9-alpine`, the images the platform's catalog offers. - `migrations/` — the kernel collections (tenancy, sign-in, files, proposals, outbox, idempotency keys) as declarative MongoDB commands in JSON — a collection with its `$jsonSchema` validator generated from the entity's zod schema, and every unique group and index as a compound index leading with `org_id` — generated by `mongoSchemaCommands` from the same entity definitions as the postgres files and committed, forward-only. A module's own MongoDB migrations live with the module: `modules//adapters/mongo/migrations/`, declared in its manifest as `migrations: { postgres: "migrations", mariadb: "...", mongodb: "adapters/mongo/migrations" }`. ## Target generated-app changes (not wired) The profile is chosen at generation time (`.conusai/template.json` `profile`), and `kit template:prune --profile mongodb` removes the other dialects. Concretely: 1. `config/src/env.ts` reads `MONGODB_URL` (every process) instead of the three Postgres URLs — one login, because there is no RLS to bind (AT-D20 is Postgres-only). 2. `apps/web` and `apps/worker` compose `connectMongoDataSourceFromEnv` (which refuses a standalone server, above) and the worker's queue is `createBullmqJobQueue`/`createBullmqWorker` over `REDIS_URL`. 3. The migrate job runs `runMongoMigrationsFromEnv` over `profiles/mongodb/migrations/` (moved to `migrations/mongodb/`) and the modules' `adapters/mongo/migrations/`, each JSON file a `mongoCommandsMigration`. 4. This folder's `conusai.json`, `compose.yaml` and `compose.dev.yaml` replace the root ones. The dialect differences are explicit, never generated at run time (spec §5.3): a module's MongoDB schema is its own numbered folder, reviewed like any migration. ## Proof - `@conusai-kit/data-mongo` passes the shared repository and capability contract suites in testcontainers against MongoDB 8 running as a single-node replica set, including a multi-entity UnitOfWork commit and rollback — the tenant predicate is the wall, and the contract is what proves it. Against a standalone mongod the adapter refuses to boot with `MongoTopologyError`, naming `replica_set` (AT-D15). The suite's image is `mongo:8.2`, not `mongo:8.0`: the 8.0 binary refuses to start on Linux kernels 6.19 and newer (SERVER-121912, the TCMalloc/rseq incompatibility — the refusal is compiled into the server), which covers current development hosts; the topology under test is the same on either minor, and the platform's managed image is `mongodb-walg:8.0`. The same applies to this folder's `compose.dev.yaml` on such a kernel: bump its `mongo:` tag to 8.2. - `@conusai-kit/jobs-bullmq` passes the shared JobQueue contract against `valkey/valkey:9` in testcontainers. - `scripts/vendor/test-template.sh app --profile mongodb` runs the template's gate and then applies this folder's and the modules' MongoDB migrations to a real MongoDB 8 container started as a single-node replica set, and probes that the adapter boots on it and refuses a standalone server — so the committed schema is proven against the engine, not just generated.