65 lines
3.8 KiB
Markdown
65 lines
3.8 KiB
Markdown
# PostgreSQL migrations
|
||
|
||
M2 issue #12 chooses the migration runner and ordered file naming. Keep schema
|
||
changes versioned and repeatable; do not introduce a competing runner here.
|
||
Subsequent issues #13-18 add physical folders, logical models, distinct files,
|
||
metadata and import jobs. Application added_at timestamps are separate from file
|
||
mtime. Migrations must never implicitly delete underlying library files.
|
||
|
||
## Catalog identity — 20261012120001
|
||
|
||
Back up the database and **stop all writers** (web requests, import workers and
|
||
other database clients) before either upgrade or downgrade. Keep them stopped
|
||
through preflight and DDL. Preflight is not a concurrency lock.
|
||
|
||
Upgrade rejects duplicate managed paths and noncanonical paths, even without a
|
||
collision, reporting offending file IDs. It makes file ownership nullable with
|
||
RESTRICT on model deletion, replaces idx_files_model_path with unique
|
||
idx_files_managed_path and nonunique idx_files_model_id, and makes
|
||
idx_models_folder_name nonunique. Explicitly detach files before model deletion.
|
||
Rows, IDs, timestamps, dependent metadata and unrelated indexes/FKs are preserved.
|
||
|
||
Managed paths are lexical slash-separated relative names, preserved verbatim.
|
||
Empty/dot/dot-dot segments, backslashes, NUL, absolute paths and URI/drive prefixes
|
||
are rejected. Windows additionally rejects colons and trailing dots/spaces in
|
||
segments. Case and Unicode are not normalized. This is not filesystem case
|
||
comparison or symlink authorization; PathSafety still governs I/O. Migration
|
||
validation performs no filesystem access.
|
||
|
||
Investigate reported IDs and explicitly resolve catalog paths and ownership
|
||
against the library before retrying. No automatic merging, renaming, reassignment
|
||
or deletion repairs conflicts.
|
||
|
||
Downgrade to 20261011120006 rejects unassigned file IDs and duplicate same-folder
|
||
model titles before DDL. Explicitly assign files and disambiguate titles first.
|
||
Only then are NOT NULL, per-model path uniqueness, unique folder/title and the
|
||
old CASCADE model FK restored. Preflight failure leaves schema, data and migration
|
||
version unchanged.
|
||
|
||
Tasks 1–3 restore repository/importer compatibility and add the bounded catalog
|
||
service: explicit same-title identities, ambiguity-safe legacy lookup, nullable
|
||
registration and expected-owner associations using savepoint-backed transactions.
|
||
Association changes update only model_id, not physical files or home folders.
|
||
|
||
Task 4 verified the full suite on 2026-10-13:
|
||
|
||
- Windows PHP 8.3.35: foundation passed; PHPUnit 377 tests / 2032 assertions /
|
||
28 skips; standard lint passed (Composer script commands invoked directly).
|
||
- Fresh isolated PostgreSQL 17 / PHP 8.4.26 via `sh bin/test-postgres.sh`: Composer
|
||
tests 377 / 2160 / 7 skips and lint passed. Log on the Docker host:
|
||
`keith@192.168.2.23:/tmp/meshvault-catalog-tests-Ov96uNzU/pg-run-3.log`.
|
||
- The suite runs production migrations in generated schemas, including populated
|
||
down/up, dependent metadata, direct constraints, index preservation and unchanged
|
||
preflight-rejection snapshots. This does not replace an operator backup/restore
|
||
drill or deployment migration smoke acceptance.
|
||
- First PG run exposed four SQLite-trigger syntax errors in rollback tests;
|
||
dialect-specific test triggers now prove rollback after an actual earlier write.
|
||
Six new two-session cases verify 55P03 contention, stale/no-op behavior, ascending
|
||
execution parameters, nested rollback/lock release and root creation serialization.
|
||
They passed existing locking code; no induced deadlock or mutation-red claim.
|
||
|
||
No development database or historical workspace was touched. Independent full-slice
|
||
review approved this bounded implementation; #28 is not complete. Importer confirmation/recovery, broader
|
||
metadata/lifecycle contracts and unresolved M2/M3 acceptance remain open. See
|
||
`docs/project-status.md` for the evidence and limitations.
|