parity(api): declare _goldbank_migrations as an ignored model; drift now zero

Prisma migrate diff proposed DROP TABLE "_goldbank_migrations" because the
table exists in the database but was not declared in the schema. Declaring
it with @@ignore removes the proposal without exposing it to Prisma Client,
and the table and all its rows are kept.

Correcting the earlier DEAD-07 note: this is not a leftover from the
pre-Prisma port. It is the tracking table of the application's own
migration runner (src/prisma/migrate.ts:5), which exists because the Docker
deploy image is copy-only and ships no Prisma CLI, so migrate deploy cannot
run in the container (migrate.ts:7-13). The project therefore keeps two
ledgers deliberately: _prisma_migrations for the CLI in development, and
_goldbank_migrations for the runtime runner in the container. That runner
already filtered out any DROP of its own table (migrate.ts:190-196); the
schema declaration removes the cause rather than relying on that guard.

The practical consequence, recorded in DECISIONS.md D15: a new migration
must be safe under both paths, so its SQL stays idempotent.

The ledger grew 12 -> 14 rows while testing, with nothing deleted: starting
the API ran prepareDatabase(), which appended the two migrations applied
earlier today. Its $$-aware statement splitter handled the PL/pgSQL trigger
body correctly — trigger and function are both present and the 9 trigger
assertions pass against the live database.

Also records the UTF-8 testing rule: Persian test input must come from a
file, never a shell argument, because the Windows shell replaces Persian
characters with '?' and a test can then pass while storing '????'.

Verified: migrate diff -> "This is an empty migration" (zero drift);
migrate status -> up to date; tsc clean; 32 jest; 9 trigger assertions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-09-22 08:25:03 +03:30
co-authored by Claude Opus 5
parent 8133a2bdf4
commit 654b98520d
4 changed files with 147 additions and 5 deletions
+20 -1
View File
@@ -51,7 +51,7 @@ while the id and the id-addressed routes remain.**
## ⚠️ Read `DECISIONS.md` before doing anything
All user rulings live there (D0–D14). Highlights that change how work is done:
All user rulings live there (D0–D15). Highlights that change how work is done:
- **D12 — the matrix is FIELD-BY-FIELD, not page-by-page**, and a 4-step
round-trip test per entity is mandatory. Both rules were added to the
@@ -104,6 +104,7 @@ All user rulings live there (D0–D14). Highlights that change how work is done:
| D12 | **Field-by-field matrix + mandatory round-trip test.** Added to the skill. |
| D13 | **Retail storefront (wallet, cashback, `ConfigStatic['percent']`) preserved but OUT OF SCOPE.** Nothing deleted or disabled; no parity work; matrices list it ⏸️ with no gap/work row; ask before touching shared surfaces. |
| D14 | **`migrate dev` in development, `migrate deploy` in production and nowhere else.** Never `migrate reset`; never edit `_prisma_migrations`. On drift + a reset offer: **stop and report**. |
| D15 | **`_goldbank_migrations` is KEPT** — it is the tracking table of the app's own migration runner (`src/prisma/migrate.ts`), needed because the Docker image has no Prisma CLI. Declared `@@ignore`d; drift is zero. **Persian test input must come from a FILE, never a shell argument.** |
## Open — awaiting user approval
@@ -196,3 +197,21 @@ different from what you wrote:
Re-read after writing if you need the stored value. See `DECISIONS.md` §D14 and
the doc comment on the `Customer` model in `schema.prisma`.
## ⚠️ Two migration ledgers, on purpose (D15)
| Ledger | Written by | Used |
|---|---|---|
| `_prisma_migrations` | the Prisma CLI | development |
| `_goldbank_migrations` | `apps/api/src/prisma/migrate.ts` | the deployed container, at boot |
The Docker deploy image is copy-only and ships **no Prisma CLI**, so the app
applies migrations itself at startup. **Every new migration must be safe under
both paths** — keep the SQL idempotent (`IF NOT EXISTS`, `CREATE OR REPLACE`).
## ⚠️ Persian test input comes from a FILE (D15)
The Windows shell replaces Persian characters with `?`. A test that passes its
data inline can "pass" while storing `????`. Write fixtures in the test file or
a UTF-8 JSON file and send bodies with `curl --data-binary @file`. Console
output of Persian is never evidence — compare values in Node.