The mongodb profile
Status (2026-11-01): a selectable app profile; local evidence only. kit template:prune --profile mongodb selects it: it sets PROFILE in config/src/env.ts, copies this folder's conusai.json,
compose.yaml and compose.dev.yaml to the app root and moves its migrations/ to migrations/mongodb/.
Every process then reads the one MONGODB_URL login and REDIS_URL (config/src/env.ts); the web
(apps/web/src/server/dialect/) and the worker and migrate job (apps/worker/src/dialect/) compose the
mongodb data source, BullMQ on Valkey and the kit's outbox relay. The modules account, notes and
documents ship mongodb migrations and adapters, so self-service account export and erasure work here;
agent and knowledge declare Postgres only and are not part of an app on this profile. Live collections
run (the web follows the live collections' change stream; the migrate job enables pre-images per collection). Module cron: the worker installs the modules' schedules that this profile ships as BullMQ job
schedulers when it starts (apps/worker/src/dialect/schedules.ts: files.recover and the account
sweeps, commit 589a06079; the agent module's run retention is Postgres-only). Source and local
tests only; no live worker has run them yet. No generated app on this profile has been deployed on a
ConusAI install. Adapter, migration and live-conformance tests do not establish a 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 |
Registered modules must support the selected persistence profile. The web, worker and migrate compositions refuse unsupported modules by name before connecting to services; their data-rights hooks and adoption history are preserved. Fresh backend conformance fixtures explicitly author a compatible module set for both the registry and data source. These fixtures do not migrate an adopted starter or establish a public scaffold command; the existing CLI custody refusal still applies.
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, linksmongodb+redis+identity. There is nomongodb.migrateflag: 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 oneMONGODB_URLand ordering is compose'sservice_completed_successfullyalone (AT-D14).compose.yaml,compose.dev.yaml— the profile's compose files. The dev overlay runsmongo:8.0as a single-node replica set (--replSetplus a one-shotmongo-initthat runsrs.initiate()) andvalkey/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$jsonSchemavalidator generated from the entity's zod schema, and every unique group and index as a compound index leading withorg_id— generated bymongoSchemaCommandsfrom the same entity definitions as the postgres files and committed, forward-only. A module's own MongoDB migrations live with the module:modules/<id>/adapters/mongo/migrations/, declared in its manifest asmigrations: { postgres: "migrations", mariadb: "...", mongodb: "adapters/mongo/migrations" }.
The composition (wired)
The profile is chosen at generation time (.conusai/template.json profile), and
kit template:prune --profile mongodb removes the other dialects. What it selects:
config/src/env.tsreadsMONGODB_URL(every process) instead of the three Postgres URLs -- one login, because there is no RLS to bind (AT-D20 is Postgres-only) -- andREDIS_URLfor the queue.apps/web(src/server/dialect/stores.ts) andapps/worker(src/dialect/runtime.ts) composeconnectMongoDataSourceFromEnv(which refuses a standalone server, above) and the queue iscreateBullmqJobQueue/createBullmqWorkeroverREDIS_URL, with the kit's outbox relay over the same data source.- The migrate job (
apps/worker/src/migrate.ts,migrateDialect) runsrunMongoMigrationsFromEnv(each JSON file amongoCommandsMigration) overmigrations/mongodb/(moved there from this folder) and the modules'adapters/mongo/migrations/, then the job adapter's table and the live capture of each collection. - This folder's
conusai.json,compose.yamlandcompose.dev.yamlreplace 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-mongopasses 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 withMongoTopologyError, namingreplica_set(AT-D15). The suite's image ismongo:8.2, notmongo: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 ismongodb-walg:8.0. The same applies to this folder'scompose.dev.yamlon such a kernel: bump itsmongo:tag to 8.2.@conusai-kit/jobs-bullmqpasses the shared JobQueue contract againstvalkey/valkey:9in testcontainers.scripts/vendor/test-template.sh app --profile mongodbruns 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.