59 lines
6.8 KiB
Markdown
59 lines
6.8 KiB
Markdown
# Перенос арендатора Staff
|
||
|
||
`scripts/rehome-tenant.mjs` переносит все строки из одного tenant ID в другой в схеме `public`. Скрипт рассчитан на остановленное приложение и запускается только привилегированной ролью БД, способной обходить RLS и изменять таблицы. Строки пароля или подключения в отчёты не выводятся.
|
||
|
||
CLI по умолчанию выполняет только read-only dry-run; `--dry-run` можно указать явно. Совместимые имена `--from`/`--to` и `--json` принимаются для rehearsal-обвязок; вывод всегда JSON. Сначала на восстановленной копии базы выполните dry-run:
|
||
|
||
```powershell
|
||
$env:DATABASE_ADMIN_URL = 'postgresql://…'
|
||
node scripts/rehome-tenant.mjs --from <ULID> --to <ULID> --dry-run --json
|
||
```
|
||
|
||
Для совместимости со старыми локальными инструкциями также принимаются `DATABASE_REHOME_URL` и `DATABASE_MIGRATION_URL` как fallback. `--apply` по-прежнему требует явный флаг, actor и проверенный `--backup-evidence`; aliases и default dry-run не разрешают запись сами по себе.
|
||
|
||
Dry-run открывает транзакцию `READ ONLY` и выводит только идентификаторы переноса и количество строк по таблицам. Он не блокирует записи; поэтому результат является снимком для планирования, а не гарантией актуальности на момент apply. На копии и в согласованное окно с остановленным приложением повторите dry-run непосредственно перед переносом.
|
||
|
||
## Обязательное подтверждение восстановления
|
||
|
||
Apply требует `--backup-evidence <путь>` и читает JSON отчёт. Само имя файла и существование файла не считаются доказательством. JSON должен содержать сведения о зашифрованном off-host `pg_dump -Fc` и успешном restore drill именно этого backup:
|
||
|
||
```json
|
||
{
|
||
"backup": {
|
||
"format": "pg_dump -Fc",
|
||
"encrypted": true,
|
||
"offHost": true,
|
||
"sha256": "<64 hex characters>",
|
||
"createdAt": "2026-09-26T08:00:00Z"
|
||
},
|
||
"restoreDrill": {
|
||
"status": "passed",
|
||
"backupSha256": "<same 64 hex characters>",
|
||
"restoredAt": "2026-09-26T08:30:00Z",
|
||
"verifiedAt": "2026-09-26T08:45:00Z",
|
||
"isolatedDatabase": "krona_staff_restore_check"
|
||
}
|
||
}
|
||
```
|
||
|
||
Этот файл удостоверяет результаты, предоставленные оператором; скрипт не проверяет доступ к хранилищу, шифрование или пригодность backup самостоятельно. Сохраните исходный backup, хеш и протокол restore drill вне сервера приложения.
|
||
|
||
## Apply
|
||
|
||
Проверьте dry-run и backup evidence, остановите приложение, затем запускайте в согласованное окно. `--actor` — ULID уполномоченного пользователя Core, не пароль или секрет:
|
||
|
||
```powershell
|
||
node scripts/rehome-tenant.mjs --apply `
|
||
--source <ULID> --target <ULID> --actor <CORE_USER_ULID> `
|
||
--backup-evidence .\evidence\restore-drill.json
|
||
```
|
||
|
||
Apply использует одну транзакцию, сериализуемый уровень изоляции, advisory lock и детерминированные `ACCESS EXCLUSIVE` locks всех таблиц `public.staff_*`. Скрипт отказывает, если целевой tenant уже содержит строки, таблица лишена `tenant_id` или FORCE RLS, обнаружен неизвестный пользовательский trigger либо внешний FK, или роль БД не может безопасно выполнить перенос. Существующие FK сохраняются с их определениями и состоянием validation; если проверка после пересоздания не совпала, транзакция откатывается.
|
||
|
||
Отчёт содержит количества перенесённых строк и суммы `staff_payroll_ledger.amount_minor` отдельно по валюте. В `staff_audit_log` перенос сам создаёт ровно одну новую запись `tenant.rehomed` под целевым tenant. Поэтому число строк `staff_audit_log` после commit равно исходному числу строк источника плюс одна; по всем остальным таблицам количество равно исходному. Запись аудита включает from/to, исходные количества, суммы реестра, Core actor, correlation ID и SHA-256/время backup и проверки restore.
|
||
|
||
При ошибке stdout/stderr не содержит URL подключения, значений строк или текста серверной ошибки: транзакция откатывается, а в stderr печатается только безопасное сообщение и, если есть, пятисимвольный PostgreSQL SQLSTATE. После успешного commit отдельно проверьте `SELECT DISTINCT tenant_id` по каждой staff таблице, количества строк, сумму реестра по валюте и наличие записи `tenant.rehomed`.
|
||
|
||
## Интеграционный тест
|
||
|
||
Тест `tests/integration/rehome-tenant.test.ts` предназначен только для отдельной пустой PostgreSQL 17 базы, имя которой заканчивается на `_rehome_test`. Он требует `DATABASE_REHOME_TEST_URL` и явное `DATABASE_REHOME_TEST_CONFIRM=I_ACKNOWLEDGE_DISPOSABLE_PG17_DATABASE`, создаёт в ней роль приложения без пароля при необходимости и применяет миграции на чистой схеме. В конце тест очищает таблицы `public.staff_*`; проверка пустоты выполняется до вставки фикстур. Не указывайте production, pilot или общую базу.
|