105 lines
7.7 KiB
Markdown
105 lines
7.7 KiB
Markdown
<!-- SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 -->
|
|
# 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.
|