9.9 KiB
MariaDB standardisation and RD21 qualification
MariaDB is the intended application database for development, integration testing, CI and production. SQLite remains only as an explicit, temporary preservation/legacy-test path. Missing MariaDB configuration and unknown provider names fail closed; they never select SQLite.
This work starts at RD21 repair 0d16a691e0249fe1264bf960de5e59eaa9b87fed on
codex/rd21-mariadb-standardisation. The final acceptance record separates
runtime, Docker/CI, retirement and release decisions. No main merge or production operation is authorized.
Version and image identity
The product owner verified production 12.2.2-MariaDB-ubu2404, using floating mariadb:latest,
with running image configuration ID
sha256:e0236fc6386e7eacd9359e59d0a078bd7aa0d18280d36d13061121bedeaee903.
This is not a pullable registry manifest digest. The repository previously advertised11.0.0 and
used a floating11 client image; those facts did not identify production.
The standalone Compose database uses the official Linux/amd64 image:
mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00
The manifest, configuration and every image layer were downloaded from the official registry and
SHA256/size verified. Image provenance records the corresponding config
digest sha256:dec309ca7f95ab98e85fcf56acb9c4f05da59125c09d9e60a521f15f12643d7b and Ubuntu24.04
package version. It differs from production's reported image ID: same server patch is not exact
production image equality. Other architectures need their own verified official manifest; do not
reuse this amd64 digest while claiming another platform.
Use explicit version plus verified digest for a future operator-reviewed production change.
latest can move independently of application releases. This task does not change, pull into,
restart, upgrade, downgrade or recreate production. 12.3 LTS investigation
recommends a separate pinned12.3.3 rehearsal, including isolation, driver and recovery gates.
Persistent local development
Prerequisites: working local Docker engine/Compose, pinned .NET9.0.317 and existing frontend dependencies. From the repository root:
rtk proxy docker compose -f docker-compose.database.yml up -d --wait mariadb-dev
rtk proxy C:/Users/Connor/.dotnet/dotnet.exe run --project JobTrackerApi/JobTrackerApi.csproj
On other hosts use the installed pinned dotnet. The database is loopback-only port33306,
database/user jobtracker_dev, development password jt-development-only. The root password
jt-development-root-only belongs only to this standalone development service. The API's
Development settings match these values; authentication settings remain separately required.
Use local user secrets for non-placeholder auth/admin configuration. Do not copy these credentials
or volumes to production. Environment overrides such as ConnectionStrings__JobTracker take precedence.
The standalone Compose project jobtracker-local owns the persistent mariadb_dev volume. It is
separate from the production Compose file, networks, .env and application data volumes. A fresh
database is initialized by the API's existing migration/reconciliation startup. Repeated/populated
startup must preserve rows. Do not run down -v to resolve a schema problem, delete the dev volume,
or point tests at an existing user database. Stop the service without removing data if needed:
rtk proxy docker compose -f docker-compose.database.yml stop mariadb-dev
There is intentionally no automatic destructive development reset. Export/backup and verify required
data before an independently authorized reset. Existing SQLite files are not opened, imported,
deleted or replaced by selecting the new default. To preserve/read an old database temporarily,
explicitly set Database__Provider=sqlite and its existing ConnectionStrings__JobTracker path;
do not confuse the Development MariaDB connection string with a SQLite connection string.
Disposable MariaDB integration lane
rtk proxy python scripts/test-mariadb-integration.py
rtk proxy python scripts/mariadb-integration.py
The second command creates a generated jobtracker-it-<guid> Compose project, allocates an
available loopback port and starts only mariadb-test with the pinned image and health checks.
Its data is private tmpfs, never the persistent development volume. The test administrator password
is separately jt-integration-only; no production credentials are needed. Each test creates a new
jt_it_<guid> schema and drops only that fixture's successfully-created schema. Tests initialize
the actual startup schema; they do not patch missing tables with EnsureCreated.
The runner performs locked restore and the complete JobTrackerApi.MariaDb.Tests project. Missing,
unreachable or version-mismatched databases fail the explicit lane, never skip or fall back.
Logs, native TRX and command/process outcomes go to .artifacts/mariadb/integration/. Cleanup
removes only the generated test service, without down -v; a cleanup error fails the runner.
To reset a manually started disposable service, first verify it is the test service with tmpfs
and contains no needed data, then remove only that service:
rtk proxy docker compose -f docker-compose.database.yml --profile integration rm --stop --force mariadb-test
An isolated existing loopback test server can run the identical project:
$env:JOBTRACKER_MARIADB_TEST_ADMIN='Server=127.0.0.1;Port=33307;User ID=root;Password=jt-integration-only;SslMode=None'
rtk proxy python scripts/mariadb-integration.py --existing-server --output .artifacts/mariadb/explicit-integration
The fixture rejects remote/non-TCP endpoints, requires exact12.2.2 by default and ignores any selected
admin database in favor of a new schema. Loopback is a guard, never permission to tunnel production
locally. Alternate JOBTRACKER_MARIADB_TEST_VERSION values label a separate compatibility run;
they cannot be used to claim12.2.2 parity. The CI workflow uses the Compose command, requires a Docker
daemon/Compose and preserves evidence. A checked-in workflow is not proof of a successful hosted run.
The first hosted execution, run843,
failed before database tests because the runner job image has no docker executable. Hosted CI
remains blocked pending an isolated Docker/Compose-capable test runner; local Compose32/32 remains
separate evidence. Do not expose a production Docker socket to resolve this prerequisite.
The ordinary backend project still contains explicitly transitional SQLite/InMemory unit/legacy contracts. The ordinary browser fixture explicitly selects SQLite until its SQL seed/proof helpers are ported. Those results remain useful but are never labelled MariaDB integration evidence.
Native MariaDB browser recovery lane
Build the API in Release and the UI static export first. Install the official MariaDB command-line
client locally and set JOBTRACKER_MARIADB_CLIENT to its absolute executable path. This lane uses
the pinned test service, never the persistent development database. For a fresh run, use an unused
loopback port (33308 below) and a generated project/schema; preserve the resulting JSON report:
$project='jobtracker-it-browser-'+[Guid]::NewGuid().ToString('N')
$db='jt_it_'+[Guid]::NewGuid().ToString('N')
$env:MARIADB_TEST_PORT='33308'
$env:JOBTRACKER_MARIADB_BROWSER_PORT='33308'
$env:JOBTRACKER_MARIADB_CLIENT=(Get-Command mariadb).Source
$env:MYSQL_PWD='jt-integration-only'
rtk proxy docker compose --project-name $project -f docker-compose.database.yml --profile integration up -d --wait mariadb-test
# Check each exit code before continuing. Only a successful CREATE establishes ownership.
& rtk proxy $env:JOBTRACKER_MARIADB_CLIENT --host=127.0.0.1 --port=33308 --user=root "--execute=CREATE DATABASE $db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
$env:JOBTRACKER_MARIADB_BROWSER_CONNECTION="Server=127.0.0.1;Port=33308;Database=$db;User ID=root;Password=jt-integration-only;SslMode=None"
$env:PLAYWRIGHT_STATIC_EXPORT='true'
$env:PLAYWRIGHT_PREBUILT_EXPORT='true'
$env:PLAYWRIGHT_JSON_OUTPUT_NAME='../.artifacts/mariadb/browser.json'
Push-Location job-tracker-ui
rtk proxy node node_modules/@playwright/test/cli.js test --config=playwright.mariadb.config.ts --reporter=list,json
Pop-Location
# Remove only this generated disposable container after retaining the test result and logs.
rtk proxy docker compose --project-name $project -f docker-compose.database.yml --profile integration rm --stop --force mariadb-test
The service's tmpfs discards only this run's test schemas when removed. Never substitute an existing
project/container or the dev service. The config accepts only the shown canonical connection format,
requires the independent SQL reader's port to match and refuses server reuse. The test checks actual
SELECT VERSION(), retains drafts across 409/network failures and checks durable SQL state before
and after reviewed retries, refresh and a new login. Run its boundary checks with
rtk proxy node --test job-tracker-ui/scripts/mariadb-browser-connection.test.mjs.
Records
- Implementation plan, actual validation, acceptance.
- All baseline SQLite references/classification, audit summary.
- Safe staged retirement, three fixture deltas.
- 12.3 LTS upgrade/recovery gates.
Historical Phase9 acceptance and the previous RD21 addendum remain historical records. The three active obsolete fixtures are intentionally corrected under the owner's new instruction; their old failures, exact deltas and before/after hashes are retained. No SQLite package, compatibility schema branch, database or migration history has been removed in this stage.