Files
jobtrackingapp/docs/database/migrations.md
T
cesnimda e75c4a4775
MariaDB persistence qualification / mariadb (push) Failing after 1m7s
docs(database): record MariaDB qualification and retirement gates
2026-10-24 01:52:03 +02:00

2.5 KiB

Migrations and compatibility

The API applies EF Core migrations on startup and performs guarded legacy-schema reconciliation. MariaDB is the standard; fresh/repeated/populated disposable MariaDB startup and persisted-state tests are the database integration lane. Explicit SQLite compatibility remains temporarily for existing data/legacy tests. Generated SQL and SQLite passes are not MariaDB runtime evidence. See current qualification; no production migration is authorized here.

SQLite startup explicitly enables write-ahead logging (WAL) before reconciliation opens the database file. This lets concurrent readers coexist with committed usage and preference writes; it changes journaling, not stored fields or ownership. MariaDB/MySQL initialization is unchanged. Use the existing VACUUM INTO backup runner for a consistent SQLite snapshot, including committed WAL contents; copying only a running database's .db file is insufficient. Disposable startup, held-reader/write and independent backup tests cover this boundary; they do not replace production restore qualification.

The Job/JobApplication opportunity cutover is an expand/verify/contract change. Keep dual writes and compatibility reads until a production report and restored-backup rehearsal pass, then observe one release before removing legacy columns in a later migration. Never edit the history of an applied migration.

Production cutover validation

After the additive backfill, run these read-only MariaDB/MySQL checks against production and a restored backup. Every result must be 0; do not turn them into an update script.

SELECT COUNT(*) AS missing_job
FROM JobApplications
WHERE JobId IS NULL;

SELECT COUNT(*) AS missing_target
FROM JobApplications a
LEFT JOIN Jobs j ON j.Id = a.JobId
WHERE a.JobId IS NOT NULL AND j.Id IS NULL;

SELECT COUNT(*) AS owner_mismatch
FROM JobApplications a
JOIN Jobs j ON j.Id = a.JobId
WHERE NOT (a.OwnerUserId <=> j.OwnerUserId);

SELECT COUNT(*) AS field_mismatch
FROM JobApplications a
JOIN Jobs j ON j.Id = a.JobId
WHERE NOT (a.CompanyId <=> j.CompanyId)
   OR NOT (a.JobTitle <=> j.JobTitle)
   OR NOT (a.Location <=> j.Location)
   OR NOT (a.JobUrl <=> j.JobUrl)
   OR NOT (a.Description <=> j.Description)
   OR NOT (a.Salary <=> j.Salary);

Observe one release after the checks pass, then change reads, re-run the checks on a fresh restore, and only then make JobId required and remove duplicated opportunity columns in a later migration.