6.1 KiB
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, 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" }.
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:
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).apps/webandapps/workercomposeconnectMongoDataSourceFromEnv(which refuses a standalone server, above) and the worker's queue iscreateBullmqJobQueue/createBullmqWorkeroverREDIS_URL.- The migrate job runs
runMongoMigrationsFromEnvoverprofiles/mongodb/migrations/(moved tomigrations/mongodb/) and the modules'adapters/mongo/migrations/, each JSON file amongoCommandsMigration. - 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.