Files
jobtrackingapp/docs/database/mariadb-standardisation/README.md
T
cesnimda 549b2cba5a
MariaDB persistence qualification / mariadb (push) Failing after 46s
docs(ci): record hosted MariaDB runner prerequisite failure
2026-10-24 01:55:56 +02:00

162 lines
9.9 KiB
Markdown

# 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](ACCEPTANCE.md) 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:
```text
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](image-provenance.json) 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](MARIADB_12_3_PLAN.md)
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:
```powershell
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:
```powershell
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
```powershell
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:
```powershell
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:
```powershell
$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](https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/843),
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:
```powershell
$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](PLAN.md), [actual validation](validation.json), [acceptance](ACCEPTANCE.md).
- [All baseline SQLite references/classification](sqlite-references.json), [audit summary](SQLITE_AUDIT.md).
- [Safe staged retirement](SQLITE_RETIREMENT.md), [three fixture deltas](fixture-delta.json).
- [12.3 LTS upgrade/recovery gates](MARIADB_12_3_PLAN.md).
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.