Журнал змін

GitHub

Кожна значуща зміна, реліз за релізом. Той самий файл постачається в репозиторії та перекладений усіма 17 мовами.

Журнал змін

Усі важливі зміни career-ops-ui. Формат — Keep a Changelog, версії за SemVer.

Переклади: 🇬🇧 English · 🇪🇸 Español · 🇧🇷 Português · 🇰🇷 한국어 · 🇯🇵 日本語 · 🇷🇺 Русский · 🇨🇳 简体中文 · 🇹🇼 繁體中文 · 🇫🇷 Français · 🇵🇱 Polski · 🇩🇰 Dansk · 🇸🇦 العربية · 🇩🇪 Deutsch · 🇮🇹 Italiano · 🇹🇷 Türkçe · 🇮🇳 हिन्दी

Примітка щодо перекладу (v1.70.0) — українську додано як одну з трьох нових мов інтерфейсу. Цей файл перекладає найновіші записи; повна історія — в 🇬🇧 англійському CHANGELOG, який є нормативним джерелом.


[1.134.1] — 2026-08-05

Посилення валідації — виправлення, виявлені під час повного аудиту проєкту.

Виправлено

  • successfactors більше не відкидає зібрані вакансії при збої в середині сканування (регресія в портуванні «неактивна дошка = помилка» з v1.134.0) — цикл пагінації не мав try/catch, тож збій на сторінці 2+ (після успішної сторінки 1) призводив до винятку й губив усе вже зібране; а якщо цей збій був 404 (вихід startrow за межі діапазону), en-scanner міг на кілька днів помилково позначити живого орендаря як неактивного. Тепер дзеркалює phenom/radancy: збій на сторінці 0 досі видає помилку (неактивна дошка), а збій на пізнішій сторінці зберігає часткові результати.
  • Фільтр-чипи #/scan тепер керуються з клавіатури (WCAG 2.1.1) — чипи фасетів (і чип «очистити») були елементами span з обробником кліку, але без tabindex/ролі, тож користувачі клавіатури та програм читання з екрана не могли до них дістатися чи перемикати їх. Тепер вони мають role="button", tabindex="0", aria-pressed і активацію по Enter/Space.
  • Три захардкоджені англійські рядки тепер локалізовано — підказка бейджа довіри #/scan, заголовок колонки релокації #/scan та заголовок колонки балу #/dashboard були голими літералами, яких не бачив паритет-контроль i18n (вони ніколи не були ключами), тож вони залишалися англійськими в кожній неанглійській локалі. Тепер scan.trustTip + scan.col.reloc (2 нових ключі) + повторне використання track.col.score, зі статичною перевіркою на рівні коду.

[1.134.0] — 2026-08-05

Паритет із батьківським career-ops v1.25.0.

Додано

  • Нове джерело сканування: getManfred (manfred) — стрічка вакансій в іспанських/європейських технологічних компаніях по всьому борду з опублікованими зарплатами, з www.getmanfred.com/api/v2/public/offers (без авторизації, прив’язка до хоста + лише HTTPS, повний каталог одним запитом). Джерело + адаптер + CI-ізольований набір тестів (tests/sources-manfred.test.mjs); реєстр тепер налічує 73 джерела = 68 англомовних + 5 російськомовних (ALL_ADAPTERS 68). З’являється у фільтрі джерел #/scan та на лендінгу cvstart.org.

