Журнал змін

GitHub

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

[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.mjs — GET /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.mjs — GET /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.mjs — GET /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.mjs — POST /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/inline → generate-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 всього проєкту.



career-ops-ui v1.267.1 · page 7/12 · mirror of the project changelog for cvstart.org