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

The mariadb profile

Status (2026-11-01): a selectable app profile; local evidence only. kit template:prune --profile mariadb 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/mariadb/. Every process then reads the one MARIADB_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 mariadb data source, BullMQ on Valkey and the kit's outbox relay. The modules account, notes and documents ship mariadb 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 migrate job adds the live log and a row trigger per collection; the web polls it every second). 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 MariaDB instead of Postgres (spec §5.1): the same procedures, the same modules, the same migrations discipline, on the Kysely MySQL dialect (@conusai-kit/data-kysely/mysql) with jobs on BullMQ over Valkey (@conusai-kit/jobs-bullmq).

postgres (default) mariadb (this profile)
Primary store Postgres 18 MariaDB LTS
Data adapter @conusai-kit/data-kysely @conusai-kit/data-kysely/mysql
Jobs pg-boss (Postgres) BullMQ on Valkey (@conusai-kit/jobs-bullmq)
Tenant wall repository predicate + RLS (three roles, AT-D20) repository predicate alone — MariaDB has no RLS
Links postgres, identity mariadb, redis, identity
Process env POSTGRES_URL, POSTGRES_READER_URL, POSTGRES_MIGRATE_URL MARIADB_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.

What this folder carries

  • conusai.json — the profile's deployment contract: the same three services, links mariadb + redis + identity. There is no mariadb.migrate flag: the three-role split it declares on Postgres (data-services DS21) exists to make row-level security bind, and MariaDB has none, so every process holds the one MARIADB_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 mariadb:lts and valkey/valkey:9-alpine, the images the platform's catalog offers.
  • migrations/ — the kernel tables (tenancy, sign-in, files, proposals, outbox, idempotency keys) as MariaDB DDL, generated by mysqlSchemaStatements from the same entity definitions as the postgres files and committed, forward-only. A module's own MariaDB migrations live with the module: modules/<id>/adapters/kysely/mysql/migrations/, declared in its manifest as migrations: { postgres: "migrations", mariadb: "adapters/kysely/mysql/migrations" }.

The composition (wired)

The profile is chosen at generation time (.conusai/template.json profile), and kit template:prune --profile mariadb removes the other dialects. What it selects:

  1. config/src/env.ts reads MARIADB_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 createMysqlDataSource (Kysely MysqlDialect + mysql2) 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 runMysqlMigrationsFromEnv over migrations/mariadb/ (moved there from this folder) and the modules' adapters/kysely/mysql/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 MariaDB schema is its own numbered SQL folder, reviewed like any migration.

Proof

  • @conusai-kit/data-kysely's MySQL dialect passes the shared repository and capability contract suites against mariadb:lts in testcontainers — the tenant predicate is the wall, and the contract is what proves it.
  • @conusai-kit/jobs-bullmq passes the shared JobQueue contract against valkey/valkey:9 in testcontainers.
  • scripts/vendor/test-template.sh app --profile mariadb runs the template's gate and then applies this folder's and the modules' MariaDB migrations to a real MariaDB LTS container, so the committed DDL is proven against the engine, not just generated.