# V2 — история 2026-06-12 (финал) ## V2 — это тестовый стенд для модулей Код в `v2/` — НЕ production. Это полигон для отладки модулей. Каждый модуль тестируется изолированно, затем будет интегрирован в основной код. ## Текущее состояние (0.5.73) ``` v2/ ├── server.js # createV2Router() → /v2/login, /v2/iam, /v2/logout ├── src/ │ ├── auth/index.js # fetchIamUser(), login(), exchangeCode(), buildAuthUrl() │ ├── config/index.js # iamUrl, appUrl, version (без KC — пока не нужен) │ ├── crud/index.js # createCrudRouter() — НЕ монтирован (будет позже) │ ├── db/ │ │ ├── index.js # pg pool │ │ ├── queries.js # CRUD SQL │ │ └── schema.js # ensureSchema(pool) — автосоздание v2_* таблиц │ └── validators/index.js # CIDR validate, overlaps, BLOCKED_RANGES └── history/ └── 2026-06-12.md ``` ## Как работает сейчас 1. `/v2/login` → редирект на `/login?returnTo=/v2/iam` 2. Основной OIDC: production-KC → `/callback` → сессия → редирект на `/v2/iam` 3. `/v2/iam` → показывает IAM-данные из `req.session.user` V2 НЕ делает свой OIDC. Использует готовую сессию основного приложения. Никаких своих KC-настроек. Никакого `/v2/callback`. ## Модуль auth/index.js — готов, но не используется Функции готовы к production: - `buildAuthUrl(config)` — URL редиректа на KC - `exchangeCode(code, config)` — обмен code → токен - `fetchIamUser(token, iamUrl)` — IAM → профиль - `generateState()` — CSRF - `login(code, oidcConfig, iamUrl)` — оркестратор Не тестировались: нужен `/v2/callback` в redirect URIs production-KC. ## Модуль crud/ — готов, не монтирован Функции: - `createCrudRouter()` — роутер с выбором компании (всегда список, даже если одна) - CRUD через `db/queries.js` Таблицы: v2_companies, v2_entries, v2_audit (автосоздание через schema.js). ## Модуль db/ — готов - `db/index.js` — pg pool - `db/queries.js` — getOrCreateCompany, listEntries, createEntry, updateEntry, deleteEntry, getAudit, ... - `db/schema.js` — ensureSchema(pool) — CREATE TABLE IF NOT EXISTS ## Модуль validators/ — готов CIDR validate, overlaps, cidrToRange, aggregateCIDRs, BLOCKED_RANGES. ## Что дальше 1. fio в fetchIamUser — возвращать строку (сейчас объект) 2. Добавить `/v2/callback` в redirect URIs production-KC 3. Протестировать auth/login() с production-KC 4. Подключить crud модуль 5. Админка, экспорт ## Ключевые решения - V2 НЕ трогает основной код (server.js — только app.use('/v2', ...)) - Каждый модуль — отдельная папка в src/ - env-переменные — через process.env, без .env/dotenv - Умолчания — хардкод, переопределяются через V2_* env --- ## Модуль router/ (0.5.75) `resolveContext` middleware — определяет контекст из `req.session.v2_user`: ``` нет сессии / нет v2_user → 302 /v2/login обычный юзер → req.v2_email, req.v2_clientId (activeClientId) юзер с несколькими компаниями → activeClientId из сессии админ + adminMode → req.v2_isAdmin = true админ без adminMode → req.v2_isAdmin = false (видит как юзер) имперсонация → email подменён на originalUserEmail clientId подменён на impersonatedCompanyId req.v2_impersonatedBy = реальный админ ``` ### Тесты (v2/src/router/test.js) 9 тестов, все пройдены ✅: 1. нет сессии → /v2/login 2. нет v2_user → /v2/login 3. обычный юзер 1 компания 4. юзер 2 компании → activeClientId 5. админ adminMode=true 6. админ adminMode=false 7. имперсонация с originalUserEmail 8. имперсонация без originalUserEmail 9. без activeClientId → fallback на clientId ### Ошибки при тестировании - Причина: спешка. null вместо undefined, двойной префикс v2_v2_ в ключах. - Урок: сначала думать, потом писать. ## Текущая структура (0.5.75) ``` v2/src/ ├── auth/index.js # fetchIamUser(), login(), exchangeCode() ├── config/index.js # iamUrl, appUrl, version ├── router/ │ ├── index.js # resolveContext middleware │ └── test.js # 9 тестов ├── user/index.js # createUserRouter (пустышка) ├── admin/index.js # createAdminRouter (пустышка) ├── crud/index.js # createCrudRouter (не монтирован) ├── db/ # pool, queries, schema └── validators/index.js # CIDR validate ```