Виправлено

  • Стрічка a16z Speedrun тихо обрізалася до 50 вакансій (#2404) — стрічка обмежує сторінку 50 елементами, але джерело запитувало PER_PAGE = 100, тож пагінація зупинялася після першої сторінки. Виправлено на 50.
  • Неактивні дошки тепер видають помилку, замість того щоб читатися як «живі, але порожні» (#2379) — cryptocurrencyjobs, phenom, radancy, successfactors: збій запиту, коли жоден запит так і не завершився успіхом, тепер видає помилку (тож перевірка стану #/portals та сканування фіксують реальний збій), замість того щоб приховувати його за порожнім списком; збій у середині сканування після хоча б одного успіху зберігає часткові результати.
  • workable тепер використовує публічний widget API (#5ab8425) — перехід на apply.workable.com/api/v1/widget/accounts/<slug>, який повертає повний список вакансій великого акаунту за один запит, тож великі акаунти більше не обрізаються.

Примітки

  • Не портовано (лише для CLI або не дзеркалюється в web-ui): переробка продуктивності групування заголовків для виявлення репостів #2389; виправлення Unicode-ключів компаній (власна дедуплікація трекера web-ui вже безпечна для не-латиниці); scan --since; cv-facts; аудит-прохід шаблону CV / PDF; doctor; директива щодо недовіреного вмісту в режимах.

[1.133.1] — 2026-08-02

Виправлено

  • #/funded (Профінансовані компанії) тепер відображає результати — через два баги таблиця завжди показувала «немає профінансованих компаній», навіть коли батьківський company-funded.mjs повертав повний список. (1) Вигляд читав результати з res.candidates, а батьківський скрипт видає їх під ключем companies (кожен елемент — { company, amount, round, funding: { sources: [{ source, url, observed_date }] } }); клієнт тепер читає правильний ключ і мапить реальну форму доказів. (2) Таблиця результатів передавала свої комірки в UI.el('tr', {}, …) як varargs, але UI.el(tag, attrs, children) приймає children як один вузол або масив, тож рендерилась лише перша колонка (Компанія) — тепер комірки передаються як масив. Перевірено в реальному браузері: 11 компаній із чотирьох стрічок відображаються з колонками Компанія / Сигнал фінансування / Джерело / Дата та робочими посиланнями на докази, нуль помилок у консолі. Порожній прохід тепер також показує діагностику по кожному джерелу, щоб тихий новинний день можна було відрізнити від заблокованої стрічки.
  • Регресійні бар’єри в tests/parity-routes-v1133.test.mjs: фейковий батьківський скрипт тепер видає реальну форму виводу companies (початкова заготовка дзеркалила неправильну форму candidates — саме тому баг і потрапив у реліз із зеленими тестами), плюс статичні канарки джерела, що funded.js читає res.companies (ніколи не res.candidates) і будує рядки таблиці з дочірніми елементами-масивом (+1 → 2144).

[1.133.0] — 2026-08-01

Додано

  • Виявлення профінансованих компаній (#/funded, паритет із батьком #2117) — новий тільки-для-читання вигляд, що ретранслює батьківський company-funded.mjs career-ops через GET /api/company-funded: список нещодавно профінансованих компаній «спершу на перегляд», знайдених у публічних стрічках про фінансування з прив’язкою до хоста (TechCrunch, PR Newswire, The Guardian, Hacker News). Ретрансляція запускає скрипт з --json --dry-run (JSON у stdout, без запису файлів), ніколи не передає користувацький ввід у --sources, має обмеження частоти запитів і запускається лише користувачем (кнопка «Знайти», ніколи при монтуванні). Новий модуль маршруту server/lib/routes/funded.mjs + public/js/views/funded.js, у розділі «Пошук».
  • Щотижневий дайджест співбесід (#/interview-digest, паритет із батьком #2129/#2130) — новий тільки-для-читання вигляд, що ретранслює батьківський weekly-digest.mjs (без ШІ) через GET /api/interview/weekly-digest: механічне зведення нотаток сесій співбесід — з якими компаніями та на яких раундах ви проходили співбесіди цього тижня, повторювані компетенції та відкриті прогалини за принципом «найкраще зусилля». Необов’язковий діапазон ?from=&to= передається, лише якщо ОБИДВА параметри — валідні YYYY-MM-DD; порожній діапазон — це коректний дайджест available:true. Додано до server/lib/routes/interview.mjs + public/js/views/interview-digest.js, у розділі «Аналітика».
  • Обидві ретрансляції дотримуються усталеного контракту fail-soft available:false, коли батьківський скрипт відсутній (CI, автономні інсталяції). 26 нових i18n-ключів ×17 локалей; CI-ізольований набір tests/parity-routes-v1133.test.mjs (+5 → 2143).

Примітки

  • Батьківський career-ops просунувся далі за v1.24.0 зі сторінкою «Follow-up Tracker» застосунку Next.js web/ (#1422) та бекенд-рендером PDF (#2182) — не портовано: web-ui вже має власну ретрансляцію нагадувань і власні PDF-раннери, а посилення followup-cadence.mjs надходить безкоштовно через shell-out ретрансляцію. Зміни set-status.mjs / tracker-utils.mjs — внутрішні для CLI і не дзеркалюються.

[1.132.0] — 2026-07-31

Змінено

  • Підсистему рендерингу результатів #/scan винесено в public/js/lib/scan-results.js (борг за контрактом розміру файлу — public/js/views/scan.js розрісся приблизно до ~1254 рядків). Підсистема (renderResults, buildChipRow, getRows, конструктори рядків/фасетів, малювальники опцій і дзеркало реєстру FALLBACK_SOURCES) перенесена у фабрику window.ScanResults.create(ctx), що замикається на об’єкт контексту, який надає вигляд. Без зміни поведінки — функції перенесено дослівно, змінні замикання переприв’язано до ctx.*; scan.js тепер має ~906 рядків (другий прохід виділення до цілі в 800 рядків заплановано).
  • Тести, що читають вихідний код статично, тепер читають обидва файли через tests/helpers/scan-src.mjs::loadScanSrc(); tests/scan-fallback-sources.test.mjs тепер читає дзеркало реєстру з scan-results.js.
  • Новий регресійний бар’єр у браузеріtests/playwright-scan-filters.mjs засіває заготовлений data/last-scan.json і проганяє кожен фільтр #/scan, перевіряючи точну кількість рядків (npm run test:e2e:browser); для цього додано стабільні ідентифікатори фільтрів (#scan-filter-*, #scan-apply).
  • Банер «Останній реліз» у README скорочено до однорядкового підсумку + посилання на повний журнал змін (довгу багатоверсійну стіну опису прибрано). Застосовано в усіх 17 локалях.

[1.131.2] — 2026-07-31

Змінено

  • Поділ app.css на три впорядковані таблиці стилів (борг за контрактом розміру файлу — єдиний файл розрісся приблизно до 1990 рядків, значно перевищивши жорсткий ліміт у 800 рядків). Тепер це app.css (~672 — a11y, дизайн-токени/тема, бічна панель, основний контент, кнопки, оболонка вмісту), components.css (~595 — картки, сітки, пагінатор, бейджі, таблиці, форми, лог/консоль, markdown, перемикач мов, фільтр-чіпи, банер з’єднання) і overlays.css (~737 — тост, шухляда сповіщень, модальне вікно, різне/адаптивність, дзеркало [dir="rtl"], docs-fab, usage-hud) — кожен у межах жорсткого ліміту.
    • Розріз суцільний і в тому ж порядку, тож каскад побайтово ідентичний файлу до поділу; index.html завантажує всі три як впорядковані <link>. Без зміни поведінки, розмітки чи i18n.
    • Тести, що перевіряють CSS, тепер читають конкатенацію через спільний хелпер tests/helpers/css.mjs::loadAppCss(). Новий tests/css-modularization.test.mjs фіксує поділ (файли існують · кожен ≤ 800 рядків · порядок <link> в index.html) → набір 2138. Перевірено в браузері: усі три таблиці стилів парсяться і їхні правила застосовуються.

[1.131.1] — 2026-07-31

Виправлено

  • Узгодженість прив’язки хоста в адаптерах для двох джерел v1.130.0 (доопрацювання за код-рев’ю, багаторівневий захист; без зміни поведінки для коректних вхідних даних):
    • Адаптер a16z-speedrun-talent тепер повторно перевіряє перевизначення api: / a16z-speedrun-talent: у buildEndpoint (HTTPS + точний хост speedrun-talent-network.com) і в разі невдачі відкочується до канонічної стрічки — паритет з адаптером cryptocurrencyjobs, тож значення з іншим хостом ніколи не потрапляє у слот запиту (раніше це покладалося виключно на перевірку assertSpeedrunUrl під час запиту). Перевірка точного хоста тепер — єдиний експортований SPEEDRUN_TALENT_HOST_RE, спільний для перевірки й адаптера.
    • Парсер cryptocurrencyjobscleanUrl тепер використовує ту саму перевірку точної відповідності хоста, що й assertCryptocurrencyJobsUrl та перевизначення адаптера (було endsWith, яке приймало субдомени). Парсер ніколи не є поблажливішим за SSRF-перевірку: посилання елемента sub.cryptocurrencyjobs.co відкидається.
    • +2 тести → 2135.

[1.131.0] — 2026-07-31

Додано

  • Дошка стадій-вкладок CRM #/tracker (портовано з вигляду /pipeline батьківського веб-застосунку). Панель чіпів воронки трекера + випадний список статусу замінено на смугу вкладок стадій: вкладка Усі плюс по одній вкладці на кожен канонічний статус — Evaluated · Applied · Responded · Interview · Offer · Rejected · Discarded · SKIP · Hired — кожна показує живий лічильник за всю історію, включно зі стадіями з нульовим лічильником, тож уся воронка завжди видима (вигляд CRM). Активна вкладка керує фільтром; повторний клік на неї скидає назад до «Усі». Рядки зберігають тональність оцінки, легітимність, можливості PDF і звіту, а комірка компанії тепер показує бренд-логотип, коли логотипи увімкнено (вимкнено за замовчуванням → без додаткових запитів).
    • Новий тільки-для-читання маршрут GET /api/tracker/stages повертає канонічну воронку (мітки за порядком) + карту згортання псевдонімів, отримані з server/lib/states.mjs (templates/states.yml, із вбудованим фолбеком) — тож клієнт ніколи не хардкодить whitelist статусів. Застаріла відповідь GET /api/tracker без параметрів лишається незмінною (лише { rows }).
    • Нова чиста, покрита юніт-тестами клієнтська бібліотека public/js/lib/tracker-stages.js розкладає рядки за стадіями сервера, толеруючи випадковий markdown bold і локалізовані псевдоніми (наприклад, aplicadoApplied). Вкладки доступні (role tablist/tab, aria-selected, зона кліку ≥44 px, лічильники в доступному імені кожної вкладки). Нових i18n-ключів немає. Набір тестів 2133.

[1.130.0] — 2026-07-31

Додано

  • Два нові джерела сканування, портовані з батьківського career-ops v1.24.0 (in-process, без нових залежностей; обидва з’являються у фільтрі джерел #/scan і на лендінгу cvstart.org):
    • a16z Speedrun (a16z-speedrun-talent, #2231) — стрічка JSON усього борду talent-network a16z Speedrun. Прив’язана до хоста speedrun-talent-network.com, лише HTTPS, 0-індексована пагінація з обмеженням сторінок, наскрізне передавання q/конфігурації по компанії, fail-soft.
    • Cryptocurrency Jobs (cryptocurrencyjobs) — дошка вакансій Web3 cryptocurrencyjobs.co, отримується через публічну стрічку RSS 2.0 (без авторизації). Дворазове декодування XML-сутностей, лише віддалені вакансії, роботодавець розбирається з хвоста заголовка "… at <Company>".
    • Загальна кількість у реєстрі тепер 72 джерела = 67 англомовних + 5 російськомовних (ALL_ADAPTERS = 67 англомовних адаптерів порталів).

Виправлено

  • echojobs — гібридні ролі лишаються відмінними від віддалених (віддзеркалює батьківський #2258). Регістронезалежний маркер hybrid тепер дає "<Місто> · Гібрид" (або просто Гібрид, якщо міста немає) і workplaceType: 'Hybrid', замість згортання в Remote.
  • radancy — застаріла розмітка TalentBrew + транспорт JSON-фрагмента результатів (віддзеркалює батьківський a3e6df9), під контролем ін’єктованого opts.fetchJson.

Примітки

  • Не портовано — CLI-специфічні можливості батька. Великий CLI/режимний шар career-ops v1.24.0 лишається поза web-ui, який є переглядачем + тонким наскрізним записом, а не хостом режимів: таблиці комплаєнсу/юрисдикції, телефонна книга контактів + vCard, транскрипт-дебриф інтерв’ю / визначення платформи дзвінків, встановлення статусу в реєстрі, запис результату, двопрохідний трайдж, jd-подібність, версійована схема артефакту CV заявки, виявлення Playwright-MCP у doctor та portals/fix-slugs.mjs. Зміни оркестрації сканування, що живуть у батьківському scan.mjs — сканер Interamt.de на Playwright, повне сканування iCIMS зворотним ATS, фільтр віддаленості за прийнятністю країни, темп DNS-пошуку, дедуп StepStone rltr і нормалізована колонка компанії в історії сканування — не застосовуються: web-ui запускає сканери EN/RU in-process і не викликає scan.mjs.
  • Вже покрито. Фікс згортання діакритики в role-matcher (#2209) було портовано в v1.127.0, тож тут це no-op.

[1.129.1] — 2026-07-29

Виправлено

  • Доопрацювання за AI-рев’ю портів web з v1.128/v1.129 (усі дорадчі, виправлено в корені): порядок рівня в job-facets.js (явний модифікатор тепер перемагає управлінське слово — Senior Engineering Managersenior, було lead); fallback у states.mjs більше не пінниться (успішне читання мемоїзується, fallback повертається без кешу — тимчасово недоступний батько на старті перечитується наступним викликом) + console.warn за присутнього, але пошкодженого файлу; score-tone.js — рядок без оцінки нейтральний (muted), не червоний; domainFromName() пропускає не-ASCII slug до /api/logo; +sanity-гард ізоляції в tests/states.test.mjs. +4 тести → 2073.

[1.129.0] — 2026-07-29

Додано

  • Фасет «Рівень» + колонка «Свіжість» у #/scan — бібліотека job-facets.js з v1.128.0 тепер вплетена в UI сканування (раніше лише логіка). Новий дропдаун Рівень розкладає заголовок кожної вакансії на lead/staff/senior/mid/junior/intern (JobFacets.seniorityFromTitle) і автозаповнюється тим, що реально є в результатах (як фасет «Країна»); заголовки без слова-рівня завжди проходять. Зберігається у збережених пошуках, Скиданні та Застосувати. У таблиці з’являються колонка Рівень (бейдж) і zero-token колонка Свіжість (сьогодні / Nдн, з JobFacets.daysSince). 12 i18n-ключів ×17, +3 тести → 2069.

[1.128.0] — 2026-07-29

Додано

  • Чотири рішення, портовані з власного веб-застосунку батька (../web/, Next.js) — переписані на ванільному JS/ESM, без нових залежностей: (1) server/lib/states.mjs читає templates/states.yml наживо як канонічний словник статусів трекера (з CI-fallback) — усуває ручний ре-синк whitelist щорелізу; POST згортає аліаси (іспанські/legacy) до канонічної мітки, funnel у GET групує за канонічним статусом; (2) логотипи компаній у ATS-хостованих рядках через domainFromName() (~90 бренд→домен); (3) score-tone.js — 4-рівневий тон оцінки (≥4.2/3.8/3.0 + літерний fallback); (4) job-facets.js — фасети seniority/source/days. +21 тест.

Примітки

  • Не портовано (лише концепт): агентський шар дій батька (actions/registry.ts + api/assistant/route.ts) — креслення на випадок, коли docs-fab стане копайлотом. Нових джерел немає (реєстр 70), змін i18n/help немає.

[1.127.0] — 2026-07-29

Додано

  • Три нові джерела сканування (паритет career-ops v1.23.0) — у реєстрі тепер 70 адаптерів (65 EN + 5 RU): Flowxtra (глобальний агрегатор без авторизації), VDAB (keyword-API фламандської служби зайнятості) та iCIMS (портали careers-<tenant>.icims.com, окремо від jibeapply). Крім того Cursor повертається до ростера CLI (parent #2115): cli-detect тепер виявляє cursor (10 інструментів), ростер відновлено в help/README/config ×17.

Виправлено

  • agenticjobs переведено зі скрейпінгу HTML на REST API (#2167); Greenhouse відновлює місто з /offices, коли location.name — лише модель роботи (#2104); паритет role-matcher (#1933/#2164/#2009: префікс MTS, базовий product, згортання акцентів, незгода sub-baseline).

Примітки

  • Не портовано. Більшість v1.23.0 — CLI/dashboard-поверхня, яку web-ui не викликає (batch-tailor, discover-ats, режими NL/PT, теми PDF, Go-дашборд, updater/doctor); релейні скрипти без змін. VERSION батька → 1.23.0.

[1.126.1] — 2026-07-25

Виправлено

  • Дві точки дрейфу ростера CLI, які пропустив ресинк v1.126.0 — (1) інтро вкладки API keys у #/config (config.providerModelNote, i18n ×17) перелічувало лише 7 CLI — тепер Antigravity і Grok Build вставлені після OpenCode; (2) другий рядок порівняльної таблиці в довідці (×17) і зібраний у CI help сайту все ще містили Inside Claude Code / Codex / Cursor / Gemini CLI — застарілий набір із Cursor — тепер повний ростер. Обидва рядки використовували роздільники слеш/середня крапка, які патерни свіпу v1.126.0 не покривали. i18n-снапшот перегенеровано; сьют лишається 1969.

[1.126.0] — 2026-07-25

Додано

  • Вкладка інструментів AI CLI тепер виявляє всі 8 першокласних CLI career-ops — ростер #/config синхронізовано з батьківським docs/SUPPORTED_CLIS.md: у server/lib/routes/cli-detect.mjs додано Grok Build CLI (grok) і Kimi CLI (kimi), а Antigravity тепер спершу шукає канонічний бінарник agy. Скан PATH лише-для-читання тепер повідомляє 9 інструментів; знайдений бінарник, як і раніше, ніколи не запускається.

Змінено

  • Ресинк документації з career-ops.org/docs — звірив кожну поверхню докумен­тації з живими сторінками батька (прочитано всі 31). Канонічний ростер AI-асистентів (help ×17 + README ×17) тепер перелічує 8 першокласних CLI — Claude Code, Codex, OpenCode, Antigravity CLI, Grok Build CLI, Qwen Code, Kimi, GitHub Copilot CLI — плюс Gemini CLI (застаріла обгортка). Help-бандли зберігають структуру 29 H2 / 105 H3.

[1.125.4] — 2026-07-23

Змінено

  • залежності site (dependabot #151–#153) — sharp 0.34.5→0.35.3, svgo 4.0.1→4.0.2, fast-uri (dev) 3.1.3→3.1.4 у site/; збірка Astro зелена, SPA/сервер не зачеплені.

Примітки

  • Паріті-свіп батьківського проєкту (career-ops 37d17ec..254764a, після v1.22.0) — портувати нічого: guard неправильного рядка в set-status (#2108) — лише CLI (у web-ui рядок трекера обирається явно в UI, і жоден маршрут не викликає set-status.mjs); Risk Summary локалізованих режимів (#2109) — файли modes/<lang>/, які web-ui не читає (лише верхньорівневі modes/*.md); перевірка маніфесту update-system (#2111) — лише апдейтер; решта — документація батька (турецький README, SIGNATURES ×4, SCRIPTS.md, акценти es). VERSION батька лишається 1.22.0parentVersion без змін.

[1.125.3] — 2026-07-23

Виправлено

  • LLM-промпти данською та гінді відповідали англійською (повідомив користувач) — LOCALE_NAMES і всі п’ять наборів SCAFFOLD_STRINGS у server/lib/prompts.mjs так і не були розширені для da та hi, тож resolveLocale() відкочувався до en, і кожен AI-промпт — deep research (живий і ручний), режими, оцінювання, інтерв’ю, нетворкінг, CV Studio — втрачав директиву # Output language у цих двох локалях. Тепер обидві — повноправні: мовна директива + локалізоване обрамлення. Регресійний гейт у tests/locale-scaffold.test.mjs тепер обходить канонічний список із 17 локалей замість захардкоджених 12, а новий структурний гейт валить будь-який ключ обрамлення, що падає в англійську — локаль, яка пропустить prompts.mjs, більше не вийде (+12 тестів, разом 1969).

[1.125.2] — 2026-07-22

Виправлено

  • Deep research через Gemini: HTTP 502 (MALFORMED_FUNCTION_CALL) (#145, внесок @Alien10140) — живий промпт /api/deep наказував моделі «Use WebFetch / WebSearch» і зберегти бриф у файл, але безінструментальні API-провайдери не мають каналу інструментів; Gemini відповідав викликом функції замість тексту, що проявлялося як порожній HTTP 502. buildDeepPrompt і bundleProjectContext отримали прапорець headless: живі запуски (Anthropic/Gemini/каскад резервів) отримують промпт без інструментів, який пише бриф із вбудованого контексту, а copy-paste-промпт для Claude Code зберігає інструкції щодо інструментів. +1 тест у tests/critical-fixes.test.mjs.

Змінено

  • Типові моделі Gemini оновлено з застарілої gemini-2.0-flash (#144, внесок @Alien10140) — випадний список у Конфігурації, серверний резерв у gemini.mjs (що мовчки розходився з підказкою), ланцюжок резервів OpenRouter, config.geminiModelHint ×17 та довідка ×17 тепер одностайно вказують gemini-3.6-flash. Новий анти-дрейф ґейт tests/gemini-default-model.test.mjs (+5 тестів) фіксує всі поверхні на одному літералі — у сьюті тепер 1957 тестів.

[1.125.1] — 2026-07-21

Виправлено

  • SuccessFactors: мультибрендові тенанти RMK зберігають свій шлях бренду (батьківський #2099, після v1.22.0) — холдингові компанії, які ведуть кілька придбаних брендів на одному спільному інстансі RMK, розрізняють їх за сегментом шляху (careers.nemetschek.com/Bluebeam/ проти …/Vectorworks/); адаптер раніше згортав налаштований URL до його origin, непомітно скануючи вакансії батьківського бренду. Тепер ендпоінт зберігає префікс бренду, відкидаючи лише кінцевий сегмент /search/ або /tile-search-results/, тож ніщо ніколи не дублюється саме на себе; тенанти з одним доменом лишаються побайтово незмінними. Новий експортований хелпер resolveTenantBase + 1 перенесений тестовий блок у tests/sources-successfactors.test.mjs.

[1.125.0] — 2026-07-21

Додано

  • cvstart.org: розділ лендінгу «Джерела вакансій» — новий розділ між скриншотами та порівнянням, який перелічує всі 67 джерел сканування у вигляді клікабельних чіпів (62 англомовні дошки/ATS + 5 російських дощок під власним підзаголовком), кожне з яких веде на публічний сайт джерела. Список синхронізується з живим реєстром адаптерів під час збірки (sync-assets.mjsfacts.sources), тож він ніколи не може розійтися із застосунком; курований довідник посилань у Sources.astro захищений новим тестом tests/site-sources.test.mjs. У навігації шапки з’явився якір Sources; додано 4 нові ключі i18n сайту ×17. Також виправлено список inLanguage у JSON-LD лендінгу, в якому досі бракувало hi.

[1.124.0] — 2026-07-21

Додано

  • П’ять джерел сканування (паритет із батьківським v1.22.0, #1808/#1572/#2024/#2055) — Welcome to the Jungle (JSON API для всієї дошки), Agentic Engineering Jobs (дошка агентного/AI-інжинірингу), Jobvite (ATS на тенант без автентифікації), Gem (ATS на тенант) і Alibaba Group (JSON API кар’єрної сторінки, шаблон Meituan/Tencent). Кожне джерело — прив’язана до хоста, CI-ізольована пара джерело + адаптер; реєстр тепер постачається з 67 адаптерами (62 англомовних + 5 російськомовних); резервний список випадаючого списку Source на #/scan та його дрейф-гейт оновлено; п’ять нових наборів тестів tests/sources-{wttj,agenticjobs,jobvite,gem,alibaba}.test.mjs.

Виправлено

  • Arbeitsagentur: загальнонаціональна віддалена робота лише коли homeofficetyp дорівнює VOLLSTAENDIG (батьківський #1981) — запит homeoffice=nv_true також повертає гібридні вакансії, тож перевірка на віддаленість тепер підтверджує кожен збіг через ендпоінт деталей вакансії невеликими партіями і безвідмовно закривається (помилка пошуку зберігає справжнє місто вакансії, тож фільтри локації все одно застосовуються).
  • SmartRecruiters: публічні URL вакансій формувалися без /postings/ (батьківський #2047) — посилання тепер ведуть на публічну сторінку вакансії замість 404 для тенантів, чий публічний сайт відкидає цей сегмент.

Примітки

  • Батьківський v1.22.0 також містив зміни на боці CLI, у які веб-інтерфейс не заходить через shell або які вже покриває: шаблон CV zh-CN + типографіка PDF, режим /expand, налаштування кешування промптів провайдерів (Gemini/OpenAI/Ollama), розбивка токенів за кроками (у веб-інтерфейсі є власний лічильник використання), серіалізація блокування запису трекера (веб-інтерфейс скеровує записи через withFileLock ще з v1.21), прапорці CLI visa_filter та абсолютної дати публікації для сканування (у веб-інтерфейсі є власний фільтр віку «Опубліковано протягом») та посів дедуплікації відомих джерел (сканер веб-інтерфейсу веде власну дедуплікацію історії сканування).

[1.123.0] — 2026-07-17

Додано

  • Джерело сканування Oracle Recruiting Cloud (паритет із батьківським v1.21.0, #1929) — REST API recruitingCEJobRequisitions без автентифікації для кар’єрних сайтів Oracle Fusion/ORC (JPMorgan Chase, Oracle, BNY Mellon, American Express, Honeywell, …): прив’язка до хоста *.fa[.<region>][.ocs].oraclecloud.com, номер сайту визначається з careers_url кожної відстежуваної компанії, пагінація за зсувом із жорсткою межею кількості сторінок і WAF-обізнані заголовки на кшталт браузерних. Реєстр тепер постачається з 62 адаптерами (57 англомовних + 5 російськомовних); резервний список випадаючого списку Source на #/scan та його дрейф-гейт оновлено; новий CI-ізольований набір тестів tests/sources-oraclecloud.test.mjs.

Виправлено

  • Детектор репостів: базові назви залишаються окремо від сиблінгів зі спеціалізованим суфіксом (батьківський #1922) — «Senior Analytics Engineer» більше не групується із «Senior Analytics Engineer, People Analytics»: якщо токени однієї назви є строгою підмножиною токенів іншої, а додатковий токен є справжньою спеціалізацією (а не базовим словом), обидві вакансії вважаються окремими відкритими позиціями. Позначки репосту («(Repost)», «relisted») тепер трактуються як стоп-слова інформаційного шуму. +2 перевірки в tests/detect-reposts.test.mjs.

Примітки

  • Батьківський v1.21.0 також містив зміни на боці CLI, у які веб-інтерфейс не заходить через shell або які вже покриває: попередження про повторну подачу заявки до тієї самої компанії (у веб-інтерфейсі є пауза для повторної подачі ще з v1.84.0), прапорці --format/--report супровідного листа, режими промпту співбесіди для red-flag / панельної розвідки / no-show листа, персистентність довіри до джерел сканування та здоров’я порталів (веб-інтерфейс запускає власний внутрішньопроцесний сканер із trust-validator і сторінкою здоров’я порталів) і розширення статистики/розриву в зарплаті (транслюються лише для читання та безвідмовно).

[1.122.0] — 2026-07-16

Додано

  • Гінді (हिन्दी) — 17-та мова — повний словник інтерфейсу (~1 110 ключів), повний вбудований посібник довідки (паритет 29 H2 / 105 H3), README.hi.md, новий CHANGELOG.hi.md (починається з v1.122.0, за прецедентом de/it/tr), лендинг cvstart.org + сторінки Методологія/Ліцензія/Журнал змін/Довідка, перемикач мов (🇮🇳), автовизначення мови браузера та локалізований знімок дашборда. Кожен гейт паритету ×16 тепер працює ×17: паритет словника i18n + знімок, гейти H2/H3 довідки, паритет CHANGELOG, check-i18n сайту та перевірка локалей Playwright.

[1.121.0] — 2026-07-16

Додано

  • Сторінки Methodology, License і Changelog на cvstart.org — лендинг отримав три нові розділи всіма 16 мовами, поруч із наявним блоком Порівняння: /methodology/ (шкала оцінювання за шістьма вимірами 0.0–5.0, поріг подання заявки 4.0 і правила «ніколи не робимо» — локалізований стислий виклад career-ops.org/methodology), /license/ (канонічний текст ліцензії MIT із посиланням на NOTICE.md) і /changelog/ (цей файл, відображений для кожної локалі з 16 перекладених CHANGELOG репозиторію). Новий пункт Methodology у шапці та посилання в блоці ресурсів футера; sync-assets.mjs тепер синхронізує CHANGELOG ×16 та LICENSE у білд сайту, тож сторінки більше не можуть розійтися з репозиторієм.
  • Посилання на методологію в документації — README (усіма 16 мовами), канонічний список §1 вбудованого посібника довідки (усіма 16 мовами) та вікі тепер посилаються на career-ops.org/methodology (а також FAQ і глосарій) поруч із наявними посібниками career-ops.org/docs.

Змінено

  • Оновлено банер релізу та бейджі в README (1850 тестів, реліз v1.121.0) — банер досі анонсував v1.119.5.

[1.120.0] — 2026-07-16

Додано

  • Маніфест CareerOps (паритет із батьком v1.20.0) — батьківський проєкт випустив Маніфест CareerOps (MANIFESTO.md · career-ops.org/manifesto) і тепер показує його у своєму README, апдейтері та Go-дашборді. Веб-інтерфейс наслідує це: нове посилання у футері бічної панелі відкриває сторінку маніфесту (новий ключ i18n footer.manifesto у всіх 16 локалях), вбудований посібник довідки отримав §29 «Маніфест CareerOps» усіма 16 мовами, README пояснює, що таке маніфест і як його підписати, а футер лендингу cvstart.org теж посилається на нього.

Примітки

  • Батько v1.20.0 також виправив придушення відомих навичок у цільовому режимі upskill, приглушив dotenv, щоб stdout scan --json залишався придатним для парсингу, і виправив HTML-шаблон CV, щоб заголовок ролі не відривався від своїх пунктів — це поверхні на боці CLI, у які веб-інтерфейс не заходить через shell; змін коду веб-інтерфейсу не знадобилося.

[1.119.5] — 2026-07-13

Виправлено

  • Кнопка мови на лендінгу більше не переноситься — після появи прапорів у v1.119.2 підпис перемикача в шапці (наприклад «🇷🇺 Русский») міг розбиватися до трьох рядків на вузьких десктопних ширинах; підпис перемикача та всі пункти випадного списку тепер whitespace-nowrap — прапор + ендонім завжди в один рядок. Список мов у футері переведено з жорсткої двоколонкової сітки на рядок однорядкових пунктів із переносом — «🇧🇷 Português (Brasil)» теж більше не рветься посеред назви.

[1.119.4] — 2026-07-13

Змінено

  • LICENSE називає автора — рядок копірайту тепер: Sergei Emelianov (Fighter90) https://sergey-cv.com and career-ops-ui contributors (канонічний текст MIT не змінено). Новий NOTICE.md детально розписує ліцензування: хто власник копірайту, що саме покриває грант MIT (код, доки, переклади, лендінг, вікі), чого НЕ покриває (ваші дані в рантаймі, батьківський проєкт, контент джоб-бордів, торговельні марки), таблицю сторонніх компонентів (express/js-yaml — MIT; Astro/Tailwind — MIT; шрифти Figtree та JetBrains Mono — SIL OFL 1.1; sharp — Apache-2.0) і необов’язковий рядок атрибуції.

[1.119.3] — 2026-07-13

Додано

  • SECURITY.md — політика безпеки, на яку посилався CONTRIBUTING, тепер існує: підтримувані версії, приватний процес репортів (у репозиторії ввімкнено private vulnerability reporting GitHub — вкладка Security → «Report a vulnerability»), модель загроз для localhost-застосунку одного користувача (у скоупі: XSS через ворожі вакансії / SSRF / path traversal / витоки секретів / послаблення CSP; поза скоупом: DoS власного localhost і проблеми батьківського проєкту) та базова лінія хардинінгу для рев’юерів.

[1.119.2] — 2026-07-13

Додано

  • CONTRIBUTING.md — гід контриб’ютора, на який лендінг і README посилалися весь цей час, тепер існує: встановлення, карта проєкту, жорсткі правила безпеки/no-build, рівні тестування, walkthrough «двох реєстрів» для додавання скан-джерела, контракт i18n ×16, конвенції комітів/PR і процес релізу.
  • Прапори мов на лендінгу — перемикач мов cvstart.org, сітка мов у футері та банер «читайте своєю мовою» тепер показують прапор кожної локалі поруч з її ендонімом (той самий набір регіональних індикаторів, що й у мовному <select> застосунку; деградує до літер регіону там, де немає гліфів прапорів).
  • Правки футера лендінгу — неробоче посилання Discussions (функцію не ввімкнено в репозиторії) тепер веде на вікі проєкту, а у футері вказано автора: Sergei Emelianov (sergey-cv.com · LinkedIn).

[1.119.1] — 2026-07-13

Виправлено

  • Фільтр джерел на #/scan наздогнав реєстр — статичний список FALLBACK_SOURCES за випадним списком Source (використовується лише коли GET /api/scan/sources недоступний) мовчки відставав із v1.87.0: в офлайн-фолбеку бракувало 20 провайдерів (Amazon, Avature, SAP SuccessFactors, Get on Board, Dassault Systèmes, beesite, HigherEdJobs, JibeApply (iCIMS), softgarden, Cornerstone, Phenom, Radancy, Deutsche Bahn, EchoJobs, TKMS, Heckler & Koch, Rheinmetall, LaraJobs і нові Meituan / Tencent). Синхронізовано з усіма 61 і тепер закрито дрейф-тестом, що валить CI при розходженні клієнтського списку з серверним реєстром (значення І лейбли). +1 тест (1845).

[1.119.0] — 2026-07-13

Паритет із батьківським career-ops v1.19.0 + оновлення лендінгу cvstart.org.

Додано

  • 2 нові сканер-провайдери — Meituan (zhaopin.meituan.com) і Tencent (careers.tencent.com): публічні JSON-API китайських тех-дощок без авторизації, визначаються за хостом або явним provider:, серверний пошук за ключовими словами з пагінацією та дедуплікацією за URL — тепер 61 адаптер (56 EN + 5 RU). +20 тестів (1844).
  • Блок контриб’юторів на лендінгу — cvstart.org показує аватари всіх, хто долучився кодом (GitHub API /contributors на етапі збірки, боти відфільтровані), локалізовано всіма 16 мовами, з посиланням на повний граф контриб’юторів.
  • Живий лічильник зірок GitHub на лендінгу — бейдж у шапці тепер оновлюється на клієнті з GitHub API при кожному візиті (знімок збірки — як fallback), а щотижнева перезбірка Pages за розкладом не дає застаріти знімку та списку контриб’юторів; API-виклики в CI автентифіковані токеном.

Виправлено

  • Запити Workday CXS несуть браузерні заголовки (батьківський #1813) — тенанти за Cloudflare (спостерігалося наживо: geico) відповідають 500 на запити без звичайних UA/accept-language/origin/referer; фетчер тепер виводить origin і слаг сайту з самого CXS-URL. Запити Glints отримали той самий браузерний UA + origin/referer — обидва з спільної константи BROWSER_LIKE_USER_AGENT в http-json.mjs.

[1.118.4] — 2026-07-10

Виправлено

  • Скан hh.ru давав 0 вакансій з російського IP (посилання на регіональному піддомені) — з російського резидентного IP hh.ru редиректить пошук на регіональний піддомен (sochi.hh.ru, spb.hh.ru, …) і віддає посилання на вакансії на цьому піддомені. Парсер шукав посилання заголовка за жорстким хостом https://hh.ru/vacancy/ і не знаходив жодного регіонального — цілком робочий скан мовчки записував 0. Тепер приймається будь-який хост *.hh.ru (реклама adsrv.hh.ru/click?… так само відсікається — у неї немає шляху /vacancy/<id>), а URL результату канонізується в https://hh.ru/vacancy/<id>. Перевірено наживо: 17 реальних вакансій парсяться зі сторінки sochi.hh.ru, де раніше було 0. +1 тест (1824).

[1.118.3] — 2026-07-10

Виправлено

  • hh.ru мовчки повертав 0 вакансій (заглушка VPN-перевірки) — hh.ru тепер відповідає 302-редиректом на заглушку /vpncheeck («VPN мешает работе сайта») мережам, які вважає VPN/проксі (датацентрові IP); заглушка віддає HTTP 200 без жодної картки вакансії, тож скан звітував 0 без помилки. Сканер тепер розпізнає редирект за фінальним URL відповіді, вимикає hh.ru до кінця прогону й пише чесну підказку: трафік має справді виходити через резидентний IP — системний VPN/проксі може лишатися ввімкненим, навіть коли перемикач у браузері вимкнено. +1 тест (1823).

[1.118.2] — 2026-07-10

Обслуговування

  • Доопрацювання лендінгу (#118)site/README.md приведено до Astro 7 (security-апгрейд з #116), прибрано невикористаний імпорт, додано 4 виконувані гарди для білд-скриптів лендінгу: гейт i18n-паритету доказово падає на зламаному словнику, а sync-assets ніколи не пише поза site/ — набір 1822. Розібрано два алерти CodeQL (один виправлено в коді, один відхилено як навмисну поведінку білда).

[1.118.1] — 2026-07-10

Виправлено

  • Сканування hh.ru з-поза меж Росії — hh.ru тепер віддає HTTP 451 (регіональне юридичне блокування) неросійським IP на публічних сторінках пошуку. Сканер обробляє 451 як 403: після першого блокування hh.ru вимикається до кінця прогону з чесним рядком у лозі про російську IP / VPN-вихід, тож решта запитів та інші RU-джерела не витрачаються марно. Довідку §7 оновлено всіма 16 мовами. +1 тест (1818).

[1.118.0] — 2026-07-09

Пакет паритету з батьківським career-ops v1.18.0.

Додано

  • 9 нових сканер-провайдерів — Cornerstone OnDemand (csod), Phenom (phenom), Radancy (radancy), Deutsche Bahn (deutschebahn), EchoJobs (echojobs), TKMS (tkms), Heckler & Koch (hecklerkoch), Rheinmetall (rheinmetall), LaraJobs (larajobs) — тепер 54 адаптери. Адаптер Lever додатково розпізнає дошки EU-тенанта (jobs.eu.lever.co).
  • Статус Hired у трекері (паритет зі states.yml батька): прийняті офери отримують власний канонічний статус, святковий бейдж і банер «роботу знайдено» на #/tracker; воронка та конверсії рахують його як такий, що пройшов усі етапи.
  • Вкладка «За весь час» у #/stats — ретрансляція лише для читання батьківського stats.mjs (зведення трекера за весь час, накопичені частки воронки, підсумки сканера, покриття порталів) плюс спостереження щодо компенсації з salary-gap.mjs (бажана vs заявлена vs фактична, за кожною заявкою). Нові маршрути GET /api/stats/lifetime і GET /api/stats/salary-gap — shell-out з нульовою вартістю токенів, м’яка деградація {available:false} без батьківського проєкту.
  • 28 нових i18n-ключів у всіх 16 локалях; довідку §14/§26 оновлено всіма мовами.

Тести

  • +38 юніт-тестів (три сьюти паритету провайдерів + маршрути релея/статусу) — разом 1817.

[1.117.2] — 2026-07-06

Фікс порожнього трекера для shell-out паритету. Батьківські скрипти виходять із кодом 1 і структурованим {error}-JSON, коли в трекері ще немає заявок; дошка фоллоу-апів і вкладка патернів показували це як «script-error». Обидва маршрути тепер передають це як здоровий порожній стан (available:true, empty:true), і UI показує чесне «поки порожньо». Перевірено наживо на реальному батькові.

Нове: немає.

[1.117.1] — 2026-07-06

Доналаштування v1.117.0 (розбір CodeQL). Три shell-out ендпоінти (GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns) тепер несуть спільний per-IP лімітер (кожен запит породжує дочірній процес; на loopback — no-op). Витяг тексту за URL у «Додати в CV» вичищає теги до нерухомої точки й потім видаляє всі залишкові </> — доказово повне очищення для тексту LLM-промпту. Поведінка на коректному вводі незмінна.

Нове: немає.

[1.117.0] — 2026-07-06

Пакет паритету з батьком — шість можливостей батьківського career-ops тепер в UI. (1) Дошка каденції на #/followup: терміновість за кожною заявкою (🔴/🟠/🟡/🔵) з followup-cadence.mjs, плюс кнопка «Проставити дати» (followup-seed.mjs --backfill). (2) Патерни відмов: четверта вкладка Статистики запускає analyze-patterns.mjs (лише читання) — розподіл результатів, рекомендації, частка просування за ATS-вендорами. (3) Додати в CV: картка CV Studio перетворює URL чи вставлений текст на ATS-пункти, засновані ЛИШЕ на цьому джерелі (лише пропозиції, без записів; завантаження URL захищене від SSRF). (4) 4 нові сканер-провайдери — beesite, HigherEdJobs (RSS), JibeApply (iCIMS), softgarden — реєстр тепер налічує 50 адаптерів (45 EN + 5 RU), усі в списку Scan. (5) Крок передперевірки нокаут-питань у чек-листі Apply. (6) Раннер reconcile (/api/run/reconcile). Shell-out-маршрути чесно деградують без батьківських скриптів.

  • Новий модуль server/lib/routes/followup.mjs (31-й) + нові маршрути + 8 файлів source/adapter. Тести: 6 + 7 нових; сьют 1737 → 1750. 41 новий ключ i18n ×16. Довідка §13/§17/§24/§26 розширена ×16.

Нове: GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns, POST /api/cv-studio/add-entry, POST /api/run/reconcile.

[1.116.0] — 2026-07-06

Перероблено лічильник витрат + перший наскрізний тест віджетів. Лічильник витрат ШІ (v1.114.0) виправлено й правильно закріплено: тепер він прикріплений унизу лівої бічної панелі (на всю ширину, та сама поверхня) й резервує внизу місце, що дорівнює його висоті, аби меню ніколи не перекривалося — навігація та підвал версії завжди прокручуються вільно над ним. Він оновлюється наживо (кожні 15 с, при фокусі вкладки та зміні маршруту), а кожен рядок вікна тепер показує реальні <токени> · <оцінка вартості> (смуги масштабуються відносно 30-денного вікна) замість завжди-100% «частки». Крім того: стійкий бар’єр typeof в імпортері CV закриває в першопричині повторюваний хибнопозитивний type-confusion CodeQL, а новий наскрізний тест Playwright проганяє обидва постійні віджети в реальному браузері.

  • public/js/lib/usage-hud.js + app.css, server/lib/cv-import.mjs. Тести: tests/playwright-widgets.mjs (2 E2E) + tests/usage-hud.test.mjs (10). Довідка §6 розширена ×16.

Нове: немає.

[1.115.0] — 2026-07-06

Шліфування дизайну (консервативне, кораловий бренд збережено). Легкий прохід удосконалення спільної дизайн-системи — без перебудови, без зміни палітри. Картки метрик на дашборді тепер трохи піднімаються та отримують коралову рамку при наведенні (як плитки швидких дій); картки контенту піднімаються ледь-ледь; кнопки primary / dark / danger отримують тінь у спокої та м’яке підняття при наведенні для глибини; великі числа вирівнюються через tabular-nums; а інтерактивні елементи отримують м’який кораловий ореол за чітким 2px-кільцем клавіатури. Уся анімація поважає prefers-reduced-motion, а ореол обмежено елементами керування — ніколи не глобальний *:focus-visible.

  • Лише CSS (public/css/app.css); без змін розмітки, i18n, маршрутів чи CSP. Тести: tests/design-polish-v1115.test.mjs (5). Перевірено вживу через Playwright.

Нове: немає.

[1.114.0] — 2026-07-06

Лічильник використання та вартості ШІ в бічній панелі (лівий нижній кут). Компактний розділ ВИКОРИСТАННЯ тепер розташований унизу бічної панелі (фіксована картка в лівому нижньому куті, якщо панелі немає; у правому нижньому для RTL) на кожній сторінці. Він показує використання токенів LLM за вікнами 24г / 7д / 30д — кожне як <токени> · <частка%> із зеленою смугою (частка від усього часу) — плюс підвал з оцінкою вартості за 24г. Дані — доступний лише для читання звід GET /api/usage із data/llm-usage.jsonl (лише локально), те саме джерело, що й сторінка #/usage; вартість оцінна, а запуски в ручному режимі безкоштовні й не враховуються. Згортається — заголовок перемикає, стан зберігається.

  • Новий клієнтський віджет public/js/lib/usage-hud.js, завантажується з index.html, монтується в бічну панель над підвалом версії (запасний варіант — фіксований кут). Безпечний для CSP; з урахуванням теми та дзеркалом RTL. Без нового маршруту сервера. Тести: tests/usage-hud.test.mjs (8). 3 нові ключі i18n ×16.

Нове: немає.

[1.113.0] — 2026-07-06

Плаваючий помічник «Запитати довідку» на кожній сторінці. Градієнтна кнопка-робот із чатом тепер плаває в правому нижньому куті (у лівому нижньому для RTL) кожної сторінки. Натисніть, щоб відкрити компактний чат, який відповідає на питання щодо використання, спираючись ЛИШЕ на вбудовану довідку вашою мовою — той самий ендпоінт, що й сторінка #/docs-assistant (POST /api/docs-assistant/ask), тож він ніколи не читає ваше резюме, профіль чи трекер. Наживо з ключем LLM; без ключа → готовий промпт. У шапці — аватар-робот і статус онлайн; чипи підставляють часті питання; Escape або клік ззовні закриває; на сторінці #/docs-assistant кнопка прихована.

  • Новий клієнтський віджет public/js/lib/docs-fab.js, монтується глобально з index.html; безпечний для CSP; стилі з урахуванням теми та дзеркалом RTL у app.css. Без нового маршруту сервера. Тести: tests/docs-fab.test.mjs (8). 6 нових ключів i18n ×16. Довідка §1 розширена на місці.

Нове: немає.

[1.112.0] — 2026-07-06

Консолідація документації та QA. Без видимих користувачу змін коду. Документ угод SDD (docs/sdd/CONVENTIONS.md) оновлено до поточних 30 модулів маршрутів (було 24) та поточної базової лінії тестів; визначальний загальнопроєктний QA-промпт (qa/QA-REGRESSION-PROMPT.md) консолідовано — механіку релізу актуалізовано (v1.111, parentVersion 1.17.0, публікація за подією релізу), таблицю доповнень §14 виправлено («Виключити» в Scan перепозначено як v1.109.0) і доповнено закриттям CodeQL з v1.111 — тож він самодостатній як єдиний регресійний промпт для всієї функціональності. Додано один тест покриття для гілки завеликого завантаження.

Нове: немає.

[1.111.0] — 2026-07-06

Безпека — закриття беклогу CodeQL. Три посилення ешелонованого захисту, що закривають решту зауважень статичного аналізу в першопричині, а не через dismiss. stripDangerousMarkdown тепер екранує < у будь-якому усіченому відкритті небезпечного тега (навантаження, що закінчується на <script/<iframe/…), тож у виводі доказово не лишається живого небезпечного тега. Імпорт CV читає розмір завантаженого буфера через явне приведення Number() — бар’єр проти плутанини типів. Рядки ролі режимів тепер є шаблонними рядками, інтерпольованими через String.replace, а не збереженими функціями, що повністю прибирає виклик динамічної диспетчеризації. Видимої для користувача зміни поведінки немає.

  • server/lib/security.mjs, server/lib/cv-import.mjs, server/lib/prompts.mjs. Тести: tests/security-hardening-v1111.test.mjs (7) + оновлений тест-страж v1108. Без змін i18n/довідки/маршрутів.

Нове: немає.

[1.110.0] — 2026-07-06

Оновлення документації та QA (усі мови). Без змін коду. Повнопроєктний QA-промпт оновлено до v1.109.0 з новим §14 (v1.98→v1.109), а вічнозелені промпти UX-аудиту та design-export отримали поточний набір екранів. Кожен абзац довідки, доданий у v1.100–v1.109, тепер перекладено всіма 16 мовами.

Нове: немає.

[1.109.0] — 2026-07-06

Фільтр «Виключити» в Scan + огляд пайплайна (паритет з веб-версією). На #/scan поле Пошук тепер трактує коми як АБО («ролі для пошуку»), а нове поле Виключити ховає рядки, де компанія/роль/локація містить будь-яке слово через кому (напр. senior, staff); обидва запам’ятовуються у збережених пошуках. На #/pipeline компактна смуга огляду показує пайплайн з одного погляду — N у вхідних, N відстежується та лічильники Applied / Responded / Interview / Offer з трекера, кожен чип веде до #/tracker.

  • Лише клієнт (без нового маршруту/записів). public/js/views/scan.js + public/js/views/pipeline.js. Тести: tests/scan-pipeline-ui-v1109.test.mjs (2). 4 нові ключі i18n ×16. Довідка §7 + §8 розширені на місці.

Нове: немає.

[1.108.0] — 2026-07-06

Посилення безпеки (розбір CodeQL, раунд 2). Виправлено ще три знахідки низької серйозності: збирач промптів розв’язує рядок ролі локалі за власним ключем + typeof === function, щоб підроблена локаль не могла викликати метод прототипу (unvalidated-dynamic-method-call); slug імені PDF-файлу обмежено 200 символами до регулярки, щоб вхід з самих дефісів не відкочувався (поліноміальний ReDoS); а імпорт документа приводить масивний filename (повторний заголовок) до рядка (type-confusion). Без зміни поведінки для коректного вводу.

  • server/lib/prompts.mjs, server/lib/routes/runners.mjs, server/lib/cv-import.mjs + tests/security-hardening-v1108.test.mjs (3). За v1.106–v1.108 беклог статичного аналізу скоротився зі 167 до ~14: усі справді значущі для безпеки знахідки виправлено, решту (захищені/санітизовані хибні спрацювання + lint рівня note) відхилено з обґрунтуванням.

Нове: немає.

[1.107.0] — 2026-07-06

Посилення санітайзера (ешелонований захист від XSS у стані спокою). stripDangerousMarkdown — нейтралізує небезпечний HTML у збереженому markdown резюме/вакансії, щоб будь-який споживач, що оминає клієнт з екрануванням-при-рендері, лишався безпечним — тепер виконує видалення тегів до нерухомої точки (повторювати до стабілізації), щоб видалення, що переформовує корисне навантаження (напр. <scr<script></script>ipt>), було впіймано, збігається із закривними тегами script/style тощо зі сміттям у кінці (</script foo>) і видаляє незакритий виконуваний відкривний тег (<script …>). Поведінка для коректного markdown не змінюється — лише видаляє більше.

  • server/lib/security.mjs: цикл нерухомої точки (обмеження 8 проходів) + шаблони закривних тегів [^>]*> + видалення незакритого відкривного тега. +3 регресійні випадки в tests/cv-xss-bypasses.test.mjs. Авторитетна межа XSS лишається екрануванням на виводі (UI.md); це посилює гарантію в спокої й закриває відповідні знахідки CodeQL.

Нове: немає.

[1.106.0] — 2026-07-06

Посилення безпеки (розбір CodeQL). Виправлено три реальні (хай і низької серйозності) знахідки після проходу беклогу статичного аналізу: шлях помилки рендера маршруту тепер екранує повідомлення про помилку до потрапляння в DOM (помилка сервера може відобразити введення користувача, тож вважається недовіреною — межа XSS), а записи властивостей профілю/конфігу відхиляють ключі __proto__ / constructor / prototype (захист від забруднення прототипу про всяк випадок — ключі беруться з фіксованих специфікацій полів, а не з сирого введення). Більшість решти попереджень — хибні спрацювання на легітимних читаннях/записах сканера в data/* та на маршрутах, що вже мають власний обмежувач; відхилено з обґрунтуванням.

  • public/js/router.js екранує err.message через UI.escapeHtml перед innerHTML; server/lib/routes/content.mjs і server/lib/routes/config.mjs захищають ключі прототипу. Без зміни поведінки для коректного введення. Тести: tests/security-hardening-v1106.test.mjs (3). Нових ключів i18n немає.

Нове: немає.

[1.105.0] — 2026-07-06

Сторінка витрат і вартості ШІ. Нова сторінка Витрати ШІ (бічна панель, поруч зі «Здоров’ям») показує, скільки токенів ви витратили на живі генерації ШІ — оцінки, звіти, чати — з розбивкою за провайдерами за останні 24 години, 7 днів, 30 днів і весь час, з оцінкою вартості в USD. Кожен живий виклик додає невеликий запис {provider, in, out} до data/llm-usage.jsonl (нікуди нічого не надсилається); запуски без ключа (ручний режим) нічого не коштують і не записуються.

  • Новий модуль маршруту (30-й) server/lib/routes/usage.mjsGET /api/usage (агрегати лише для читання) + server/lib/llm-usage.mjs (recordUsage нормалізує формати usage Anthropic/OpenAI/Gemini і додає best-effort; readUsage/aggregate агрегують за вікнами 24г/7д/30д/усе × провайдер) + server/lib/llm-pricing.mjs (редагована таблиця цін за провайдерами $/1M токенів — токени точні, долари — приблизні прайс-ціни, які можна виправити; не виставляються до оплати). Запис підключено в точках диспетчеризації (runActiveProvider + routes/llm.mjs).
  • Нове представлення public/js/views/usage.js (#/usage, вкладки вікон). Тести: tests/usage-routes.test.mjs. 17 нових ключів i18n ×16 (usage.* + nav.usage). Довідка §6 розширена на місці.

Нове: server/lib/routes/usage.mjs; server/lib/llm-usage.mjs; server/lib/llm-pricing.mjs; public/js/views/usage.js.

[1.104.0] — 2026-07-06

Логотипи компаній у таблиці сканування (без витоку приватності). Новий перемикач Вигляд у НалаштуванняхПоказувати логотипи компаній у таблиці сканування (типово вимкнено) — малює логотип кожної компанії поруч із назвою на #/scan. Логотип — це favicon компанії, узятий з її власного домену та проксі на сервері (GET /api/logo), тож жоден сторонній сервіс логотипів не дізнається, яких роботодавців ви переглядаєте. Вакансії на спільному порталі (Greenhouse, Lever, Ashby, …) показують кольоровий літерний значок замість іконки порталу, і будь-який логотип, що не завантажився, відкочується на той самий значок.

  • Новий модуль маршруту (29-й) server/lib/routes/logos.mjsGET /api/logo?domain=. Він валідує домен (без схеми/шляху/loopback), бере /favicon.ico через SSRF-безпечний safeGet (новий режим binary повертає сирі байти + content-type; DNS-піннінг, перевірка редиректів і ліміт розміру не змінені), виконує сніфінг сигнатури зображення, щоб ніколи не віддати HTML-сторінку помилки як картинку, кешує влучення і промахи в LRU у пам’яті та нічого не пише на диск.
  • Нова клієнтська бібліотека public/js/lib/company-logo.js (window.CompanyLogo): типово вимкнена через прапорець у localStorage; пропускає спільні ATS-хости на користь детермінованого літерного аватара; CSP-безпечний відкат img.onerror. Тести: tests/logo-routes.test.mjs. 5 нових ключів i18n ×16 (appear.*). Довідка §2 розширена на місці.

Нове: server/lib/routes/logos.mjs; public/js/lib/company-logo.js.

[1.103.0] — 2026-07-06

Налаштування: «Інструменти CLI для ШІ» — які встановлені. career-ops працює на Claude Code, але сумісний із будь-яким агентським CLI відкритого стандарту skills. Нова вкладка Інструменти CLI для ШІ у Налаштуваннях (#/config) показує, які з них — Claude Code, Codex, Gemini CLI, OpenCode, GitHub Copilot CLI, Qwen, Antigravity — встановлені на машині, де запущено сервер, і їхні шляхи. Це сканування PATH лише для читання: перевіряється лише наявність кожного бінарника, і він ніколи не запускається (без --version, без виконання), нічого не пишеться і дані користувача не зачіпаються.

  • Новий модуль маршруту (28-й) server/lib/routes/cli-detect.mjsGET /api/cli-detect. Визначення резолвить шлях бінарника з фіксованого списку з 7 записів за process.env.PATH (шими .cmd/.exe/.bat у Windows; біт виконання в POSIX); ворожий файл на PATH ніколи не буде виконано цим маршрутом.
  • Нова вкладка «Інструменти CLI для ШІ» у public/js/views/config.js (лінива загрузка, діплінк через #/config?tab=cli). Тести: tests/cli-detect-routes.test.mjs. 8 нових ключів i18n ×16 (cli.* + config.tabCli). Довідка §2 розширена на місці.

Нове: server/lib/routes/cli-detect.mjs.

[1.102.0] — 2026-07-05

«Запитати довідку» — чат з опорою на вбудовану довідку. Нова сторінка Запитати довідку 💬 (бічна панель, під «Довідкою»): введіть запитання на кшталт «Як сканувати портали вакансій?» і отримайте відповідь лише зі вбудованої довідки застосунку вашою мовою — показує використані розділи й ніколи не читає ваше резюме, профіль чи пошук роботи. Це про те, як користуватися застосунком, а не про вас. З ключем LLM відповідає наживо; без ключа видає готовий промпт, уже заповнений потрібними розділами довідки.

  • Новий модуль маршруту (27-й) server/lib/routes/docs-assistant.mjsPOST /api/docs-assistant/ask. Пошук без залежностей: довідка вашою мовою розбивається на розділи ## й оцінюється за збігом ключових слів із запитанням; найкращі включаються, і модель має відповідати з них або сказати, що довідка це не охоплює (без вигаданих функцій/маршрутів). Спільний каскад провайдерів, ручний відкат, обмеження частоти, без записів, не читає дані користувача.
  • Нове представлення public/js/views/docs-assistant.js. Тести: tests/docs-assistant-routes.test.mjs. 14 нових ключів i18n ×16 (docs.* + nav.docsAssistant). Довідка §1 розширена на місці.

Нове: server/lib/routes/docs-assistant.mjs; public/js/views/docs-assistant.js.

[1.101.0] — 2026-07-05

CV Studio: адаптуйте резюме + напишіть супровідний лист під конкретну вакансію, з рекрутерським чек-лістом. Нова картка Адаптувати під вакансію на #/cv-studio: вставте опис вакансії (і, за бажанням, цільову роль/заголовок), і CV Studio створює адаптоване під цю вакансію резюме та відповідний супровідний лист, а потім проганяє обидва через чек-лист-гейт перед видачею — error блокує (виправляється до того, як ви побачите результат), warn радить. Механіка — витяжка з практики кар’єрного консультування в загальні правила: рекрутер читає за секунди, тож релевантне йде вгору, заголовок збігається з роллю вакансії, у результатах — конкретні цифри, а лист лишається коротким тизером з єдиною «смичкою» «вимога ↔ ваш відповідний факт». Ґрунтується лише на вашому резюме, профілі та two-pager і нічого не вигадує — без зашитих компаній, ролей чи історії.

  • Новий ендпоінт POST /api/cv-studio/tailor (розширює наявний модуль cv-studio — без 27-го модуля): buildTailorPrompt + загальний гейт TAILOR_INSTRUCTIONS, на основі bundleProjectContext, спільний каскад провайдерів, ручний промпт без ключа, з обмеженням частоти, без записів. Результат експортується у Markdown / PDF / DOCX через спільну панель report-export.js.
  • Тести: +3 у tests/cv-studio-routes.test.mjs. 10 нових ключів i18n ×16 (cvs.tailor*). Загальний референс docs/prompts/resume-cover.md. Довідка §24 розширена на місці.

Нове: docs/prompts/resume-cover.md.

[1.100.0] — 2026-07-05

Two-pager: ШІ-автозаповнення з вашого резюме + Перегляд + експорт у PDF/DOCX/Markdown. Two-pager (#/two-pager) фіксує те, чого ви насправді хочете від наступної ролі, але раніше кожне поле доводилося писати вручну або копіювати промпт в інший інструмент. Тепер ✨ ШІ-помічник заповнення працює наживо з налаштованим провайдером — читає лише ваше резюме + профіль (через bundleProjectContext, нічого не вигадуючи), складає всі поля (хто я / що подобається / обов’язкове / що ненавиджу / стоп-фактори / непорушне / цільове середовище) і заповнює форму, щоб ви перевірили, відредагували та зберегли. Без API-ключа повертається до модалки «скопіювати промпт», як раніше. Нова кнопка 👁 Перегляд і експорт відображає two-pager як форматований документ із панеллю Завантажити .md / Зберегти як PDF / Зберегти як DOCX / Копіювати.

  • Експорт .docx без залежностей. Новий server/lib/docx.mjs формує мінімальний, але валідний Office Open XML .docx (ZIP із DEFLATE із чотирьох частин OOXML, CRC-32 на запис) — без нової залежності (залежності лишаються express + js-yaml). Новий маршрут POST /api/export/docx (server/lib/routes/export.mjs, 26-й модуль маршрутів; без стану, ліміт 200 КБ, без записів / без LLM / без fetch за URL). Під’єднано до спільного public/js/lib/report-export.js, тож звіт по ринку, кар’єрний план і профорієнтація теж отримують експорт у DOCX.
  • Живе автозаповнення використовує спільний каскад провайдерів (runActiveProvider / providerAvailable); повернутий YAML парситься й приводиться назад до обмеженої форми two-pager (parseYamlFields + normalizeTwoPager) — невідомі ключі відкидаються, масиви/рядки обмежуються. Ручний режим збережено.
  • Тести: tests/export-routes.test.mjs. 4 нові ключі i18n ×16 (export.saveDocx, twoPager.preview, twoPager.aiFilling, twoPager.aiFilled).

Нове: server/lib/docx.mjs; server/lib/routes/export.mjs.

[1.99.0] — 2026-07-05

Сторінка здоров’я порталів (#/portals). Сканер стежить за набором компаній у portals.yml; slug ATS може тихо зламатися, і цей роботодавець зникає з усіх майбутніх сканувань. Нова сторінка Portals перелічує кожну відстежувану компанію і за кнопкою Check portal health перевіряє кожен careers_url через safeGet із закріпленим DNS (захист від SSRF), позначаючи мертві (404 = тихо відкинута) — лише читання. Також посилює репортер багів v1.98.0 за підсумками ревʼю: кільцевий буфер помилок тепер ловить мережеві збої fetch, а скрабер вичищає непозначені ключі провайдерів.

Нове: server/lib/routes/portals.mjs; public/js/views/portals.js.

[1.98.0] — 2026-07-05

Вбудований репортер багів (паритет із веб-частиною web-v0.2.0 батьківського проєкту). Кнопка 🐞 Report a bug у панелі сповіщень збирає діагностичний знімок із пріоритетом приватності — версії, ваш екран, браузер, зведення перевірок /api/health і останні 20 помилок із нового клієнтського кільцевого буфера — плюс детермінований відбиток для дедуплікації (co-web-<base36>), дає переглянути точний Markdown і потім відкриває попередньо заповнений issue на GitHub. Нічого не надсилається автоматично; він ніколи не несе ваше CV, профіль, відповіді, URL вакансій чи ключі. Нові бібліотеки logbuf.js + bug-report.js; 11 ключів i18n ×16; tests/bug-report.test.mjs.

Нове: public/js/lib/logbuf.js; public/js/lib/bug-report.js.

[1.97.1] — 2026-07-05

Посилення за підсумками рев’ю та паритет документації (продовження v1.97.0). Розбір логів AI-рев’ю виявив реальні виправлення:

  • fit-score.js (значок відповідності під час сканування). salaryFloor() більше не перетворює ставку, меншу за річну, на фіктивний річний мінімум — «at least 500 EUR/day», «$80/hr», «6000 monthly» тепер повертають null замість дилбрейкера у 500k/80k. Зіставлення країн тепер іде за цілим словом (\b…\b), тож «Germany» більше не збігається з прикметником «German» (як і «Nigeria» всередині «Nigerian») і не спрацьовує хибним порушенням «обов’язково-деінде». +3 тести у tests/fit-score.test.mjs.
  • Паритет документації. Кожен локалізований README тепер однаково заявляє 16 локалей — лічильник/список у рядку Help (×13) та текст розділу локалізації плюс примітка «додайте ключ до всіх N файлів» (×8) усе ще трималися на лічильниках до v1.85 (8/9). Лічильник адаптерів §17 у вбудованій довідці виправлено на 46 адаптерів — 41 англійський + 5 російських в усіх 16 бандлах.

Жодних змін поведінки, окрім евристики значка відповідності; ні нових маршрутів, ні ключів, ні додавань i18n.

[1.97.0] — 2026-07-05

Джерело сканера Dassault Systèmes + фронт покращень якості за трьома напрямами.

  • Нове джерело сканування — Dassault Systèmes (паритет із батьківським career-ops, #1498). server/lib/sources/dassault.mjs + server/lib/portals/adapters/dassault.mjs відтворюють zero-token-провайдер «карткового пошуку» Exalead із батьківського проєкту (публічна стрічка за 3ds.com/careers/jobs). Це єдина глобальна кінцева точка, тож вона обирається за провайдером (provider: dassault) або автоматично визначається за хостом 3ds.com, із захистом від SSRF, прив’язкою хоста до www.3ds.com та redirect:'error'. XML розбирається без DOM (карти <Meta> для кожного <Hit>), місто/країна беруться з локалізованого рядка категорії, а вакансії зберігаються лише тоді, коли їхній публічний URL перебуває на *.3ds.com. Реєстр тепер постачає 46 адаптерів (41 EN + 5 RU); лічильник ALL_ADAPTERS, перевірки відсортованих id та EN-набору /api/scan/sources підняті з 40 → 41. Набір tests/sources-dassault.test.mjs (10 випадків).
  • Перенесені з батьківського проєкту виправлення надійності. Парсер Avature тепер допускає два живі варіанти розмітки орендарів (article--result із суфіксом позиційного індексу + безкласовий якір заголовка JobDetail, #1541); Get on Board захищається від 0/від’ємного published_at (більше жодних хибних дат 1970 року); SuccessFactors обмежує останню сторінку, щоб вона не могла перевищити MAX_JOBS (#1528).
  • Виправлення серверного аудиту. safe-fetch більше не зависає на відповіді, що перевищує ліміт розміру — шлях обмеження розміру тепер напряму завершує проміс замість очікування події 'end', яку зруйнований потік ніколи не випустить (виправляє запити /api/pipeline/preview та авто-пайплайну для великих сторінок). Логування активності SSE stream.* знову досяжне (перевірку /api/stream/ переміщено вище загального захисту «пропускати GET»).
  • Виправлення аудиту SPA. Перемикач вкладок #/stats захищений від гонки під час асинхронного рендерингу — результат повільної вкладки більше не може затерти новішу вкладку, на яку користувач уже перемкнувся. Підтвердження видалення у mock interview та нетворкінгу тепер передають коректні заголовок + тіло (більше жодних діалогів із порожнім тілом).
  • Виправлення перекладу. Виправлено неперекладені значення словника — українські config.modes* (Adaptive Framing / Exit Narrative / Location Policy), російський eval.jdLbl («Job Description»), італійський dash.quick.contactoSub («referral» → «segnalazione») — а також англійську заготовку 16 локалей локалізовано в CHANGELOG для ru/uk/ja/ko/zh-CN/zh-TW.

Нове: server/lib/sources/dassault.mjs; server/lib/portals/adapters/dassault.mjs.

[1.96.0] — 2026-07-04

Кар’єрна орієнтація (Epic 27). Нова сторінка #/orientation відповідає на питання «які напрями мені насправді підходять?» — така оцінка, яку дав би профорієнтаційний тест, але виведена з вашого власного резюме та профілю замість опитувальника. Натисніть Згенерувати профіль, і модель поверне ваші найкращі кар’єрні вектори (які з восьми архетипів — Функціоналіст, Адміністратор, Комунікатор, Спеціаліст, Аналітик, Новатор, Менеджер, Підприємець — підходять, з доказами), схильність до кар’єрного типу, рекомендовані ролі, професійні сильні сторони, прив’язані до вашого резюме, тенденції робочого стилю та рекомендації щодо розвитку. Це ШІ-рефлексія того, як читається ваше резюме, — а не психометричний тест: воно ніколи не вигадує досягнень і ніколи не подає числових результатів так, ніби їх виміряли. Експортуйте його в Markdown або PDF; нічого не записується на диск.

  • Новий маршрут server/lib/routes/orientation.mjs (24-й модуль маршрутів) — POST /api/orientation/generate будує промпт профілю з CV+профілю+two-pager+пам’яті через спільну каскаду провайдерів, із ручним відкатом для копіювання-вставлення та без запису файлів.
  • Повторно використовує report-export.js для Markdown/PDF/копіювання, у навігаційній групі Зростання.
  • Тести: tests/orientation-routes.test.mjs (рамка рефлексії / без вигаданих оцінок, ручний режим із засівом із CV/профілю). 7 нових ключів i18n ×16 локалей, довідка §28 ×16.

Нове: #/orientation; server/lib/routes/orientation.mjs.

[1.95.0] — 2026-07-04

План кар’єри (Epic 26). Нова сторінка #/career-plan перетворює ваше резюме та профіль на конкретний, персоналізований план розвитку. Виберіть горизонт (6/12/24 місяці) та, за бажанням, фокус, і модель — читаючи ваше CV, профіль, two-pager і нотатку пам’яті — пише знімок відправної точки, SWOT сильних сторін і зростання, цілі у форматі SMART / OKR / WOOP, альтернативні траєкторії, план hard/soft-навичок, помісячну дорожню карту, методи відстеження прогресу, підводні камені та підтримувальні кроки. Вона планує вперед від того, що дійсно показують ваші матеріали, і ніколи не вигадує факти про вашу історію. Редагуйте її на місці, Збережіть її в користувацький шар (config/career-plan.md) та експортуйте її у Markdown або PDF.

  • Новий маршрут server/lib/routes/career-plan.mjs (23-й модуль маршрутів) — GET/PUT /api/career-plan (пише config/career-plan.md) + POST /api/career-plan/generate (спільна каскада провайдерів, ручний відкат, без фабрикації). PATHS.careerPlan.
  • Повторно використовує спільний report-export.js (v1.94.0) для Markdown/PDF/копіювання та нову навігаційну групу Зростання.
  • Тести: tests/career-plan-routes.test.mjs (обмеження, круговий обхід GET/PUT, промпт із урахуванням горизонту, засіяний із CV/профілю). 20 нових ключів i18n в усіх 16 локалей, довідка §27 ×16.

Нове: #/career-plan; server/lib/routes/career-plan.mjs; PATHS.careerPlan.

[1.94.0] — 2026-07-04

Статистика, перероблена (Epic 25). Сторінка #/stats тепер є розділом Статистика з трьома вкладками, зі справжніми графіками та значно більшою кількістю даних. Нова вкладка Звіт про ринок просить модель проаналізувати зарплати та ринок праці для ваших цільових ролей у вибраному регіоні та валюті — стисле резюме, зарплати за рівнем із перцентилями P10/P25/P75/P90, провідні роботодавці, таблиця затребуваних навичок, частота пільг, розподіл офіс/гібрид/віддалено, тренди на 12–24 місяці та поради щодо перемовин. Кожна цифра позначена як орієнтовна оцінка зі знань моделі, і ніколи не подається як зібрані дані. Нова вкладка Мій пайплайн будує графіки за вашим власним трекером: розподіл оцінок, воронка статусів, провідні компанії та ролі, заявки в часі та коефіцієнти конверсії. Початковий вигляд цільових ролей (вакансії/зарплати за країнами + тренд збережених знімків) переходить у третю вкладку, тепер із вибором валюти та оглядом вакансій за роллю.

  • Експортуйте будь-який звіт у Markdown або PDF чи скопіюйте його — через спільний помічник report-export.js (завантаження Markdown як blob; PDF через наявний вбудований PDF-раннер).
  • Новий маршрут server/lib/routes/market.mjs (22-й модуль маршрутів) — POST /api/stats/market будує промпт аналізу ринку на основі вашого CV/профілю (щоб знати ваші цільові ролі), регіону та валюти, запускає його через спільну каскаду провайдерів і відкочується до промпту для копіювання за відсутності ключа. Без запису файлів.
  • Тести: tests/market-routes.test.mjs (обмеження регіону/валюти, промпт із чесним маркуванням, ручний режим із передзаповненням із CV/профілю). 36 нових ключів i18n в усіх 16 локалей, довідка §26 ×16.

Нове: #/stats перероблено на вкладки; server/lib/routes/market.mjs; public/js/lib/report-export.js.

[1.93.0] — 2026-07-04

Шар пам’яті (Epic 24). Нова сторінка #/memory містить коротку редаговану нотатку «запам’ятай це про мене», яку асистент тримає в голові на кожному завданні:

  • Одна нотатка, всюди — оскільки вона вбудована в bundleProjectContext, нотатка автоматично доходить до кожного AI-запиту (оцінка, пробна співбесіда, нетворкінг, CV Studio) в усіх провайдерах. Напишіть її раз — вона керує всім.
  • Керування, а не факти — вона фіксує ваші вподобання й те, як вам зручно працювати (тон, формат, стоп-фактори, ритм), і ніколи не нові фактичні твердження про ваш досвід — ті й далі живуть лише у вашому резюме, профілі та two-pager. Зберігається в користувацький шар за адресою config/memory.md і ніколи не перезаписується оновленнями.
  • Підказки з ваших данихPOST /api/memory/suggest аналізує ваш власний трекер заявок на поведінкові патерни й готує пункти для перегляду й редагування. Він читає ваш трекер; ніколи не вигадує фактів і не робить жодного онлайн-виклику.

Нове: server/lib/routes/memory.mjs (21-й модуль маршрутів — GET/PUT /api/memory + POST /api/memory/suggest), public/js/views/memory.js, PATHS.memory та блок config/memory.md, доданий до bundleProjectContext. 11 нових ключів i18n в усіх 16 локалей. Тести: tests/memory-routes.test.mjs.

[1.92.0] — 2026-07-04

CV Studio (Epic 21). Нова сторінка #/cv-studio дає вашому резюме три чесні, здебільшого локальні інструменти:

  • Діагностика резюме — детермінована оцінка 0–100 із поясненнями за кожною перевіркою (кількісно виміряний вплив, слабкі дієслова, штампи, обсяг, ключові розділи, контактні дані). Повністю на боці клієнта (window.CvDiagnostics) — без LLM, нічого вигаданого, кожен висновок пояснено, тож ви вирішуєте, що змінювати.
  • Маска приватності — вилучення PII (email, телефон, посилання/нікнейми, поштова адреса й за бажанням ваше ім’я → ініціали) перед тим, як поділитися резюме як зразком чи скриншотом. Виконується цілком у браузері (window.CvPrivacy); повідомляє, що саме було вилучено, і ніколи не зберігає оригінал.
  • Make it human / збіг голосу — вставте суху фразу чи абзац і перепишіть її вашим голосом, обґрунтованим на боці сервера через voice-dna.md і writing-samples/. Жорсткий запобіжник: воно може переставляти, стискати й переголошувати, але ніколи не додає факту, метрики чи досягнення, якого ще немає в тексті. Виконується наживо через спільний каскад провайдерів або повертає готовий до копіювання промпт без ключа.

Нове: server/lib/routes/cv-studio.mjs (20-й модуль маршрутів — POST /api/cv-studio/humanize), public/js/views/cv-studio.js, public/js/lib/cv-diagnostics.js, public/js/lib/cv-privacy.js, PATHS.voiceDna + PATHS.writingSamplesDir. 29 нових ключів i18n в усіх 16 локалей. Тести: tests/cv-diagnostics.test.mjs, tests/cv-studio-routes.test.mjs. (Галерея шаблонів, експорт у Word та архів PDF-оголошень відстежуються як подальша робота над CV Studio.)

[1.91.0] — 2026-07-04

Нетворкінг і глибоке дослідження компаній (Epic 16). Нова сторінка #/networking перетворює компанію на дієвий план отримання співбесіди, обґрунтований вашим резюме, профілем і two-pager:

  • Досьє компанії — стислий бриф про те, чим займається компанія, нещодавні сигнали, варті згадування, і зачіпки «чому я підходжу», взяті з вашого реального досвіду.
  • З ким зв’язатися — 3–5 цільових персон (наймальний менеджер, внутрішній рекрутер, старший IC з команди, теплий контакт/випускник того самого вишу) з конкретним пошуковим рядком LinkedIn для пошуку кожного. Реальні імена ніколи не вигадуються.
  • Найтепліший шлях для представлення — найреалістичніший теплий вхід саме для вашого досвіду (спільний роботодавець/навчальний заклад/спільнота, шлях другого рівня або сильний за сигналом холодний DM) і чому.
  • Чернетки для контакту — короткі, конкретні повідомлення для головних персон, обґрунтовані вашими реальними точками доказу.
  • Наживо або вручну — виконується наживо через спільний каскад провайдерів із будь-яким ключем або повертає готовий до копіювання промпт (чесний fallback, нічого вигаданого). Зберегти план зберігає готовий план у користувацький шар (networking/net-{company}-{role}-{date}.md); сторінка показує список, відкриває й видаляє збережені плани.

Нове: server/lib/routes/networking.mjs (19-й модуль маршрутів), public/js/views/networking.js, PATHS.networkingDir. Повторно використовує каскад server/lib/llm-dispatch.mjs з v1.90.0. 24 нові ключі i18n в усіх 16 локалей. Тести: tests/networking-routes.test.mjs.

[1.90.0] — 2026-07-04

Mock Interview 2.0 (Epic 15). Нова сторінка #/mock-interview перетворює ваше резюме, профіль, two-pager і банк історій на покрокову репетицію співбесіди:

  • Діалогова практика — задайте цільову роль (+ за бажанням компанію / JD), і інтерв’юер починає з точкового запитання. На кожну надіслану відповідь ви отримуєте структуровану репліку: Feedback (сильні сторони + прогалина за STAR+R), Score (N/5) та Next question, яке промацує найслабше місце вашої останньої відповіді. Обґрунтовано на боці сервера вашими реальними матеріалами — воно ніколи не вигадує досвід, якого у вас немає.
  • Враховує банк історійinterview-prep/story-bank.md вбудовується в промпт (той самий рівень довіри, що й cv.md), тож зворотний зв’язок може вказати вам на ваші ж найкращі історії.
  • Наживо або вручну — за наявності ключа провайдера хід виконується наживо через спільний каскад провайдерів (Anthropic → Gemini → OpenAI → Qwen → OpenRouter → GitHub Models); без ключа ви отримуєте готовий до запуску промпт для копіювання та вставлення (чесний fallback, без вигаданих відповідей).
  • Збережені сесії — натисніть Save transcript, щоб зберегти завершену співбесіду в шар користувача (interview-prep/mock-{company}-{role}-{date}.md); сторінка показує список, відкриває та видаляє збережені сесії.

Нове: server/lib/routes/interview.mjs (18-й модуль маршрутів), public/js/views/mock-interview.js, server/lib/llm-dispatch.mjs (спільний каскад провайдерів), PATHS.storyBank, bundleProjectContext({ extraFiles }). 30 нових ключів i18n в усіх 16 локалей. Тести: tests/interview-routes.test.mjs.

[1.89.0] — 2026-07-04

Відповідність кандидата й ринку — two-pager (Epic 14). Нова сторінка #/two-pager дозволяє зафіксувати те, чого ви насправді хочете від наступної ролі, за зразком «Mnookin two-pager» із книги Never Search Alone:

  • Покроковий конструктор — оповідь від першої особи «Хто я», нотатка «Цільове середовище» та п’ять редакторів списків-чипів: loves, must-haves, hates, deal-breakers і non-negotiables. Зберігається в користувацький шар батьківського проєкту (config/two-pager.yml) через PUT /api/two-pager — ніколи не перезаписується системними оновленнями.
  • ШІ-помічник заповнення (POST /api/two-pager/draft) — збирає готовий до запуску Mnookin-промпт із вбудованими вашими CV + профілем, щоб ви запустили його в будь-якому LLM і вставили результат назад. Він використовує лише ваші власні матеріали; нічого не вигадується.
  • Бейдж відповідності-тому-що-ви-хочете — кожна вакансія на #/scan тепер показує оцінку відповідності ◎ N (на боці клієнта, через window.FitScore), що зіставляє формат роботи, країну, мінімальну зарплату та релокацію вакансії з вашим two-pager. Чесний за задумом: якщо вакансія не дає зіставного сигналу, бейдж не показується (ніколи не вигадане число). Порушення deal-breakers важать більше, ніж легкі неприязні.
  • Живить кожну оцінку — збережений two-pager вбудовується в bundleProjectContext, тож усі подальші оцінки LLM поєднують заявлені вами вподобання з відповідністю CV-проти-JD.

Нове: server/lib/routes/two-pager.mjs, public/js/views/two-pager.js, public/js/lib/fit-score.js, PATHS.twoPager. 27 нових ключів i18n в усіх 16 локалях. Тести: tests/two-pager-routes.test.mjs, tests/fit-score.test.mjs.

[1.88.0] — 2026-07-04

Доопрацювання issue #29 — прогалини i18n у Скануванні + гігієна API.

  • Локалізовано останні захардкоджені рядки Сканування (дорожня карта v1.69.4): плашки зведення за джерелом (N нових / M збігів), тости N нових вакансій та бейдж reloc тепер проходять через t() — 4 нові ключі (scan.pillNew, scan.pillMatching, scan.newOffers, scan.relocBadge) в усіх 16 локалях. Неангломовні користувачі більше не бачать випадкової англійської в основному потоці сканування.
  • Вимкнено заголовок X-Powered-By (дорожня карта v1.69.5): app.disable('x-powered-by') у createApp() — сервер більше не повідомляє, що працює на Express. (Решту цього епіку вже було випущено: parentVersion вирізає свій коментар release-please, перемикач світлої теми, закриття модальних вікон під час зміни маршруту та локалізація «Score» (rep.score) у Звітах.)

Тести: tests/scan-i18n-gaps.test.mjs + перевірка відсутності X-Powered-By у tests/security-headers.test.mjs.

[1.87.0] — 2026-07-04

4 нові провайдери сканування без автентифікації (паритет із батьківським career-ops v1.16.0). Реєстр сканера зростає з 41 → 45 адаптерів (40 EN + 5 RU) — усі публічні, без автентифікації, із закріпленим хостом, redirect:'error' (захист від SSRF), кожен з ізольованим для CI тестом:

  • Get on Board (getonbrd) — публічний JSON:API по всьому порталу (LATAM/віддалені технічні ролі), обирається за провайдером, із пагінацією. server/lib/sources/getonbrd.mjs.
  • Amazon (amazon) — публічний JSON пошуку amazon.jobs, визначається за хостом або provider: amazon, пагінація за зміщенням. server/lib/sources/amazon.mjs.
  • Avature (avature) — ATS *.avature.net для кожного орендаря, парсинг HTML, визначається за хостом або provider: avature. server/lib/sources/avature.mjs.
  • SAP SuccessFactors (successfactors) — список плиток RMK для кожного орендаря (*.successfactors.eu/.com, jobs2web.com), парсинг HTML. server/lib/sources/successfactors.mjs.

Кожен постачає sources/<slug>.mjs (автовиявлюваний meta → випадний список #/scan) та portals/adapters/<slug>.mjs у ALL_ADAPTERS (правило двох реєстрів) + tests/sources-<slug>.test.mjs. Лічильник ALL_ADAPTERS, а також перевірки відсортованих id та EN-набору /api/scan/sources зросли з 36→40; GET /api/scan/sources тепер перелічує 45.

[1.86.0] — 2026-07-03

Статистика за цільовими ролями (#/stats) — ринкова статистика вакансій і зарплат за ВАШИМИ цільовими ролями. Нова сторінка Аналітики читає ваші цільові ролі з профілю (config/profile.yml → не захардкоджені) та вакансії з останнього сканування, а потім показує для кожної ролі й країни:

  • Вакансії за країнами та медіанну зарплату за країнами (USD) — агрегуються на боці клієнта (public/js/lib/role-stats.js, повторно використовуючи window.Countries) з розріджених даних, які сканери вже збирають. Зарплати в будь-якій валюті нормалізуються до USD через явно приблизну таблицю FX, із застереженням щодо розміру вибірки — ніколи не вигадуються.
  • Фільтри ролі та країни й саморобні вбудовані SVG-графіки: стовпчикові та трендові (без нових залежностей, безпечно для CSP — лише addEventListener).
  • Зберегти знімок (POST /api/stats/snapshot) зберігає поточний агрегат у data/role-stats.jsonl; графік тренду (GET /api/stats/trend) відстежує кількість вакансій у часі — подання «динаміки». Чесний гібрид: знімки формуються з локальних даних сканування й оновлюються за запитом.
  • Повністю локалізовано в усіх 16 локалях (26 нових ключів i18n).

Нове: server/lib/routes/stats.mjs (16-й модуль маршрутів), public/js/lib/role-stats.js, public/js/views/stats.js, PATHS.roleStats; тести role-stats.test.mjs (7) + stats-routes.test.mjs (5).

[1.85.0] — 2026-07-03

Локалі німецької, італійської та турецької (паритет локалей із батьківським career-ops v1.16.0). Інтерфейс тепер постачається 16 мовамиde 🇩🇪, it 🇮🇹 і tr 🇹🇷 додаються до наявних 13.

  • Повний переклад інтерфейсу — усі 730 ключів i18n перекладено в public/js/lib/locales/i18n-dict.{de,it,tr}.js; перемикач мов показує Deutsch / Italiano / Türkçe, а автовизначення мови браузера розпізнає de/it/tr (public/js/lib/i18n.js).
  • Вбудований довідковий посібникdocs/help/{de,it,tr}.md перекладено (повна структура з 19 H2 / 75 H3), надаються через GET /api/help/:lang.
  • Документація — додано README.{de,it,tr}.md і CHANGELOG.{de,it,tr}.md; перевірка паритету локалей CHANGELOG тепер охоплює 15 не-EN локалей.
  • Каркас промптівserver/lib/prompts.mjs (LOCALE_NAMES + SCAFFOLD_STRINGS) локалізовано для трьох нових локалей, тож вивід LLM дотримується мови інтерфейсу.

Усі перевірки паритету (i18n-locale-files, i18n-coverage, check-changelog-parity, lang-switcher-rtl) розширено на набір із 16 локалей.

[1.84.0] — 2026-06-30

Кулдаун повторних заявок + компенсація в pipeline.md (паритет із батьківським career-ops v1.15.0). Два покращення сканера:

  • Кулдаун повторних заявок (#1201): EN-скан тепер пропускає ролі в компаніях, до яких ви нещодавно вже подавали заявку, — результати лишаються зосередженими на НОВИХ вакансіях. Налаштуйте часові вікна на рівні компанії в config/profile.yml у секції re_apply_windows: (last_apply_date, same_role_days, applied_to: [roles], необов’язковий cross_role_bucket); порівняння компаній нечутливе до пунктуації й працює за межами слів (server/lib/cooldown.mjs). Не діє, якщо ключ відсутній; до журналу сканування виводиться Cooldown skipped: N.
  • Компенсація в pipeline.md (#1017): знайдені під час сканування вакансії тепер зберігають зарплату у вигляді необов’язкового кінцевого стовпця (url | <salary>) у data/pipeline.md. URL залишається ключем дедуплікації (стовпець | comp прибирається під час читання), значення комірки санується (без ін’єкції рядка/стовпця, формульний префікс нейтралізується), а pipeline у форматі «лише URL» зберігає зворотну сумісність.

Постачається з tests/cooldown.test.mjs і тестами компенсації для pipeline. Кількість джерел не змінилась — 41 (обидва покращення стосуються логіки сканування, а не нових дошок).

[1.83.0] — 2026-06-30

Детектор повторних публікацій / фантомних вакансій (паритет із батьківським career-ops v1.15.0). На сторінці #/scan з’явилася панель 🔁 Повторні публікації / фантомні вакансії, яка позначає кластери «компанія + посада», повторно розміщені під різними URL у ковзному 90-денному вікні — сигнал застарілих конвеєрів і фантомних оголошень. Базується на нечіткому порівнянні заголовків (server/lib/role-matcher.mjs) та read-only детекторі (server/lib/detect-reposts.mjs) по data/scan-history.tsv, надається через GET /api/scan/reposts. Також: parentVersion у /api/health тепер повертає лише semver (коментар # x-release-please-version від release-please прибирається). Постачається з tests/detect-reposts.test.mjs. Кількість джерел не змінилась — 41: повторні публікації — аналітична функція, а не нова дошка.

[1.82.0] — 2026-06-30

Джерело сканування NoDesk (паритет із батьківським career-ops v1.15.0). Загальнодошкова RSS-стрічка віддаленої роботи NoDesk тепер повноцінне джерело — додайте запис provider: nodesk, і воно з’явиться у списку Source на #/scan (загалом 41 адаптер: 36 EN + 5 RU). Хост закріплено за nodesk.co із redirect:'error' (захист від SSRF); заголовки діляться за Role at Company (NoDesk не має тегу локації, поле місцеположення залишається порожнім); усі вакансії — віддалені. Постачається з CI-ізольованим набором тестів tests/sources-nodesk.test.mjs; повний набір юніт-тестів зелений, 1523.

[1.81.0] — 2026-06-29

Паритет із батьківським career-ops — 13 нових джерел сканування вакансій. Переносить останній пакет провайдерів із main Fighter90/career-ops у вбудований сканер. Загальнодоступні API дошок (вибір за provider:): Arbeitnow, Himalayas, Jobicy, Landing.jobs, 4 Day Week, The Muse, The Hub, Jobspresso (RSS) і Hacker News “Who is hiring?” (Algolia, два кроки). Польські дошки (визначаються за хостом або provider:): JustJoin.it і NoFluffJobs (POST-пошук). Per-tenant ATS (автовизначення за careers_url): Pinpoint (<slug>.pinpointhq.com/postings.json) і Rippling (ats.rippling.com/<slug>api.rippling.com board). Кожне джерело закріплено за хостом із redirect:'error' (захист від SSRF) і доступне у списку Source на #/scan — реєстр тепер налічує 40 адаптерів сканера (35 EN + 5 RU). Додано 13 CI-ізольованих наборів тестів на джерело; повний набір юніт-тестів зелений, 1513.

[1.80.0] — 2026-06-28

П’ять покращень сканера (ідеї з job-crawler, переписані). (1) Джерело Teamtailor — сайти <slug>.teamtailor.com через публічну стрічку /jobs.rss, автовизначення за careers_url (хост закріплено + redirect:'error'); у реєстрі тепер 27 адаптерів. (2) Карантин джерел — джерело зі сталим 404/410 записується в data/scan-quarantine.json і пропускається в наступних сканах (самовідновлення: повтор через 14 днів). (3) Макс. на джерело — необов’язкове поле на #/scan, що обмежує кількість вакансій з борду (∞ за замовчуванням). (4) Опубліковано за — клієнтський фільтр за віком (24г / 7д / 30д). (5) Збережені пошуки + ★ обране — називайте й повторно використовуйте набори фільтрів і позначайте вакансії, у localStorage із захисною валідацією (пошкоджений кеш скидається чисто); кеш результатів скидається перед скануванням і наповнюється наживо.

[1.79.0] — 2026-06-28

Джерело сканування WeWorkRemotely (паритет із career-ops v1.14.0). Загальнодошкова RSS-стрічка віддаленої роботи We Work Remotely тепер повноцінне джерело — додайте запис provider: weworkremotely, і воно з’явиться у списку Source на #/scan (26 адаптерів загалом). Хост закріплено за weworkremotely.com із redirect:'error' (захист від SSRF); заголовки діляться за Company: Role. Також: ключові слова title_filter тепер обрізаються перед перевіркою довжини (parent #1261).

[1.78.2] — 2026-06-27

Зміцнення i18n та UX (виправлення після v1.78.1). Доступна назва логотипа тепер локалізована всіма 13 мовами (nav.logoHome). Enter у глобальному пошуку, коли ви вже на #/scan, примусово ре-рендерить, щоб не втратити введений термін (guard тієї ж маршрутизації). health.title тепер перекладено польською (Kondycja) та данською (Systemtilstand) — раніше англійською. Тести 1235 → 1238.

[1.78.1] — 2026-06-27

Виправлення UX на Scan. Таблиця результатів #/scan тепер автоматично оновлюється під час сканування та ще раз після завершення — без перезавантаження. Глобальний пошук у шапці показує підказку Enter і за не-URL-запитом переходить на #/scan із заповненим полем (раніше #/tracker). Логотип тепер веде на дашборд (головну).

[1.78.0] — 2026-06-27

Гео-фільтр на сторінці Scan — фільтр вакансій за країною, з прапорцями. Новий список Країна у #/scan показує кожну країну, виявлену в результатах (емодзі-прапор + лічильник), щоб лишити лише ролі, прив’язані до країни — поряд із фільтром Remote/Hybrid/Onsite, тож можна шукати як прив’язану до країни, так і віддалену роботу. На основі нового помічника countries.js, що зіставляє вільний текст локації (назви країн, аліаси та ~100 великих міст) з країною ISO + прапором; детекція консервативна й ніколи не вгадує.

[1.77.0] — 2026-06-27

Додано данську (Dansk) — 13-ту мову інтерфейсу. Повний переклад UI, вбудованого довідника Help (19 H2 / 75 H3), README та CHANGELOG. Данська додана до перемикача мов із прапорцями; механіка i18n (асемблер, аудит, перевірки паритету, знімок) тепер охоплює 13 локалей.

[1.76.0] — 2026-06-26

Паритет із career-ops v1.13.0 — шість нових джерел, зміцнення сканера та таблиця результатів без ліміту.

Додано

  • Шість ATS-джерел на тенант — BambooHR, Breezy HR, Comeet, Personio, Recruitee, SolidJobs. Визначаються за хостом careers_url (Comeet потребує повного api:); кожен хост закріплено якірним regex + redirect:'error' (захист від SSRF). Доступні у списку Source на #/scan — реєстр тепер має 25 адаптерів (20 EN + 5 RU). Додано помічник fetchText для XML-стрічки Personio.
  • trust_filter — необов’язкова оцінка довіри (0–100, рівень high/medium/low, прапорці), лише анотує. Рядки нижче high отримують нейтральний значок ⚠ на #/scan; нічого не відкидається.
  • Arbeitsagentur remoteMatch + remoteMaxPages — визначення віддаленої роботи з конфігу: title, filter (homeoffice=nv_true на сервері + пагінація) або off.

Змінено

  • Немає ліміту результатів. MAX_STORED_RESULTS (2000) прибрано — зберігаються всі збіги, таблиця #/scan гортає їх (200/стор.).
  • Надійність фільтра заголовків — короткі абревіатури (COO, SDR…) збігаються за межами слів; некоректний title_filter більше не ламає скан. Обидва сканери.

Тести

  • +32 кейси (1190 → 1222): sources-ats-providers, title-filter, arbeitsagentur-remote, trust-validator і переписаний страж scan-result-cap («без ліміту»).

[1.75.2] — 2026-06-19

docs: повний паритет документації для агрегаторів сканера з v1.75.0 в усіх 12 локалях. Без зміни коду — приводить документацію для користувача у відповідність до семи джерел, що з’явилися в v1.75.0:

  • Довідковий посібник (12 локалей). §5 отримує блок content_filter (гейтинг за ключовими словами опису/сніпета, аналог location_filter) та примітку про агрегатори; §7 перелічує сім нових джерел у проході сканування в один клік та в повному переліку випадного списку Source; лічильник адаптерів у §17 виправлено зі застарілого «11 adapters» на «19 adapters — 14 English + 5 Russian». Заголовків ##/### не додавалося, тож закріплена структура 19 H2 / 75 H3 залишається незмінною.
  • README (9 повних локалей). Новий пункт «Aggregator boards (v1.75.0)» під джерелами сканування, плюс значок релізу, оновлений до v1.75.2. (Скорочені README pl/uk/ar не мають списку за джерелами, і там вони навмисно не зачеплені.)
  • Довідкові документи. docs/portals-examples.md отримує готовий до копіювання розділ «Aggregator boards» з точними блоками конфігурації provider: / <provider>: для всіх семи; docs/PROJECT.md оновлено до 19 adapters; docs/sdd/CONVENTIONS.md документує розрізнення двох реєстрів (sources/registry.mjs для випадного списку проти portals/registry.mjs для вибірки), вибір агрегатора на основі provider:, що передається як opts.company, санітайзер запису сканування (scan-sanitize.mjs) та кількість тестів v1.75.1 (1190).
  • QA. Додано qa/QA-REGRESSION-PROMPT-v1.75.2-FULL.md — драйвер релізного шлюзу за повною поверхнею, оновлений під цикл агрегаторів сканування v1.75.x.

[1.75.1] — 2026-06-19

fix(scan): доопрацювання надійності джерел на основі конфігурації з v1.75.0. Три невеликі зміцнювальні виправлення за підсумками післярелізного розбору (без зміни поведінки за штатного сканування):

  • Паузи пагінації з урахуванням скасування. Міжсторінкові ввічливі паузи Glints (300 мс) та Jobstreet/SEEK (200 мс) тепер негайно завершуються, коли спрацьовує AbortSignal сканування — через новий помічник delay(ms, signal) у server/lib/http-json.mjs, тож від’єднаний клієнт не може утримувати пагіноване сканування відкритим ще на одну паузу.
  • Описова помилка для не-JSON відповіді. fetchJson тепер загортає не-JSON тіло з кодом 2xx (наприклад, HTML-сторінку обслуговування, віддану зі статусом 200) як non-JSON 2xx response from <url>, замість того щоб видавати голий SyntaxError, тож журнал помилок сканера за кожним джерелом називає некоректно поводжуваний ендпоінт.
  • Посилена нормалізація запису сканування. normalizeScanScalar тепер згортає вертикальну табуляцію, переведення сторінки та розділювачі рядка/абзацу Unicode (\v \f U+2028 U+2029) на додачу до \r \n \t — суворий надмножина, тож жоден розділювач запису/рядка, який могли б врахувати таблиця чи переглядач, не потрапляє до scan-history.tsv.

[1.75.0] — 2026-06-19

feat(scan): переносить паритет з батьківським career-ops v1.12.0 — сім нових джерел вакансій, фільтрація контенту та виправлення безпеки/якості. web-ui запускає власні внутрішньопроцесні сканери (він не викликає shell out до батьківського scan.mjs), тож зміни провайдерів і сканування з батьківської v1.12.0 не надходять автоматично — цей реліз переносить застосовні з них згідно з контрактом адаптерів web-ui.

  • Сім нових джерел сканера. Три глобальні агрегатори віддалених вакансій — RemoteOK, Remotive, Working Nomads — вписуються в автоматично виявлюваний патерн server/lib/sources/*.mjs (обираються через provider: remoteok / remotive / workingnomads). Чотири керовані конфігурацією регіональні агрегатори — careers IBM, Arbeitsagentur (німецьке Федеральне агентство зайнятості), Glints (Південно-Східна Азія), Jobstreet / SEEK — читають поелементний конфігураційний блок <provider>:; en-scanner тепер прокидає розв’язаний запис компанії аж до кожного фетчера, щоб вони могли його прочитати. Усі сім автоматично з’являються у випадному списку джерел #/scan.
  • content_filter (батьківський #974). Необов’язковий блок portals.yml (списки ключових слів positive / negative), що фільтрує вакансію за текстом її опису/сніпета — повторює семантику location_filter; вакансії без опису завжди проходять. Підключений до обох сканерів — EN і RU.
  • Посилення запису під час сканування (батьківський #1098). Метадані зовнішніх стрічок тепер санітизуються перед потраплянням у data/scan-history.tsv та data/pipeline.md: керівні символи згортаються (перенесення рядка в назві компанії/посади більше не може ін’єктувати рядок TSV), а провідні = + - @ нейтралізуються проти ін’єкції формул електронних таблиць.
  • secondaryLocations Ashby (батьківський #1073). Джерело Ashby тепер згортає мітку регіону кожної вторинної локації разом із поштовими addressLocality / addressCountry у рядок локації (з дедуплікацією), тож роль із правом працювати в ЄС, чия основна мітка читається, наприклад, як “Canada”, спливає для location_filter.
  • Валідація форми звіту про оцінку (батьківський #819). Внутрішньопроцесні провайдери /api/evaluate (Anthropic / OpenAI / Qwen / OpenRouter / GitHub Models) тепер позначають некоректний звіт A–G / SCORE_SUMMARY як нефатальний масив warnings; шлях оцінки Gemini вже успадковує цей захист від батьківського gemini-eval.mjs.
  • docs: Antigravity CLI додано до списків підтримуваних асистентів у всіх 12 README (зіставляється з провайдером Gemini).

Успадковано безкоштовно з git pull батьківського проєкту (web-ui викликає їх через shell out): резервні шрифти CJK для японського PDF (#1053), ATS-сумісні шрифти PDF (#1074), захист CJK для LaTeX (#1054), виправлення tracker/merge/followup/dashboard і китайські режими modes/zh (web-ui перелічує режими динамічно).


[1.74.3] — 2026-06-18

docs(parent-source): спрямовує батьківський репозиторій career-ops на форк Fighter90/career-ops. web-ui тепер посилається на форк супровідника як на батьківський проєкт усюди, де це реальне джерело: типове значення CAREER_OPS_REPO в інсталяторі bin/setup.sh, кожне посилання git clone / «побудовано на основі» / онбординг у всіх 12 README, а також документація агентів (CLAUDE.md, AGENTS.md, GEMINI.md, .github/copilot-instructions.md, docs/). Зазначення авторства santifer (та застереження про неофіційний інтерфейс) не змінилося — перемістилися лише URL джерела/клонування. tests/sh-files.test.mjs тепер перевіряє, що інсталятор клонує форк.


[1.74.2] — 2026-06-17

fix(health): відображення GITHUB_MODELS_API_KEY як необов’язкової перевірки на #/health та в /api/status/providers. Провайдер GitHub Models із v1.74.0 налаштовувався в #/config, але не мав рядка на сторінці Health і був відсутній у провайдерській поверхні keysConfigured. Додано необов’язкову перевірку (з тим самим формулюванням “set / unset (manual mode)”, що й у решти п’яти провайдерів живого оцінювання) та github (+ його GITHUB_MODELS_MODEL) до /api/status/providers, тож маршрутизація активного провайдера й сторінка Health тепер відображають усі шість. Тест рядка health у tests/api.test.mjs розширено на всі шість провайдерів.


[1.74.1] — 2026-06-17

docs + test: розділ README «Встановлення ШІ-асистента»; повне покриття гілок для конектора Gemini. До README додано таблицю встановлення/входу — посилання для встановлення Claude Code / Gemini CLI / Codex / Qwen Code / OpenCode / GitHub Copilot CLI + відповідність постачальника #/config для кожного + «увійдіть перед продовженням» (відповідає розділу швидкого старту career-ops.org/docs; пояснює, що web-ui є автономною альтернативою, яка не потребує CLI). Новий tests/gemini-connector.test.mjs (8 сценаріїв) охоплює кожну гілку runGemini — без ключа, успіх, помилка API, порожнє/заблоковане завершення, некоректне тіло відповіді, тайм-аут, мережева помилка, hasGeminiKey — доводячи server/lib/gemini.mjs до 100% за інструкціями. Загальне покриття: 96% рядків / 88% гілок / 96% функцій. Набір тестів 1126 → 1134.


[1.74.0] — 2026-06-17

feat(llm): GitHub Models (Copilot) як 6-й провайдер + канонічне вирівнювання 6 асистентів. career-ops.org/docs перераховує шість ІІ-асистентів для написання коду — Claude Code, Gemini CLI, Codex, Qwen Code, OpenCode, GitHub Copilot CLI. Тепер web-ui підтримує всі шість: п’ять відповідають наявним активним провайдерам (Anthropic / Gemini / OpenAI / Qwen / OpenRouter), а GitHub Copilot CLI отримує виділений конектор GitHub Models — runGitHubModels (OpenAI-compatible; PAT GitHub з областю models), що налаштовується в #/config (GITHUB_MODELS_API_KEY + GITHUB_MODELS_MODEL) і вибирається через LLM_PROVIDER=github; 6-й у порядку auto. Пакети довідки та README тепер перераховують канонічні шість (перейменовано Qwen CLI→Qwen Code; додано Gemini CLI + GitHub Copilot CLI), а README додає повну таблицю посилань на режими та адаптери порталів на career-ops.org/docs, щоб кожна функція відстежувалась до батьківського проекту. tests/llm-provider-context.test.mjs розширює матрицю меж отримання до всіх шести провайдерів (cv.md + profile.yml вбудовані + повернутий артефакт); нові ключі GITHUB_MODELS_* додані до всіх 12 словників локалей. Набір тестів 1125 → 1126.


[1.73.0] — 2026-06-17

feat(llm): універсальний конектор Gemini + верифікований контекст CV/профілю для всіх провайдерів. Додано server/lib/gemini.mjs (runGemini) — клієнт Gemini generateContent без зовнішніх залежностей, що повертає ту саму форму {markdown, usage, error}, що й клієнти, сумісні з Anthropic / OpenAI. Виправлення: /api/mode/:slug і /api/deep раніше спрямовували промпти через gemini-eval.mjs, призначений виключно для оцінювання вакансій, через що Gemini Run live повертав оцінку замість запитаного артефакту (супровідний лист, аутрич, бриф). Тепер вони викликають runGemini з bundleProjectContext, тому cv.md + config/profile.yml вбудовуються інлайн для Gemini так само, як і для всіх інших провайдерів — листи та брифи є детальними й персоналізованими. Новий tests/llm-provider-context.test.mjs імітує HTTP-межу кожного провайдера та перевіряє, що всі п’ять (Anthropic / Gemini / OpenAI / Qwen / OpenRouter) вбудовують cv.md + profile.yml інлайн і повертають артефакт (матриця mode + deep + evaluate, 9 випадків). /api/evaluate зберігає свій gemini-eval.mjs, налаштований під вакансії. Suite 1116 → 1125.


[1.72.0] — 2026-06-17

feat(modes): Run live тепер повертає підсумковий артефакт безпосередньо (контракт виведення за один запит). Батьківські шаблони modes/<slug>.md написані для інтерактивних сесій Claude Code — деякі з них (cover, contacto та інші) роблять паузу, щоб задати уточнювальні запитання перед формуванням результату, через що Run live у вебінтерфейсі видавав анкету замість артефакту. buildModePrompt тепер огортає кожен режим у неінтерактивний контракт виведення: виконує аналіз (розбір вакансії, нотатки про компанію, ключові слова ATS, розбіжності профілю↔вакансії, вибір тону/подачі) у фоновому режимі, обирає розумні значення за замовчуванням із cv.md / config/profile.yml для всього, про що шаблон зазвичай питав, і виводить лише підсумковий артефакт — із завершальним нагадуванням для кожного режиму «output ONLY {the cover letter / outreach message / …}». Тепер клік на Run live у #/cover повертає саме супровідний лист; те саме виправлення застосовується до всіх загальних режимів (cover, contacto, interview-prep, project, training, followup, patterns) у всіх 12 локалях (артефакт створюється мовою інтерфейсу через директиву локалі). Suite 1103 → 1116.


[1.71.2] — 2026-06-17

docs(i18n): публікує прохід з узгодженості документації. Блок “Translations of this guide” у кожному README тепер містить усі 11 мов-«сестер» (раніше деякі пропускали English/Français або мали посилання на самих себе), а порожній рядок перед роздільником розділу відновлено. Повний QA-запит регресійного тестування перейменовано на поточну версію, а документацію (CLAUDE.md, CONVENTIONS, LOCALIZATION, PROJECT-CONTEXT) синхронізовано з поточною версією та кількістю тестів (1103). Жодних змін у коді чи поведінці — лише документація, тому переклади довідки/UI та всі функції версій 1.70.0–1.71.1 залишаються без змін.


[1.71.1] — 2026-06-17

fix(i18n): вбудований посібник із довідки тепер повністю перекладено всіма 12 мовами. Додано docs/help/{pl,uk,ar}.md (кожен містить перевірену структуру 19 H2 / 75 H3), завдяки чому #/help надає нативний пакет польською, українською та арабською мовами замість переходу на англійську — GET /api/help/{pl,uk,ar} тепер повертають власну локаль. Підключено до всіх перевірок довідки (help-ui, help.test, help-ru-config-section, canonical-docs-coverage). Також завершено всі списки перекладів на 12 мов: блок «Translations of this guide» у README (9 файлів README), заголовки «Translations:» у локалізованих CHANGELOG (8 файлів) та оновлено застарілі лічильники документації. Suite 1100 → 1103.


[1.71.0] — 2026-06-16

feat(cover): генерація PDF супровідного листа безпосередньо з #/cover. Режим cover (доданий у v1.70.0) формує текст листа; тепер у результаті з’являється кнопка Generate PDF, яка рендерить його через спільний вбудований конвеєр markdown→PDF (POST /api/stream/pdf/inlinegenerate-pdf.mjs) — той самий шлях, що використовує interview-prep. Тепер можна створити лист і надіслати PDF, не залишаючи SPA.

test/docs: посилення перевірки v1.70.0. Додано CI-ізольоване покриття для режиму cover (список дозволів + збірка промпту), перемикача <select> прапорів + арабського RTL (dirFor/<html dir>), top.langLabel у кожній локалі, підключення PDF супровідного листа, а також директиви локалі prompts.mjs + скаффолдингу для fr/pl/uk/ar. Оновлено застарілі посилання «всі 8» → 12 локалей у docs/sdd/CONVENTIONS.md і в промпті регресійного QA всього проєкту.


[1.70.0] — 2026-06-16

feat(i18n): три нові мови інтерфейсу — польська (pl), українська (uk) та арабська (ar, з повною підтримкою RTL) — розширюють SPA до 12 локалей, що відповідає всім мовам README батьківського проекту career-ops. Кожна нова локаль постачається з повним словником із 697 ключів (public/js/lib/locales/i18n-dict.{pl,uk,ar}.js), перевіреним наявними наборами тестів паритету / покриття / відсутності витоків латиниці / відсутності персональних даних. Арабська додає справжню підтримку письма справа наліво: i18n.js встановлює <html dir="rtl"> для RTL-локалей, а блок [dir="rtl"] в app.css відображає хром (бічна панель, ящик сповіщень, таблиці та блок-цитати markdown, вбудовані відступи) — LTR-локалі залишаються незмінними побайтово. Новий ключ top.langLabel (×12) іменує перемикач для програм читання з екрана.

feat(ui): випадаючий список <select> із піктограмами прапорів замінює ряд кнопок, що переносилися. При 12 локалях старий ряд .lang-btn переносився на три рядки в бічній панелі; нативний <select> (кожен пункт з префіксом у вигляді емодзі прапора) масштабується акуратно, підтримує клавіатуру та програми читання з екрана без додаткових налаштувань, а також є безпечним для CSP (обробник зміни через addEventListener, без вбудованого JS). Там, де платформа не має гліфів прапорів, вони замінюються літерами регіону, тому мовна мітка завжди є основним ідентифікатором.

feat(cover): перенесення режиму супровідного листа з батьківського проекту (career-ops v1.10.0 + вітання v1.11.0) до SPA. Нова сторінка #/cover у групі навігації «Заявки», побудована на базовому виконавці режимів: опис вакансії + компанія/роль + необов’язкове вітання → персоналізований лист, згенерований із cv.md / modes/_profile.md. Додано cover до серверного MODE_ALLOWLIST та блок i18n cover.* (×12 локалей).

chore(compat): відстеження батьківського career-ops v1.11.0. Підтверджено, що контракт читання/запису залишається чинним — data/applications.md й надалі є джерелом істини у форматі markdown (SQLite-індекс трекера у v1.11.0 є похідним кешем), стовпці трекера й надалі зіставляються за заголовком. parentVersion тепер повідомляє 1.11.0.

fix(i18n): усунення прихованої прогалини, де французька мова (додана у v1.61.0) була відсутня в LOCALE_NAMES та SCAFFOLD_STRINGS у server/lib/prompts.mjs — LLM-виклики французькою мовою мовчки переходили на англійський вивід та англійські шаблони. fr/pl/uk/ar тепер усі підключені до шляху локалі підказок.

Відомі подальші дії: вбудований довідковий посібник (docs/help/) повертається до англійської для pl/uk/ar (сам UI-хром повністю локалізований); інтерактивне введення для співбесід батьківського проекту, зворотне виявлення ATS та новіші постачальники сканування ще не представлені в SPA.