Міграція Golden
Новий family-golden, family-application-api, Gateway та Electron вводяться поруч із чинними stack-golden і Golden Electron. Production перемикається частинами, без big bang.
Незмінні правила
- Legacy collections, queues та endpoints не змінюємо до переведення відповідної логіки.
- Нові consumers використовують окремі versioned queues та commands.
- Read-only sync можна виконувати паралельно для порівняння з legacy.
- Partner-write для конкретної TU та операції виконує лише legacy або нова система, але не обидві.
- Workers мають idempotency, lock і явний owner.
- Rollback перемикає routing назад; canonical дані не видаляються.
Одиниця міграції
Мігруємо не весь stack-golden одним релізом і не окремий endpoint без його залежностей. Одиниця міграції — завершена capability: frontend route, canonical data, partner operation, background writer, logs і post-effects.
Для capability, яку вже переключили:
- Frontend звертається лише до
family-application-api. - Canonical collection має одного owner-а запису для конкретних полів та операцій.
- Старий публічний route вимкнений або тимчасово проксіює команду у V2; він не виконує власний write.
- Ще не перенесений legacy-код читає canonical collection через один compatibility repository.
- Старі довільні Mongoose models не направляємо на нову collection: назви полів, шифрування та семантика query несумісні.
- Після parity, pilot і rollback period legacy collection та bridge цієї capability видаляються.
Постійного двостороннього sync між legacy і canonical collections не робимо. Тимчасова проєкція допустима лише як короткий rollback-bridge з метрикою lag і явною датою видалення.
Співіснування V2 і legacy
flowchart LR Front["Frontend"] -->|"перенесені routes"| V2["family-application-api"] Front -->|"решта routes"| Stack["stack / stack-golden"] V2 --> Family["family-golden"] Family --> Partner["Golden partner API"] V2 --> Canonical[("family_admins / family_tus")] Family --> Canonical Stack --> Compat["LegacyGolden compatibility repositories"] Compat --> Canonical V2 -->|"лише неперенесені post-effects"| LegacyEffects["versioned legacy commands"] LegacyEffects --> Stack
Compatibility repository є anti-corruption layer: він робить конкретні canonical query, розшифровує secret на межі та повертає стару форму тільки legacy consumer-у. Його не імпортуємо хаотично по файлах — старі сервіси отримують вузькі методи на кшталт findActiveAdmins(), findTUCredentials() і findTUsByPartnerIds().
Допускається кілька writer-ів однієї collection лише для різних, явно зафіксованих полів. Наприклад, поки TU Card живе у Stack, Stack володіє зв’язком KM, а V2 refresh — partner profile/status. Два сервіси не можуть одночасно змінювати одне assignment або partner password.
Середовища
| Контур | Хто працює | Дані й доступ |
|---|---|---|
| Legacy production | Чинні Stack, Golden service та Electron | Поточні endpoints, queues і collections |
| V2 test | Нові family-application-api, Gateway, Golden service та Electron | Test endpoints, окремі queues/collections, test operators і TU |
| V2 shadow | Нові server services без live-write | Читають production-compatible дані й порівнюють результат із legacy |
| V2 pilot | Allowlist операторів/TU | Live-write дозволений лише для явно переведеного scope |
| V2 production | Нові services | Legacy лишається rollback-контуром до завершення міграції |
Test Electron має окремі appId, product name, user data directory, API origin, socket namespace та update channel. Його можна встановити поруч із production Electron.
Етапи
| № | Етап | Результат | Умова переходу далі |
|---|---|---|---|
| 01 | Packages і tooling | @it-monkeys/contracts, @it-monkeys/backend-common та family-platform | Packages збираються через link, pack і ручний release |
| 02 | Каркаси | family-application-api, Gateway і family-golden розгорнуті без production routing | Healthcheck, auth, RMQ і observability працюють |
| 03 | Admins і TU read model | Новий Golden читає partner API та пише canonical Admin/TU | Повторний sync і backfill не створюють дублікати |
| 04 | Shadow comparison | Legacy і V2 результати порівнюються автоматично | Узгоджені counts, status, assignments і profile fields |
| 05 | Test Electron | Нова програма працює на V2 test із тестовими TU | Login, startup, reconnect, sync та workspace проходять сценарії |
| 06 | Production pilot | Кілька операторів/TU переведені через allowlist | Немає подвійних writes, втрати actions/tasks і деградації partner API |
| 07 | Вертикальна міграція | Фічі переходять по одній із власним flag і rollback | Кожна фіча пройшла parity та pilot |
| 08 | Розширення | Allowlist поступово збільшується | Метрики й support стабільні на кожному кроці |
| 09 | Вимкнення legacy | Старі workers/routes зупинені, repository архівується пізніше | Повний scope працює на V2 і минув rollback period |
Фактичний стан на 2026-08-27
| Частина | Уже є | Що блокує production cutover |
|---|---|---|
| Packages | contracts, backend-common, canonical schemas/repositories | Release packages і точні production versions |
| Deployables | family-application-api, family-golden, healthcheck, Stack JWT, internal HTTP | Production config, secrets, network policy та telemetry |
| Admins | migration, list/resolve/create/update, Golden credentials validation | Legacy admin compatibility repository, TU count, routing flag |
| TU catalog | migration, Golden list adapter, compare/refresh, canonical update | Read endpoints, shadow/dry-run, legacy TU compatibility reads |
| TU password | Golden partner mutation і encrypted canonical password | Legacy Electron/workspace повинні читати canonical credentials |
| Assignments | supervisor/operator batch flow, stale-state check, user/TU update | Tasks, Electron effects, canonical logs і production parity |
| KM | service method синхронізації зі Stack TU Card | Визначити Stack command; refresh не має знімати KM |
| Logs | тимчасовий спільний writer | Нові collections і fields від власника log migration |
Поточні migration endpoints є apply-командами, а не безпечним shadow: повторний запуск переносить значення зі старих collections і може перезаписати нові canonical зміни. Перед production вони мають отримати dry-run/compare, deployment guard і бути вимкнені одразу після cutover.
Перший production vertical slice
frontend Admin/TU routes
→ family-application-api
→ internal HTTP
→ family-golden
→ Golden partner API
family-application-api ↔ canonical family_admins / family_tus
stack-golden → compatibility repositories → ті самі canonical collectionsНа цьому тижні реалістичний production scope:
| Черга | Capability | Результат | Чи можна закрити повністю |
|---|---|---|---|
| 0 | Dark deploy двох сервісів | Health, auth, internal network, secrets та індекси перевірені без frontend traffic | ✅ |
| 1 | Admins | Frontend CRUD працює через V2; family_admins — єдине джерело; legacy лише читає через adapter | ✅ |
| 2 | TU catalog/read | Backfill, read API та shadow comparison працюють на family_tus; legacy Electron читає canonical TU | ✅ після compatibility reads |
| 3 | TU password | V2 є єдиним writer partner/canonical password; legacy workspace читає розшифровані canonical credentials | ✅ після credentials adapter |
| 4 | TU refresh write | Старий LadySyncService вимкнений; V2 володіє profile/status/admin | ✅ лише після detach post-effects |
| 5 | Manual assignments | До cutover legacy flow пише assignments у canonical TU через compatibility repository; після cutover усі TU/user/log/task/Electron effects переходять у V2 | ❌ V2 не вмикати до parity |
| 6 | Electron workspace, statistics, favorites, sender | Залишаються у stack-golden і старому Electron | окремі наступні vertical slices |
Отже, самі сервіси можна безпечно залити цього тижня. Frontend routing треба вмикати окремими flags: admins, tu-read, tu-password, tu-refresh, tu-assignments. Один загальний goldenV2=true для всього сервісу не використовуємо.
Міграція Admins
family_admins стає єдиним source of truth. Старий golden_admins не можна просто замінити імпортом schema: legacy очікує id_api, відкритий password, isBlocked і підтримує довільні query, а canonical document має login, passwordEncrypted і status.
У stack-golden є 13 файлів із прямим import AdminModel, плюс залежності від legacy IAdmin. Вони покривають CRUD, sync/statistics, Electron/API operations і тести. Для завершеного cutover:
- Додати один
LegacyGoldenAdminRepositoryповерхFamilyAdminRepository. - Реалізувати лише фактично потрібні typed methods; не переносити legacy endpoint із довільним Mongo query.
- Замінити прямі imports
AdminModelу runtime-коді на repository. - У коротке maintenance-вікно зупинити legacy Admin writes, виконати backfill зі збереженням
_idі звірити count/login/status/hash credentials. - Переключити frontend Admin routes на V2; старий Admin CRUD вимкнути або зробити proxy без власного write.
- Вимкнути Admin migration endpoint і залишити
golden_adminsтільки як rollback snapshot на обмежений строк.
Compatibility spike вже підтвердив роботу @it-monkeys/contracts і @it-monkeys/backend-common з legacy Mongoose 6.2.2. Не можна неявно оновлювати Mongoose у stack-golden: підняття lock-версії вже спричиняло сторонні type errors.
Міграція TU
TU складніша за Admin: GoldenLadyModel читають і змінюють Electron, favorites, metrics, statistics, workspace, sync та assignment flows. Тому підміна model на family_tus небезпечна.
Робимо один LegacyGoldenTURepository з вузькими projections:
- знайти TU/credentials за partner ID;
- знайти canonical admin і partner admin ID;
- отримати TU за списком partner ID або Stack Card ID;
- оновити лише ті legacy-owned поля, власник яких зафіксований у migration matrix.
Порядок cutover:
- Додати
GET /v2/tusі, за потреби frontend,GET /v2/tus/{id}з role scope. - Додати dry-run TU migration та shadow compare без canonical write.
- Перевести legacy runtime reads, необхідні Electron/workspace, на
LegacyGoldenTURepository. - Зупинити старий TU sync, виконати фінальний backfill зі збереженням
_id, звірити profile/status/admin/assignments/password presence. - Увімкнути V2 read і password окремими flags.
- Увімкнути V2 refresh write лише після того, як видалення/деактивація виконує всі operator detach effects.
- Manual assignment routes залишити legacy до готовності tasks, Electron
SET_LADY/DROP_LADYта canonical logs; потім перемкнути всією capability за один cutover.
Поки manual assignments належать legacy, вони вже повинні змінювати family_tus.assignments через compatibility repository, а не продовжувати запис у golden_ladies. Інакше V2 read одразу стане застарілим.
KM не входить у системний detach: його canonical зв’язок оновлюється тільки під час зміни TU Card у Stack.
Shadow comparison
Поточний POST /v2/tus/refresh є writer і не використовується як shadow. Потрібна окрема read-only команда, яка отримує partner snapshot, викликає TUSyncService.compareSnapshot, повертає diff і нічого не змінює у Mongo, users, logs або partner API.
Для кожного shadow run зберігаємо або рахуємо:
- кількість записів legacy/V2;
- пропущені та зайві external IDs;
- відмінності status і assignments;
- hash нормалізованих важливих полів;
- час і кількість partner requests;
- помилки та повторні спроби.
Shadow не виконує password change, assignment, sender, task close, media upload, online ping або іншу partner mutation.
Production cutover checklist
- Зафіксувати package versions; не використовувати локальні links.
- Перевірити однаковий cipher key у
family-application-api,family-goldenі legacy compatibility layer. - Запустити
db:indexes:syncяк окремий deployment job після переглядуdiffIndexes; application instances не синхронізують indexes на startup. - Закрити internal Family API від зовнішньої мережі.
- Обмежити або вимкнути apply-migration endpoints; роль director не повинна мати постійного доступу до повторного production backfill.
- Поставити feature flags у стан off, розгорнути обидва сервіси й перевірити health/partner test calls.
- Виконати dry-run, maintenance freeze, Admin backfill, потім TU backfill.
- Перевірити counts, IDs, status, admin relations, assignment relations і можливість розшифрувати вибіркові credentials без їх логування.
- Вмикати flags у порядку
admins → tu-read → tu-password → tu-refresh;tu-assignmentsокремо. - Для кожного flag мати owner, метрики, allowlist і одну дію rollback без видалення canonical data.
Перемикання Electron
Stack після login повертає, який workspace доступний оператору: legacy, v2-test або v2. TU, передана у V2 pilot, не повинна одночасно видаватися для роботи legacy Electron.
Gateway додатково тримає Redis lease на family + tuId. Lease захищає V2 від двох нових sessions, але головний захист від legacy/V2 конфлікту — routing і allowlist у Stack.
Перед розширенням pilot перевіряємо:
- Login, update і reconnect.
- Одна активна session на TU.
- Startup data та локальна БД.
- Chat/mail send із partner confirmation.
- Tasks, actions, online і sender sync з record-level ACK.
- Відновлення після падіння Electron, Gateway, API та Family service.
Перемикання server-фічі
Кожна фіча має окремий flag із scope family, user або tuId:
legacy read/write
→ V2 shadow read
→ V2 read + legacy write
→ V2 read/write для pilot
→ V2 read/write для FamilyНе всі фічі потребують проміжного V2 read + legacy write. Його використовуємо лише там, де V2 може коректно прочитати legacy результат.
Rollback
- Заборонити нові V2 sessions або requests для pilot scope.
- Дочекатися ACK активних sync batches і зупинити V2 writers/workers.
- Повернути Stack routing та frontend feature flag на legacy.
- Перепідключити оператора до legacy Electron.
- Зберегти V2 collections і telemetry для аналізу; не робити rollback через видалення даних.
Після rollback новий writer не запускається повторно, доки не перевірено незавершені tasks, sender operations і partner mutations.