Files
2026-11-14 09:56:45 +00:00

7.7 KiB

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, 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/<id>/adapters/mongo/migrations/, declared in its manifest as migrations: { 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:

  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) -- and REDIS_URL for the queue.
  2. apps/web (src/server/dialect/stores.ts) and apps/worker (src/dialect/runtime.ts) compose connectMongoDataSourceFromEnv (which refuses a standalone server, above) and the queue is createBullmqJobQueue/createBullmqWorker over REDIS_URL, with the kit's outbox relay over the same data source.
  3. The migrate job (apps/worker/src/migrate.ts, migrateDialect) runs runMongoMigrationsFromEnv (each JSON file a mongoCommandsMigration) over migrations/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.
  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.