feat(tradein/db): seed существующих юзеров + ASCII-CHECK на username (#2557) #2564

Merged
lekss361 merged 2 commits from feat/tradein-users-seed into main 2026-07-30 19:17:35 +00:00
Owner

Closes #2557 (эпик #2549, шаг 7/8).

193_tradein_users_seed.sql:

  • ASCII-CHECK username ~ '^[A-Za-z0-9._-]{3,64}$' (требование deep-review #2561) — fail-closed на уровне схемы против latin-1 схлопывания кириллических логинов в общий downstream-identity. Добавлен ДО инсертов, идемпотентно через pg_constraint-проверку (паттерн 189_*).
  • Seed org-карты: admin→admin; kopylov, praktika→manager; user1, user3–user10→employee (свободные слоты без org); user2→employee + is_active=false (Брусника, закрыт 2026-07-30). QA-фикстуры (admintest/pilottest/analysttest/expiredtest) не мигрируются — остаются в roles.yaml.
  • password_hash = NULL у всех: вход по паролю невозможен, доступ держится на legacy Caddy (dual-mode) — миграция никого не отключает. Пароли админ проставит через team-UI (#2556).
  • display_name='Копылов' — единственные задокументированные реальные данные (auth.py _USERNAME_PROFILE), остальное NULL (не выдумываем).
  • Идемпотентность: ON CONFLICT DO UPDATE с COALESCE(текущее, EXCLUDED) на password_hash/is_active/профильных полях — повторный прогон не затирает то, что менеджер поменял через UI; role/manager_id намеренно синкаются (источник истины org-карты).

Валидация на scratch-БД в tradein-postgres: прогон 192 → 193 (13 строк) → симуляция ручной правки через UI → прогон 193 повторно (правка сохранена, констрейнт не задублирован) → sanity-check INSERT 'иванов' → отказ по констрейнту → DROP DATABASE. Боевая БД не тронута.

Closes #2557 (эпик #2549, шаг 7/8). `193_tradein_users_seed.sql`: - **ASCII-CHECK** `username ~ '^[A-Za-z0-9._-]{3,64}$'` (требование deep-review #2561) — fail-closed на уровне схемы против latin-1 схлопывания кириллических логинов в общий downstream-identity. Добавлен ДО инсертов, идемпотентно через `pg_constraint`-проверку (паттерн 189_*). - **Seed org-карты**: admin→admin; kopylov, praktika→manager; user1, user3–user10→employee (свободные слоты без org); user2→employee + `is_active=false` (Брусника, закрыт 2026-07-30). QA-фикстуры (admintest/pilottest/analysttest/expiredtest) не мигрируются — остаются в roles.yaml. - `password_hash = NULL` у всех: вход по паролю невозможен, доступ держится на legacy Caddy (dual-mode) — миграция никого не отключает. Пароли админ проставит через team-UI (#2556). - `display_name='Копылов'` — единственные задокументированные реальные данные (auth.py `_USERNAME_PROFILE`), остальное NULL (не выдумываем). - Идемпотентность: `ON CONFLICT DO UPDATE` с `COALESCE(текущее, EXCLUDED)` на password_hash/is_active/профильных полях — повторный прогон не затирает то, что менеджер поменял через UI; role/manager_id намеренно синкаются (источник истины org-карты). Валидация на scratch-БД в tradein-postgres: прогон 192 → 193 (13 строк) → симуляция ручной правки через UI → прогон 193 повторно (правка сохранена, констрейнт не задублирован) → sanity-check `INSERT 'иванов'` → отказ по констрейнту → `DROP DATABASE`. Боевая БД не тронута.
lekss361 added 1 commit 2026-07-30 18:57:47 +00:00
feat(tradein/db): seed существующих юзеров + ASCII-CHECK на username (#2557)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 10s
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 1m56s
e7a658c7fa
Migration 193: переносит org-карту (admin/kopylov/praktika/user1-10), утверждённую
владельцем продукта, из auth/roles.yaml в tradein_users (Foundation — миграция 192).
password_hash=NULL для всех — пароли админ проставит вручную через team-UI (#2556).
ASCII-CHECK на username (deep-review #2561): rbac кодирует session-username через
encode("latin-1","replace"), кириллические логины одинаковой длины схлопываются
в общий downstream-identity (IDOR) — constraint запрещает это fail-closed.

ON CONFLICT DO UPDATE защищает password_hash/is_active/display_name/org_name/email
через COALESCE — повторный прогон (recovery / staging без _schema_migrations
tracking) не затирает то, что менеджер поменял через UI.
bot-backend added 1 commit 2026-07-30 19:09:21 +00:00
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
f915e1ee4d
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-файла.
lekss361 merged commit a916ceea52 into main 2026-07-30 19:17:35 +00:00
lekss361 deleted branch feat/tradein-users-seed 2026-07-30 19:17:35 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2564
No description provided.