fix(tradein/db): не затирать manager_id при повторном прогоне сида (#2557)
All checks were successful
CI / changes (pull_request) Successful in 12s
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m0s
All checks were successful
CI / changes (pull_request) Successful in 12s
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m0s
Deep-review #2564: manager_id синкался из EXCLUDED безусловно — повторный прогон сида тихо обнулял связь сотрудник->менеджер, назначенную через team-API (#2563), сотрудник выпадал из _LIST_EMPLOYEES_BY_MANAGER_SQL. Защищён COALESCE, как остальные UI-managed поля. is_active убран из ON CONFLICT DO UPDATE SET вовсе (не COALESCE — колонка NOT NULL DEFAULT true делала бы COALESCE-ветку недостижимой, мёртвый код вводил в заблуждение симметрией с реально работающими COALESCE-полями). Open/close доступа — решение владельца продукта через UI (#2556), не повторный прогон seed-файла.
This commit is contained in:
parent
e7a658c7fa
commit
f915e1ee4d
1 changed files with 35 additions and 20 deletions
|
|
@ -22,8 +22,9 @@
|
||||||
--
|
--
|
||||||
-- WHAT:
|
-- WHAT:
|
||||||
-- 1. ASCII-CHECK: tradein_users_username_ascii_ck CHECK (username ~ '^[A-Za-z0-9._-]{3,64}$').
|
-- 1. ASCII-CHECK: tradein_users_username_ascii_ck CHECK (username ~ '^[A-Za-z0-9._-]{3,64}$').
|
||||||
-- Добавлен ДО seed-инсертов (порядок важен: constraint должен успеть провалидировать
|
-- Добавлен ДО seed-инсертов ниже для читаемости файла (CHECK — immediate constraint,
|
||||||
-- вставляемые строки, а не просто существовать после них).
|
-- Postgres валидирует им и ROW-строки транзакции независимо от того, в каком месте
|
||||||
|
-- файла он объявлен относительно INSERT, так что порядок сам по себе не критичен).
|
||||||
-- 2. Seed — org-карта, утверждённая владельцем продукта (2026-07-30):
|
-- 2. Seed — org-карта, утверждённая владельцем продукта (2026-07-30):
|
||||||
-- admin role=admin, manager_id=NULL, is_active=true (владелец)
|
-- admin role=admin, manager_id=NULL, is_active=true (владелец)
|
||||||
-- kopylov role=manager, manager_id=NULL, is_active=true (отдельный клиент)
|
-- kopylov role=manager, manager_id=NULL, is_active=true (отдельный клиент)
|
||||||
|
|
@ -46,16 +47,27 @@
|
||||||
-- `ADD CONSTRAINT IF NOT EXISTS` для CHECK) — паттерн из
|
-- `ADD CONSTRAINT IF NOT EXISTS` для CHECK) — паттерн из
|
||||||
-- 189_account_estimate_usage_nonnegative.sql.
|
-- 189_account_estimate_usage_nonnegative.sql.
|
||||||
-- - INSERT ... ON CONFLICT (username) DO UPDATE, но НЕ безусловно: password_hash,
|
-- - INSERT ... ON CONFLICT (username) DO UPDATE, но НЕ безусловно: password_hash,
|
||||||
-- is_active, display_name, org_name, email защищены COALESCE(текущее, EXCLUDED) —
|
-- manager_id, display_name, org_name, email защищены COALESCE(текущее, EXCLUDED) —
|
||||||
-- если админ уже проставил пароль / поменял is_active / display_name вручную через
|
-- если админ уже проставил пароль / назначил manager_id (team-API #2563 пишет
|
||||||
-- team-UI (#2556) между двумя прогонами этого файла (например ручной re-apply при
|
-- manager_id при создании сотрудника менеджером) / поменял display_name вручную
|
||||||
-- recovery — обычный auto-apply тречит filename в _schema_migrations и не запускает
|
-- через team-UI (#2556) между двумя прогонами этого файла (например ручной re-apply
|
||||||
-- файл дважды на одном окружении, но scratch/staging БД такого трекинга не имеют),
|
-- при recovery — обычный auto-apply тречит filename в _schema_migrations и не
|
||||||
-- повторный прогон НЕ должен затереть это состояние NULL-ом / seed-дефолтом.
|
-- запускает файл дважды на одном окружении, но scratch/staging БД такого
|
||||||
-- role/manager_id намеренно синкаются с EXCLUDED (не защищены) — это и есть источник
|
-- трекинга не имеют), повторный прогон НЕ должен затереть это состояние NULL-ом /
|
||||||
-- истины org-карты из этой миграции; если владелец продукта поправит эту таблицу
|
-- seed-дефолтом. Deep-review #2564 нашёл это живым багом: manager_id, назначенный
|
||||||
-- новой миграцией поверх, DO UPDATE-ветка должна донести исправление, а не заморозить
|
-- через #2563, тихо обнулялся повторным прогоном сида — employee выпадал из
|
||||||
-- первый прогон навсегда.
|
-- `_LIST_EMPLOYEES_BY_MANAGER_SQL`, менеджер переставал видеть его в дашборде.
|
||||||
|
-- role намеренно синкается с EXCLUDED (не защищён) — это и есть источник истины
|
||||||
|
-- org-карты из этой миграции; если владелец продукта поправит эту таблицу новой
|
||||||
|
-- миграцией поверх, DO UPDATE-ветка должна донести исправление роли, а не
|
||||||
|
-- заморозить первый прогон навсегда.
|
||||||
|
-- - is_active НАМЕРЕННО отсутствует в SET (не COALESCE — колонка NOT NULL DEFAULT
|
||||||
|
-- true, COALESCE(NOT NULL, x) никогда не берёт x, это была бы мёртвая, вводящая в
|
||||||
|
-- заблуждение симметрия с password_hash/manager_id, deep-review #2564 medium).
|
||||||
|
-- Открытие/закрытие доступа (is_active) — решение владельца продукта, принимается
|
||||||
|
-- через UI (#2556), НЕ повторным прогоном этого seed-файла: после первой вставки
|
||||||
|
-- колонка сознательно «замораживается» на текущем значении в БД, seed её больше
|
||||||
|
-- не трогает.
|
||||||
--
|
--
|
||||||
-- Dependencies: 192_tradein_users_auth.sql (создаёт tradein_users, tradein_sessions).
|
-- Dependencies: 192_tradein_users_auth.sql (создаёт tradein_users, tradein_sessions).
|
||||||
-- Deploy order: после 192 (Foundation). Backend auth-код (login/password-verify) и
|
-- Deploy order: после 192 (Foundation). Backend auth-код (login/password-verify) и
|
||||||
|
|
@ -64,7 +76,7 @@
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
-- Часть 1: ASCII-CHECK — должен применяться ДО вставки seed-строк ниже.
|
-- Часть 1: ASCII-CHECK (immediate constraint — валидирует и вставляемые ниже строки).
|
||||||
DO $$
|
DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NOT EXISTS (
|
IF NOT EXISTS (
|
||||||
|
|
@ -100,13 +112,16 @@ VALUES
|
||||||
('user9', NULL, 'employee', NULL, NULL, NULL, NULL, true),
|
('user9', NULL, 'employee', NULL, NULL, NULL, NULL, true),
|
||||||
('user10', NULL, 'employee', NULL, NULL, NULL, NULL, true)
|
('user10', NULL, 'employee', NULL, NULL, NULL, NULL, true)
|
||||||
ON CONFLICT (username) DO UPDATE SET
|
ON CONFLICT (username) DO UPDATE SET
|
||||||
role = EXCLUDED.role,
|
role = EXCLUDED.role,
|
||||||
manager_id = EXCLUDED.manager_id,
|
-- manager_id защищён COALESCE: team-API (#2563) пишет manager_id при назначении
|
||||||
|
-- сотрудника менеджером, повторный прогон seed'а не должен тихо обнулять эту связь.
|
||||||
|
manager_id = COALESCE(tradein_users.manager_id, EXCLUDED.manager_id),
|
||||||
password_hash = COALESCE(tradein_users.password_hash, EXCLUDED.password_hash),
|
password_hash = COALESCE(tradein_users.password_hash, EXCLUDED.password_hash),
|
||||||
is_active = COALESCE(tradein_users.is_active, EXCLUDED.is_active),
|
display_name = COALESCE(tradein_users.display_name, EXCLUDED.display_name),
|
||||||
display_name = COALESCE(tradein_users.display_name, EXCLUDED.display_name),
|
org_name = COALESCE(tradein_users.org_name, EXCLUDED.org_name),
|
||||||
org_name = COALESCE(tradein_users.org_name, EXCLUDED.org_name),
|
email = COALESCE(tradein_users.email, EXCLUDED.email),
|
||||||
email = COALESCE(tradein_users.email, EXCLUDED.email),
|
-- is_active НЕ в SET: NOT NULL DEFAULT true колонка, COALESCE был бы мёртвым кодом
|
||||||
updated_at = now();
|
-- (см. IDEMPOTENCY выше) — open/close доступа решается через UI (#2556), не seed'ом.
|
||||||
|
updated_at = now();
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue