JSON Feed Validator

Check whether your feed is valid. For more information about JSON Feed, see the specification. Find the validator source code on GitHub.

GET validation response in JSON format.

Feed source

{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Engineer — Портфоліо та нотатки",
  "home_page_url": "https://engineer.company/uk/",
  "feed_url": "https://engineer.company/uk/feed.json",
  "description": "Engineer ApS — розробка програмного забезпечення та IT-консалтинг у Копенгагені, Данія. Портфоліо підтверджених інженерних досягнень у даних, хмарі та IT.",
  "language": "uk",
  "icon": "https://engineer.company/assets/images/brand/card.webp",
  "favicon": "https://engineer.company/assets/icons/apple/apple-touch-icon.png",
  "authors": [
    {
      "name": "Engineer ApS",
      "url": "https://engineer.company/uk/"
    }
  ],
  "items": [
    {
      "id": "https://engineer.company/uk/portfolio/improved-geographical-map-application-performance-by-10x-through-6/",
      "url": "https://engineer.company/uk/portfolio/improved-geographical-map-application-performance-by-10x-through-6/",
      "title": "Підвищила продуктивність застосунку географічних карт у 10 разів завдяки стратегічному переходу бази даних з MSSQL на PostgreSQL, включно з data cutover, оптимізувавши обробку та безпеку даних.",
      "summary": "Досягнуто підвищення продуктивності просторових запитів у 10 разів, скоротивши середній час відповіді з 2,5 секунди до менш ніж 250 мілісекунд.",
      "content_html": "<p><strong>Ситуація.</strong> Географічний картографічний застосунок організації, що підтримував просторові запити в реальному часі для багатьох користувачів, зазнавав серйозних проблем із продуктивністю. Затримки при рендерингу картографічних шарів і виконанні запитів до даних на основі місцезнаходження впливали як на користувацький досвід, так і на надійність бекенд‑сервісів. Система працювала на застарілій базі даних Microsoft SQL Server (MSSQL), яка не мала нативної геопросторової індексації.</p>\n<p><strong>Завдання.</strong> Підвищити продуктивність, масштабованість і безпеку картографічного застосунку, з конкретною метою скоротити затримку запитів і збільшити пропускну здатність для просторових операцій.</p>\n<p><strong>Дія.</strong> Здійснено стратегічну міграцію бази даних з MSSQL на PostgreSQL із розширенням PostGIS для забезпечення нативної підтримки геопросторових даних.</p>\n<ul>\n<li>Спроєктовано нову схему, оптимізовану для просторових даних, з упровадженням індексів GIST та SP‑GiST на стовпцях geometry та geography для пришвидшення запитів.</li>\n<li>Визначено суворі обмеження зовнішніх ключів і обмеження перевірки для забезпечення реляційної цілісності та застосування правил валідації даних для просторових координат.</li>\n<li>Мігровано понад 50 мільйонів просторових записів за допомогою ETL‑пайплайнів із кроками трансформації даних для відповідності новим стандартам SRID (EPSG:4326).</li>\n<li>Налаштовано параметри конфігурації PostgreSQL (наприклад, work_mem, effective_cache_size) для оптимальної продуктивності вводу‑виводу за умов паралельного доступу.</li>\n<li>Впроваджено рольове керування доступом (RBAC) та безпеку на рівні рядків для забезпечення політик захисту даних для кількох груп користувачів.</li>\n</ul>\n<p><strong>Результат.</strong> Досягнуто підвищення продуктивності просторових запитів у 10 разів, скоротивши середній час відповіді з 2,5 секунди до менш ніж 250 мілісекунд. Навантаження на CPU бекенду знизилося на 65%, а доступність системи покращилася в періоди пікового навантаження. Рівень безпеки також посилено завдяки деталізованим політикам доступу та обмеженням валідації даних, що зменшило ймовірність пошкодження просторових даних.</p>\n",
      "date_published": "2026-10-09T14:27:31+02:00",
      "date_modified": "2026-10-09T14:27:31+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Бази даних",
        "Безпека",
        "Інженерія даних",
        "Міграції та модернізація",
        "Оптимізація продуктивності",
        "Пайплайни даних (ETL/ELT)",
        "GIS та геопросторові рішення",
        "Міграція та модернізація баз даних",
        "Оптимізація продуктивності баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/established-a-technical-support-department-servicing-over-10-40/",
      "url": "https://engineer.company/uk/portfolio/established-a-technical-support-department-servicing-over-10-40/",
      "title": "Заснувала відділ технічної підтримки, що обслуговував понад 10 000 клієнтів, надаючи IT‑підтримку та вирішення несправностей, а звернення клієнтів обліковувалися в CRM‑системі.",
      "summary": "Зрештою відділ обслуговував понад 10 000 клієнтів, надаючи надійну підтримку та усуваючи несправності.",
      "content_html": "<p><strong>Ситуація.</strong> Клієнтська база зростала і потребувала надійної технічної підтримки, а окремої функції, здатної забезпечити її в реальному масштабі, просто не існувало. Підтримка надавалася безсистемно, що працює для жменьки клієнтів, але непомітно розвалюється зі зростанням їх кількості.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб створити повноцінну функцію технічної підтримки, здатну обслуговувати велику й таку, що продовжує зростати, клієнтську базу.</p>\n<p><strong>Дія.</strong> Відділ технічної підтримки було побудовано з нуля. Це означало спершу визначити, як він працюватиме, ще до найму людей, — процес приймання й вирішення звернень, інструментарій для роботи з великими обсягами, стандарт того, як виглядає якісна підтримка, — і лише потім нарощувати спроможність надавати ІТ‑підтримку та усувати несправності одразу для великої кількості клієнтів. Старт із нуля був, чесно кажучи, перевагою: відділ можна було спроєктувати під масштаб, до якого прямувала компанія, а не латати те, що виросло випадково.</p>\n<p><strong>Результат.</strong> Зрештою відділ обслуговував понад 10 000 клієнтів, надаючи надійну підтримку та усуваючи несправності. Підтримка перетворилася з реактивної дії на справжню сильну сторону компанії — те, що масштабувалося разом із клієнтською базою, а не прогиналося під її тиском.</p>\n",
      "date_published": "2026-10-09T14:27:31+02:00",
      "date_modified": "2026-10-09T14:27:31+02:00",
      "language": "uk",
      "tags": [
        "Керівництво командою",
        "Менторство та коучинг",
        "Продукт і вимоги",
        "Системне адміністрування",
        "Стейкхолдери та звітність",
        "Управління проєктами",
        "IT‑підтримка та helpdesk",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/delivered-analysis-and-regular-progress-reports-to-the-81/",
      "url": "https://engineer.company/uk/portfolio/delivered-analysis-and-regular-progress-reports-to-the-81/",
      "title": "Надавала аналітику та регулярні звіти про хід роботи CEO, перетворюючи інженерні KPI та статус постачання на рішення.",
      "summary": "У підсумку керівництво отримало чітку, чесну й актуальну картину інженерії та могло скеровувати продуктові пріоритети й інвестиції з певною впевненістю, а не…",
      "content_html": "<p><strong>Ситуація.</strong> У міру того як платформа складалася в ціле, її прогрес і стан мали бути видимими для керівництва в термінах, з якими воно справді могло щось зробити. Сирі інженерні сигнали — статус білдів, темп постачання, інциденти — самі по собі мало що означають для того, хто ухвалює продуктові та інвестиційні рішення: вони знаходяться не на тій висоті. Хтось мав перекладати це на іншу мову.</p>\n<p><strong>Завдання.</strong> Саме цей переклад і був завданням: брати інженерну реальність — на якому етапі перебувало постачання, що показували системні метрики — і доносити її до CEO чітко й регулярно, щоб рішення спиралися на факти, а не на здогадки.</p>\n<p><strong>Дія.</strong> Замість звітування на запит, яке завжди трохи запізнюється, впроваджено стабільний ритм звітності. Прогрес постачання, обсяг робіт, ризики та стан системи відстежувалися й перетворювалися на прості, орієнтовані на рішення оновлення: що йде за планом, що під ризиком і у що конкретно обійдеться той чи інший пріоритет з погляду компромісів. Чого варто було уникати — це передавати сирі цифри й залишати інтерпретацію тому, хто не має контексту; кожен звіт супроводжувався конкретними рекомендаціями, а там, де це допомагало розповіді, вона підкріплювалася базовим аналізом, тож керівництво могло заглибитися в деталі, якщо хотіло, а не приймати все на віру.</p>\n<p><strong>Результат.</strong> У підсумку керівництво отримало чітку, чесну й актуальну картину інженерії та могло скеровувати продуктові пріоритети й інвестиції з певною впевненістю, а не наосліп. Звітність перестала бути ритуалом статусу, який ніхто не читає, і стала тим, на основі чого справді ухвалювалися рішення, — що тримало технічну роботу й бізнес‑напрямок спрямованими в один бік.</p>\n",
      "date_published": "2026-10-09T14:27:31+02:00",
      "date_modified": "2026-10-09T14:27:31+02:00",
      "language": "uk",
      "tags": [
        "Аналітика даних",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Технічне лідерство",
        "Управління проєктами",
        "Аналітика даних та BI‑дашборди",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/",
      "url": "https://engineer.company/uk/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/",
      "title": "Довела WCAG 2.2 рівня AA на 32 представницьких сторінках — по одній на шаблон на мову — в обох колірних темах, плюс два критерії AAA, із задокументованим записом відповідності та перевіркою, що захищає кожне твердження.",
      "summary": "Відповідність заявлено на рівні AA трьома мовами й у двох темах, з двома критеріями AAA понад це та одним, названим як виняток, і за кожною заявою стоїть…",
      "content_html": "<p><strong>Ситуація.</strong> Консультація, що продає інженерну розсудливість і випускає недоступний вебсайт, має проблему з довірою ще до того, як має проблему з доступністю. Сайт до того ж має незвично широку поверхню для цього: три мови, дві колірні теми, повну таблицю стилів для друку, палітру з темною темою як основною, мальовані від руки примітки та ілюстрованого персонажа — і кожне з цього є способом провалити критерій в одній конфігурації, проходячи його в іншій.</p>\n<p><strong>Завдання.</strong> Сайт мав відповідати WCAG 2.2 на рівні AA на кожній сторінці, кожною мовою та в обох темах, і цю відповідність мали захищати перевірки, а не заява в документі.</p>\n<p><strong>Дія.</strong> Запис відповідності документує кожен критерій в обсязі, і кожен рядок називає, що його задовольняє і що це перевіряє. Два критерії рівня AAA взято понад ціль — візуальне подання цілком і вигляд фокуса, який радше пропонують, ніж заявляють. Автоматизація запускає рушій правил доступності з увімкненими правилами найкращих практик, а не лише з тими, що стосуються відповідності, а це різниця в тридцять правил, і вона важила одразу: одне з додаткових правил провалилося тієї миті, коли його ввімкнули, бо знак бренду стояв поза всіма орієнтирами на кожній внутрішній сторінці. Друга, повільніша перевірка проганяє тридцять дві представницькі сторінки у двох колірних схемах і двох ширинах, і те, що вона стверджує, є незвичним: фокус доводиться в пікселях, а не в документі, справжнім натисканням клавіші табуляції та порівнянням знімків екрана, бо однакові пікселі означають, що користувач не може сказати, де фокус, хай би що казала розмітка. Вона також обходить усю сторінку в пошуках клавіатурної пастки, застосовує зазначені перевизначення міжлітерних і міжслівних відступів, подвоює кореневий розмір шрифту та вимірює довжину рядка, вирівнювання, центрування та відступи між абзацами.</p>\n<p><strong>Результат.</strong> Відповідність заявлено на рівні AA трьома мовами й у двох темах, з двома критеріями AAA понад це та одним, названим як виняток, і за кожною заявою стоїть перевірка. Найважчою була контрастність над фотографією, яку автоматичний механізм правил позначає як таку, що її не оцінити, і яку сайт захищав аргументом, а не числом: справжні показники — 49 із 64 пар сторінки й теми нижче AA. Причиною виявилися дві поверхні, якими дизайн ніколи не володів, а перевірка, що їх знайшла, тепер є підлогою: кожна пара має витримувати AA над стіною, яку малює збірка, а пара, що не витримує, валить збірку. Те, що сайт каже на власній сторінці подяк, є чесною частиною: жоден автоматичний інструмент не знаходить більш ніж приблизно третину порушень WCAG, підписи, що з&rsquo;являються під вказівником, не можна закрити клавішею, бо для цього потрібен скрипт, а сайт виконує лише один, і випробувань зі справжніми допоміжними технологіями не було — ці межі записано там, де читач їх побачить, а не вилучено із заяви.</p>\n",
      "date_published": "2026-09-30T14:19:06+02:00",
      "date_modified": "2026-09-30T14:19:06+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Документація",
        "Інтернаціоналізація",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Інтернаціоналізація та локалізація",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/notes/safari-underline-font-subset/",
      "url": "https://engineer.company/uk/notes/safari-underline-font-subset/",
      "title": "Підкреслення, яке не обходило літери",
      "summary": "Safari проводив наші підкреслення крізь кожен виносний елемент. Причиною був кириличний підшрифт на сторінках, які його не завантажують.",
      "content_html": "<p>Наш власний сайт підкреслює кожне посилання й дозволяє браузеру вирізати\nпроміжок там, де хвостик літери перетинає лінію, — <code>g</code>, <code>p</code>, кома. У Safari\nцього не відбувалося. Лінія йшла просто крізь них. І так було на англійських та\nданських сторінках відтоді, як сайт став\nбагатомовним (вада, про яку ніхто не повідомляє, бо вона просто має дешевий вигляд).</p>\n<p>Причиною були три оголошення шрифту для абетки, яку ті сторінки ніколи не\nзавантажують.</p>\n<h2 id=\"що-браузер-має-робити\">Що браузер має робити</h2>\n\n<p><code>text-decoration-skip-ink</code> — це властивість, яка піднімає підкреслення над\nнижнім виносним елементом. Вона ввімкнена за замовчуванням, і роками відповіддю\nна «моє підкреслення має неправильний вигляд» було взятися за\n<code>text-underline-offset</code> і посунути лінію нижче. Це хибний рефлекс: зсув лінії\nзмінює дизайн, а бракувало насправді саме проміжку.</p>\n<p>Перш ніж дійти до цікавого, ми знайшли дві справжні причини, і обидві варті\nуваги.</p>\n<ul>\n<li><strong>Підкреслення завтовшки <code>1px</code> отримує проміжок розміром <code>1px</code>.</strong> Розрив, який\nвирізає рушій, пропорційний товщині лінії, що його вирізає. Наш стиль\nзафіксував товщину на одному пікселі, і це лишало близько 0,6px повітря з\nкожного боку штриха — технічно проміжок, візуально лінія просто крізь літеру.\n<code>text-decoration-thickness: auto</code> змасштабував обидві величини разом і збільшив\nпроміжок з 3,5px до 12,4px, не зсунувши підкреслення ані на піксель.</li>\n<li><strong><code>from-font</code> — не той безпечний варіант, яким здається.</strong> Він читає товщину,\nяку оголошує сам шрифт, а Ubuntu оголошує 0,056em для Light, 0,020em для\nMedium і 0,120em для Bold — родина, у якої лінія Medium важить менше за\nполовину лінії Light. На великих розмірах це шестипіксельна лінія поряд із\nдвопіксельною на одній сторінці.</li>\n</ul>\n<p>Це виправило Chrome. Safari й далі вів лінію крізь усе.</p>\n<h2 id=\"частина-яка-забрала-найбільше-часу\">Частина, яка забрала найбільше часу</h2>\n\n<p>Ми виміряли це як належить: запустити справжній Safari, перефарбувати\nпідкреслення, зробити знімок екрана у восьмикратному масштабі й порахувати\nпікселі, де лінія уривається й починається знову.</p>\n<table>\n\t<thead>\n\t\t\t<tr>\n\t\t\t\t\t<th></th>\n\t\t\t\t\t<th>намальована товщина</th>\n\t\t\t\t\t<th>проміжок навколо виносного елемента</th>\n\t\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t\t<tr>\n\t\t\t\t\t<td>Chrome</td>\n\t\t\t\t\t<td>2,00px</td>\n\t\t\t\t\t<td>5,8 / 12,5 / 6,3px</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t\t<td>Safari</td>\n\t\t\t\t\t<td>1,38px</td>\n\t\t\t\t\t<td>1,8 / 1,0 / 1,0px</td>\n\t\t\t</tr>\n\t</tbody>\n</table>\n<p>Отже, Safari таки вирізав проміжок. Просто вшестеро вужчий за Chrome, а в\nрозмірі для читання проміжок в один піксель — це не проміжок. Гірше: звичний\nважіль лише погіршував справу. За товщини 3px Safari падав із трьох проміжків до\nодного, за 4px — до жодного, бо він не масштабує проміжок разом із лінією. Він\nфіксує його приблизно на 0,07em за будь-якого розміру, тоді як Chrome дає 0,6em.</p>\n<p>Ми перебрали проти нього близько двадцяти оголошень — <code>skip-ink: all</code>, обидва\nзастарілі написання властивості, кожну товщину від половини пікселя до чотирьох,\n<code>text-underline-position</code>, <code>font-smoothing</code>, <code>text-rendering</code>, <code>paint-order</code>.\nНіщо не розширило проміжок. Чесний висновок на той момент був такий: WebKit\nпросто обмежує проміжок, і зі стилів більше нічого не вдіяти.</p>\n<p>Той висновок виявився хибним, а зламав його\n<a href=\"https://github.com/fontsource/fontsource/issues/1096\">звіт про ваду проти шрифтового проєкту</a>:\nSafari ігнорує skip-ink, коли шрифт завантажено з нелатинською підмножиною.</p>\n<h2 id=\"справжня-причина\">Справжня причина</h2>\n\n<p>Сайт віддає Ubuntu шістьма частинами — три накреслення латиницею, три\nкирилицею, — щоб українська сторінка була набрана тим самим шрифтом, що й\nанглійська, а не відкочувалася до того, що запропонує система. Кожна частина\nоголошує діапазон символів, який покриває, і браузер завантажує лише ті\nчастини, які сторінці справді потрібні.</p>\n<p>Усі шість були оголошені під однією назвою родини — це найочевидніший спосіб це\nзаписати. І саме він є спусковим гачком, зафіксованим як\n<a href=\"https://bugs.webkit.org/show_bug.cgi?id=255159\">вада WebKit 255159</a>: <strong>коли\nодне накреслення в родині оголошує нелатинський діапазон символів, Safari\nпогіршує skip-ink для кожного символу цієї родини</strong> — зокрема для латинського\nтексту на сторінці, яка ніколи не завантажує той інший файл.</p>\n<p>Англійська сторінка малювала свої підкреслення погано, бо десь у стилях існувало\nукраїнське оголошення шрифту. Коли ми видалили ті три рядки під час виконання й\nне змінили більше нічого, проміжки зросли з 1,8/1,0/1,0px до 4,5/11,0/5,0px.</p>\n<h2 id=\"виправлення\">Виправлення</h2>\n\n<p>Дайте другій системі письма власну назву родини й назвіть її у стеку шрифтів\nпісля першої:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-css\" data-lang=\"css\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">@</span><span class=\"k\">font-face</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nt\">font-family</span><span class=\"o\">:</span> <span class=\"nt\">UbuntuCyrillic</span><span class=\"o\">;</span>   <span class=\"c\">/* було: Ubuntu */</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nt\">src</span><span class=\"o\">:</span> <span class=\"nt\">url</span><span class=\"o\">(</span><span class=\"nt\">ubuntu_300_cyrillic</span><span class=\"p\">.</span><span class=\"nc\">woff2</span><span class=\"o\">)</span> <span class=\"nt\">format</span><span class=\"o\">(</span><span class=\"s1\">&#39;woff2&#39;</span><span class=\"o\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nt\">unicode-range</span><span class=\"o\">:</span> <span class=\"nt\">U</span><span class=\"o\">+</span><span class=\"nt\">0400-045F</span><span class=\"o\">,</span> <span class=\"nt\">U</span><span class=\"o\">+</span><span class=\"nt\">0490-0491</span><span class=\"o\">;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">:</span><span class=\"nd\">root</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nv\">--body-font</span><span class=\"p\">:</span> <span class=\"n\">Ubuntu</span><span class=\"p\">,</span> <span class=\"n\">UbuntuCyrillic</span><span class=\"p\">,</span> <span class=\"n\">system-ui</span><span class=\"p\">,</span> <span class=\"kc\">sans-serif</span><span class=\"p\">;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>Латинська літера знаходиться в першій родині й ніколи не доходить до другої.\nКирилична проминає першу, де такого гліфа немає, і потрапляє в другу, а не в\nсистемний шрифт. Діапазони символів і далі вирішують, що завантажується, тож в\nзавантаженні не змінюється нічого: англійські та данські сторінки беруть три\nлатинські файли й жодного кириличного, українські — навпаки.</p>\n<p>Три перейменовані оголошення й один запис у стеку. Проміжки в Safari зросли до\n4,5/11,0/5,0px, Chrome лишився недоторканим, підкреслення не зрушило з місця, а\nукраїнська й далі набирається в Ubuntu з тими самими ширинами.</p>\n<h2 id=\"що-ми-сказали-б-наступному\">Що ми сказали б наступному</h2>\n\n<ul>\n<li><strong>Вимірювання skip-ink справедливе лише для того рушія, який його дав.</strong> Ми\nмали таблицю чисел, правильний діагноз і справжнє виправлення — і все це було\nChromium. Знімок екрана, який відкрив справу наново, надійшов від людини, яка\nподивилася на сторінку.</li>\n<li><strong>Беріться за товщину раніше, ніж за зсув.</strong> Ширший проміжок зберігає дизайн;\nзсув лінії вниз його замінює.</li>\n<li><strong>Ділити шрифт за системами письма — правильно, але поділ має бути й у назві\nродини.</strong> Одна назва на кілька систем письма читається краще й коштує вам\nskip-ink у Safari. Злити їх назад має вигляд прибирання, а є регресом.</li>\n<li><strong>Завантаження ніколи не було проблемою.</strong> Будь-яка інтуїція підказує, що\nсторінка, яка малюється погано через кириличний шрифт, мусить завантажувати\nщось зайве. Вона не завантажувала. Досить було самого оголошення.</li>\n</ul>\n<h2 id=\"джерела\">Джерела</h2>\n\n<ul>\n<li><a href=\"https://bugs.webkit.org/show_bug.cgi?id=255159\">Вада WebKit 255159 — <code>text-decoration-skip-ink</code> і підмножини шрифтів</a></li>\n<li><a href=\"https://github.com/fontsource/fontsource/issues/1096\">Issue 1096 у Fontsource, який назвав спусковий гачок</a></li>\n<li><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-skip-ink\">MDN: <code>text-decoration-skip-ink</code></a></li>\n<li><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range\">MDN: <code>unicode-range</code></a></li>\n</ul>\n",
      "date_published": "2026-09-28T00:00:00Z",
      "date_modified": "2026-09-28T21:35:48+02:00",
      "language": "uk"
    },
    {
      "id": "https://engineer.company/uk/portfolio/measured-thirteen-addresses-from-the-access-log-alone-166/",
      "url": "https://engineer.company/uk/portfolio/measured-thirteen-addresses-from-the-access-log-alone-166/",
      "title": "Виміряла тринадцять адрес лише за власним журналом доступу вебсервера — без кукі, без трекерів і без сторонніх сервісів — маскуючи мережу клієнта в момент запису рядка та згортаючи результат у постійний архів із 21 денного показника та 20 місячних фасетів.",
      "summary": "Так вимірюються тринадцять адрес, і сайт не надсилає ні кукі, ні трекера, ні стороннього запиту, тож немає на що давати згоду й немає де виконатися тегу.",
      "content_html": "<p><strong>Ситуація.</strong> Сайт не мав жодного способу дізнатися, чи його хтось читає. Кожна звична відповідь на це коштує читачеві чогось &ndash; кукі, скрипт, піксель, хостована служба, що дізнається про відвідувача мимохідь, &ndash; і кожну з них було відхилено ще до першого рядка цієї роботи. Лишався власний журнал доступу вебсервера, єдиний запис, який існує й так, бо на запит треба відповісти.</p>\n<p><strong>Завдання.</strong> Питання було в тому, чи можна збудувати корисний запис про читацьку аудиторію з рядка журналу, з якого вже вилучено ідентифікаційні частини, і чи можна це вилучення довести, а не пообіцяти.</p>\n<p><strong>Дія.</strong> Маскування відбувається в момент запису рядка, а не під час прибирання потім, бо обіцянку не зберігати щось порушують, зберігши це й прибравши згодом. Сервер виводить адресу клієнта під двома іменами, і маскуються обидва &ndash; замаскувати одне читається в конфігурації як правильне, доки повна адреса лежить на диску під іншим, і це знайшла лише жива перевірка. Сім заголовків із переадресованими адресами відкидаються цілком, бо кодувальник пише мапу заголовків точно так, як її надіслав клієнт, і відвідувач за корпоративним проксі інакше заніс би власну повну адресу у файл під іменем, на яке жодна маска не дивилася. Заголовок кукі, заголовок авторизації та ефемерний порт джерела йдуть тим самим шляхом, а рядки запиту відрізаються, перш ніж будь‑що прочитає шлях, тож ані слова, набрані в пошуковій системі, ані слова, набрані у власному пошуку сайту, не можуть дістатися жодного файлу. Збір &ndash; це витягування: скрипт лише на стандартній бібліотеці читає потоком живий журнал і його згорнутих побратимів на хості й друкує підрахунки, а не рядки, обмежений кількістю різних шляхів, а не розміром журналу, бо машина має 464 МБ. Зберігання вимагало двох механізмів, а не одного, після того як стеля за розміром і стеля за часом на одній полиці означали, що менша перемагає мовчки &ndash; жвавий сайт тримав десять днів замість тридцяти, а тихий не видаляв нічого. Журнал переживає архів із 21 підрахунку на день і 20 фасетів на місяць, злитих, а не дописаних, за правилом, що вікно може лише недоспостерігати, із сумою поряд із кожним рейтингом, щоб урізана таблиця сама казала, скільки вона відкинула.</p>\n<p><strong>Результат.</strong> Так вимірюються тринадцять адрес, і сайт не надсилає ні кукі, ні трекера, ні стороннього запиту, тож немає на що давати згоду й немає де виконатися тегу. Задум відмовляє більше, ніж відповідає &ndash; унікальні відвідувачі, пошукові запити, шлях відвідувача сайтом, час на сторінці, кліки, географія та пристрій тут усі без відповіді й самі про це кажуть, &ndash; а межі друкуються поряд із числами, а не ховаються дрібним шрифтом, бо грубе число, прочитане як точне, гірше за відсутнє.</p>\n",
      "date_published": "2026-09-26T15:48:02+02:00",
      "date_modified": "2026-09-26T15:48:02+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "Python",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Моніторинг та observability",
        "Data Governance та якість даних",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/increased-brand-popularity-by-200x-through-successful-brand-1/",
      "url": "https://engineer.company/uk/portfolio/increased-brand-popularity-by-200x-through-successful-brand-1/",
      "title": "Підвищила популярність бренду у 200 разів завдяки успішному розвитку бренду на офлайн- та онлайн‑платформах.",
      "summary": "Охоплення бренду зросло приблизно у 200 разів на офлайн- та онлайн-платформах — невідомий новачок перетворився на щось, що люди справді впізнавали.",
      "content_html": "<p><strong>Ситуація.</strong> Engineer ApS була абсолютно новою консалтинговою компанією з реальною технічною глибиною, про яку майже ніхто не чув. Це особливий різновид розчарування: майстерність є, робота була б якісною, але ніщо з цього не має значення, якщо клієнти й партнери, яким це було б потрібно, не знають про існування компанії. Молода компанія має стати помітною, перш ніж зможе щось здобути.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб побудувати бренд, який люди справді впізнавали б — як в офлайні, так і онлайн — і перетворити інженерну репутацію компанії на видиму присутність на ринку, а не залишати її добре збереженою таємницею.</p>\n<p><strong>Дія.</strong> Бренд будувався свідомо й послідовно. Усе почалося з чіткої ідентичності — голосу, візуальної мови та портфоліо, що спиралося на конкретні інженерні результати замість розмитих формулювань на кшталт «ми створюємо цінність», які використовують усі інші. Далі це поширилося на канали, важливі для компанії такого типу, — вебсайт, LinkedIn, GitHub, офлайн‑заходи — причому кожна точка контакту говорила одне й те саме, а не жила своїм життям. Наскрізною лінією було подання реальних кейсів і реальних результатів, тож довіру можна було підкріпити доказами, а не просто твердженням.</p>\n<p><strong>Результат.</strong> Охоплення бренду зросло приблизно у 200 разів на офлайн- та онлайн‑платформах — невідомий новачок перетворився на щось, що люди справді впізнавали. І це було не показне охоплення: видимість почала приносити стабільний потік вхідних звернень і можливостей, яких раніше просто не існувало.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Бренд і маркетинг",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Бренд, маркетинг та SEO",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/drove-brand-engagement-and-loyalty-by-100-through-2/",
      "url": "https://engineer.company/uk/portfolio/drove-brand-engagement-and-loyalty-by-100-through-2/",
      "title": "Підвищила залученість та лояльність до бренду на 100% завдяки аналізу ринкових трендів і поведінки споживачів.",
      "summary": "Залученість і лояльність подвоїлися — покращення на 100% — аудиторія почала повертатися й взаємодіяти, а не поглядати один раз і йти геть, а стосунки з…",
      "content_html": "<p><strong>Ситуація.</strong> У міру зростання видимості Engineer ApS охоплювала дедалі більше людей — але залученість була слабкою. Люди помічали й проходили повз; ранній інтерес не перетворювався на тривалі стосунки. Охоплення без залученості — це просто шум, і бренд радше створював шум, ніж зв&rsquo;язки.</p>\n<p><strong>Завдання.</strong> Метою було поглибити залученість і лояльність, спираючись при цьому не на інтуїцію, а на реальний аналіз того, на що відгукувалися ринок і аудиторія.</p>\n<p><strong>Дія.</strong> Тож підхід до бренду став ґрунтуватися на даних, а не на інтуїції. Це означало аналіз ринкових трендів і реальної поведінки аудиторії в різних каналах — не того, що комусь здавалося привабливим, а того, з чим аудиторія демонстративно взаємодіяла. Було виявлено теми й формати, що привертали справжню увагу, і контент та комунікацію було переорієнтовано на них. Важливою частиною стало замикання циклу зворотного зв&rsquo;язку: відстежувати, що спрацювало, публікувати більше подібного наступного разу і робити кожен цикл трохи точнішим за попередній.</p>\n<p><strong>Результат.</strong> Залученість і лояльність подвоїлися — покращення на 100% — аудиторія почала повертатися й взаємодіяти, а не поглядати один раз і йти геть, а стосунки з потенційними клієнтами й партнерами помітно зміцніли. Бренд припинив мовлення в порожнечу і почав будувати те, що приносило віддачу.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Аналітика даних",
        "Бренд і маркетинг",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Аналітика даних та BI‑дашборди",
        "Бренд, маркетинг та SEO",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-a-comprehensive-infrastructure-framework-for-a-research-institute-3/",
      "url": "https://engineer.company/uk/portfolio/designed-a-comprehensive-infrastructure-framework-for-a-research-institute-3/",
      "title": "Спроєктувала комплексну інфраструктурну систему для науково‑дослідного інституту, що охопила 14 департаментів, з гнучкими модулями, уніфікованими пайплайнами даних та структурованими стратегіями підтримки для довгострокового впровадження.",
      "summary": "Отриманий план інфраструктури виявився і технічно обґрунтованим, і стратегічно узгодженим із дослідницькими цілями інституту.",
      "content_html": "<p><strong>Ситуація.</strong> У науково‑дослідному інституті, що об&rsquo;єднував 14 різнопрофільних дослідницьких груп, кожна група працювала з різними джерелами даних, форматами, масштабами та програмними інструментами. Технічна експертиза та доступні ІТ‑ресурси суттєво відрізнялися між групами. Хоча декільком групам вдалося створити й розгорнути власні ІТ‑рішення, багато інших стикалися зі складністю власних потреб у сфері дата‑інфраструктури, що відволікало цінний час і увагу від основної дослідницької роботи.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб розробити рішення, яке дозволило б дослідникам зосередитися на науковій роботі, а не на ІТ‑проблемах. Метою було спроєктувати та впровадити масштабовану дата‑інфраструктуру для всього інституту, здатну задовольнити широкі та відмінні одна від одної вимоги більшості дослідницьких груп.</p>\n<p><strong>Дія.</strong> Було розроблено надійний, перспективний план інфраструктури, що збалансовував гнучкість і стандартизацію. План окреслював ключові компоненти, такі як модульна архітектура, шляхи інтеграції різноманітних джерел даних, зручні для користувача інтерфейси, адаптовані до різного рівня технічних навичок, а також масштабовані рішення для зберігання та обробки даних. Він також охоплював стратегії впровадження, підтримки та управління, покликані забезпечити прийняття рішення й довгострокову стійкість.</p>\n<p><strong>Результат.</strong> Отриманий план інфраструктури виявився і технічно обґрунтованим, і стратегічно узгодженим із дослідницькими цілями інституту. Він об&rsquo;єднав бачення управління даними в межах усієї організації, окреслив чіткий шлях до зменшення ІТ‑навантаження на дослідників і заклав основу для спільного, ефективного та готового до майбутнього дослідницького середовища даних. План отримав високу оцінку за інклюзивність, чіткість та адаптивність, задавши чіткий напрям трансформації дата‑інфраструктури інституту.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "Архітектура платформи",
        "Архітектура рішень",
        "Документація",
        "Інженерія даних",
        "Інфраструктура",
        "Пайплайни даних (ETL/ELT)",
        "Стейкхолдери та звітність",
        "Технічне лідерство",
        "Data Governance та якість даних",
        "Архітектура платформи та рішень",
        "Розробка пайплайнів даних (ETL/ELT)",
        "Технічна документація",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/engineered-hourly-electricity-consumption-aggregation-pipeline-in-python-4/",
      "url": "https://engineer.company/uk/portfolio/engineered-hourly-electricity-consumption-aggregation-pipeline-in-python-4/",
      "title": "Розробила пайплайн погодинної агрегації споживання електроенергії на Python / SQL / Bash + Jq, досягнувши 180 мс для наборів даних за 30 днів із різнорідних джерел JSONL.",
      "summary": "Реалізація на Python виявилася найшвидшим і найбільш масштабованим рішенням, забезпечивши: - обробку даних за 1 день лише за 34 мс - набір даних за 30 днів —…",
      "content_html": "<p><strong>Ситуація.</strong> Компанія обробляє великі обсяги гетерогенних даних про електроенергію з кількох джерел, кожне з яких має власну частоту звітності — від погодинних інтервалів до інтервалів у 15 хвилин, а подекуди й нерегулярні часові мітки. Ця варіативність ускладнює створення узгодженого, порівнюваного набору даних. Для підтримки точної енергетичної аналітики ці дані потрібно нормалізувати до узгоджених погодинних значень споживання, агрегованих по зонах.</p>\n<p><strong>Завдання.</strong> Мета полягала в тому, щоб узяти сирі дані про події з історичного набору даних (у форматі JSONL) і перетворити їх на погодинно вирівняні показники споживання електроенергії, структуровані як один рядок на годину й на зону. Конкретно завдання включало:</p>\n<ul>\n<li>Вирівнювання даних із часовими мітками до строгих погодинних інтервалів,</li>\n<li>Агрегування загального виробництва електроенергії в межах кожного інтервалу шляхом підсумовування значень міксу,</li>\n<li>Врахування транскордонного обміну шляхом додавання імпорту та віднімання експорту,</li>\n<li>Виведення підсумкових значень у структурованому, масштабованому форматі, придатному для подальшого аналізу.</li>\n<li>Рішення також мало бути достатньо ефективним, щоб масштабуватися на великі часові вікна (30+ днів) і кілька країн/зон.</li>\n</ul>\n<p><strong>Дія.</strong> Для розв&rsquo;язання цього завдання було реалізовано три різні варіанти рішення з використанням Python, JQ (для обробки JSON у командному рядку) та SQL, кожен оптимізований під свій контекст:</p>\n<p>Python було обрано за його гнучкість, простоту роботи з даними та здатність ефективно виконувати трансформації в пам&rsquo;яті. За допомогою чистих функцій Python було побудовано пайплайн, який:</p>\n<ul>\n<li>Парсив файли JSONL у структуровані датафрейми</li>\n<li>Ресемплював часові ряди до погодинних інтервалів</li>\n<li>Агрегував виробництво та обчислював чисте споживання електроенергії (виробництво + імпорт − експорт)</li>\n<li>Експортував результати у форматі CSV або завантажував їх у легку базу даних SQLite для перевірки.</li>\n</ul>\n<p>JQ використовувався для створення швидкого рішення з мінімальними залежностями для середовищ командного рядка, побудованого як ланцюжок фільтрів JQ.</p>\n<p>У PostgreSQL дані JSONL було імпортовано, створено нормалізовані таблиці та написано низку SQL‑запитів.</p>\n<p>Для оцінки продуктивності кожне рішення було протестовано на історичних наборах даних за 1 день і за 30 днів.</p>\n<p><strong>Результат.</strong> Реалізація на Python виявилася найшвидшим і найбільш масштабованим рішенням, забезпечивши:</p>\n<ul>\n<li>обробку даних за 1 день лише за 34 мс</li>\n<li>набір даних за 30 днів — за 180 мс</li>\n</ul>\n<p>Це підтвердило її придатність для роботи з більшими часовими вікнами при збереженні продуктивності на рівні до секунди. Рішення також пропонувало зрозумілий, підтримуваний код, який можна було легко розширити для обробки кількох зон або інтегрувати в ETL‑пайплайн.</p>\n<p>Загалом підхід із використанням кількох інструментів продемонстрував гнучкість у виборі інструментів, потужну оптимізацію продуктивності та надійну обробку задач вирівнювання за часом і агрегування в реальних пайплайнах даних про електроенергію.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "PostgreSQL",
        "Python",
        "SQL",
        "Автоматизація та CI/CD",
        "Аналітика даних",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Пайплайни даних (ETL/ELT)",
        "Аналітика даних та BI‑дашборди",
        "Оптимізація продуктивності баз даних",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/",
      "url": "https://engineer.company/uk/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/",
      "title": "Прискорила продуктивність пайплайну географічних даних у 50 разів, вдосконаливши SQL‑програмування та моделювання даних у PostgreSQL, MS SQL та Google Cloud BigQuery.",
      "summary": "Ці комплексні оптимізації прискорили продуктивність пайплайну географічних даних у 50 разів, суттєво скоротивши час обробки даних.",
      "content_html": "<p><strong>Ситуація.</strong> Організація стикалася зі значними затримками в обробці великих обсягів географічних даних, що впливало на ефективність процесів прийняття рішень на основі даних та аналітичної звітності.</p>\n<p><strong>Завдання.</strong> Мета полягала в тому, щоб оптимізувати пайплайн географічних даних для підвищення продуктивності та скорочення часу обробки, забезпечивши можливість ефективнішого проведення аналітики даних у режимі реального часу.</p>\n<p><strong>Дія.</strong> Було ретельно проаналізовано наявні структури SQL‑програмування та моделювання даних у PostgreSQL, MS SQL і Google Cloud BigQuery, що виявило вузькі місця, пов&rsquo;язані з неефективними стратегіями індексації, неоптимальним дизайном запитів та відсутністю належних обмежень. Для вирішення цих проблем:</p>\n<ul>\n<li>Моделі даних було перепроєктовано для нормалізації критично важливих наборів даних, а також впроваджено стратегії партиціонування для скорочення часу отримання даних.</li>\n<li>Застосовано розширені техніки індексації, зокрема B‑tree та GiST індекси для PostgreSQL, фільтровані індекси в MS SQL і кластеризацію в BigQuery.</li>\n<li>Оптимізовано складні SQL‑запити шляхом рефакторингу підзапитів, скорочення операцій з&rsquo;єднання та впровадження матеріалізованих подань там, де це доречно.</li>\n<li>Встановлено обмеження цілісності даних, такі як зовнішні ключі та обмеження перевірки, для забезпечення узгодженості даних без шкоди для продуктивності.</li>\n</ul>\n<p><strong>Результат.</strong> Ці комплексні оптимізації прискорили продуктивність пайплайну географічних даних у 50 разів, суттєво скоротивши час обробки даних. Це покращення уможливило аналітику в режимі реального часу, розширило можливості звітності та надало зацікавленим сторонам своєчасні дані для прийняття рішень, що зрештою сприяло ухваленню більш обґрунтованих стратегічних рішень.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Пайплайни даних (ETL/ELT)",
        "Сховища даних",
        "GIS та геопросторові рішення",
        "Оптимізація продуктивності баз даних",
        "Проєктування сховищ даних",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/resolved-1-000-issues-in-geographical-data-and-7/",
      "url": "https://engineer.company/uk/portfolio/resolved-1-000-issues-in-geographical-data-and-7/",
      "title": "Вирішила 1 000 проблем у географічних даних та часових рядах, використовуючи GDAL, ArcGIS, PostGIS, Mapbox, QGIS, SQL (PL/pgSQL, Transact‑SQL), Bash, забезпечивши високоякісну обробку великих даних.",
      "summary": "Завдяки цим зусиллям було усунено понад 1 000 критичних проблем, що суттєво покращило точність даних і швидкість обробки.",
      "content_html": "<p><strong>Ситуація.</strong> Під час роботи над масштабним проєктом геопросторової аналітики команда виявила численні невідповідності й аномалії в географічних наборах даних і часових рядах. Ці проблеми впливали на точність просторового аналізу та інструментів прийняття рішень, що використовувалися в кількох підрозділах.</p>\n<p><strong>Завдання.</strong> Відповідальність полягала в тому, щоб виявити, усунути та оптимізувати понад 1 000 проблем якості даних у цих складних наборах даних для забезпечення цілісності та продуктивності подальших застосунків і візуалізацій.</p>\n<p><strong>Дія.</strong> Просторові помилки систематично діагностувалися та виправлялися за допомогою комбінації інструментів, зокрема GDAL, QGIS та ArcGIS, а автоматизовані робочі процеси на Bash дозволяли пришвидшити повторювані завдання з очищення даних. PostGIS забезпечував виконання складних просторових запитів і просторову індексацію, а надійні процедури на PL/pgSQL і Transact‑SQL використовувалися для управління та трансформації географічних і часових даних у базах даних PostgreSQL та SQL Server. Крім того, очищені дані було інтегровано в інтерактивні візуалізації за допомогою Mapbox, що підвищило доступність даних для кінцевих користувачів.</p>\n<p><strong>Результат.</strong> Завдяки цим зусиллям було усунено понад 1 000 критичних проблем, що суттєво покращило точність даних і швидкість обробки. Це безпосередньо сприяло скороченню часу виконання просторових запитів на 35% і уможливило проведення командою надійнішого просторового аналізу. Робота забезпечила постійну доступність якісних, готових до використання даних для аналітики та звітності, підтримуючи стратегічні рішення в межах усієї організації.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Пайплайни даних (ETL/ELT)",
        "Data Governance та якість даних",
        "GIS та геопросторові рішення",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/",
      "url": "https://engineer.company/uk/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/",
      "title": "Спроєктувала, реалізувала та адмініструвала 6 пайплайнів ETL/ELT, використовуючи Google BigQuery, MSSQL, PostgreSQL, Shell scripting, PL/pgSQL та Transact‑SQL, інтегрувавши дані для ефективної обробки через Python API.",
      "summary": "Ці автоматизовані пайплайни суттєво скоротили ручні витрати та час обробки — з понад 3 годин ручної роботи до менш ніж 20 хвилин наскрізно, водночас покращивши…",
      "content_html": "<p><strong>Ситуація.</strong> Організації потрібно було консолідувати та обробляти великі обсяги структурованих даних із віддаленого сховища даних, розташованого за IPSec VPN. Ці дані мали критичне значення для роботи внутрішніх аналітичних дашбордів і зовнішніх Python API, якими користувалися клієнти й партнери.</p>\n<p><strong>Завдання.</strong> Мета полягала в тому, щоб спроєктувати, реалізувати та підтримувати набір надійних автоматизованих ETL/ELT‑пайплайнів для безпечного отримання, трансформації та завантаження даних у Google BigQuery, забезпечуючи точність даних, продуктивність і масштабованість у всіх системах.</p>\n<p><strong>Дія.</strong> Було спроєктовано, реалізовано та адміністровано 6 наскрізних ETL/ELT‑пайплайнів на основі кількох технологій, включно з Google BigQuery, MSSQL, PostgreSQL, Shell‑скриптами, PL/pgSQL та Transact‑SQL.</p>\n<ul>\n<li>Налагоджено захищені з&rsquo;єднання з віддаленим сервером, захищеним IPSec VPN, для автоматизації отримання даних.</li>\n<li>Заплановано та виконано завантаження стиснутих архівів даних, що містили файли Parquet, CSV та .bak.</li>\n<li>Розроблено скрипти на Bash і Python для витягування та класифікації файлів за типом і схемою.</li>\n<li>Для файлів .bak резервні копії відновлювалися в локальному екземплярі MSSQL Server за допомогою робочих процесів RESTORE DATABASE, а цілісність схеми перевірялася.</li>\n<li>Завантажено структуровані дані в проміжні схеми в MSSQL і PostgreSQL за допомогою інструментів bcp, psql та SSIS, залежно від формату джерела.</li>\n<li>Написано модульні та придатні для повторного використання процедури PL/pgSQL і T‑SQL для очищення, нормалізації та збагачення даних відповідно до бізнес‑логіки.</li>\n<li>Експортовано впорядковані набори даних і таблиці в проміжні формати, стиснуто їх за допомогою gzip і безпечно передано в бакет Google Cloud Storage.</li>\n<li>Автоматизовано процеси завантаження та зіставлення схем у Google BigQuery за допомогою bq CLI та скриптів для завантаження даних на основі Python.</li>\n</ul>\n<p><strong>Результат.</strong> Ці автоматизовані пайплайни суттєво скоротили ручні витрати та час обробки — з понад 3 годин ручної роботи до менш ніж 20 хвилин наскрізно, водночас покращивши актуальність даних із щотижневої до щоденної синхронізації. Python API, що споживали ці дані, отримали приріст продуктивності на 30%, а покращена прозорість допомогла бізнес‑аналітикам швидше надавати інсайти зацікавленим сторонам. Рішення залишається масштабованим і легко розширюваним для підключення нових джерел даних у міру зростання бізнесу.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "PostgreSQL",
        "Python",
        "SQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Інженерія даних",
        "Мережі та VPN",
        "Пайплайни даних (ETL/ELT)",
        "Сховища даних",
        "Backend- та API‑розробка",
        "Проєктування сховищ даних",
        "Проєктування та моделювання баз даних",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/developed-and-launched-the-company-s-first-observability-9/",
      "url": "https://engineer.company/uk/portfolio/developed-and-launched-the-company-s-first-observability-9/",
      "title": "Розробила та запустила перший у компанії дашборд observability, що забезпечував аналітику продуктивності системи в реальному часі та візуалізацію даних на великому офісному телевізорі.",
      "summary": "Дашборд суттєво підвищив прозорість системи та швидкість реагування на операційні проблеми. Команди отримали змогу виявляти та усувати інциденти на 40% швидше.",
      "content_html": "<p><strong>Ситуація.</strong> Компанія стикалася з труднощами в моніторингу продуктивності систем у реальному часі, що часто призводило до затримок у реагуванні на інциденти та зниження видимості стану інфраструктури. Централізованого рішення, яке дозволяло б командам отримувати уявлення про операційні метрики, не існувало.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб розробити рішення, яке дозволило б технічним і нетехнічним зацікавленим сторонам відстежувати ключові системні метрики в реальному часі, з акцентом на доступність, зрозумілість і проактивне виявлення проблем.</p>\n<p><strong>Дія.</strong> Було спроєктовано та впроваджено перший дашборд observability компанії, що збирав усі ключові системні метрики — такі як CPU, RAM, HDD, температура тощо — з віддалених серверів Linux через SSH. Навіть контейнери Docker відстежувалися за допомогою цього методу. Пізніше було спроєктовано та впроваджено другу версію з використанням Grafana та Prometheus для розширених можливостей візуалізації й моніторингу. У співпраці з командами DevOps та інженерії було визначено критичні метрики, такі як утилізація CPU, використання пам&rsquo;яті, час безвідмовної роботи сервісів і затримка API. Пайплайни даних було налаштовано для приймання й обробки метрик продуктивності з різних систем, а дашборд розгорнуто на великому телевізорі в офісі для максимальної видимості. Також було впроваджено механізми сповіщень про перевищення порогових значень для забезпечення негайного реагування.</p>\n<p><strong>Результат.</strong> Дашборд суттєво підвищив прозорість системи та швидкість реагування на операційні проблеми. Команди отримали змогу виявляти та усувати інциденти на 40% швидше. Це також сформувало культуру спільної відповідальності за стан системи, зробивши дані про продуктивність доступними для всіх в офісі, що зрештою сприяло стабільнішому й ефективнішому продакшн‑середовищу.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Аналітика даних",
        "Інфраструктура",
        "Контейнери (Docker/Kubernetes)",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Аналітика даних та BI‑дашборди",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/",
      "url": "https://engineer.company/uk/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/",
      "title": "Реалізувала 8 проєктів Power BI з докладними посібниками, інтегрувавши інструменти Microsoft Power BI з NodeJS API та Python FastAPI для ефективної аналітики та візуалізації даних.",
      "summary": "Успішно реалізовано 8 проєктів з аналітики даних, підвищивши ефективність формування звітів на 60% і давши змогу міжфункціональним командам ухвалювати швидші…",
      "content_html": "<p><strong>Ситуація.</strong> Організації потрібні були динамічні візуальні уявлення про складні набори даних, що охоплювали продуктивність електромереж і показники географічного розподілу, для підтримки прийняття рішень у технічних і стратегічних командах.</p>\n<p><strong>Завдання.</strong> Розробити інтерактивні дашборди та рішення для звітності, здатні ефективно подавати як дані в реальному часі, так і історичні географічні та електричні дані, даючи змогу зацікавленим сторонам швидко виявляти тренди, аномалії та показники продуктивності.</p>\n<p><strong>Дія.</strong> Інтегровано Microsoft Power BI з власним бекенд‑стеком на основі NodeJS API та Python FastAPI для оптимізації приймання, трансформації та візуалізації даних. Спроєктовано й реалізовано дашборди з картографічними візуалізаціями, показниками споживання енергії, відстеженням відключень та індикаторами ефективності електромережі. Розроблено багаторазові шаблони та детальну документацію для підтримки масштабованості та зручності використання.</p>\n<p><strong>Результат.</strong> Успішно реалізовано 8 проєктів з аналітики даних, підвищивши ефективність формування звітів на 60% і давши змогу міжфункціональним командам ухвалювати швидші рішення на основі даних. Зацікавлені сторони повідомили про суттєве покращення розуміння регіональної продуктивності електромереж і точності планування ресурсів.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "GIS / геопростір",
        "Python",
        "Аналітика даних",
        "Документація",
        "Інженерія даних",
        "Продукт і вимоги",
        "Backend- та API‑розробка",
        "Аналітика даних та BI‑дашборди",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/",
      "url": "https://engineer.company/uk/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/",
      "title": "Випустила 500 звітів з аналізу даних електроенергетики та GIS, застосовуючи поглиблені дослідження та усунення несправностей для забезпечення точної аналітики географічних і часових великих даних.",
      "summary": "Звіти стали стандартним довідковим матеріалом у різних підрозділах, допомагаючи в балансуванні регіонального навантаження, плануванні енергоефективності та…",
      "content_html": "<p><strong>Ситуація.</strong> Команда управляла величезними наборами даних, що генерувалися розумними лічильниками, встановленими в кількох географічних регіонах. Ці розумні лічильники виробляли деталізовані часові ряди даних про споживання електроенергії, які використовували енергетичні аналітики, інженери та регіональні планувальники для операційних і стратегічних рішень.</p>\n<p><strong>Завдання.</strong> Відповідальність полягала в тому, щоб готувати якісні, прозорі та відтворювані аналітичні звіти, здатні виявляти патерни у споживанні енергії, виявляти аномалії та визначати регіональні тренди використання, водночас гарантуючи, що нетехнічні зацікавлені сторони зможуть легко інтерпретувати й повторно використовувати результати.</p>\n<p><strong>Дія.</strong> Було створено та надано понад 500 детальних аналітичних звітів, використовуючи чистий SQL для виконання всіх завдань з видобування, трансформації та аналізу даних, працюючи безпосередньо в хмарних середовищах, таких як PostgreSQL і BigQuery. Дані включали геолокаційні координати, ідентифікатори лічильників, дані про споживання енергії з часовими мітками та метадані про довкілля. SQL‑скрипти використовували CTE, віконні функції, підзапити та геопросторові з&rsquo;єднання, що забезпечувало масштабовану та ефективну обробку.</p>\n<p>Кожен звіт містив анотований SQL‑код, що давало змогу колегам і співавторам повністю відтворити й перевірити дослідження, що суттєво скорочувало час, необхідний для подальшого аналізу. Також додавалися нотатки з усунення несправностей і документувалися типові проблеми якості даних, такі як відсутні GPS‑координати або пошкоджені значення лічильників, разом із рекомендованими процедурами їх обробки.</p>\n<p><strong>Результат.</strong> Звіти стали стандартним довідковим матеріалом у різних підрозділах, допомагаючи в балансуванні регіонального навантаження, плануванні енергоефективності та виявленні аномалій. Забезпечуючи повну прозорість і відтворюваність, ця робота допомогла підвищити довіру зацікавлених сторін до даних і сприяла створенню точніших прогнозних моделей та покращенню ефективності операційного планування на 10–15%.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Аналітика даних",
        "Бази даних",
        "Документація",
        "Стейкхолдери та звітність",
        "Сховища даних",
        "Data Governance та якість даних",
        "GIS та геопросторові рішення",
        "Аналітика даних та BI‑дашборди"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/",
      "url": "https://engineer.company/uk/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/",
      "title": "Спроєктувала, створила та керувала 100 базами даних сховищ даних на PostgreSQL, MS SQL та Google BigQuery, переважно з GIS‑даними та часовими рядами, оптимізувавши продуктивність і масштабованість.",
      "summary": "Ці ініціативи призвели до суттєвих покращень: - Приріст продуктивності: час відповіді на запити для GIS-даних і часових рядів скоротився на 40–60%, що…",
      "content_html": "<p><strong>Ситуація.</strong> У технологічній компанії, що стрімко зростала, виникла критична потреба створювати, керувати та оптимізувати різноманітний портфель зі 100+ баз даних у PostgreSQL, Microsoft SQL Server та Google BigQuery. Ці бази даних переважно оброблювали складні набори даних, включно з даними геоінформаційних систем (GIS) (наприклад, просторові координати та аналітика на основі місцезнаходження) і часовими рядами (наприклад, показання сенсорів, логи та метрики в реальному часі). Наявна інфраструктура стикалася з проблемами масштабованості, продуктивності запитів і узгодженості даних, особливо в міру експоненційного зростання обсягу даних. Організації була потрібна надійна архітектура для забезпечення надійності даних і скорочення операційних витрат.</p>\n<p><strong>Завдання.</strong> Основна мета полягала в тому, щоб спроєктувати, реалізувати та підтримувати масштабовану, високопродуктивну екосистему сховища даних, адаптовану для GIS‑даних і часових рядів. Це включало:</p>\n<ul>\n<li>Усунення вузьких місць продуктивності в складних просторових і часових запитах.</li>\n<li>Забезпечення масштабованості для обробки зростаючих обсягів даних при збереженні економічної ефективності.</li>\n<li>Співпрацю з міжфункціональними командами (наприклад, дата‑сайєнтистами, продукт‑менеджерами) для узгодження дизайну бази даних з бізнес‑потребами.</li>\n</ul>\n<p><strong>Дія.</strong> Для досягнення цих цілей:</p>\n<ol>\n<li>Спроєктовано масштабовані архітектури:</li>\n</ol>\n<ul>\n<li>Створено нормалізовані та денормалізовані схеми для PostgreSQL і SQL Server із застосуванням просторової індексації (наприклад, PostGIS для PostgreSQL) і партиціонування часових рядів для оптимізації продуктивності запитів.</li>\n<li>Використано таблиці BigQuery з розбиттям за часом та кластеризацією для ефективної обробки великомасштабних часових рядів.</li>\n</ul>\n<ol start=\"2\">\n<li>Впроваджено стратегії оптимізації:</li>\n</ol>\n<ul>\n<li>Застосовано техніки оптимізації запитів, такі як індексація, матеріалізовані подання та кешування, для скорочення затримки GIS‑запитів і запитів до часових рядів.</li>\n<li>Застосовано стиснення даних і колонкове зберігання в BigQuery для мінімізації витрат на зберігання й підвищення швидкості сканування.</li>\n</ul>\n<ol start=\"3\">\n<li>Здійснено співпрацю щодо міжплатформної інтеграції:</li>\n</ol>\n<ul>\n<li>Задокументовано найкращі практики моделювання GIS‑даних і часових рядів для орієнтування команд у майбутніх проєктах.</li>\n</ul>\n<p><strong>Результат.</strong> Ці ініціативи призвели до суттєвих покращень:</p>\n<ul>\n<li>Приріст продуктивності: час відповіді на запити для GIS‑даних і часових рядів скоротився на 40–60%, що уможливило швидшу аналітику та прийняття рішень.</li>\n<li>Операційна надійність: автоматизований моніторинг скоротив час простою на 50%, тоді як стандартизовані процеси підвищили продуктивність команди та зменшили кількість помилок.</li>\n<li>Вплив на бізнес: оптимізована інфраструктура дала змогу компанії запустити нові продукти на основі даних (наприклад, дашборди аналітики в реальному часі) і виконати нормативні вимоги щодо управління даними (data governance).</li>\n</ul>\n<p>Ця робота зміцнила здатність організації розв&rsquo;язувати складні проблеми, пов&rsquo;язані з даними.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Архітектура платформи",
        "Бази даних",
        "Інженерія даних",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Сховища даних",
        "GIS та геопросторові рішення",
        "Адміністрування баз даних (DBA)",
        "Оптимізація продуктивності баз даних",
        "Проєктування сховищ даних",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/",
      "url": "https://engineer.company/uk/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/",
      "title": "Спроєктувала, розгорнула та підтримувала 10 серверів PostgreSQL і MS SQL на Ubuntu Linux VPS, забезпечивши оптимальну продуктивність і надійність серверів.",
      "summary": "- Досягнуто 99,9% безвідмовної роботи на всіх 10 серверах баз даних. - Покращено час відповіді запитів на 30% завдяки налаштуванню конфігурації та оптимізації…",
      "content_html": "<p><strong>Ситуація.</strong> На посаді DevOps‑інженера в компанії середнього розміру завдання полягало в тому, щоб керувати інфраструктурою баз даних та оптимізувати її для підтримки зростаючої бази користувачів і критично важливих бізнес‑застосунків. Організація значною мірою покладалася на PostgreSQL та Microsoft SQL Server для зберігання даних та аналітики, що вимагало високої доступності, масштабованості та безпеки.</p>\n<p><strong>Завдання.</strong> Основна відповідальність полягала в тому, щоб спроєктувати, розгорнути, налаштувати та підтримувати 10 інстансів PostgreSQL і MS SQL Server на VPS з Ubuntu Linux. Це включало забезпечення оптимальної продуктивності, впровадження надійних протоколів безпеки та налаштування проактивного моніторингу для запобігання простоям. Крім того, завдання включало масштабування інфраструктури для майбутнього зростання з мінімізацією витрат та дотриманням галузевих стандартів.</p>\n<p><strong>Дія.</strong> 1. Розгортання та налаштування:</p>\n<ul>\n<li>Встановлено та налаштовано PostgreSQL 14 і MS SQL Server 2019 на інстансах VPS з Ubuntu 20.04 LTS, з забезпеченням сумісності із застосунками компанії.</li>\n<li>Налаштовано автоматичне резервне копіювання за допомогою <code>pg_dump</code> для PostgreSQL і завдань SQL Server Agent для MS SQL, з політиками зберігання та офсайт‑зберіганням.</li>\n<li>Оптимізовано конфігурації серверів (наприклад, розподіл пам&rsquo;яті, кешування запитів та пулінг з&rsquo;єднань) для покращення продуктивності запитів та зниження затримок.</li>\n</ul>\n<ol start=\"2\">\n<li>\n<p>Моніторинг та обслуговування:</p>\n<ul>\n<li>Впроваджено інструменти моніторингу, такі як Prometheus, Grafana, для відстеження CPU, пам&rsquo;яті, дискового вводу‑виводу та метрик продуктивності запитів у режимі реального часу.</li>\n<li>Проведено регулярне патчування та оновлення як баз даних, так і ОС Ubuntu для усунення вразливостей безпеки та забезпечення відповідності стандартам.</li>\n<li>Створено власні скрипти для аналізу логів.</li>\n</ul>\n</li>\n<li>\n<p>Безпека та масштабованість:</p>\n<ul>\n<li>Налаштовано фаєрволи (UFW), впроваджено рольове керування доступом (RBAC) для захисту чутливих даних.</li>\n<li>Задокументовано процедури аварійного відновлення, включно з відновленням на конкретний момент часу та протоколами failover.</li>\n</ul>\n</li>\n</ol>\n<p><strong>Результат.</strong> - Досягнуто 99,9% безвідмовної роботи на всіх 10 серверах баз даних.</p>\n<ul>\n<li>Покращено час відповіді запитів на 30% завдяки налаштуванню конфігурації та оптимізації індексів, що підвищило продуктивність застосунків.</li>\n<li>Скорочено ручні завдання з обслуговування на 50% за рахунок автоматизації, вивільнивши понад 10 годин на місяць для стратегічних проєктів.</li>\n<li>Успішно масштабовано інфраструктуру для підтримки зростання трафіку користувачів на 40% без погіршення якості обслуговування, що сприяло зростанню доходу на 20% у наступному кварталі.</li>\n<li>Отримано визнання від CTO за впровадження найкращих практик безпеки, які запобігли потенційним витокам даних.</li>\n</ul>\n<p>Цей досвід закріпив глибоку експертизу в управлінні базами даних, DevOps‑автоматизації та оптимізації інфраструктури, забезпечуючи надійні, безпечні та масштабовані рішення для складних корпоративних середовищ.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "PostgreSQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Безпека",
        "Інфраструктура",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Системне адміністрування",
        "Адміністрування баз даних (DBA)",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/",
      "url": "https://engineer.company/uk/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/",
      "title": "Посилила безпеку даних, впровадивши 1 000 правил RBAC для розробників, екземплярів застосунків, PostgreSQL, MS SQL та інших Linux‑серверів, запобігши несанкціонованому доступу; задокументувала за допомогою автоматизації Ansible.",
      "summary": "Впровадження забезпечило понад 1 000 правил без внесення зайвої складності, скоротивши ризики несанкціонованого доступу на 85%.",
      "content_html": "<p><strong>Ситуація.</strong> Організації потрібно було посилити контроль доступу в кількох системах, включно з середовищами розробників, інстансами застосунків, PostgreSQL, MS SQL та Linux‑серверами. Хоча базова модель RBAC була простою, складність полягала в керуванні понад 1 000 окремих правил для різних ролей користувачів та системних вимог. Метою було забезпечити суворі обмеження доступу без внесення зайвої складності.</p>\n<p><strong>Завдання.</strong> Впровадити масштабоване рішення RBAC шляхом визначення та застосування понад 1 000 правил контролю доступу. Це передбачало відображення дозволів на конкретні ролі (наприклад, розробники, інстанси застосунків, адміністратори баз даних) та забезпечення послідовного застосування правил у всіх системах. Завдання також вимагало документування правил та автоматизації їхнього розгортання для уникнення ручних помилок.</p>\n<p><strong>Дія.</strong> Підхід був зосереджений на створенні простої, модульної структури RBAC, розбиваючи дозволи на чіткі, повторно використовувані категорії (наприклад, «доступ лише для читання до продакшн‑баз даних»). За допомогою Ansible налаштування кожного правила було автоматизовано, що забезпечило узгодженість у всіх середовищах. Наприклад, розробники отримували доступ лише до призначених їм серверів, тоді як інстанси застосунків мали обмежені дозволи для запобігання латеральному переміщенню. Процес пріоритизував ясність над складністю: кожне правило було явно прив&rsquo;язане до конкретної ролі та системи.</p>\n<p><strong>Результат.</strong> Впровадження забезпечило понад 1 000 правил без внесення зайвої складності, скоротивши ризики несанкціонованого доступу на 85%. Автоматизація спростила розгортання, скоротивши час налаштування на 60% порівняно з ручними методами. Задокументована структура дала змогу командам швидко перевіряти або змінювати правила, забезпечуючи масштабованість у міру зростання інфраструктури. Завдяки фокусу на простоті та обсязі рішення забезпечило надійну безпеку при збереженні операційної ефективності.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Безпека",
        "Документація",
        "Інфраструктура",
        "Системне адміністрування",
        "Infrastructure as Code",
        "Адміністрування баз даних (DBA)",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/accelerated-postgresql-performance-by-10x-via-strategic-indexing-15/",
      "url": "https://engineer.company/uk/portfolio/accelerated-postgresql-performance-by-10x-via-strategic-indexing-15/",
      "title": "Прискорила продуктивність PostgreSQL у 10 разів завдяки стратегічній індексації, партиціонуванню та оптимізації запитів, підвищивши ефективність бази даних для користувацьких, тенантних, геопросторових та часових електричних даних.",
      "summary": "Після оптимізації час відповіді запитів покращився у 10 разів, а критичні операції (наприклад, автентифікація користувачів, геопросторові пошуки) виконуються…",
      "content_html": "<p><strong>Ситуація.</strong> База даних PostgreSQL обслуговувала застосунок середнього розміру, що керував обліковими записами користувачів, інформацією про орендарів, географічними даними (наприклад, локації, регіони) та щоденними показниками споживання електроенергії. Хоча система працювала за низького навантаження, з ростом обсягів даних виникли проблеми з продуктивністю. Запити, пов&rsquo;язані з геопросторовими даними та часовими рядами електроенергетичних журналів, стали повільними, що призводило до непослідовного часу відповіді. Відсутність оптимізованої індексації, фрагментовані запити та непартиціоновані таблиці загострювали проблему, створюючи вузькі місця для критичних операцій, таких як автентифікація користувачів, управління орендарями та звітність за даними.</p>\n<p><strong>Завдання.</strong> Метою було підвищити продуктивність бази даних у 10 разів без капітальної переробки наявної архітектури. Увага була зосереджена на оптимізації виконання запитів, зниженні затримок та забезпеченні масштабованості для майбутнього зростання даних. Ключові пріоритети включали покращення часу відповіді для геопросторових та часових запитів, мінімізацію конкуренції за ресурси та збереження цілісності даних під час впровадження змін.</p>\n<p><strong>Дія.</strong> 1. <strong>Індексація:</strong> Проаналізовано найчастіше запитувані стовпці (наприклад, ID користувачів, ID орендарів, геопросторові координати) та створено цільові індекси. Для геопросторових даних додано індекси GiST для пришвидшення просторових запитів. Впроваджено композитні індекси для багатоколонкових фільтрів, таких як ID орендаря + діапазони дат для електроенергетичних даних.\n2. <strong>Партиціонування:</strong> Впроваджено партиціонування за часовими діапазонами для таблиці електроенергетичних даних, розділивши її за днями/місяцями. Це зменшило розмір набору даних для запитів та покращило ефективність сканування. Для географічних даних використано хеш‑партиціонування для рівномірного розподілу навантаження між вузлами.\n3. <strong>Оптимізація запитів:</strong> Переписано складні запити для уникнення повного сканування таблиць, з використанням CTE (Common Table Expressions) та матеріалізованих представлень для часто використовуваних наборів даних. Інструмент <code>EXPLAIN ANALYZE</code> виявив неефективні з&rsquo;єднання та підзапити, які були реструктуровані для кращих планів виконання. Крім того, налаштовано кешування запитів та пулінг з&rsquo;єднань для зниження накладних витрат.</p>\n<p><strong>Результат.</strong> Після оптимізації час відповіді запитів покращився у 10 разів, а критичні операції (наприклад, автентифікація користувачів, геопросторові пошуки) виконуються за мілісекунди. Використання ресурсів бази даних знизилося на 40%, що дало змогу системі обробляти зростаючі обсяги даних без погіршення продуктивності. Користувачі повідомляли про плавнішу взаємодію, а система стала більш масштабованою для майбутнього зростання. Зміни також скоротили потребу в апаратних оновленнях, заощаджуючи витрати при забезпеченні довгострокової надійності. Цей проєкт продемонстрував, як стратегічна індексація, партиціонування та вдосконалення запитів можуть перетворити навіть слабко навантажені системи на ефективні, готові до майбутнього бази даних.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "GIS / геопростір",
        "PostgreSQL",
        "SQL",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Адміністрування баз даних (DBA)",
        "Оптимізація продуктивності баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/",
      "url": "https://engineer.company/uk/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/",
      "title": "Автоматизувала розгортання GIS SaaS‑застосунку, обробку даних та систему звітності за допомогою GitHub Actions CI/CD, Python, Bash та SQL.",
      "summary": "Розгортання, обробка даних та звітність стали автоматизованими й надійними, ручна рутина зникла з плеча команди, а цикл релізів скоротився.",
      "content_html": "<p><strong>Ситуація.</strong> Розгортання GIS SaaS‑застосунку, обробка його даних та формування звітів були повністю ручними кроками — а ручні кроки одночасно й повільні, і тихо небезпечні. Кожен реліз забирав час інженерів і ніс ризик помилки, а повторювана робота з даними та звітністю сиділа там, з&rsquo;їдаючи потужність тиждень за тижнем.</p>\n<p><strong>Завдання.</strong> Завданням була автоматизація всього шляху від коду до продакшну, а також повторюваної обробки даних і звітності — з метою отримати релізи, які були б швидкими, безпечними та відтворюваними, а не ретельним ручним ритуалом щоразу.</p>\n<p><strong>Дія.</strong> Весь шлях було автоматизовано. Пайплайни GitHub Actions взяли на себе цикл test‑build‑deploy, тож реліз перестав залежати від того, чи хтось пам&rsquo;ятає всі кроки. Повторювана обробка даних та звіти перейшли в заплановані завдання на Python, Bash та SQL, тож вони просто виконувалися, а не були чиєюсь рутинною роботою. А конфігурація та секрети були стандартизовані так, щоб кожне середовище поводилося однаково — саме це усуває несподіванки на кшталт «у мене на машині працює», бо не залишається «моєї машини», яка відрізняється від продакшну.</p>\n<p><strong>Результат.</strong> Розгортання, обробка даних та звітність стали автоматизованими й надійними, ручна рутина зникла з плеча команди, а цикл релізів скоротився. Команда змогла зосередити увагу на продукті, а не на операціях, що його оточували.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "GIS / геопростір",
        "Python",
        "SQL",
        "Автоматизація та CI/CD",
        "Інженерія даних",
        "Надійність і резервне копіювання",
        "Пайплайни даних (ETL/ELT)",
        "DevOps та автоматизація CI/CD",
        "GIS та геопросторові рішення",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/",
      "url": "https://engineer.company/uk/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/",
      "title": "Автоматизувала постачання 20 пайплайнів GIS‑даних та ETL‑процесів даних застосунку, оптимізувавши автоматизацію інфраструктури та звітність.",
      "summary": "Усі двадцять пайплайнів та їхній ETL працювали автоматично й передбачувано, а вся картина автоматизації інфраструктури та звітності стала охайнішою.",
      "content_html": "<p><strong>Ситуація.</strong> Платформа працювала на великій кількості GIS‑пайплайнів даних та ETL‑процесів для даних застосунку, які постачалися й контролювалися вручну. Ручні пайплайни створюють вузькі місця, вони втрачають узгодженість, і найгірше — вони несуть постійний невеликий ризик того, що один із них тихо відмовить, і ніхто цього не помітить, доки дані далі за потоком уже не стануть неправильними.</p>\n<p><strong>Завдання.</strong> Завданням була автоматизація постачання цих пайплайнів та ETL‑процесів — щоб дані надходили надійно та передбачувано без того, щоб хтось їх супроводжував.</p>\n<p><strong>Дія.</strong> Двадцять GIS‑пайплайнів даних та ETL для даних застосунку перейшли на автоматизоване постачання, від початку до кінця. Планування, логування та обробку відмов було стандартизовано, тож кожен пайплайн поводився однаково і, що важливо, було видно, коли якийсь із них поводився інакше — тиха відмова залишається тихою, лише якщо ніхто не стежить. І їх було вбудовано в наявну автоматизацію інфраструктури та звітність, тож вони стали частиною однієї узгодженої системи, а не шухляди зі скриптами, які хтось мусив пам&rsquo;ятати запустити.</p>\n<p><strong>Результат.</strong> Усі двадцять пайплайнів та їхній ETL працювали автоматично й передбачувано, а вся картина автоматизації інфраструктури та звітності стала охайнішою. Бізнес отримав надійні, актуальні дані без того, щоб хтось проводив їх вручну — і без ризику тихої відмови, що висів над цим.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "GIS / геопростір",
        "Автоматизація та CI/CD",
        "Інженерія даних",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Пайплайни даних (ETL/ELT)",
        "DevOps та автоматизація CI/CD",
        "GIS та геопросторові рішення",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-100-critical-data-backups-using-barman-google-18/",
      "url": "https://engineer.company/uk/portfolio/automated-100-critical-data-backups-using-barman-google-18/",
      "title": "Автоматизувала 100 критично важливих резервних копій даних за допомогою Barman, Google Cloud, Bash та Python, забезпечивши цілісність даних у базах даних.",
      "summary": "Резервне копіювання виконувалося автоматично й підлягало перевірці для кожної бази даних, що перетворило відновлюваність даних із припущення на щось…",
      "content_html": "<p><strong>Ситуація.</strong> Критичні GIS‑дані, інстанси застосунків та бази даних були розкидані по системах з резервним копіюванням, яке було непослідовним і частково ручним. Для продукту, що живе своїми даними, це не той ризик, який можна залишити без уваги — і день, коли резервна копія справді знадобиться, це саме той день, найгірший для того, щоб дізнатися, що вона неповна.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб гарантувати можливість відновлення всіх критичних даних, що означало автоматизацію всебічного, перевіреного резервного копіювання в усьому господарстві — де саме слово «перевіреного» й мало значення.</p>\n<p><strong>Дія.</strong> Режим резервного копіювання було побудовано від початку до кінця. Сто критичних резервних копій даних було автоматизовано, з Barman на стороні PostgreSQL та Google Cloud для офсайт‑копій, а весь процес було оркестровано й перевірено за допомогою Bash та Python — бо резервна копія, яку зроблено, але ніколи не перевірено, це не насправді резервна копія, а лише сподівання. Тож були впроваджені політики зберігання, щоб тримати їх актуальними, та перевірки цілісності, щоб підтвердити, що кожна з них справді хороша, а не просто присутня.</p>\n<p><strong>Результат.</strong> Резервне копіювання виконувалося автоматично й підлягало перевірці для кожної бази даних, що перетворило відновлюваність даних із припущення на щось перевірене. Значний операційний ризик було знято з бізнесу та замінено шляхом відновлення, якому справді можна довіряти — різниця в тому, що цей шлях був перевірений, а не лише налаштований.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "PostgreSQL",
        "Python",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Адміністрування баз даних (DBA)",
        "Резервне копіювання та відновлення"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/",
      "url": "https://engineer.company/uk/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/",
      "title": "Розгорнула та підтримувала 20 контейнеризованих застосунків Docker, усуваючи несправності за допомогою Podman і Kubernetes, а також керувала застосунками на R у Google Cloud та AWS.",
      "summary": "Контейнеризоване господарство надійно працювало в обох хмарах, проблеми діагностувалися швидше, а розгортання залишалися стабільними й відтворюваними.",
      "content_html": "<p><strong>Ситуація.</strong> Існував зростаючий набір контейнеризованих застосунків — включно з деякими аналітичними застосунками на R — що працювали як на Google Cloud, так і на AWS. Розподілені між двома хмарами й кількома середовищами виконання контейнерів, вони мали розгортатися послідовно та швидко діагностуватися у разі проблем, що складніше, ніж звучить, коли жодні два середовища не є цілком однаковими.</p>\n<p><strong>Завдання.</strong> Роботою було надійне розгортання та підтримка цих навантажень, а також здатність швидко діагностувати проблеми в різних середовищах виконання та хмарах.</p>\n<p><strong>Дія.</strong> Контейнеризоване господарство керувалося в обох хмарах — двадцять Docker‑застосунків розгорнуто й підтримувано з узгодженою конфігурацією та моніторингом, тож жоден з них не був власною сніжинкою. Коли щось йшло не так, усунення несправностей відбувалося через Podman, а налагодження оркестрації — через Kubernetes. Аналітичні застосунки на R отримали окрему увагу в продакшн‑середовищах Google Cloud та AWS, залишаючись стабільними й відтворюваними, що для аналітики важливо — результат, який не можна відтворити, це не дуже й результат.</p>\n<p><strong>Результат.</strong> Контейнеризоване господарство надійно працювало в обох хмарах, проблеми діагностувалися швидше, а розгортання залишалися стабільними й відтворюваними. Застосунки, на які спирався продукт, залишалися надійними незалежно від того, в якій хмарі вони на той момент працювали.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Автоматизація та CI/CD",
        "Аналітика даних",
        "Інфраструктура",
        "Контейнери (Docker/Kubernetes)",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Контейнеризація та оркестрація",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/",
      "url": "https://engineer.company/uk/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/",
      "title": "Керувала 30 екземплярами Ubuntu Linux VPS, впровадивши стратегії аварійного відновлення та забезпечивши оптимальні конфігурації мережі.",
      "summary": "Інфраструктура стала стійкою й послідовною, з шляхами відновлення, які були перевірені, та мережею, на яку можна покластися.",
      "content_html": "<p><strong>Ситуація.</strong> Компанія працювала на флоті інстансів VPS з Ubuntu Linux, чиє налаштування органічно розросталося з часом — що є ввічливим способом сказати, що воно радше накопичувалося, ніж проєктувалося. Це залишило прогалини: непослідовні конфігурації та механізми відновлення й мережі, які були радше історичною випадковістю, ніж планом.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб взяти флот під належне управління, посилити сторону аварійного відновлення та зробити мережеву конфігурацію послідовною й розумною для кожного інстансу.</p>\n<p><strong>Дія.</strong> Тридцять інстансів перейшли під свідоме управління — до них ставилися як до одного узгодженого флоту, а не тридцяти окремих «домашніх улюбленців». Було впроваджено справжнє аварійне відновлення: резервні копії та процедури відновлення, які справді перевірялися, бо неперевірене відновлення — це лише теорія. А мережеву конфігурацію було стандартизовано для безпеки й продуктивності, тож кожен інстанс дотримувався того самого захищеного базового рівня замість того, з чим випадково опинявся.</p>\n<p><strong>Результат.</strong> Інфраструктура стала стійкою й послідовною, з шляхами відновлення, які були перевірені, та мережею, на яку можна покластися. Ризик простою знизився, і бізнес отримав надійну основу для зростання замість клаптикового рішення, яке доводилося постійно доглядати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Налаштування мереж та VPN",
        "Резервне копіювання та відновлення"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/",
      "url": "https://engineer.company/uk/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/",
      "title": "Запобігла порушенням безпеки, очоливши ініціативи з керування доступом, використовуючи M365, 1Password, Red Hat SSO та OKTA SSO.",
      "summary": "Ризик несанкціонованого доступу різко знизився, а доступ став підданим аудиту й послідовним — нарешті можна було відповісти на запитання «хто має доступ до…",
      "content_html": "<p><strong>Ситуація.</strong> Доступ до систем і сервісів в усій компанії керувався непослідовно — дозволи надавалися ситуативно, з часом, різними людьми. Це подвійна проблема: вона відкриває двері до доступу, якого ніхто не планував, і робить аудит майже неможливим, бо ніхто насправді не може сказати, хто до чого має доступ і чому.</p>\n<p><strong>Завдання.</strong> Метою було закрити цю вразливість безпеки шляхом централізації та посилення керування доступом у всій організації.</p>\n<p><strong>Дія.</strong> Перегляд консолідував ідентифікаційні дані та доступ у M365, 1Password, Red Hat SSO та OKTA SSO, тож замість розрізнених дозволів по системах з&rsquo;явилася узгоджена картина. Було впроваджено принцип найменших привілеїв — люди й системи мали рівно те, що їм потрібно, і нічого зайвого — а онбординг і офбординг стандартизовано, тож доступ надавався і, що не менш важливо, вчасно й послідовно відкликався, а не залишався після того, як хтось пішов далі.</p>\n<p><strong>Результат.</strong> Ризик несанкціонованого доступу різко знизився, а доступ став підданим аудиту й послідовним — нарешті можна було відповісти на запитання «хто має доступ до цього і чому». Дивна деталь у тому, що це також спростило повсякденне життя команди: потрібні двері відкривалися легко, а непотрібні залишалися зачиненими, а саме так і відчувається добре керування доступом.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Системне адміністрування",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/",
      "url": "https://engineer.company/uk/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/",
      "title": "Знизила операційні ризики, впровадивши дашборд моніторингу на базі Grafana та Prometheus, підвищивши надійність системи.",
      "summary": "Проблеми почали фіксуватися й вирішуватися до того, як вони ескалювалися, і надійність системи від цього покращилася.",
      "content_html": "<p><strong>Ситуація.</strong> Проблеми зазвичай помічали вже після того, як вони зачіпали користувачів, бо не існувало єдиного огляду того, як почуваються системи. Без цієї видимості команда постійно була в програшній позиції — реагуючи на те, що вже пішло не так, замість того, щоб бачити це заздалегідь.</p>\n<p><strong>Завдання.</strong> Метою було знизити операційний ризик, надавши команді видимість у реальному часі щодо систем, від яких вона залежала.</p>\n<p><strong>Дія.</strong> Було вибудовано шар observability. Дашборд моніторингу на Grafana та Prometheus, ключові сервіси інструментовано, і — та частина, яка справді має значення — метрики, які щось означали, а не показні числа, що виглядають зайнятими й нічого не повідомляють. Далі — порогові значення сповіщень, налаштовані на цих метриках, показані там, де команда справді їх бачила б і могла діяти, поки на дії ще був час.</p>\n<p><strong>Результат.</strong> Проблеми почали фіксуватися й вирішуватися до того, як вони ескалювалися, і надійність системи від цього покращилася. Команда перейшла від реактивного гасіння пожеж до чогось спокійнішого й проактивнішого — виловлюючи проблеми, поки ті ще були достатньо дрібними, щоб бути нудними.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Інфраструктура",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/",
      "url": "https://engineer.company/uk/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/",
      "title": "Керувала та усувала несправності 8 з'єднань WireGuard VPN та IPSEC VPN, забезпечивши безпечний зв'язок між системами Google Cloud та Linux.",
      "summary": "Усі вісім тунелів працювали безпечно й надійно, зв'язок між середовищами залишався захищеним, а повторювані інциденти зі з'єднанням, що раніше переривали…",
      "content_html": "<p><strong>Ситуація.</strong> Захищене з&rsquo;єднання між хмарою та локальними Linux‑системами проходило через кілька VPN‑тунелів, які були крихкими й незручними для діагностики у разі падіння. Мертвий тунель міг обірвати зв&rsquo;язок між середовищами, а усунення несправностей одного з них було повільним і невизначеним — ніколи не було повної впевненості, що справжню причину знайдено.</p>\n<p><strong>Завдання.</strong> Роботою було керування та усунення несправностей цих з&rsquo;єднань для гарантування безпечного й безперебійного зв&rsquo;язку.</p>\n<p><strong>Дія.</strong> VPN‑господарство взяли під контроль — вісім тунелів WireGuard та IPSec між Google Cloud та Linux‑системами, якими керували й для яких усували несправності як для єдиного набору, а не восьми окремих загадок. Їхню конфігурацію стандартизували, тож вони стали послідовними й зрозумілими замість того, щоб кожен був власним особливим випадком, а їхній стан моніторили, вирішуючи повторювані проблеми з маршрутизацією та обміном ключами в корені, а не заклеюючи їх перезапуском.</p>\n<p><strong>Результат.</strong> Усі вісім тунелів працювали безпечно й надійно, зв&rsquo;язок між середовищами залишався захищеним, а повторювані інциденти зі з&rsquo;єднанням, що раніше переривали роботу, припинилися. Саме усунення першопричин, а не догляд за симптомами, перетворило їх з повторюваного головного болю на щось, що просто працювало.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "Linux та сервери",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/led-the-software-development-of-a-gis-map-24/",
      "url": "https://engineer.company/uk/portfolio/led-the-software-development-of-a-gis-map-24/",
      "title": "Очолила розробку програмного забезпечення GIS‑картографічного застосунку, збільшивши дохід у 10 разів та позиціонувавши продукт як основний актив даних.",
      "summary": "GIS-застосунок став наріжним каменем SaaS-платформи, забезпечивши зростання доходу у 10 разів завдяки допродажам, ліцензуванню даних та залученню нових…",
      "content_html": "<p><strong>Ситуація.</strong> Основним викликом була побудова платформи, здатної відстежувати, моніторити та оптимізувати активи відновлюваної енергетики, такі як сонячні панелі та вітрові турбіни. Проте початкове рішення не мало надійних геопросторових можливостей, через що клієнтам було важко візуалізувати розташування активів, аналізувати просторові дані чи отримувати практичні висновки. Розпізнавши цю прогалину, керівна команда пріоритизувала розробку GIS‑застосунку (Geographic Information System) для карт, щоб підвищити цінність платформи та відповідати потребам клієнтів, що змінювалися.</p>\n<p><strong>Завдання.</strong> Завданням було очолити розробку GIS‑застосунку — критичного компонента для диференціації продукту на конкурентному ринку зеленої енергетики. Роль виходила за межі розробки програмного забезпечення, охоплюючи технічного лідера, DevOps‑інженера, інженера даних та SRE (Site Reliability Engineer), забезпечуючи узгодженість рішення з траєкторією зростання компанії. Метою було створити масштабований, інтуїтивно зрозумілий GIS‑інструмент, що безшовно інтегрувався б із SaaS‑платформою, даючи змогу користувачам візуалізувати розташування активів, відстежувати показники продуктивності та використовувати просторові дані для прийняття рішень. Це вимагало балансування технічних інновацій з обмеженнями зростаючого стартапу, забезпечуючи водночас можливість продукту розвиватися разом із компанією.</p>\n<p><strong>Дія.</strong> Почалося зі співпраці із зацікавленими сторонами для визначення основних функцій GIS‑застосунку, з фокусом на інтеграцію з наявною SaaS‑платформою та візуалізацію даних у реальному часі. З огляду на невеликий розмір команди, було спроєктовано модульну архітектуру з використанням бібліотек GIS з відкритим кодом, щоб система залишалася легкою й масштабованою. Також були впроваджені пайплайни CI/CD, автоматизоване надання інфраструктурних ресурсів та інструменти моніторингу для забезпечення надійності. У міру зростання команди нових інженерів наставляли, налагоджували міжфункціональну співпрацю та пріоритизували зворотний зв&rsquo;язок від користувачів для ітеративного вдосконалення застосунку. З часом GIS‑інструмент еволюціонував від базового прототипу до складної платформи, включаючи розширену аналітику та кастомні дашборди для задоволення потреб клієнтів.</p>\n<p><strong>Результат.</strong> GIS‑застосунок став наріжним каменем SaaS‑платформи, забезпечивши зростання доходу у 10 разів завдяки допродажам, ліцензуванню даних та залученню нових клієнтів. Його здатність візуалізувати активи зеленої енергетики в реальному часі підвищила операційну ефективність для клієнтів, а безперервне вдосконалення інструменту закріпило за ним статус основного інформаційного активу. Успіх проєкту не лише зміцнив репутацію компанії в секторі відновлюваної енергетики, а й продемонстрував цінність міждисциплінарного підходу в динамічному стартап‑середовищі. Поєднання технічної експертизи зі стратегічним баченням зробило GIS‑застосунок ключовим диференціатором, що підживлював довгострокове зростання та інновації.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Full‑Stack розробка",
        "GIS / геопростір",
        "Архітектура платформи",
        "Архітектура рішень",
        "Керівництво командою",
        "Менторство та коучинг",
        "Надійність і резервне копіювання",
        "Продукт і вимоги",
        "Технічне лідерство",
        "Full‑Stack продуктова розробка",
        "GIS та геопросторові рішення",
        "Архітектура платформи та рішень",
        "Продуктова стратегія та вимоги",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/",
      "url": "https://engineer.company/uk/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/",
      "title": "Керувала full‑stack розробкою GIS‑карт, наглядаючи за PostgreSQL, Mapbox, ReactJS та NodeJS, щоб постачити інтегроване рішення.",
      "summary": "У результаті вийшов єдиний інтегрований картографічний застосунок, у якому дані, рендеринг та інтерфейс нарешті тягнули в один бік.",
      "content_html": "<p><strong>Ситуація.</strong> На цьому етапі GIS‑карта перестала бути просто функцією і стала причиною, чому клієнти взагалі заходили в систему. Проблема полягала в тому, що вона розросталася фрагментарно. Просторові дані зберігалися в PostgreSQL, саму карту малював Mapbox, а застосунок навколо неї складався з ReactJS на фронтенді та NodeJS на бекенді. Кожна частина працювала сама по собі. Просто їх не було побудовано так, щоб вони поєднувалися одна з одною, і шви вже почали розходитися.</p>\n<p><strong>Завдання.</strong> Роль охоплювала full‑stack розробку карти та відповідний технічний напрям: модель даних, рендеринг, API та React‑фронтенд. Метою було перетворити чотири речі, які випадково опинилися в одному репозиторії, на єдиний продукт, за який не соромно.</p>\n<p><strong>Дія.</strong> Спочатку було визначено архітектуру, а далі робота велася близько до коду, а не з відстані. З боку даних просторову модель у PostgreSQL підтримували в порядку, щоб запити не сповільнювалися до повзання зі зростанням наборів даних. Mapbox відповідав за малювання; завдання полягало в тому, щоб подавати йому правильні дані на правильних рівнях масштабування, а не все одразу. З боку застосунку код на ReactJS і NodeJS проходив перевірку, команду підштовхували до спільних конвенцій, а відповідальність постійно повертали на той рівень, якому вона належала, щойно вона починала протікати в сусідній. Значна частина цієї роботи була неефектною: виловлювати дрібні неузгодженості, доки вони не застигли в архітектурі.</p>\n<p><strong>Результат.</strong> У результаті вийшов єдиний інтегрований картографічний застосунок, у якому дані, рендеринг та інтерфейс нарешті тягнули в один бік. Він став ключовою частиною платформи — тим, що команда могла й далі розширювати, не побоюючись, що все ламатиметься щоразу, коли додається новий шар.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "GIS / геопростір",
        "PostgreSQL",
        "Архітектура платформи",
        "Бази даних",
        "Оптимізація продуктивності",
        "Технічне лідерство",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "GIS та геопросторові рішення",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/saved-4-000-hours-by-mentoring-and-growing-26/",
      "url": "https://engineer.company/uk/portfolio/saved-4-000-hours-by-mentoring-and-growing-26/",
      "title": "Заощадила 4 000 годин, наставляючи та розвиваючи команду з 2 до 18 осіб, оптимізувавши робочі процеси та сприяючи міжвідомчій співпраці.",
      "summary": "Більша, краще підготовлена команда, яка працювала за реально спроєктованими робочими процесами, заощадила приблизно 4 000 годин. Але справа не так у цифрі.",
      "content_html": "<p><strong>Ситуація.</strong> Команда з двох осіб більше не встигала. Продукт вимагав більше роботи, ніж могли виконати двоє людей, а спосіб, у який ця робота відбувалася, — знання в головах людей, без справжніх конвенцій — не мав шансів пережити масштабування. Додавання людей до настільки неструктурованої команди зазвичай лише збільшує хаос.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб розширити команду і водночас побудувати структуру, яка дозволила б більшій групі рухатися швидше, а не повільніше. Наставництво над новими людьми було половиною справи. Друга половина — виправити робочі процеси так, щоб ніхто не застряг в очікуванні когось іншого.</p>\n<p><strong>Дія.</strong> Команда з часом зросла з 2 до 18 осіб, при цьому найм і наставництво розглядалися як одна й та сама робота: кожен, хто приєднувався, мав уміти працювати без нагляду. Спільні стандарти означали, що код і процеси виглядали однаково незалежно від того, хто їх написав, а справжні зусилля були вкладені в передачу роботи між спеціалізаціями, адже саме там команди непомітно втрачають дні. Коли щось постійно заважало людям, виправлення спрямовувалося на процес, а не на симптом.</p>\n<p><strong>Результат.</strong> Більша, краще підготовлена команда, яка працювала за реально спроєктованими робочими процесами, заощадила приблизно 4 000 годин. Але справа не так у цифрі. Побудовано було стійку інженерну спроможність — групу, здатну нести роботу незалежно від того, чи присутня в кімнаті якась конкретна людина.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Керівництво командою",
        "Менторство та коучинг",
        "Технічне лідерство",
        "Управління проєктами",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/",
      "url": "https://engineer.company/uk/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/",
      "title": "Оптимізувала стратегії прогнозування та інвестування для 11 операторів електромереж, підвищивши операційну ефективність за допомогою GIS‑рішень на основі даних.",
      "summary": "Оператори отримали прогнози, яким можна довіряти, та інвестиційні рішення, спрямовані на конкретну мету, а не засновані на сподіваннях.",
      "content_html": "<p><strong>Ситуація.</strong> Оператори електромереж живуть і гинуть рішеннями про те, де підсилювати мережу і куди вкладати гроші, а одинадцять із них ухвалювали ці рішення майже без геопросторового аналізу під ними. У них були операційні дані. Чого в них не було — це способу побачити ці дані на карті, там, де насправді живуть закономірності.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб за допомогою GIS загострити їхнє прогнозування та інвестиційні стратегії — перетворити таблиці показників на щось, що показувало б, де потужність стає обмеженою, де накопичується ризик і куди найдоцільніше спрямувати наступні кошти.</p>\n<p><strong>Дія.</strong> Їхні операційні дані було об&rsquo;єднано з геопросторовим моделюванням так, щоб вони підсилювали одне одного. Замість абстрактного прогнозування мережу можна було розглядати просторово й ставити конкретні запитання: які ділянки наближаються до своїх меж, які території виправдовують інвестиції в першу чергу. Для одинадцяти операторів це означало підганяти аналіз під те, як кожен із них фактично керує своєю мережею, а не пропонувати всім один шаблон у надії, що він підійде.</p>\n<p><strong>Результат.</strong> Оператори отримали прогнози, яким можна довіряти, та інвестиційні рішення, спрямовані на конкретну мету, а не засновані на сподіваннях. Прив&rsquo;язка планування до того, що показувала карта, зробила весь процес ефективнішим — гроші та увага спрямовувалися туди, куди вказували дані, а не туди, куди вела звичка.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "GIS / геопростір",
        "Аналітика даних",
        "Інженерія даних",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "GIS та геопросторові рішення",
        "Аналітика даних та BI‑дашборди",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/",
      "url": "https://engineer.company/uk/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/",
      "title": "Представила 200 покращень UI/UX для GIS‑картографічного застосунку, збільшивши дохід у 10 разів завдяки вдосконаленим функціям програмного забезпечення.",
      "summary": "Інтерфейс став помітно зручнішим у використанні, а цінність продукту зросла відповідно: ця робота сприяла зростанню доходу у 10 разів.",
      "content_html": "<p><strong>Ситуація.</strong> Інтерфейс карти став потужним і водночас — ускладненим. Були місця, де було відчутно, що клієнти не отримують цінність, яка лежала прямо перед ними, — хороша функціональність, замкнена за незграбними взаємодіями. Цей розрив між тим, що продукт умів робити, і тим, що людям було легко робити, непомітно коштував бізнесу грошей.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб знайти ці розриви і провести виправлення до кінця: роботу з юзабіліті, яка мала зробити продукт простішим для отримання цінності і, не випадково, комерційно ціннішим.</p>\n<p><strong>Дія.</strong> Замість того, щоб здогадуватися, що не так, робота велася на основі зворотного зв&rsquo;язку та даних про використання, і з цього утворився беклог із 200 конкретних покращень UI/UX. До них не ставилися як до рівнозначних — їх ранжували за впливом, а ті, що мали значення, відстоювалися і проводилися через команду, щоб бути випущеними як реальні функції, а не як список побажань, що застарівав у документі.</p>\n<p><strong>Результат.</strong> Інтерфейс став помітно зручнішим у використанні, а цінність продукту зросла відповідно: ця робота сприяла зростанню доходу у 10 разів. Це приклад, вартий того, щоб до нього повертатися, бо він чітко доводить думку — ретельна робота над UX не є косметикою, вона позначається на рахунку.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Аналітика даних",
        "Дизайн‑системи та UI",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "UI/UX‑дизайн та дизайн‑системи",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-and-managed-5-000-hours-of-map-29/",
      "url": "https://engineer.company/uk/portfolio/designed-and-managed-5-000-hours-of-map-29/",
      "title": "Спроєктувала та керувала 5 000 годин розробки карт, застосовуючи Agile‑методології, зокрема Scrum і Jira, для ефективного управління проєктами.",
      "summary": "Ці 5 000 годин були реалізовані контрольовано й прозоро, а не зникли в чорній скриньці. Управління проєктом робило те, для чого воно призначене, — і те, що…",
      "content_html": "<p><strong>Ситуація.</strong> Карту не було побудовано за один спринт. Це були тисячі годин роботи, розподілені між великою кількістю людей і місяців, а такі зусилля мають властивість розповзатися, якщо ніхто не тримає межі обсягу та графіка. Залишені без нагляду, вони непомітно перетворюються на запізнення.</p>\n<p><strong>Завдання.</strong> Відповідальність полягала в тому, щоб спроєктувати та вести процес розробки так, щоб результат досягався навмисно, а не завдяки удачі, — тримати пріоритети чесними, а прогрес видимим для кожного, хто хотів на нього подивитися.</p>\n<p><strong>Дія.</strong> Робота велася за Agile: справжній Scrum, у якому церемонії реально використовувалися, а не просто виконувалися для форми, а роботу відстежували в Jira, щоб люди бачили стан справ, не питаючи про це. Через цей процес пройшло приблизно 5 000 годин розробки карти. Акцент робився не так на церемоніях заради самих церемоній, як на тому, щоб тримати пріоритети спрямованими на важливе й вчасно ловити відхилення, поки їх ще було дешево виправити.</p>\n<p><strong>Результат.</strong> Ці 5 000 годин були реалізовані контрольовано й прозоро, а не зникли в чорній скриньці. Управління проєктом робило те, для чого воно призначене, — і те, що здебільшого залишається непоміченим, коли працює добре: воно тримало роботу узгодженою з цілями й приблизно в межах графіка, без героїзму наприкінці.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Керівництво командою",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Управління проєктами",
        "Продуктова стратегія та вимоги",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/wrote-50-000-words-of-comprehensive-software-documentation-30/",
      "url": "https://engineer.company/uk/portfolio/wrote-50-000-words-of-comprehensive-software-documentation-30/",
      "title": "Написала 50 000 слів вичерпної документації програмного забезпечення, використовуючи Markdown у GitHub, Craft та Confluence, забезпечивши збереження знань і прозорість процесу.",
      "summary": "Знання перестали бути крихкими. Нові люди виходили на робочий темп швидше, процес перетворився на те, на що можна вказати, а не відновлювати з пам'яті, а все…",
      "content_html": "<p><strong>Ситуація.</strong> Більшість важливого про продукт і про те, як працювала команда, існувала лише в головах людей. Це нормально, аж поки не приєднується нова людина або хтось не звільняється, — і тоді онбординг сповільнюється до повзання, а частина інституційної пам&rsquo;яті опиняється за крок від того, щоб зникнути назавжди.</p>\n<p><strong>Завдання.</strong> Мета полягала в тому, щоб перенести ці знання з голів у документацію, яку люди справді зберігали б і використовували: достатньо зрозумілу, щоб її читали, і достатньо структуровану, щоб її підтримували, а не покидали через місяць.</p>\n<p><strong>Дія.</strong> Значну частину написано вручну — приблизно 50 000 слів на завершальному етапі — у Markdown, у GitHub, Craft та Confluence, залежно від того, куди належав кожен фрагмент. Документація охоплювала архітектуру, процеси та практичні матеріали типу «як зробити» — ті питання, які люди ставили знову і знову. Її підтримували під контролем версій і, що не менш важливо, у стані, зручному для пошуку, адже документація, яку ніхто не може знайти, майже так само марна, як її відсутність.</p>\n<p><strong>Результат.</strong> Знання перестали бути крихкими. Нові люди виходили на робочий темп швидше, процес перетворився на те, на що можна вказати, а не відновлювати з пам&rsquo;яті, а все загалом стало прозорим для аудиту: можна було побачити, як і чому виконувалася робота, а не приймати це на віру.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Документація",
        "Керівництво командою",
        "Менторство та коучинг",
        "Технічне лідерство",
        "Технічна документація",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/gathered-and-analyzed-business-requirements-to-translate-into-31/",
      "url": "https://engineer.company/uk/portfolio/gathered-and-analyzed-business-requirements-to-translate-into-31/",
      "title": "Зібрала та проаналізувала бізнес‑вимоги, перетворивши їх на практичні функції та user stories відповідно до стандартів управління даними.",
      "summary": "Розробка велася на основі чітких, узгоджених функцій замість напівзрозумілих прохань. Неоднозначність знизилася, а разом із нею й переробка, а постачання…",
      "content_html": "<p><strong>Ситуація.</strong> Вимоги зазвичай надходили у формі розмов — хтось хотів чогось, приблизно, а розробникам доводилося вгадувати деталі. Вгадування означає переробку, а переробка — один із найдорожчих способів щось будувати.</p>\n<p><strong>Завдання.</strong> Роль перебувала на межі між бізнесом та інженерією, перекладаючи одне в інше: перетворюючи розмиті потреби на роботу, яку розробник міг узяти в роботу без здогадок, і водночас узгоджуючи це зі стандартами управління даними.</p>\n<p><strong>Дія.</strong> Вимоги опрацьовувалися безпосередньо із зацікавленими сторонами: незручні питання ставилися рано, а не виявлялися пізно, після чого вимоги оформлювалися як функції та user stories, які справді визначали, що означає «готово». Кожну з них перевіряли на відповідність правилам управління даними, адже функція, яка корисна, але неправильно поводиться з даними, насправді не завершена. Уся мета полягала в тому, щоб людина могла прочитати story й одразу побудувати правильну річ.</p>\n<p><strong>Результат.</strong> Розробка велася на основі чітких, узгоджених функцій замість напівзрозумілих прохань. Неоднозначність знизилася, а разом із нею й переробка, а постачання залишалося спрямованим на реальні бізнес‑цілі — у межах правил управління даними, а не підлаштованим під них заднім числом.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Data Governance",
        "Документація",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Управління проєктами",
        "Data Governance та якість даних",
        "Продуктова стратегія та вимоги",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/managed-the-execution-of-30-successful-gis-projects-32/",
      "url": "https://engineer.company/uk/portfolio/managed-the-execution-of-30-successful-gis-projects-32/",
      "title": "Керувала виконанням 30 успішних GIS‑проєктів, продемонструвавши керівництво в постачанні інноваційних рішень у галузі.",
      "summary": "Усі тридцять проєктів було здано. Ця послідовність важила більше, ніж будь-який окремий проєкт, — клієнт, який тридцять разів бачив постачання вчасно, не…",
      "content_html": "<p><strong>Ситуація.</strong> Компанія заробляла на постачанні GIS‑проєктів, і водночас їх виконувалося багато. Зростання компанії трималося на тому, щоб надійно доводити їх до завершення, — не один флагманський проєкт, зроблений блискуче, а стабільний потік проєктів, що здавалися вчасно й трималися купи, а це можливо лише тоді, коли координація в команді дійсно працює.</p>\n<p><strong>Завдання.</strong> Відповідальність полягала в тому, щоб забезпечити постачання цього портфеля — тримати обсяг, людей і терміни узгодженими по всьому портфелю та давати команді напрямок для випуску.</p>\n<p><strong>Дія.</strong> За ці роки через цю роль пройшло постачання тридцяти GIS‑проєктів. На практиці це означало утримувати обсяг стабільним, коли він намагався розповзатися, спрямовувати потрібних людей на потрібну роботу і триматися достатньо близько до кожного проєкту, щоб ловити проблеми, поки вони ще були малими. Якщо щось мало зірвати терміни, краще було дізнатися про це рано й перегрупуватися, ніж дізнатися про це на дедлайні. Значна частина роботи полягала просто в тому, щоб утримувати всі тарілки в повітрі та чесно інформувати клієнта про те, що і коли буде готове.</p>\n<p><strong>Результат.</strong> Усі тридцять проєктів було здано. Ця послідовність важила більше, ніж будь‑який окремий проєкт, — клієнт, який тридцять разів бачив постачання вчасно, не хвилюється за тридцять перший, і ця репутація значною мірою пояснює, чому компанія продовжувала зростати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "GIS / геопростір",
        "Керівництво командою",
        "Стейкхолдери та звітність",
        "Управління проєктами",
        "GIS та геопросторові рішення",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/led-company-growth-from-4-to-14-employees-33/",
      "url": "https://engineer.company/uk/portfolio/led-company-growth-from-4-to-14-employees-33/",
      "title": "Очолила зростання компанії з 4 до 14 співробітників, застосовуючи Agile‑методології та ефективні практики управління проєктами.",
      "summary": "Команда зросла до чотирнадцяти осіб без падіння якості й без розколу на людей, які не знають, чим займаються інші.",
      "content_html": "<p><strong>Ситуація.</strong> Компанія була готова зростати, а в цей момент існує конкретна небезпека: людей додають швидше, ніж процеси, і тоді і якість, і спільне розуміння того, як усе робиться, починають розхитуватися. Четверо людей, які знають, чим займається кожен інший, — це зовсім не те саме, що чотирнадцять, які цього не знають.</p>\n<p><strong>Завдання.</strong> Завданням було очолити це зростання — залучати людей, водночас утримуючи дисципліну постачання та команду, що рухається в одному напрямку.</p>\n<p><strong>Дія.</strong> Компанія виросла з чотирьох людей до чотирнадцяти. Найм і онбординг проводилися свідомо, а не в паніці, але більшою частиною роботи стало впровадження способів роботи, які дозволяли команді такого розміру не спотикатися об саму себе, — практики Agile, справжнє управління проєктами, звички, що робили роботу кожного видимою для всіх інших. Десятий і чотирнадцятий наймані працівники мали потрапити в середовище, яке вже мало чітку форму, а не вгадувати, як тут прийнято робити.</p>\n<p><strong>Результат.</strong> Команда зросла до чотирнадцяти осіб без падіння якості й без розколу на людей, які не знають, чим займаються інші. Саме складова Agile утримувала більшу групу продуктивною — процес зростав разом із чисельністю команди, а не відставав від неї.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Керівництво командою",
        "Менторство та коучинг",
        "Технічне лідерство",
        "Управління проєктами",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/",
      "url": "https://engineer.company/uk/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/",
      "title": "Покращила комунікацію та співпрацю в команді, впровадивши Slack, Mattermost, 1Password та Jira, заощадивши 8 000 людино‑годин.",
      "summary": "Комунікація та співпраця помітно покращилися, а впорядкована система заощадила приблизно 8 000 годин праці — час, який раніше йшов на пошук інформації та…",
      "content_html": "<p><strong>Ситуація.</strong> У міру зростання команди комунікація та інструменти не встигали за нею, і це було помітно. Щось говорилося в одному місці й губилося для людей, яким це було потрібно, робота дублювалася, бо ніхто не бачив, що вже зробив хтось інший, а координація будь‑чого займала більше часу, ніж сама робота. Такий тип тертя непомітний день у день, але з часом складається у велику втрату часу.</p>\n<p><strong>Завдання.</strong> Мета полягала в тому, щоб виправити спосіб, у який команда спілкувалася та працювала разом, і повернути час, який непомітно втрачався через це тертя.</p>\n<p><strong>Дія.</strong> Інструменти було впроваджено та стандартизовано, і — це та частина, яка справді має значення, — було встановлено практики їх використання, щоб вони не перетворилися просто на ще одне місце, яке треба перевіряти. Slack і Mattermost для комунікації, 1Password, щоб спільні секрети не передавалися способами, які ніхто не міг відстежити, Jira, щоб робота відстежувалася в одному місці, а не жила в головах і поштових скриньках людей. Інструменти були простою частиною; змусити всіх дійсно використовувати їх однаково — це і була справжня робота.</p>\n<p><strong>Результат.</strong> Комунікація та співпраця помітно покращилися, а впорядкована система заощадила приблизно 8 000 годин праці — час, який раніше йшов на пошук інформації та переробку роботи, тепер спрямовувався на реальне постачання.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Керівництво командою",
        "Управління проєктами",
        "Безпека та керування доступом",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/led-the-development-deployment-and-support-of-over-35/",
      "url": "https://engineer.company/uk/portfolio/led-the-development-deployment-and-support-of-over-35/",
      "title": "Очолила розробку, розгортання та підтримку понад 30 GIS‑проєктів, продемонструвавши експертизу в технологіях PostgreSQL, Bash, Python, JavaScript, GDAL, ArcGIS, PostGIS та Mapbox.",
      "summary": "Понад тридцять проєктів було побудовано, розгорнуто і підтримувано в усьому цьому діапазоні. Відповідальність за весь життєвий цикл, а не лише за побудову, —…",
      "content_html": "<p><strong>Ситуація.</strong> Увесь випуск компанії становив GIS «на замовлення» — кастомна картографія та просторові системи, побудовані під конкретну проблему клієнта, а потім підтримувані в роботі після запуску. Побудувати систему — це лише половина справи; геопросторовий проєкт, який запускається, а потім падає в продакшені, насправді не було доставлено.</p>\n<p><strong>Завдання.</strong> Ці проєкти проходили через цю роль від початку до кінця — розробка, розгортання та підтримка після запуску — з технічним керівництвом у доволі широкому стеку технологій.</p>\n<p><strong>Дія.</strong> Постачання охопило понад тридцять GIS‑проєктів, з практичною роботою по всьому стеку. PostgreSQL із PostGIS в основі для просторових даних, GDAL/OGR для перенесення їх між форматами — shapefiles, GeoJSON, GeoTIFF, KML, vector tiles — а також QGIS і JOSM для самої роботи з даними. На фронті — вебкарти, побудовані на Mapbox GL і Leaflet, іноді з використанням API ArcGIS чи HERE, з рівнем застосунку на JavaScript, Python, PHP і SQL. Робота охоплювала діапазон від 2D- і 3D‑цифрової картографії через обробку LiDAR, георектифікацію та векторизацію до карт приміщень і навігації в них. І відповідальність не закінчувалася на моменті запуску — розгортання та подальша підтримка в продакшені теж входили до неї, тож проблеми не передавалися комусь іншому; з ухваленими рішеннями доводилося жити.</p>\n<p><strong>Результат.</strong> Понад тридцять проєктів було побудовано, розгорнуто і підтримувано в усьому цьому діапазоні. Відповідальність за весь життєвий цикл, а не лише за побудову, — саме те, що тримало якість чесною: проєктування відбувається інакше, коли знаєш, що саме тобі дзвонитимуть, якщо щось зламається.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Full‑Stack розробка",
        "GIS / геопростір",
        "PostgreSQL",
        "Python",
        "SQL",
        "Бази даних",
        "Веброзробка",
        "Інженерія даних",
        "Керівництво командою",
        "Надійність і резервне копіювання",
        "Технічне лідерство",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "GIS та геопросторові рішення",
        "Розробка пайплайнів даних (ETL/ELT)",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/",
      "url": "https://engineer.company/uk/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/",
      "title": "Долучилася до процесів проєктування користувацьких інтерфейсів, забезпечивши інтуїтивні, візуально привабливі та зручні для користувача інтерфейси проєктів.",
      "summary": "Інтерфейси стали інтуїтивнішими та відшліфованішими, що кінцеві користувачі відчували безпосередньо, і це підняло загальну якість того, що випускалося.",
      "content_html": "<p><strong>Ситуація.</strong> Інтерфейси в проєктах компанії були нерівномірними за якістю. Деякі були непогані, деякі явно були побудовані інженерами, які думали про модель даних, а не про людину, якій доведеться цим користуватися, і рішення щодо дизайну не завжди ухвалювалися з думкою про кінцевого користувача. Особливо на вебкартографічному продукті карта — це найпростіша частина; саме в елементах керування, фільтрації та потоці навколо неї люди губляться.</p>\n<p><strong>Завдання.</strong> Участь у процесі UI‑дизайну була частиною ролі — допомагати робити інтерфейси такими, що люди справді вважали б їх інтуїтивними та приємними у використанні, а не просто функціональними.</p>\n<p><strong>Дія.</strong> Роль не була роллю дизайнера, але вона була присутня в процесі дизайну і привносила інженерну перспективу — акцентуючи увагу на розкладці, на потоці проходження завдання, на тому, чи справді екран був зрозумілим, чи лише звичним для тих, хто його побудував. Це були фронтенди на React, Angular і Vue поверх карт Mapbox і Leaflet, і значна частина юзабіліті полягала в деталях: як фільтрувався набір даних, як відбувався перехід між поверхами на карті приміщення, чи повідомляла система, що саме вона робить. Здебільшого це означало ставити «наївні» запитання від імені користувача рано, поки їх було ще дешево виправити, а не після релізу, коли плутанина поверталася у вигляді звернень у підтримку.</p>\n<p><strong>Результат.</strong> Інтерфейси стали інтуїтивнішими та відшліфованішими, що кінцеві користувачі відчували безпосередньо, і це підняло загальну якість того, що випускалося. Те, що питання юзабіліті ставилися під час дизайну, а не після релізу, — це здебільшого і є те, що визначило різницю.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "GIS / геопростір",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "UI/UX‑дизайн та дизайн‑системи"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/guided-the-execution-of-numerous-company-projects-offering-37/",
      "url": "https://engineer.company/uk/portfolio/guided-the-execution-of-numerous-company-projects-offering-37/",
      "title": "Спрямувала виконання численних проєктів компанії, надавши експертну підтримку на етапах розробки програмного забезпечення.",
      "summary": "Проєкти проходили складні етапи розробки плавніше, маючи змогу спертися на досвідчену підтримку в потрібні моменти, і це стабілізувало постачання результатів у…",
      "content_html": "<p><strong>Ситуація.</strong> Одночасно виконувалося багато проєктів, кожен на своєму етапі розробки, і всі вони потребували стабільного технічного супроводу, щоб не збитися з курсу. Залишені без уваги, проєкти відхиляються від курсу — неправильний підхід, обраний на ранньому етапі, стає дорогим до того моменту, коли хтось це помічає.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб супроводжувати це виконання — бути тією технічною опорою, на яку команди могли покластися протягом усіх етапів розробки.</p>\n<p><strong>Дія.</strong> Робота залишалася практичною одночасно в багатьох проєктах компанії. Це означало усувати перешкоди, коли люди застрягали, уважно розглядати підхід до того, як на його основі буде забагато побудовано, і загалом тримати достатньо близький контроль, щоб помітити проєкт, який рухається не в той бік, поки це ще можна було скоригувати, а не перебудовувати заново. Ідея полягала в тому, щоб бути доступним, а не бар&rsquo;єром, — підтримувати рух справ, а не змушувати все чекати на одну людину.</p>\n<p><strong>Результат.</strong> Проєкти проходили складні етапи розробки плавніше, маючи змогу спертися на досвідчену підтримку в потрібні моменти, і це стабілізувало постачання результатів у всьому портфелі проєктів компанії.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Керівництво командою",
        "Менторство та коучинг",
        "Технічне лідерство",
        "Управління проєктами",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/",
      "url": "https://engineer.company/uk/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/",
      "title": "Реорганізувала внутрішні процеси, заощадивши 8 000 годин завдяки вдосконаленню архітектури програмного забезпечення, систем та ефективності планування.",
      "summary": "Переробка зекономила приблизно 8 000 годин завдяки суттєвому підвищенню ефективності архітектури, систем і планування.",
      "content_html": "<p><strong>Ситуація.</strong> У внутрішніх процесах накопичилися типові нашарування — архітектура програмного забезпечення, що розросталася стихійно, а не за задумом, системи, які працювали, але неефективно, і планування, через яке люди то простоювали, то були перевантажені. Нічого з цього не «горіло», саме тому це й залишали без змін, але тихо це коштувало багато часу.</p>\n<p><strong>Завдання.</strong> Метою було докорінно переглянути ці процеси — знайти витрати й усунути їх, а не продовжувати за них платити.</p>\n<p><strong>Дія.</strong> Внутрішні процеси було перероблено за трьома напрямами: архітектуру програмного забезпечення — так, щоб її можна було логічно осмислювати й розвивати, а не обходити; системи — оптимізовано так, щоб рутинна робота більше не займала більше часу, ніж потрібно; і планування — так, щоб потужності справді відповідали обсягу роботи. Зміни закріпили так, щоб вони прижилися, — вбудували в те, як працює команда, а не залишили у вигляді меморандуму, який усі кивнули й забули, — адже покращення процесів, які не закріплюються, просто відкочуються назад до старого способу роботи.</p>\n<p><strong>Результат.</strong> Переробка зекономила приблизно 8 000 годин завдяки суттєвому підвищенню ефективності архітектури, систем і планування. Це потужності, які пішли безпосередньо на роботу з вищою цінністю, а не на накладні витрати, які раніше ніхто навіть не ставив під сумнів.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Автоматизація та CI/CD",
        "Архітектура платформи",
        "Архітектура рішень",
        "Інфраструктура",
        "Оптимізація продуктивності",
        "Технічне лідерство",
        "Управління проєктами",
        "DevOps та автоматизація CI/CD",
        "Архітектура платформи та рішень",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/",
      "url": "https://engineer.company/uk/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/",
      "title": "Адмініструвала мережеву інфраструктуру для понад 1 000 серверів, забезпечивши оптимальне розгортання систем, безпеку та усунення несправностей.",
      "summary": "Парк серверів працював із надійним розгортанням, надійною безпекою та проблемами, які вирішувалися оперативно, а не накопичувалися.",
      "content_html": "<p><strong>Ситуація.</strong> Операційна діяльність компанії трималася на великому парку серверів — понад тисяча одиниць, — а парк такого масштабу сам собою надійним не залишається. Розгортання, безпека та постійний потік того, що йде не так, потребують справжньої дисципліни в управлінні, інакше все стає нестабільним, і ніхто до кінця не розуміє чому.</p>\n<p><strong>Завдання.</strong> Завданням було адмініструвати цю мережеву інфраструктуру — забезпечувати її безпеку, надійність і узгодженість у масштабі, де саме неузгодженість здатна все зіпсувати.</p>\n<p><strong>Дія.</strong> Мережева інфраструктура працювала на понад тисячі серверів. Розгортання систем було стандартизовано, тож кожен сервер піднімався одним і тим самим передбачуваним способом, а не був трохи «індивідуальним»; безпеку посилили, а не покладалися на те, що ніхто не почне шукати вразливості; а усунення несправностей відбувалося щоразу, коли щось справді ламалося. У такому масштабі саме стандартизація рятує ситуацію — тисяча унікальних конфігурацій не піддається керуванню, а тисяча однакових — це просто робота.</p>\n<p><strong>Результат.</strong> Парк серверів працював із надійним розгортанням, надійною безпекою та проблемами, які вирішувалися оперативно, а не накопичувалися. Це саме той тип інфраструктурної роботи, який непомітний, коли все йде добре, — і в цьому суть: вона була стабільним кістяком, на якому трималося все інше в компанії.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/",
      "url": "https://engineer.company/uk/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/",
      "title": "Автоматизувала створення сертифікатів SSL/TLS для 100 застосунків Docker, забезпечивши безпечні з'єднання на хостах Ubuntu Linux.",
      "summary": "Усі сто застосунків самостійно підтримували дійсні сертифікати та захищені з'єднання. Ручна робота із сертифікатами просто зникла, а разом із нею — і ціла…",
      "content_html": "<p><strong>Ситуація.</strong> Сто застосунків на Docker потребували сертифікатів SSL/TLS, а сертифікати — це саме те, що працює нормально, доки раптом не перестає. Видавати й поновлювати сто сертифікатів вручну — повільно, нудно, і це якраз той тип ручної роботи, де одне забуте поновлення виводить застосунок з ладу через помилку простроченого сертифіката в найгірший можливий момент.</p>\n<p><strong>Завдання.</strong> Метою було автоматизувати створення й поновлення сертифікатів — щоб кожен застосунок мав дійсне, довірене шифрування, і нікому не доводилося пам&rsquo;ятати про це.</p>\n<p><strong>Дія.</strong> Робочий процес на основі ACME обробляв увесь життєвий цикл сертифікатів для ста застосунків на Docker — створював сертифікати й поновлював їх до завершення терміну дії — і автоматично розгортав їх на хостах Ubuntu Linux, де працювала суміш Apache та Nginx. Уся мета полягала в тому, щоб виключити людину з цього процесу, адже саме людина — та ланка, яка забуває.</p>\n<p><strong>Результат.</strong> Усі сто застосунків самостійно підтримували дійсні сертифікати та захищені з&rsquo;єднання. Ручна робота із сертифікатами просто зникла, а разом із нею — і ціла категорія збоїв, коли щось ламається не через відмову, а через те, що сертифікат непомітно прострочився, і ніхто цього не помітив.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Контейнери (Docker/Kubernetes)",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом",
        "Контейнеризація та оркестрація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/",
      "url": "https://engineer.company/uk/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/",
      "title": "Оптимізувала процеси CI/CD, заощадивши 4 000 годин завдяки впровадженню автоматизації в пайплайнах розробки програмного забезпечення.",
      "summary": "Автоматизація повернула приблизно 4 000 годин і зробила релізи швидшими та надійнішими водночас. Команда могла випускати реліз без внутрішнього напруження —…",
      "content_html": "<p><strong>Ситуація.</strong> Випуск програмного забезпечення залежав від ручних, неузгоджених кроків — комусь доводилося пам&rsquo;ятати послідовність дій і щоразу виконувати їх трохи по‑різному, — і це сповільнювало релізи та з&rsquo;їдало інженерні години, які мали б витрачатися на розробку.</p>\n<p><strong>Завдання.</strong> Метою було оптимізувати процес CI/CD і впровадити автоматизацію в пайплайни, щоб релізи перестали бути ручним ритуалом.</p>\n<p><strong>Дія.</strong> Було впроваджено автоматизовані пайплайни збирання, тестування та розгортання, тож шлях від зміни до її роботи у production став стандартизованим, а не імпровізованим. Повторювані ручні кроки — повільні й, що гірше, виконувані по‑різному залежно від того, хто їх робив, — прибрали. Коли пайплайн щоразу робить це однаково, ціла категорія проблем на кшталт «на моїй машині працювало» та напівзабутих кроків розгортання просто зникає.</p>\n<p><strong>Результат.</strong> Автоматизація повернула приблизно 4 000 годин і зробила релізи швидшими та надійнішими водночас. Команда могла випускати реліз без внутрішнього напруження — впевненість була наслідком узгодженості процесу, а не того, що всі діяли обережно.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Технічне лідерство",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/",
      "url": "https://engineer.company/uk/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/",
      "title": "Оптимізувала процеси аналізу даних та розробки програмного забезпечення, заощадивши 4 000 годин завдяки впровадженню практик CI/CD на базі GitHub, GitLab, Bash та Python.",
      "summary": "Оптимізовані процеси заощадили приблизно 4 000 годин і пришвидшили як аналіз даних, так і розробку програмного забезпечення, а також, що не менш корисно,…",
      "content_html": "<p><strong>Ситуація.</strong> І роботу з аналізу даних, і розробку програмного забезпечення стримувало одне й те саме: ручні процеси. Робота рухалася від розробки до постачання повільно й неузгоджено, а на боці аналізу накопичилася власна купа повторюваних кроків, які щоразу доводилося виконувати вручну.</p>\n<p><strong>Завдання.</strong> Метою було оптимізувати обидва напрями, впровадивши сучасну автоматизацію та практики CI/CD у робочі процеси, які їх раніше не мали.</p>\n<p><strong>Дія.</strong> Було впроваджено практики CI/CD на основі GitHub та GitLab, а автоматизацію в основі забезпечували Bash і Python. Повторювані кроки в робочих процесах аналізу даних і розробки автоматизували, а те, як робота рухалася від розробки до постачання, стандартизували, щоб вона щоразу відбувалася однаково, а не вигадувалася заново для кожного проєкту. Значною частиною цього стало включення аналітичного напряму в той самий дисциплінований пайплайн, що й розробка, — раніше його розглядали як окремий, більш ручний світ.</p>\n<p><strong>Результат.</strong> Оптимізовані процеси заощадили приблизно 4 000 годин і пришвидшили як аналіз даних, так і розробку програмного забезпечення, а також, що не менш корисно, зробили результати постачання більш узгодженими — менше несподіванок від роботи, яку щоразу виконували трохи по‑різному.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Python",
        "Автоматизація та CI/CD",
        "Аналітика даних",
        "Інженерія даних",
        "Пайплайни даних (ETL/ELT)",
        "DevOps та автоматизація CI/CD",
        "Аналітика даних та BI‑дашборди",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/",
      "url": "https://engineer.company/uk/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/",
      "title": "Розробила систему звітності Data Analytics, збільшивши квартальний дохід від програмного забезпечення на 400% завдяки PDF‑звітам на базі Python.",
      "summary": "Саме ця звітність спричинила зростання квартального доходу від програмного забезпечення на 400%. Покращення й пришвидшення аналітики не було просто зручністю…",
      "content_html": "<p><strong>Ситуація.</strong> Зацікавлені сторони не отримували аналітику у своєчасній, зрозумілій формі. Дані існували, але перетворення їх на щось, на основі чого справді можна ухвалювати рішення, відбувалося повільно й вручну, тож видимість того, як усе працює, відставала, а разом із нею відставали й комерційні рішення.</p>\n<p><strong>Завдання.</strong> Завданням було побудувати систему звітності з аналізу даних — таку, що перетворювала б необроблені дані на чіткі, регулярні висновки без ручного складання щоразу.</p>\n<p><strong>Дія.</strong> Систему звітності, яка генерувала PDF‑звіти на Python, було побудовано так, щоб автоматизувати весь ланцюжок: вибірку даних, проведення аналізу та представлення результатів у чіткому, узгодженому форматі, який зацікавлені сторони справді могли прочитати. Суть полягала в регулярності та ясності — той самий професійний звіт з&rsquo;являвся передбачувано, тож цифри стали тим, на що люди дивилися як на звичну справу, а не тим, що доводилося самостійно розшукувати.</p>\n<p><strong>Результат.</strong> Саме ця звітність спричинила зростання квартального доходу від програмного забезпечення на 400%. Покращення й пришвидшення аналітики не було просто зручністю для бек‑офісу — коли перед людьми, які ухвалюють комерційні рішення, з&rsquo;являються чіткі й своєчасні цифри, рішення стають кращими, і тут це напряму позначилося на доході.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Python",
        "Автоматизація та CI/CD",
        "Аналітика даних",
        "Інженерія даних",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Backend- та API‑розробка",
        "Аналітика даних та BI‑дашборди",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/",
      "url": "https://engineer.company/uk/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/",
      "title": "Автоматизувала завдання обробки даних за допомогою Shell scripting, PL/pgSQL, Python та Transact‑SQL, підвищивши продуктивність і ефективність.",
      "summary": "Продуктивність та ефективність зросли, ручне навантаження зникло з плечей людей, а обробка даних стала узгодженою й надійною замість того, щоб бути джерелом…",
      "content_html": "<p><strong>Ситуація.</strong> Існувало стабільне навантаження повторюваної роботи з обробки даних, яку виконували вручну. Ручна робота з даними має одразу дві проблеми: вона з&rsquo;їдає час і вона неузгоджена — виконуй одну й ту саму задачу вручну достатньо разів, і щоразу вона робитиметься трохи по‑різному, а деякі з цих відмінностей — це помилки.</p>\n<p><strong>Завдання.</strong> Метою було автоматизувати ці задачі, щоб і повернути час, і зробити їх надійними.</p>\n<p><strong>Дія.</strong> Обробку даних автоматизували в усіх базах даних і системах, яких вона стосувалася, використовуючи те, що підходило під конкретне завдання, — Shell‑скрипти для «клею» між компонентами, PL/pgSQL і Transact‑SQL на рівні баз даних, Python там, де потрібно було більше, ніж міг дати SQL. Ручні кроки замінили завданнями, які щоразу виконувалися однаково, а в цьому й уся суть: скрипт не втомлюється, не пропускає крок і не робить усе по‑іншому у п&rsquo;ятницю під кінець дня.</p>\n<p><strong>Результат.</strong> Продуктивність та ефективність зросли, ручне навантаження зникло з плечей людей, а обробка даних стала узгодженою й надійною замість того, щоб бути джерелом дрібних повторюваних помилок.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "PostgreSQL",
        "Python",
        "SQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Інженерія даних",
        "Пайплайни даних (ETL/ELT)",
        "DevOps та автоматизація CI/CD",
        "Адміністрування баз даних (DBA)",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/enhanced-project-efficiency-saving-150-hours-per-month-46/",
      "url": "https://engineer.company/uk/portfolio/enhanced-project-efficiency-saving-150-hours-per-month-46/",
      "title": "Підвищила ефективність проєктів, заощадивши 150 годин на місяць у 30 проєктах, оптимізувавши робочі процеси та управління ресурсами.",
      "summary": "Зміни заощаджували близько 150 годин на місяць у межах усього портфеля. Це регулярна щомісячна економія, а не одноразовий ефект, — тридцять проєктів працюють…",
      "content_html": "<p><strong>Ситуація.</strong> У портфелі приблизно з тридцяти проєктів щомісяця втрачався час через робочі процеси, які ніколи не оптимізували, і нерівномірне управління ресурсами — одних людей недовантажували, інших перевантажували, а роботу в кожному проєкті планували по‑своєму.</p>\n<p><strong>Завдання.</strong> Метою було зробити портфель ефективнішим і повернути час, який зникав місяць за місяцем.</p>\n<p><strong>Дія.</strong> Опрацьовуючи всі тридцять проєктів, робочі процеси та управління ресурсами доопрацьовували разом — усували вузькі місця, вирівнювали навантаження, щоб одні й ті самі кілька людей не були постійним обмеженням, і стандартизували те, як роботу планують і виконують, щоб кожен проєкт не був окремим особливим випадком. Тридцять проєктів, кожен з яких втрачає трохи часу, у сумі дають чимало; виправлення полягало здебільшого в тому, щоб зробити хороші практики послідовними, а не вигадувати щось нове.</p>\n<p><strong>Результат.</strong> Зміни заощаджували близько 150 годин на місяць у межах усього портфеля. Це регулярна щомісячна економія, а не одноразовий ефект, — тридцять проєктів працюють ощадливіше місяць за місяцем.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Автоматизація та CI/CD",
        "Керівництво командою",
        "Оптимізація продуктивності",
        "Управління проєктами",
        "Управління проєктами (Agile)",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/managed-a-team-delivering-it-support-data-recovery-47/",
      "url": "https://engineer.company/uk/portfolio/managed-a-team-delivering-it-support-data-recovery-47/",
      "title": "Керувала командою, що надавала послуги з IT‑підтримки, відновлення даних та ремонту обладнання понад 1 000 клієнтам, забезпечивши високу якість обслуговування.",
      "summary": "Команда обслужила понад тисячу клієнтів і здобула справжню репутацію надійного сервісу. У такому бізнесі репутація — це все: люди повертаються та розповідають…",
      "content_html": "<p><strong>Ситуація.</strong> Компанія була місцем, куди зверталася велика база клієнтів, коли в них ламалася ІТ‑система, — підтримка, відновлення даних, ремонт обладнання, увесь спектр послуг. Задовольняти такий стабільний, непоказний попит — це не про героїзм, а про те, щоб мати команду, яка добре працює день у день, адже робота практично ніколи не припиняється.</p>\n<p><strong>Завдання.</strong> Завданням було керувати командою, що надавала всі ці послуги, і підтримувати стабільну якість незалежно від того, чи був тиждень спокійним, чи все навалювалося одночасно.</p>\n<p><strong>Дія.</strong> Команда надавала ІТ‑підтримку, відновлення даних і ремонт обладнання для понад тисячі клієнтів. Значна частина цього — це організація роботи «під капотом»: контроль за тим, щоб звернення бралися в роботу, а не губилися, встановлення стандарту того, що насправді означає «полагоджено», щоб люди не отримували назад напіввідремонтовані пристрої, і підтримка ефективності команди, коли черга ставала довгою. Відновлення даних — це особливо та робота, до якої не можна ставитися недбало; на цьому диску зазвичай лежать чиїсь фотографії або чийсь бізнес, і на момент звернення в людини вже й так поганий день.</p>\n<p><strong>Результат.</strong> Команда обслужила понад тисячу клієнтів і здобула справжню репутацію надійного сервісу. У такому бізнесі репутація — це все: люди повертаються та розповідають про сервіс іншим саме тому, що минулого разу, коли щось зламалося, це справді вирішили.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Керівництво командою",
        "Менторство та коучинг",
        "Системне адміністрування",
        "Стейкхолдери та звітність",
        "IT‑підтримка та helpdesk",
        "Ремонт обладнання та відновлення даних",
        "Формування команди та менторство"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/",
      "url": "https://engineer.company/uk/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/",
      "title": "Налаштувала та розгорнула 1 000 Wi‑Fi‑роутерів, покращивши доступність і продуктивність мережі для клієнтів.",
      "summary": "Тисяча роутерів забезпечила клієнтам надійний бездротовий зв'язок — кращий доступ, кращу продуктивність — і робила це послідовно, оскільки налаштування були…",
      "content_html": "<p><strong>Ситуація.</strong> Клієнтам потрібен був бездротовий зв&rsquo;язок, який просто працює, а це зводилося до налаштування й розгортання великої кількості Wi‑Fi‑роутерів — і робити це щоразу однаково ретельно, адже недбало налаштований роутер буде або небезпечним, або повільним, а яким саме — зазвичай з&rsquo;ясовується вже потім.</p>\n<p><strong>Завдання.</strong> Завданням було налаштувати й розгорнути ці роутери, щоб забезпечити клієнтам кращий доступ до мережі та продуктивність.</p>\n<p><strong>Дія.</strong> Було налаштовано й розгорнуто тисячу Wi‑Fi‑роутерів. Хитрість за такої кількості полягає в стандартизації налаштувань — узгодженій, безпечній, продуманій конфігурації, — а не в підборі кожного роутера окремо з нуля в день установлення, адже тисяча «ручних» роутерів — це тисяча різних систем, які потім треба підтримувати. Тож щоразу їх налаштовували на безпеку й продуктивність однаковим способом і надійно розгортали на об&rsquo;єктах клієнтів.</p>\n<p><strong>Результат.</strong> Тисяча роутерів забезпечила клієнтам надійний бездротовий зв&rsquo;язок — кращий доступ, кращу продуктивність — і робила це послідовно, оскільки налаштування були стандартними, а не імпровізованими. Мета — роутер, про який більше нікому не потрібно думати; більшість із них цього досягли.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "IT‑підтримка та helpdesk",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/managed-4-000-computer-repairs-ensuring-rapid-and-49/",
      "url": "https://engineer.company/uk/portfolio/managed-4-000-computer-repairs-ensuring-rapid-and-49/",
      "title": "Керувала 4 000 ремонтами комп'ютерів, забезпечивши швидке та ефективне вирішення апаратних і програмних несправностей.",
      "summary": "Усі чотири тисячі ремонтів було виконано, і швидко. Люди отримували техніку працездатною та поверталися до своїх справ, а репутація компанії як надійного…",
      "content_html": "<p><strong>Ситуація.</strong> Надходив постійний потік комп&rsquo;ютерних ремонтів — за весь час їх набралося чотири тисячі — і за кожним стояла людина, яка чекала повернення своєї техніки, щоб повернутися до звичних справ. Апаратні несправності, програмні збої, весь спектр проблем, і клієнти оцінювали сервісний центр за тим, наскільки швидко й наскільки якісно все виправлялося.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб керувати цими ремонтами — забезпечувати швидке й, що не менш важливо, коректне вирішення проблем.</p>\n<p><strong>Дія.</strong> Опрацьовано чотири тисячі комп&rsquo;ютерних ремонтів — діагностовано апаратні та програмні несправності, організовано робочий процес так, щоб техніка рухалася далі, а не накопичувалася в черзі, і підтримано якість, щоб ремонт справді виконувався правильно, а не повертався клієнту, щоб знову вийти з ладу наступного тижня. Повторний ремонт гірший за повільний: він коштує клієнту ще одного візиту, а сервісному центру — довіри. Тож пропускна здатність мала значення, але ніколи не на шкоду виправленню з першого разу.</p>\n<p><strong>Результат.</strong> Усі чотири тисячі ремонтів було виконано, і швидко. Люди отримували техніку працездатною та поверталися до своїх справ, а репутація компанії як надійного сервісу залишалася непохитною — а для сервісного центру це і є весь бізнес.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Системне адміністрування",
        "IT‑підтримка та helpdesk",
        "Ремонт обладнання та відновлення даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/",
      "url": "https://engineer.company/uk/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/",
      "title": "Адмініструвала 100 серверів Bare Bone, фізичні мережі та системи IP‑телефонії, забезпечивши надійну інфраструктуру для зростання компанії.",
      "summary": "Сервери, мережі та телефонія працювали надійно, і саме цей стабільний фізичний фундамент дав компанії змогу продовжувати зростати, не відчуваючи, як ґрунт…",
      "content_html": "<p><strong>Ситуація.</strong> В основі всього, чим займалася компанія, лежала фізична складова — сервери, реальні мережі, IP‑телефонія — і все це мало просто працювати. Цей рівень непомітний, коли працює справно, і надзвичайно помітний у ту мить, коли перестає, а зростання компанії трималося на його безвідмовності.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб адмініструвати цю інфраструктуру та підтримувати її стабільність у міру зростання компанії.</p>\n<p><strong>Дія.</strong> Обслуговувалися сто bare‑bone серверів разом із фізичними мережами та системами IP‑телефонії — налаштування, обслуговування, усунення несправностей у разі збоїв. Bare‑bone сервери означають роботу безпосередньо з апаратним забезпеченням, тож тут є практична, фізична складова: кабелі, корпуси, телефонна система, збій якої помічають усі в ту саму секунду. Завдання полягало в тому, щоб усе це залишалося нудним — у хорошому сенсі.</p>\n<p><strong>Результат.</strong> Сервери, мережі та телефонія працювали надійно, і саме цей стабільний фізичний фундамент дав компанії змогу продовжувати зростати, не відчуваючи, як ґрунт хитається під ногами.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/developed-100-web-applications-using-html-html5-css-51/",
      "url": "https://engineer.company/uk/portfolio/developed-100-web-applications-using-html-html5-css-51/",
      "title": "Розробила 100 вебзастосунків за допомогою HTML/HTML5, CSS/SCSS, Django, WordPress та Joomla, забезпечивши різноманітну онлайн‑присутність.",
      "summary": "Сто застосунків дали клієнтам різноманітну, дієву присутність онлайн, кожен реалізований на технології, яка справді йому підходила.",
      "content_html": "<p><strong>Ситуація.</strong> Клієнти хотіли вебзастосунки, і хотіли вони дуже різні речі — різні масштаби, різні бюджети, різні рівні від «просто виведіть мене онлайн» до «зробіть мені щось індивідуальне». Відповідати цьому означало бути універсальним, а не заганяти кожного клієнта в межі однієї й тієї самої технології.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб створювати вебзастосунки, які давали б кожному клієнту різноманітну й ефективну присутність онлайн.</p>\n<p><strong>Дія.</strong> Було створено сто вебзастосунків, і суть полягала в тому, щоб підбирати інструмент під завдання, а не мати улюблений. Там, де клієнту потрібне було щось індивідуальне, у хід ішли HTML/HTML5, CSS/SCSS та Django; там, де потрібне було щось більш стандартне, з чим клієнт міг би впоратися і самостійно, швидшою й розумнішою відповіддю ставали WordPress або Joomla. Частина майстерності полягала саме в тому, щоб розрізняти ці випадки — відмовити клієнту в індивідуальній розробці, яка йому не потрібна, або переконати в тій, яка потрібна.</p>\n<p><strong>Результат.</strong> Сто застосунків дали клієнтам різноманітну, дієву присутність онлайн, кожен реалізований на технології, яка справді йому підходила. Саме підбір підходу під клієнта, а не навпаки, зробив їх ефективними, а не просто зданими в експлуатацію.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Python",
        "Веброзробка",
        "Full‑Stack продуктова розробка",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/",
      "url": "https://engineer.company/uk/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/",
      "title": "Спроєктувала 30 вебсайтів, надавши унікальні та гнучкі рішення завдяки перетворенню дизайнів Photoshop на HTML.",
      "summary": "Тридцять сайтів відповідали своїм дизайнам і залишалися придатними до роботи — самобутні, вишукані вебсайти, які не ламалися від першого ж редагування…",
      "content_html": "<p><strong>Ситуація.</strong> Клієнти приходили з бажаним виглядом сайту — часто це вже був готовий візуальний дизайн — і потребували, щоб вебсайт був побудований точно за ним. Розрив між файлом дизайну та робочим сайтом — це саме те місце, де здебільшого виграється або втрачається якість: легко здати щось приблизно правильне, але з непомітними відхиленнями.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб проєктувати сайти й перетворювати дизайни на точні, гнучкі реалізації.</p>\n<p><strong>Дія.</strong> Спроєктовано тридцять вебсайтів, і дизайни з Photoshop вручну перетворено на HTML. Точність була стандартом — відступи, типографіка, деталі, які насправді мав на увазі дизайнер, а не їх наближення — але так само важливою була і гнучкість, адже сайт, який збігається з макетом піксель у піксель, а потім розвалюється щойно змінюється контент, насправді побудовано погано. Тож мета полягала в розмітці, яка залишалася вірною дизайну і водночас лишалася придатною до подальшої підтримки.</p>\n<p><strong>Результат.</strong> Тридцять сайтів відповідали своїм дизайнам і залишалися придатними до роботи — самобутні, вишукані вебсайти, які не ламалися від першого ж редагування контенту. Вірність дизайну при збереженні придатності до підтримки — саме той баланс, що мав значення, і саме до нього прийшли ці сайти.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/",
      "url": "https://engineer.company/uk/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/",
      "title": "Адмініструвала 40 вебсайтів на хостинг‑серверах Ubuntu Linux з Apache та Nginx, забезпечивши високу доступність і продуктивність.",
      "summary": "Усі сорок сайтів працювали з високою доступністю та гарною продуктивністю, що дало клієнтам хостинг, про який не треба було думати.",
      "content_html": "<p><strong>Ситуація.</strong> Існував портфель робочих вебсайтів, які мали залишатися онлайн і швидкими — а хостинг це ще одна з тих робіт, які непомітні, доки сайт не впаде, і от тоді про нього думають усі й нічого більше.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб адмініструвати ці сайти та підтримувати їхню високу доступність і швидкість.</p>\n<p><strong>Дія.</strong> Сорок вебсайтів працювали на хостинг‑серверах Ubuntu Linux, на поєднанні Apache та Nginx — конфігурація, налаштування продуктивності, постійне обслуговування для підтримання надійності під реальним трафіком. Саме реальний трафік тут ключовий: сайт, який нормально почувається, коли ним ніхто не користується, і падає, щойно ним починають користуватися, насправді не адмініструвався — його просто залишили без уваги. Тож робота полягала в тому, щоб підтримувати їхню справність під фактичним навантаженням.</p>\n<p><strong>Результат.</strong> Усі сорок сайтів працювали з високою доступністю та гарною продуктивністю, що дало клієнтам хостинг, про який не треба було думати. Стабільність і надійність під реальним використанням — це вся суть хостингу, і саме це забезпечили ці сайти.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Веброзробка",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Системне адміністрування",
        "Надійність та моніторинг (SRE)",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/engineered-600-pl-pgsql-based-etl-elt-pipelines-54/",
      "url": "https://engineer.company/uk/portfolio/engineered-600-pl-pgsql-based-etl-elt-pipelines-54/",
      "title": "Розробила 600 пайплайнів ETL/ELT на основі PL/pgSQL для оптимізації складних робочих процесів обробки даних у кількох середовищах розробки та продакшн PostgreSQL.",
      "summary": "Новий фреймворк ETL/ELT суттєво покращив узгодженість, надійність і продуктивність процесів обробки даних: - Досягнуто скорочення середнього часу виконання…",
      "content_html": "<p><strong>Ситуація.</strong> Організація опрацьовувала великі обсяги транзакційних та аналітичних даних у кількох середовищах розробки й продакшн PostgreSQL. Наявні пайплайни даних були фрагментованими, не мали узгодженості й спричиняли вузькі місця продуктивності, що призводило до затримок у критично важливій для бізнесу звітності та ухваленні рішень.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб спроєктувати та реалізувати надійні, масштабовані й ефективні пайплайни ETL/ELT на основі PL/pgSQL для впорядкування складних робочих процесів приймання, трансформації та завантаження даних. Ключовою метою було покращити продуктивність запитів і забезпечити цілісність даних у всіх середовищах.</p>\n<p><strong>Дія.</strong> Розроблено понад 600 пайплайнів ETL/ELT на основі PL/pgSQL для автоматизації видобування, трансформації та завантаження даних із різних джерел. Основні технічні рішення включали:</p>\n<ul>\n<li>Використання партиціонованих таблиць і матеріалізованих подань для оптимізації продуктивності читання великих наборів даних.</li>\n<li>Застосування обмежень первинного та зовнішнього ключів для підтримання референційної цілісності під час трансформацій.</li>\n<li>Проєктування унікальних і композитних індексів для прискорення операцій JOIN та складних умов фільтрації.</li>\n<li>Впровадження обробки винятків і транзакційного контролю для забезпечення відмовостійкості й відкату у разі збоїв.</li>\n<li>Реалізація інкрементальних завантажень за допомогою механізмів change data capture (CDC) та дельт на основі часових міток, що скоротило час обробки більш ніж на 60%.</li>\n<li>Розроблення автоматизованих процедур логування та аудиту для відстеження виконання пайплайнів, моніторингу аномалій і полегшення налагодження.</li>\n</ul>\n<p><strong>Результат.</strong> Новий фреймворк ETL/ELT суттєво покращив узгодженість, надійність і продуктивність процесів обробки даних:</p>\n<ul>\n<li>Досягнуто скорочення середнього часу виконання пайплайну на 35%.</li>\n<li>Збільшено пропускну здатність пайплайнів даних більш ніж на 50%, що уможливило доступність даних для звітності у режимі, близькому до реального часу.</li>\n<li>Скорочено проблеми з якістю даних шляхом усунення понад 90% помилок трансформації завдяки кращому забезпеченню обмежень і логіці валідації.</li>\n<li>Покращено супроводжуваність і масштабованість, що підтримує майбутні зміни моделі даних із мінімальною переробкою.</li>\n</ul>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "PostgreSQL",
        "SQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Пайплайни даних (ETL/ELT)",
        "Data Governance та якість даних",
        "Адміністрування баз даних (DBA)",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/",
      "url": "https://engineer.company/uk/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/",
      "title": "Спроєктувала, розробила, впровадила та підтримувала інфраструктуру, обробку даних і картографічний застосунок безперервно протягом 2 років без вихідних, свят чи відпустки, по 10–14 годин на день.",
      "summary": "Платформа залишалася безперервно доступною та еволюціонувала від крихкого раннього прототипу до надійного хребта продукту, підтримуючи компанію протягом…",
      "content_html": "<p><strong>Ситуація.</strong> Стартап у сфері зеленої енергетики на ранній стадії розвитку залежав від єдиної платформи для відстеження, моніторингу та оптимізації активів відновлюваної енергетики, проте не мав ані окремої інфраструктурної команди, ані сформованої інженерної організації для її побудови й експлуатації. Усю технічну основу — хмарну інфраструктуру, пайплайни обробки даних і клієнтський GIS‑застосунок з картою — потрібно було створити й підтримувати в безперервній роботі на ринку, де будь‑який простій чи розрив у даних напряму підривав довіру клієнтів і дохід.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб одноосібно спроєктувати, побудувати та експлуатувати всю систему наскрізно, охоплюючи інженерію платформи й даних, DevOps та забезпечення надійності (site reliability). Окрім написання коду, це означало відповідальність за продакшн: розгортання та убезпечення інфраструктури, проєктування рівня обробки даних, що живив карту, і гарантування безперервної доступності застосунку для зростаючої бази клієнтів — і все це в межах обмежень і невпинного темпу стартапу, що стрімко розвивався.</p>\n<p><strong>Дія.</strong> Протягом двох років інфраструктура, пайплайни даних і картографічний застосунок проєктувалися, впроваджувалися та підтримувалися без перерв — без вихідних, свят чи відпусток, часто по 10–14 годин на день. Було обрано прагматичну, модульну архітектуру, щоб зберегти придатність до підтримки одноосібної експлуатації, з автоматизованим розгортанням, моніторингом та сповіщеннями, аби проблеми виявлялися й вирішувалися швидко. Обробка даних постійно донастроювалася для надійності та продуктивності, релізи випускалися поступово, і кожен рівень — від серверів до карти, орієнтованої на користувача, — підтримувався та вдосконалювався особисто, у відповідь на реальне використання клієнтами.</p>\n<p><strong>Результат.</strong> Платформа залишалася безперервно доступною та еволюціонувала від крихкого раннього прототипу до надійного хребта продукту, підтримуючи компанію протягом критичної фази зростання завдяки одноосібній відповідальності одного інженера. Таке безпосереднє, практичне управління забезпечувало достатню надійність інфраструктури, даних і картографічного застосунку для підтримки допродажів, ліцензування даних і залучення нових клієнтів, а також продемонструвало рідкісний рівень відданості, широти охоплення й наскрізної відповідальності на всіх рівнях стеку.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Full‑Stack розробка",
        "GIS / геопростір",
        "Архітектура платформи",
        "Інженерія даних",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Пайплайни даних (ETL/ELT)",
        "Full‑Stack продуктова розробка",
        "GIS та геопросторові рішення",
        "Архітектура платформи та рішень",
        "Надійність та моніторинг (SRE)",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/",
      "url": "https://engineer.company/uk/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/",
      "title": "Оптимізувала бюджетні витрати у 10 разів без втрати продуктивності для міжнародного клієнта, переосмисливши загальну інфраструктуру, усунувши непотрібні сервіси та перенісши систему з хмари AWS.",
      "summary": "Бюджетні витрати скоротилися приблизно у 10 разів, без жодної втрати продуктивності — та сама спроможність за частку тієї суми, яку сплачували раніше.",
      "content_html": "<p><strong>Ситуація.</strong> Міжнародний клієнт ніс на собі суттєво роздуті інфраструктурні витрати. Її налаштування AWS було надлишково забезпечене ресурсами й накопичило сервіси, якими вже ніхто не користувався, тож рахунок за хмару повністю вийшов з будь‑якої пропорції до того, що бізнесу дійсно було потрібно. Історія звична — ніхто не планує перевитрачати, це просто накопичується, коли ніхто не стежить за лічильником.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб суттєво скоротити витрати без жодної втрати продуктивності, а це означало по‑справжньому переосмислити інфраструктуру, а не підрізати по краях — підрізання по краях рідко відчутно змінює рахунок, який структурно є занадто великим.</p>\n<p><strong>Дія.</strong> Тож робота велася наскрізно. Спочатку проведено аудит того, що фактично використовувалося — саме тут проявляють себе дубльовані та непотрібні сервіси — і їх було прибрано. Потім усе, що залишилося, приведено у відповідність до реального попиту замість розрахунків на найгірший сценарій, закладених у початкове налаштування. А головним кроком стало повне перенесення навантажень з AWS на більш економічно вигідний варіант хостингу — виконане обережно, поетапно, так, щоб діючий бізнес жодного разу не відчув, як під ним відбувається міграція.</p>\n<p><strong>Результат.</strong> Бюджетні витрати скоротилися приблизно у 10 разів, без жодної втрати продуктивності — та сама спроможність за частку тієї суми, яку сплачували раніше. Це вивільнило реальну суму коштів, яка місяць за місяцем тихо витікала у надто великий рахунок за хмару, а для бізнесу це означало гроші, що напряму повернулися до чистого прибутку.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Архітектура платформи",
        "Архітектура рішень",
        "Інфраструктура",
        "Міграції та модернізація",
        "DevOps та автоматизація CI/CD",
        "Архітектура платформи та рішень",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/",
      "url": "https://engineer.company/uk/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/",
      "title": "Спроєктувала багаторівневу морську платформу, розділивши фронтенд Next.js PWA, API на Go (Huma/Fiber) та рівень функцій PostgreSQL, зберігши всю бізнес‑логіку в базі даних.",
      "summary": "Систему й далі було легко тримати в голові. Бізнес-логіка розташована в одному місці, яке справді можна перевірити, API — нудний у хорошому сенсі адаптер, а…",
      "content_html": "<p><strong>Ситуація.</strong> Продукт мав стати морською платформою — професійні мережі, відгуки про компанії, спонсорована освіта — і це був молодий продукт, що є ввічливим способом сказати, що вимоги мали суттєво змінюватися. Чого варто було уникнути — це архітектури, у якій зміна бізнес‑правила означала одночасне втручання у фронтенд, API та базу даних. На невеликій кодовій базі, яка швидко росте, саме такий рівень зв&rsquo;язаності перетворює зміну у два рядки коду на роботу на ціле пообіддя.</p>\n<p><strong>Завдання.</strong> Як архітектору, першим рішенням, яке треба було ухвалити, було те, де мала жити кожна логіка, з межами, достатньо чіткими, щоб витримувати тиск, а не розмиватися, щойно хтось поспішав.</p>\n<p><strong>Дія.</strong> Усе усталилося у три рівні, кожен зі своєю роллю. Фронтенд на Next.js відповідає за представлення й інтерактивність і більше ні за що. API на Go — Huma поверх Fiber — навмисно тонкий: він маршрутизує, валідує запит, застосовує фільтрацію безпеки та оркеструє, але не містить жодної бізнес‑логіки. Уся бізнес‑логіка живе у функціях PostgreSQL, які збирають повний результат і повертають його, щоб API просто передав далі. Тож коли правило змінюється, воно змінюється в одному рівні, у SQL, а решта двох про це навіть не знають. Межі було зафіксовано письмово, а потім закріплено через код‑рев&rsquo;ю, адже конвенція, яку ніхто не контролює, перестає бути конвенцією.</p>\n<p><strong>Результат.</strong> Систему й далі було легко тримати в голові. Бізнес‑логіка розташована в одному місці, яке справді можна перевірити, API — нудний у хорошому сенсі адаптер, а фронтенд не переймається, коли схема змінюється під ним. Саме це розділення дало продукту змогу й далі нарощувати функціональність без тихого гниття архітектури.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "PostgreSQL",
        "Архітектура платформи",
        "Архітектура рішень",
        "Бази даних",
        "Технічне лідерство",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Архітектура платформи та рішень",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/",
      "url": "https://engineer.company/uk/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/",
      "title": "Спроєктувала архітектуру наскрізної передачі JSON, у якій функції PostgreSQL повертають повний JSON, що дослівно пересилається через Go API, усунувши проміжний unmarshalling та унезалежнивши фронтенд від змін схеми.",
      "summary": "Код обробників став суттєво коротшим, а що важливіше — фронтенд перестав бути прив'язаним до Go. Достатньо змінити те, що повертає функція, і нова форма даних…",
      "content_html": "<p><strong>Ситуація.</strong> Звичний шлях даних від бази до браузера — це естафета трансформацій. База даних передає API рядки, API десеріалізує їх у структури (structs), переформатовує, серіалізує назад у JSON, і лише тоді дані йдуть далі. Кожен із цих переходів — це код, який потрібно написати, код, який потрібно протестувати, і ще одне місце, де уявлення API про дані та уявлення бази даних про них можуть розійтися.</p>\n<p><strong>Завдання.</strong> Ідея полягала в тому, щоб прибрати цю естафету. Якщо база даних могла б повертати готову відповідь, API міг би просто передавати її далі, а фронтенд міг би залежати безпосередньо від форми даних бази даних замість її вручну підтримуваної копії, що живе в Go.</p>\n<p><strong>Дія.</strong> Тож це було побудовано як пряму передачу без проміжних перетворень. Функції PostgreSQL збирають усю відповідь у вигляді JSON — формування є завданням SQL, виконуваним там, де дані вже є. Обробник на Go отримує це назад як json.RawMessage і передає далі без змін; він ніколи не розкладає це на частини, ніколи не перекодовує. Невеликий допоміжний метод QueryJSON перетворив цей патерн на шлях найменшого опору, а не на те, про що щоразу треба пам&rsquo;ятати окремо. Випало все проміжне обладнання, яке зазвичай накопичує традиційний шаруватий API — DTO, мапери, структури відповідей.</p>\n<p><strong>Результат.</strong> Код обробників став суттєво коротшим, а що важливіше — фронтенд перестав бути прив&rsquo;язаним до Go. Достатньо змінити те, що повертає функція, і нова форма даних напряму доходить до клієнта без редагування жодного рядка коду обробника. Менше рухомих частин, і цілий клас розбіжностей між рівнями тут просто не існує.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "PostgreSQL",
        "SQL",
        "Архітектура платформи",
        "Бази даних",
        "Оптимізація продуктивності",
        "Backend- та API‑розробка",
        "Архітектура платформи та рішень",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-an-organization-context-switching-system-with-client-59/",
      "url": "https://engineer.company/uk/portfolio/designed-an-organization-context-switching-system-with-client-59/",
      "title": "Спроєктувала систему перемикання контексту організації з клієнтським localStorage та серверним дзеркалюванням cookie, що дозволила користувачам діяти від імені керованих організацій, забезпечуючи авторизацію за принципом найменших привілеїв.",
      "summary": "Користувач може діяти від імені будь-якої організації, якою керує, без жодних перешкод, а інтерфейс залишається синхронізованим і на клієнті, і на сервері.",
      "content_html": "<p><strong>Ситуація.</strong> На платформі морський фахівець може керувати організаціями — компаніями, академіями — які не мають власних облікових записів для входу. Обліковим записом є сама людина; організація — це те, від імені чого вона діє. Тож користувачу потрібно переміщуватися по всьому застосунку як будь‑яка з організацій, якими він керує, вільно перемикаючись між ними, і ця зручність не повинна перетворюватися на діру в авторизації.</p>\n<p><strong>Завдання.</strong> Перемикання контексту мало бути швидким і непомітним для користувача, і водночас потрібно було гарантувати, що активний контекст сам собою ніколи не надасть доступу, на який немає прав.</p>\n<p><strong>Дія.</strong> За це відповідає OrganizationContext зі зберіганням стану на обох сторонах. На клієнті джерелом істини щодо того, від імені якої організації користувач наразі діє, є localStorage, тож перемикання відбувається миттєво — без звернення до сервера. Серверний cookie дзеркалить цей стан, щоб сторінки, що рендеряться на сервері, визначали той самий контекст під час SSR; на сервері є getServerViewMode, який його зчитує. Важливо, що жодне з цього не використовується для ухвалення рішень щодо доступу. Авторизація повторно перевіряється на сервері під час кожного запиту. Контекст на фронтенді існує заради досвіду користування — показати саме те, що потрібно, — а сервер є єдиним джерелом істини щодо того, що дозволено робити.</p>\n<p><strong>Результат.</strong> Користувач може діяти від імені будь‑якої організації, якою керує, без жодних перешкод, а інтерфейс залишається синхронізованим і на клієнті, і на сервері. Але оскільки права щоразу перевіряються на сервері, ця зручність жодним чином не послаблює безпеку. Втручання у вміст localStorage змінює лише те, що бачить власний інтерфейс користувача, і нічого більше — сервер усе одно відмовить.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Архітектура платформи",
        "Безпека",
        "Backend- та API‑розробка",
        "Архітектура платформи та рішень",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/migrated-the-http-api-from-fiber-to-huma-60/",
      "url": "https://engineer.company/uk/portfolio/migrated-the-http-api-from-fiber-to-huma-60/",
      "title": "Мігрувала HTTP API з Fiber на Huma v2 — 649 шляхів і 760 операцій — досягнувши та втримавши 100% відповідність між маршрутами, які реєструє сервер, і описом OpenAPI, який він публікує.",
      "summary": "Нові ендпоінти отримують валідацію та актуальну документацію без додаткових зусиль, а цілий клас помилок обробки запитів — на кшталт «ой, а тут ми забули…",
      "content_html": "<p><strong>Ситуація.</strong> API розпочинав своє життя на Fiber, із валідацією запитів, написаною вручну для кожного ендпоінта окремо. Це нормально, коли ендпоінтів жменька. Але перестає бути нормальним, коли поверхня API розростається: рукописна валідація перетворюється на податок на підтримку, а дрібні неузгодженості накопичуються, бо перевірки кожного ендпоінта — це своя окрема сніжинка. І ніде не було жодного єдиного опису форми API.</p>\n<p><strong>Завдання.</strong> Метою було отримати валідацію, що походить із типів, а не з рукописних перевірок, і справжній контракт, який описує API, — без зупинки на повномасштабне переписування.</p>\n<p><strong>Дія.</strong> HTTP‑рівень перенесено на Huma v2 поверх Fiber, тож наявний рантайм зберігся. Кожен ендпоінт отримує вхідні та вихідні структури (structs), а Huma генерує валідацію запитів і моделювання відповіді на основі цих типів. Опис OpenAPI виходить із цього безкоштовно, а це означає, що документація йде в ногу з кодом, а не застаріває десь у вікі. Усе нове писалося під Huma, а наявні маршрути перенесено, залишивши рівно два ендпоінти на чистому Fiber — це WebSocket‑ендпоінти, де справді потрібен саме сокет, а модель запиту/відповіді Huma не підходить. Те, у що це виросло, — 649 шляхів із 760 операціями та перевірка в CI, яка порівнює маршрути, що їх сервер справді реєструє, з тими, що їх декларує опис OpenAPI. Паритет становить 100%, і він там і лишається, бо маршрут, який не описано, завалює білд.</p>\n<p><strong>Результат.</strong> Нові ендпоінти отримують валідацію та актуальну документацію без додаткових зусиль, а цілий клас помилок обробки запитів — на кшталт «ой, а тут ми забули перевірити це поле» — зник. На 760 операціях цей опис — єдиний практичний спосіб, у який хтось узагалі читає API, тож гарантія його повноти важить більше, ніж важила на п&rsquo;ятдесяти. Типізований контракт зробив API одночасно безпечнішим для змін і простішим для передачі іншій людині, адже типи самі повідомляють, чого очікує ендпоінт.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Архітектура платформи",
        "Документація",
        "Міграції та модернізація",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "Архітектура платформи та рішень",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-request-schema-validation-contract-with-automated-61/",
      "url": "https://engineer.company/uk/portfolio/built-a-request-schema-validation-contract-with-automated-61/",
      "title": "Згенерувала контракт API з бази даних назовні — OpenAPI, типізований TypeScript‑клієнт на 44 076 рядків, 61 mock‑обробник та обмеження, які застосовує UI, — з перевіркою на кожній ланці, що падає при розходженні.",
      "summary": "Поле не може змінитися лише з одного боку — воно завалюється на першому ж переході, який це помічає, у білді, за кілька хвилин після зміни.",
      "content_html": "<p><strong>Ситуація.</strong> Фронтенд і бекенд розвиваються у власному темпі, і їхні уявлення про payload запиту можуть непомітно розходитися. Зазвичай про це дізнаються за 422 у браузері — вже після того, як розбіжність потрапила в продакшн, а це найдорожчий момент, щоб про неї дізнатися. Написання обох сторін вручну за одним документом цього не виправляє: воно лише переносить розбіжність на того, хто забув перечитати документ.</p>\n<p><strong>Завдання.</strong> Обидві сторони мали генеруватися з одного джерела, а не узгоджуватися між двома, і кожен крок цієї генерації мав перевірятися, а не братися на віру.</p>\n<p><strong>Дія.</strong> Ланцюг починається з бази даних і йде назовні. Схема та її функції визначають структури даних; типи Go визначають API; Huma формує з них опис OpenAPI; з цього опису генерується типізований клієнт TypeScript — 44 076 рядків; поряд із ним генерується 61 mock‑обробник, тож власні тести фронтенду виконуються проти реального контракту, а не проти рукописної фікстури; а обмеження, які UI застосовує до форми, походять із того самого місця, замість того щоб їх перенабирали у валідаторі. Кожен перехід має запобіжник. Перевірка контракту в CI порівнює те, що надсилає фронтенд, із тим, що очікує API, і завалює білд за розбіжності, а під нею є перевірка схеми, яка звіряє реальну структуру даних, а не її опис. Вона свідомо охоплює місця, де розбіжності люблять ховатися: опціональні поля тіла запиту, де плутають «відсутнє» і null, та enum‑и query‑параметрів, де обидві сторони можуть тихо розійтися в допустимих значеннях.</p>\n<p><strong>Результат.</strong> Поле не може змінитися лише з одного боку — воно завалюється на першому ж переході, який це помічає, у білді, за кілька хвилин після зміни. Це усунуло повторюваний і по‑справжньому набридливий клас багів: непомітний під час code review і такий, що проявляється лише в рантаймі. Ціна — крок генерації посеред усього: перегенерація є рутиною, а ланцюг вартий довіри рівно настільки, наскільки надійна його найменш захищена ланка, — тому запобіжник отримав кожен перехід.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "DevOps",
        "Автоматизація та CI/CD",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-email-as-a-platform-capability-with-failover-62/",
      "url": "https://engineer.company/uk/portfolio/built-email-as-a-platform-capability-with-failover-62/",
      "title": "Побудувала електронну пошту як можливість платформи — три провайдери з резервним перемиканням, webhooks доставки, логування надсилання й доставки, шаблонізацію та кампанії — за перевіркою під час запуску, яка не дасть застосунку стартувати без жодного з них.",
      "summary": "Ціла категорія тихих збоїв перейшла зі стану «користувач помічає це через кілька днів» у стан «розгортання зупиняється», а невдалий день у провайдера став…",
      "content_html": "<p><strong>Ситуація.</strong> Електронна пошта відіграє значну роль на платформі — верифікація, сповіщення, дайджести, кампанії, усе те, на що користувач насправді чекає. А поштовий провайдер — це саме той тип залежності, що тихо ламається: конфігурація виглядає нормально, застосунок запускається, і про проблему дізнаються лише тоді, коли реальна людина так і не отримує обіцяного листа. Це найгірший спосіб про це дізнатися. З одним провайдером усе ще гірше, бо збій є повним, а виправляти його — комусь іншому.</p>\n<p><strong>Завдання.</strong> Пошту потрібно було трактувати як спроможність, якою володіє платформа, а не як клієнтську бібліотеку, яку вона викликає, — здатну пережити збій провайдера, здатну сказати, що сталося з конкретним листом, і голосну під час запуску в тих середовищах, де мовчання небезпечне.</p>\n<p><strong>Дія.</strong> Три провайдери стоять за одним інтерфейсом — SendGrid як основний, а SMTP2GO та Azure Communication Services позаду нього, — і перемикання між ними автоматичне, а не є зміною конфігурації, зробленою під тиском. Доставка не вважається даністю: вхідні webhooks повідомляють, що кожен провайдер зробив із листом, і обидві сторони записуються — у журнал надсилань і таблицю подій доставки, — тож «чи отримала ця людина свій лист із верифікацією» є запитом, а не здогадом. Шаблонізація тримає тіла листів поза кодом, а окрема схема broadcast — 5 таблиць і 24 функції — доставляє кампанії сегментам користувачів, і це інша задача, ніж транзакційна пошта, тож її й будували як іншу. Перед усім цим стартова перевірка надсилає реальний лист через увесь стек, за прапорцем: у середовищі розробки це просто логує попередження й продовжує роботу, бо ніхто не хоче, щоб ноутбук відмовлявся запускатися через прострочений ключ пісочниці, а в staging і production збій є фатальним і процес завершується, а не розгортає білд, який не може надсилати пошту. Сам шлях надсилання проходить через клієнт із захистом від SSRF і тайм‑аутом 30 секунд, а асинхронний шлях доставки має retries і backoff, тож короткочасний збій не втрачає повідомлення.</p>\n<p><strong>Результат.</strong> Ціла категорія тихих збоїв перейшла зі стану «користувач помічає це через кілька днів» у стан «розгортання зупиняється», а невдалий день у провайдера став деградованим шляхом, а не аварією. Ціна — три інтеграції, які треба підтримувати робочими замість однієї, і журнали доставки, що ростуть і потребують чищення; обидві прийнятні, бо пошта — це канал, який платформа не може обійти.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Cloud",
        "Безпека",
        "Надійність і резервне копіювання",
        "Backend- та API‑розробка",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-a-postgresql-function-first-data-layer-across-63/",
      "url": "https://engineer.company/uk/portfolio/designed-a-postgresql-function-first-data-layer-across-63/",
      "title": "Спроєктувала рівень даних PostgreSQL, побудований насамперед на функціях — 1 275 збережених функцій у 34 схемах — щоб кожне читання й кожен запис проходили через функцію, на яку база даних може видати права, а не через таблицю.",
      "summary": "Логіка живе в одному місці, яке справді можна перевірити, API лишається тонким і нудним у хорошому сенсі, а межу доступу забезпечує сам Postgres, а не те, що…",
      "content_html": "<p><strong>Ситуація.</strong> Бізнес‑логіка має звичку просочуватися. Частина потрапляє в API, частина — у якийсь SQL, що виконується прямо в обробнику, і незабаром те саме правило виявляється записаним двома‑трьома трохи різними способами, і немає жодного місця, на яке можна вказати й сказати: «ось що система робить зі своїми даними». Так у систему потрапляють баги й діри в безпеці.</p>\n<p><strong>Завдання.</strong> Метою було одне місце для всього цього: кожне читання й запис проходить через базу даних, API залишається тонким адаптером, який не знає бізнес‑правил, а все разом можна щільно замкнути.</p>\n<p><strong>Дія.</strong> Рівень даних побудовано за принципом function‑first. Схему поділено за доменами — identity, organization, review, message, notification і ще 29 інших, 34 разом, — і кожна операція, яку може виконати застосунок, є однією з 1 275 функцій PostgreSQL, які він викликає; прямого доступу до таблиць із Go взагалі немає. Далі це забезпечує сама база даних. Роль, під якою логіниться API, mariner, має EXECUTE на функціях застосунку та USAGE на схемах — і нічого більше: жодного SELECT, жодного INSERT, жодного способу торкнутися таблиці напряму — а це виходить приблизно 4 000 явних грантів, а не один загальний. Функції виконуються як SECURITY DEFINER, належать окремій non‑login ролі function_owner із зафіксованим search_path, а обліковий запис суперкористувача лишається зарезервованим для міграцій і cron, подалі від застосунку, що працює.</p>\n<p><strong>Результат.</strong> Логіка живе в одному місці, яке справді можна перевірити, API лишається тонким і нудним у хорошому сенсі, а межу доступу забезпечує сам Postgres, а не те, що всі пам&rsquo;ятають правила. Якщо API раптом буде скомпрометовано, воно все одно не зможе зробити нічого, чого не дозволяють функції. На 1 275 функціях ця дисципліна коштує чогось реального — нове поле означає міграцію та зміну функції, а не рядок у запиті, — і це тертя є ціною того, що межа тримається.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Data Governance",
        "PostgreSQL",
        "SQL",
        "Архітектура платформи",
        "Бази даних",
        "Безпека",
        "Backend- та API‑розробка",
        "Data Governance та якість даних",
        "Архітектура платформи та рішень",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/adopted-uuid-v7-time-ordered-identifiers-postgresql-18-64/",
      "url": "https://engineer.company/uk/portfolio/adopted-uuid-v7-time-ordered-identifiers-postgresql-18-64/",
      "title": "Впровадила часовпорядковані ідентифікатори UUID v7 (PostgreSQL 18) як ключі сутностей, щоб зменшити фрагментацію індексів B‑tree та пришвидшити запити.",
      "summary": "Id лишилися глобально унікальними, індекс перестав фрагментуватися так, як це роблять випадкові UUID, а часово впорядковані вставки й range-запити стали…",
      "content_html": "<p><strong>Ситуація.</strong> Кожній сутності потрібен унікальний id, і рефлекторний вибір — випадковий UUID. Проблема в тому, що випадкові id розкидані по всьому B‑tree‑індексу. Вставки розсіюються, індекс фрагментується, і зі зростанням таблиць за це платять і записи, і range‑скани. На платформі, яка й далі має зростати, це повільна витрата, яку краще не закладати в архітектуру.</p>\n<p><strong>Завдання.</strong> Зберегти глобальну унікальність UUID, але позбутися фрагментації, яку спричиняє випадковість.</p>\n<p><strong>Дія.</strong> Стандартом став UUID v7 — часово впорядкований формат: перші біти є міткою часу, тож нові рядки вбудовуються в індекс, а не розсипають його. PostgreSQL 18 підтримує це нативно як uuidv7(), обгорнуте в невелику функцію uuid_generate_v7(), щоб той самий виклик коректно поводився на Azure Flexible Server, і зроблено значенням за замовчуванням для первинних ключів сутностей у всій схемі. Нічого екзотичного; це саме те рішення, яке дешеве, якщо прийняти його рано, і болісне, якщо доводиться впроваджувати заднім числом.</p>\n<p><strong>Результат.</strong> Id лишилися глобально унікальними, індекс перестав фрагментуватися так, як це роблять випадкові UUID, а часово впорядковані вставки й range‑запити стали швидшими — рівномірно, на всіх таблицях, без потреби комусь про це думати. Як бонус, кожна сутність отримує ключ, за яким можна безкоштовно сортувати за часом.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "PostgreSQL",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Оптимізація продуктивності баз даних",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/",
      "url": "https://engineer.company/uk/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/",
      "title": "Впровадила deep‑merge на основі каталогу для збережених JSON‑налаштувань, запобігши збоям через відсутні ключі при еволюції схеми.",
      "summary": "Налаштування можуть зростати без побоювань. Додавання параметра більше не ризикує крашем через undefined-поле на клієнті, а фронтенд перестав потребувати…",
      "content_html": "<p><strong>Ситуація.</strong> Платформа зберігає JSON‑налаштування — налаштування сповіщень і подібне — як збережені значення користувача, накладені поверх набору значень за замовчуванням. Початкове злиття робило це на одному рівні. Проблема виявляється пізніше: додається новий ключ до значень за замовчуванням, а рядки, збережені до появи цього ключа, просто його не мають. Тоді якийсь клієнтський код читає це поле, отримує undefined і падає — саме для тих користувачів, які тут найдовше.</p>\n<p><strong>Завдання.</strong> Розвиток схеми налаштувань мав бути безпечним, щоб додавання нового параметра ніколи не ламало людей, які зареєструвалися до того, як він з&rsquo;явився.</p>\n<p><strong>Дія.</strong> Однорівневе злиття замінено на deep‑merge, керований значеннями за замовчуванням як каталогом. Значення за замовчуванням розглядаються як авторитетний перелік усіх ключів, які мають існувати; збережені значення користувача рекурсивно накладаються зверху, тож усе, що є в каталозі, гарантовано присутнє на виході — незалежно від того, чи було воно в збереженому blob. Додається ключ до значень за замовчуванням — і він автоматично з&rsquo;являється в ефективних налаштуваннях кожного наявного рядка, включно з вкладеними ключами. Це впроваджено через міграцію, тож наявні дані отримали перевагу одразу, а не чекали на переписування.</p>\n<p><strong>Результат.</strong> Налаштування можуть зростати без побоювань. Додавання параметра більше не ризикує крашем через undefined‑поле на клієнті, а фронтенд перестав потребувати захисних перевірок, розкиданих у кожному місці, де він читає налаштування. Це також дало решті платформи надійний спосіб розширювати будь‑який збережений JSON‑blob — не лише окреме виправлення, а й сам патерн.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Data Governance",
        "PostgreSQL",
        "Бази даних",
        "Міграції та модернізація",
        "Backend- та API‑розробка",
        "Data Governance та якість даних",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/",
      "url": "https://engineer.company/uk/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/",
      "title": "Змоделювала морський домен — фахівців, компанії, судна, вакансії, відгуки та решту — у 348 нормалізованих таблицях у межах 34 схем PostgreSQL, з довідниками SMALLINT та ключами UUID v7.",
      "summary": "Результатом стала модель даних, яка є послідовною і швидкою, а працювати з нею передбачувано, бо ті самі правила діють усюди — немає особливих випадків, які…",
      "content_html": "<p><strong>Ситуація.</strong> Серцем платформи є щільний морський домен — фахівці, компанії, судна, вакансії, відгуки, — і всі ці сутності постійно посилаються одна на одну. Фахівець ходить у рейси на суднах, працює в компаніях, залишає відгуки; компанія володіє суднами й публікує вакансії. Майже кожна функція — це запит через усю цю мережу зв&rsquo;язків, тож від того, наскільки добре змодельовані дані, залежить, наскільки добре працює більшість застосунку і наскільки розумно його розширювати.</p>\n<p><strong>Завдання.</strong> Цей домен потрібно було змоделювати так, щоб він лишався швидким і зберігав цілісність, а додавання наступного типу сутності не перетворювалося на боротьбу зі схемою.</p>\n<p><strong>Дія.</strong> Дані організовано як нормалізовані схеми PostgreSQL, згруповані за доменами, — 348 таблиць у 34 схемах на цей момент. Численні дрібні стабільні переліки — статуси, типи, категорії — перетворено на довідкові таблиці SMALLINT, що робить рядки компактними, а джойни дешевими, замість того щоб зберігати текстові коди всюди. Сутності отримують первинні ключі UUID v7, тож вони глобально унікальні, але водночас часово впорядковані в індексі. Крізь усе проходить одна угода про іменування — таблиці в множині всередині схем з іменами в однині, — застосована без винятків, що як бонус дає змогу уникнути багатьох конфліктів із зарезервованими словами. А зв&rsquo;язки підтримуються реальними foreign key та constraints, тож цілісність — це робота бази даних, а не те, що застосунок мусить пам&rsquo;ятати сам.</p>\n<p><strong>Результат.</strong> Результатом стала модель даних, яка є послідовною і швидкою, а працювати з нею передбачувано, бо ті самі правила діють усюди — немає особливих випадків, які треба запам&rsquo;ятовувати. Додавання функції зазвичай означає розширення схеми за наявною логікою, а не боротьбу проти неї, і це єдина причина, чому 34 схеми — це структура, а не розповзання. Це той фундамент, на якому стоїть решта платформи.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "PostgreSQL",
        "SQL",
        "Архітектура платформи",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Data Governance та якість даних",
        "Архітектура платформи та рішень",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/",
      "url": "https://engineer.company/uk/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/",
      "title": "Розгорнула інфраструктуру Azure як код за допомогою Bicep — Container Apps, PostgreSQL Flexible Server, Front Door/WAF та мережу — у середовищах development, staging і production.",
      "summary": "Середовища стали відтворюваними й доступними для перегляду. Дрейф перестав бути загадкою, бо джерелом істини є код, а підняти чи відновити інфраструктуру — це…",
      "content_html": "<p><strong>Ситуація.</strong> Платформа живе на Azure, а Azure, зроблений вручну — клацання по порталу, налаштування то тут, то там, — це пастка. Усе дрейфує, ніхто не пам&rsquo;ятає, чому щось саме таке, яке є, а відновлення після поганого дня повільне й нервове. А коли середовищ, які треба тримати синхронізованими, більше одного, стає тільки гірше.</p>\n<p><strong>Завдання.</strong> Перевести все в код, щоб середовище було чимось, що можна прочитати, переглянути й відтворити, а не купою ручного стану.</p>\n<p><strong>Дія.</strong> Уся інфраструктура описана в Bicep. Кожне середовище — testing, staging, product — виходить із тих самих шаблонів: api та www працюють як Azure Container Apps у managed environment, PostgreSQL Flexible Server, Redis для кешування, Front Door з політикою WAF попереду та мережа під цим усім (VNet, NSG, приватний DNS), з підключеним Log Analytics для діагностики. Образи витягуються з Azure Container Registry проєкту. Оскільки все параметризовано, розгортання нового середовища чи зміна наявного — це pull request, а не заявка в підтримку самому собі.</p>\n<p><strong>Результат.</strong> Середовища стали відтворюваними й доступними для перегляду. Дрейф перестав бути загадкою, бо джерелом істини є код, а підняти чи відновити інфраструктуру — це питання застосування шаблонів, а не пригадування, що клацали минулого разу. Це різниця між інфраструктурою, яку контролюють, і інфраструктурою, що починає контролювати сама.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Автоматизація та CI/CD",
        "Архітектура платформи",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/",
      "url": "https://engineer.company/uk/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/",
      "title": "Побудувала пайплайни CI/CD на GitHub Actions з distroless‑образом продакшн‑фронтенду та просуванням між кількома середовищами.",
      "summary": "Релізи перестали бути обережним ручним ритуалом і стали рутинною, нудною подією, а це саме те, чого хочеться від релізів.",
      "content_html": "<p><strong>Ситуація.</strong> Постачання не повинне залежати від того, чи хтось пам&rsquo;ятає всі кроки, а те, що зрештою працює в продакшн, не повинне бути товстим контейнером загального призначення з оболонкою та пакетним менеджером, якими він ніколи не скористається, — це просто зайва поверхня для атак без жодної потреби.</p>\n<p><strong>Завдання.</strong> Зробити шлях від коміту до запуску в Azure автоматичним і тримати продакшн‑образи такими малими й закритими, наскільки дозволяє кожне навантаження.</p>\n<p><strong>Дія.</strong> Пайплайн побудовано на GitHub Actions. Окремі workflow відповідають за перевірку якості коду, тести й розгортання для кожного середовища, а поруч працюють CodeQL, dependency review та крок формування SBOM, тож нічого не потрапляє в середовище без попереднього проходження перевірок. Образи — це multi‑stage‑білди, і базовий образ для кожної частини обрано за його перевагами, а не за єдиним загальним правилом: фронтенд постачається на distroless‑образі (gcr.io/distroless/cc‑debian13 — без оболонки, без пакетного менеджера), Go API — на легкому Alpine, а образ бази даних — на postgres‑slim. Просування переміщує білд через середовища за визначеним маршрутом, а не вручну.</p>\n<p><strong>Результат.</strong> Релізи перестали бути обережним ручним ритуалом і стали рутинною, нудною подією, а це саме те, чого хочеться від релізів. Продакшн‑фронтенд працює на настільки малому, наскільки це взагалі можливо, перевірки ловлять проблеми до того, як вони потраплять у продакшн, а «розгортання» — це те, що робить пайплайн, а не те, через що будь‑кому доводиться перейматися.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Контейнери (Docker/Kubernetes)",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Контейнеризація та оркестрація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/authored-578-go-task-automation-targets-70/",
      "url": "https://engineer.company/uk/portfolio/authored-578-go-task-automation-targets-70/",
      "title": "Написала 578 цілей автоматизації go‑task, що охоплюють нативний, Docker та HTTPS режими розробки, лінтинг, тестування, базу даних та розгортання.",
      "summary": "Будь-хто може виконати task --list і побачити весь інструментарій викладеним, і запустити будь-яку його частину однаково, незалежно від того, що під капотом.",
      "content_html": "<p><strong>Ситуація.</strong> Кодова база — це поліглотний монорепозиторій: Go, TypeScript, SQL, Python, shell, — і кожен з них приносить власний спосіб збирати, тестувати, лінтити й запускати. Якщо це нічим не впорядкувати, кожен носить у голові шпаргалку команд для конкретних інструментів, а новачки витрачають перший день лише на те, щоб зрозуміти, як усе запустити.</p>\n<p><strong>Завдання.</strong> Дати всьому проєкту одні вхідні двері: єдиний послідовний спосіб запускати що завгодно, незалежно від того, якою мовою це написано.</p>\n<p><strong>Дія.</strong> Це побудовано на go‑task — шарі Taskfile, що виріс до 578 іменованих цілей: 50 у кореневому файлі та 528 у файлах із namespace&rsquo;ами під ним. Тут є режими розробки (native, Docker, HTTPS‑варіант для тестування PWA й мобільних застосунків), сторона якості коду (lint, format, test, fix для всіх мов), керування базою даних і специфічні для середовищ завдання збирання й розгортання. Є навіть режим low‑memory для машин, яким бракує RAM, щоб зібрати фронтенд звичайним способом. Мета полягала не в тому, щоб мати багато завдань, а в тому, щоб ніколи не доводилося знати базову команду.</p>\n<p><strong>Результат.</strong> Будь‑хто може виконати task &ndash;list і побачити весь інструментарій викладеним, і запустити будь‑яку його частину однаково, незалежно від того, що під капотом. Онбординг став коротшим, а дрібні дурні помилки — не той прапорець, не та директорія, напівзабута команда — здебільшого зникли. Це число водночас є попередженням: 578 цілей — це більше, ніж будь‑хто здатен утримати в голові, тож зручність користування тримається на іменуванні та namespace&rsquo;ах, а не на тому, що кількістю варто пишатися.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "Технічне лідерство",
        "DevOps та автоматизація CI/CD",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/owned-end-to-end-deployments-of-the-platform-71/",
      "url": "https://engineer.company/uk/portfolio/owned-end-to-end-deployments-of-the-platform-71/",
      "title": "Відповідала за наскрізне розгортання платформи в Azure, керуючи релізами в середовищах development, staging і production.",
      "summary": "Зміни передбачувано доходять до кожного середовища заданим шляхом, без жодних ситуативних ручних розгортань у процесі.",
      "content_html": "<p><strong>Ситуація.</strong> Платформа мала охоплювати користувачів у кількох середовищах Azure, а розгортання — це той шов, де сходяться інфраструктура, пайплайн збирання й застосунок. Це також те місце, де маленька помилка перестає бути багом і стає збоєм у роботі, тож це та частина, яку найменше хочеться робити вручну й напівпо пам&rsquo;яті.</p>\n<p><strong>Завдання.</strong> Розгортання було взято під повний контроль від початку до кінця, щоб зміна щоразу виходила в кожне середовище однаково передбачуваним способом.</p>\n<p><strong>Дія.</strong> Релізи рухаються фіксованим маршрутом — спочатку development, потім staging, потім production, — а не так, що хтось пушить напряму в live‑середовище. Пайплайн CI/CD збирає образи й постачає їх, а шаблони Bicep тримають цільову інфраструктуру ідентичною від одного середовища до іншого, тож білд щоразу не потрапляє в трохи інше місце. Конфігурація, що відрізняється для кожного середовища, зберігається окремо від секретів, а це означає, що той самий зібраний артефакт можна просувати через середовища, і він просто підхоплює правильні налаштування там, де приземляється, замість того щоб перезбиратися для кожного з них.</p>\n<p><strong>Результат.</strong> Зміни передбачувано доходять до кожного середовища заданим шляхом, без жодних ситуативних ручних розгортань у процесі. Реліз перетворився на контрольований, повторюваний крок замість моменту із затамованим подихом, і саме це значною мірою тримало живу платформу стабільною, поки під нею все ще швидко змінювалося.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Надійність та моніторинг (SRE)",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/",
      "url": "https://engineer.company/uk/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/",
      "title": "Налаштувала зберігання резервних копій бази даних як infrastructure‑as‑code, провела аудит готовності до відновлення й задокументувала процедуру відновлення — назвавши залишкові прогалини, а не залишивши їх на час інциденту.",
      "summary": "Відновлення перестало бути туманною заспокійливою фразою й стало задокументованою позицією з названими прогалинами.",
      "content_html": "<p><strong>Ситуація.</strong> Продукт, що живе на своїх даних, не може дозволити собі втратити хоч якісь, а «десь є бекапи» — це сподівання, а не план відновлення. Єдиний бекап, який чогось вартий, — це той, про який відомо, що він відновлюється, у середовище, яке відомо, що можна відбудувати. У продукті не було записано жодної з цих двох половин.</p>\n<p><strong>Завдання.</strong> Визначити реальну готовність до відновлення замість того, щоб її припускати, — дані, середовище навколо них і чесний опис того, наскільки далеко це сягає сьогодні.</p>\n<p><strong>Дія.</strong> Retention резервних копій налаштовано в Bicep поруч із базою даних, яку він захищає, тож відновлення на конкретний момент часу є властивістю шаблону, а не налаштуванням, яке колись хтось клікнув у порталі. Середовище навколо неї теж описане як infrastructure‑as‑code, а це та тиха половина, про яку люди забувають: відновити базу даних у середовище, яке довелося б відбудовувати вручну по пам&rsquo;яті, — це не справжнє відновлення. Далі готовність проаудитували й описали — процедуру відновлення, навчання, яке її виміряло б, і прогалини, що досі відкриті: геонадлишковість вимкнено, а цільовий час відновлення запропоновано, а не виміряно, бо навчання ще не проводили.</p>\n<p><strong>Результат.</strong> Відновлення перестало бути туманною заспокійливою фразою й стало задокументованою позицією з названими прогалинами. Це звучить менш ефектно, ніж «аварійне відновлення: зроблено», і коштує значно більше — той, хто візьметься за це наступним, знає, що покрито, що ні і яке саме навчання закриває різницю. Названу прогалину можна закрити; неназвану знаходять під час інциденту.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "PostgreSQL",
        "Бази даних",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Infrastructure as Code",
        "Адміністрування баз даних (DBA)",
        "Резервне копіювання та відновлення"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-next-js-16-frontend-with-deliberate-73/",
      "url": "https://engineer.company/uk/portfolio/built-the-next-js-16-frontend-with-deliberate-73/",
      "title": "Побудувала фронтенд на Next.js 16 зі свідомими стратегіями SSR, SSG і CSR та багаторазовою фабрикою prefetched‑server‑page, що усуває каскад N+1 на кожній автентифікованій сторінці, перенесеній на неї.",
      "summary": "Сторінки, перенесені на цю фабрику, піднімаються за одне звернення замість шторму звернень, а оскільки це фабрика, а не патерн, який копіюють вручну, наступна…",
      "content_html": "<p><strong>Ситуація.</strong> Автентифікований дашборд мав відчуватися швидким і водночас залишатися по‑справжньому інтерактивним, а ці дві мети тягнуть у різні боки, якщо підійти до них наївно. Якщо забирати все на клієнті, перше завантаження затягується, а гірше — виникає патерн N+1, коли кожен компонент прокидається і робить власний запит, тож одна сторінка перетворюється на каскад мережевих звернень.</p>\n<p><strong>Завдання.</strong> Кожну частину застосунку потрібно було рендерити саме так, як їй насправді підходило, не жертвуючи клієнтською інтерактивністю там, де вона мала значення.</p>\n<p><strong>Дія.</strong> Фронтенд на Next.js 16 використовує для кожної поверхні застосунку той режим, який їй підходить, замість одного рішення на всі випадки. Маркетингові й публічні сторінки генеруються статично — вони не змінюються залежно від користувача, тож рендерити їх на кожен запит немає сенсу. Справді інтерактивні частини лишаються клієнтськими. А там, де каскад N+1 справді дошкуляє, — автентифікований дашборд і великі сторінки‑каталоги — рішення винесли у фабрику, а не робили вручну: createPrefetchedServerPage отримує дані сторінки на сервері й передає їх клієнту вже заповненими, тож компоненти одразу з&rsquo;являються зі своїми даними, а не йдуть по них кожен окремо. Стратегія інвалідації кешу задокументована для кожного запиту, тож дані лишаються актуальними без повторного завантаження того, що застосунок уже має.</p>\n<p><strong>Результат.</strong> Сторінки, перенесені на цю фабрику, піднімаються за одне звернення замість шторму звернень, а оскільки це фабрика, а не патерн, який копіюють вручну, наступна перенесена сторінка успадковує цю поведінку безкоштовно. Решта автентифікованого застосунку досі рендериться на клієнті й стоїть у черзі за нею — це міграція з робочим механізмом і очевидною наступною сторінкою, а не завершений перехід.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Архітектура платформи",
        "Веброзробка",
        "Оптимізація продуктивності",
        "Full‑Stack продуктова розробка",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/delivered-full-progressive-web-app-support-installable-and-74/",
      "url": "https://engineer.company/uk/portfolio/delivered-full-progressive-web-app-support-installable-and-74/",
      "title": "Реалізувала повну підтримку Progressive Web App — з можливістю встановлення та офлайн‑роботи — з кешуванням Workbox під час виконання через next‑pwa.",
      "summary": "Користувачі можуть встановити застосунок і продовжувати користуватися ним офлайн, а повторні завантаження швидко повертаються з кешу замість мережі.",
      "content_html": "<p><strong>Ситуація.</strong> Значна частина користувачів платформи перебуває в морі. Моряки та польовий персонал працюють з телефонів, часто офлайн або на нестабільному з&rsquo;єднанні, — це не люди за робочим столом зі стабільним офісним wifi. Якби застосунок будувався так, ніби в усіх є швидка й постійна мережа, це непомітно відсікло б значну частину реальної аудиторії.</p>\n<p><strong>Завдання.</strong> Застосунок мав встановлюватися як нативний і залишатися придатним до використання навіть при зникненні мережі.</p>\n<p><strong>Дія.</strong> Продукт постачається як повноцінний Progressive Web App. Він встановлюється на головний екран з коректними іконками різних розмірів, екраном заставки та кольорами теми, тож виглядає і запускається як застосунок, а не як закладка. Service worker налаштовано через плагін next‑pwa, а Workbox для runtime‑кешування використовує стратегію CacheFirst для того, що не змінюється від запиту до запиту, — шрифтів, зображень, аудіо, відео, CDN‑ресурсів, — разом з розумними HTTP‑заголовками cache‑control. Оскільки service worker коректно працює лише через HTTPS, тестування на основі HTTPS підтвердило офлайн- та інсталяційну поведінку на реальних пристроях, замість того щоб просто сподіватися, що все спрацює.</p>\n<p><strong>Результат.</strong> Користувачі можуть встановити застосунок і продовжувати користуватися ним офлайн, а повторні завантаження швидко повертаються з кешу замість мережі. Платформа поводиться як нативний застосунок на пристроях, які реально носять із собою користувачі, а для цієї аудиторії це не приємний бонус — це різниця між тим, чи придатний застосунок до використання в морі, чи ні.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Веброзробка",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-an-ios-26-liquid-glass-design-system-75/",
      "url": "https://engineer.company/uk/portfolio/designed-an-ios-26-liquid-glass-design-system-75/",
      "title": "Спроєктувала дизайн‑систему iOS 26 'Liquid Glass' та канонічний реєстр компонентів, дотримання якого забезпечували правила лінтингу для запобігання розбіжностям UI.",
      "summary": "UI лишається послідовним і відповідним бренду, а одноразові компоненти, які інакше почали б поширюватися, перехоплюються раніше, ніж це стається.",
      "content_html": "<p><strong>Ситуація.</strong> UI без спільної візуальної мови й фіксованого набору компонентів пливе, і пливе швидко. Кожен новий екран винаходить власні кнопки, бейджі й картки, трохи інакші щоразу, і ці дрібні неузгодженості накопичуються, доки продукт не починає виглядати нецілісним, а будь‑яка зміна означає торкатися п&rsquo;яти саморобних версій одного й того самого.</p>\n<p><strong>Завдання.</strong> Дизайн‑система мала бути достатньо цілісною, щоб виглядати продуманою, і достатньо примусовою, щоб не розмиватися в ту мить, коли команда завантажена іншим.</p>\n<p><strong>Дія.</strong> Візуальну мову й систему компонентів було спроєктовано як одне ціле. Мова — це вигляд у стилі iOS 26 «Liquid Glass»: напівпрозорі панелі з розмиттям фону, шаруваті тіні, легка рефракція, пружинні анімації, — побудований на утилітах Tailwind. Над цим стоїть канонічний набір компонентів, з яких має складатися кожен екран: Card, Label, Button, GlassIconButton, DirectoryGrid та інші. Тримається все це завдяки лінтингу: правила відхиляють саморобний бейдж чи чіп і натомість вказують на канонічний компонент, тож систему підтримує інструментарій, а не пам&rsquo;ять того, хто саме цього дня перевіряє код. А документація супроводжується конкретними нотатками «помилка → рішення»: замість абстрактного принципу — приклад неправильного та правильного варіанта.</p>\n<p><strong>Результат.</strong> UI лишається послідовним і відповідним бренду, а одноразові компоненти, які інакше почали б поширюватися, перехоплюються раніше, ніж це стається. Візуальна узгодженість перестала залежати від дисципліни кожного й стала тим, що утримує інструментарій, — а це єдина версія узгодженості, яка переживає дедлайн.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Дизайн‑системи та UI",
        "Документація",
        "UI/UX‑дизайн та дизайн‑системи"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-the-product-s-ui-and-ux-end-76/",
      "url": "https://engineer.company/uk/portfolio/designed-the-product-s-ui-and-ux-end-76/",
      "title": "Спроєктувала UI та UX продукту наскрізно — сітки каталогів, подвійні подання картка/таблиця, валідатори вимог у реальному часі та навігацію breadcrumb.",
      "summary": "У результаті вийшов вилощений, послідовний досвід, який робить щільні морські дані доступними для сприйняття та проводить людей крізь складні місця.",
      "content_html": "<p><strong>Ситуація.</strong> Платформа показує людям багато різних сутностей — фахівців, компанії, судна, вакансії, відгуки, — і інтерфейс мав поєднувати дві речі, які суперечать одна одній: привабливий вигляд і справжню зручність. Достатньо щільний, щоб показувати реальні морські дані, але не настільки, щоб перетворитися на стіну, об яку розбиваєшся.</p>\n<p><strong>Завдання.</strong> UI та UX продукту було опрацьовано наскрізно — макети, патерни взаємодії та дрібніші речі на кшталт того, як провести людину крізь форму, не змушуючи її відчувати тиск.</p>\n<p><strong>Дія.</strong> Основну роботу виконали кілька рішень. Сітки каталогів мають перемикач картка/таблиця, тож можна переглядати дані візуально або сканувати щільну таблицю, і застосунок пам&rsquo;ятає обраний варіант. Форми використовують живі валідатори вимог, розташовані над полем вводу: кожне правило показується зеленим, коли воно виконане, і жовтогарячим, коли ні, — тож користувача скеровують під час вводу, а не докоряють йому після відправлення. Навігація — це послідовні хлібні крихти та двоколонкові макети сутностей, тож сторінки відчуваються як один продукт, а не набір непов&rsquo;язаних екранів. А філософія помилок — це підказка замість провалу: жодних червоних стін, редиректи замість глухих кутів, застосунок намагається вести користувача далі, а не зупиняти його.</p>\n<p><strong>Результат.</strong> У результаті вийшов вилощений, послідовний досвід, який робить щільні морські дані доступними для сприйняття та проводить людей крізь складні місця. Він виглядає продуманим і таким, якому можна довіряти, а на платформі, яку люди використовують для власної кар&rsquo;єри, це не просто косметика: якщо все виглядало б недбало, вони довіряли б даним менше, і мали б рацію.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Продукт і вимоги",
        "UI/UX‑дизайн та дизайн‑системи",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/",
      "url": "https://engineer.company/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/",
      "title": "Посилила захист застосунку за допомогою CSP на основі nonce, HSTS, cookie SameSite, ролей бази даних за принципом найменших привілеїв та серверних повторних перевірок прав доступу.",
      "summary": "Безпека не залежить від того, як поводиться UI. Захист побудовано шарами так, щоб подолання одного рівня не давало проходу через решту, а вся система базується…",
      "content_html": "<p><strong>Ситуація.</strong> Платформа зберігає професійні та організаційні дані — саме ті, які люди очікують бачити захищеними належним чином, тож одного рубежу оборони було апріорі недостатньо. Робоче припущення таке: клієнт вороже налаштований, — усе, що примусово виконує браузер, може бути вимкнене тим, у чиїх руках цей браузер, — і безпека все одно мусить триматися.</p>\n<p><strong>Завдання.</strong> Платформу потрібно було захистити на кожному рівні — фронтенд, API, база даних, — так, щоб безпеку забезпечував сервер незалежно від того, що саме дозволяв інтерфейс.</p>\n<p><strong>Дія.</strong> На фронтенді проксі‑мідлвар Next.js — proxy.ts — встановлює Content‑Security‑Policy з nonce для кожного запиту та strict‑dynamic, а також HSTS і SameSite cookies, тож браузер жорстко обмежений у тому, що він виконає й надішле. На рівні API діють rate limiting, CORS, обмеження розміру запиту, валідація вводу до того, як щось торкнеться бази даних, і логування подій, пов&rsquo;язаних із безпекою. У базі даних API входить під роллю з мінімальними привілеями, яка може лише виконувати (EXECUTE) функції застосунку, самі функції запускаються з SECURITY DEFINER, а все параметризовано. А права доступу — тариф, роль, організація, прив&rsquo;язка до судна — перевіряються сервером повторно на кожен запит, тоді як фронтендні обмеження розглядаються лише як UX. Ці обмеження визначають, що видно; сервер визначає, що дозволено робити.</p>\n<p><strong>Результат.</strong> Безпека не залежить від того, як поводиться UI. Захист побудовано шарами так, щоб подолання одного рівня не давало проходу через решту, а вся система базується на припущенні, що клієнту довіряти не можна, — і це правильне припущення для даних, які люди довіряють платформі.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Frontend‑розробка",
        "Архітектура платформи",
        "Бази даних",
        "Безпека",
        "Backend- та API‑розробка",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/established-an-english-danish-internationalization-system-with-linter-78/",
      "url": "https://engineer.company/uk/portfolio/established-an-english-danish-internationalization-system-with-linter-78/",
      "title": "Створила систему інтернаціоналізації для англійської та данської мов, що несе 12 027 повідомлень на локаль у 458 файлах namespace, зі словником, дотримання якого забезпечував лінтер, та бюджетом у 400 рядків на файл.",
      "summary": "Обидві локалі лишаються коректними й узгодженими на 24 054 повідомленнях між ними, а файли лишаються придатними до підтримки навіть у міру зростання кількості…",
      "content_html": "<p><strong>Ситуація.</strong> Платформа працює англійською та данською, а системи перекладу мають властивість розповзатися в хаос. Файли ростуть без обмежень, ключі протікають — присутні в одній локалі й відсутні в іншій, — а мовно‑специфічні конвенції застосовуються нерівномірно, тож одна з локалей зрештою читається так, ніби її перекладав комітет, учасники якого між собою не спілкувалися. Для професійного продукту це не дрібна вада — це виглядає як недбалість.</p>\n<p><strong>Завдання.</strong> Налаштування інтернаціоналізації мало масштабуватися — утримувати обидві мови узгодженими й коректними, а файли — придатними для підтримки людиною навіть через рік.</p>\n<p><strong>Дія.</strong> Систему побудовано на next‑intl з правилами, які інструментарій справді примусово застосовує. Данська сторона має зафіксований словник і стиль — буквальні æøå, неформальне звертання «du», правильні наголоси в наказовому способі та семантичні відповідники для складних іменників, щоб їх перекладали за змістом, а не дослівно, — і лінтер стежить за цим. Діє жорсткий ліміт у 400 рядків на файл namespace, з підходом split‑and‑merge: велика область ділиться на вкладені файли, які потім чисто зливаються назад, замість того щоб один файл ріс нескінченно; саме через цей ліміт 12 027 повідомлень на локаль живуть у 458 файлах, а не в кількох величезних. Лінтер‑перевірка звіряє ключі між локалями, тож нічого не протікає і не губиться. А збережені overrides зливаються на основі каталогу, а не через крихкі фолбеки верхнього рівня — та сама ідея deep‑merge, що використовується для налаштувань.</p>\n<p><strong>Результат.</strong> Обидві локалі лишаються коректними й узгодженими на 24 054 повідомленнях між ними, а файли лишаються придатними до підтримки навіть у міру зростання кількості рядків. Якість мови стала тим, що інструментарій гарантує на кожному коміті, а не тим, що непомітно псується щоразу, коли хтось поспіхом додає рядок. Саме ліміт є несучою конструкцією: без обмеження на файл замість 458 файлів було б дванадцять, і ніхто б їх не відкривав.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Автоматизація та CI/CD",
        "Документація",
        "Інтернаціоналізація",
        "Інтернаціоналізація та локалізація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/set-a-zero-warnings-quality-bar-across-six-79/",
      "url": "https://engineer.company/uk/portfolio/set-a-zero-warnings-quality-bar-across-six-79/",
      "title": "Встановила стандарт якості без жодних попереджень для шести мов — Go, TypeScript, SQL, Python, Shell і Markdown — дотримання якого забезпечували pre‑commit hooks.",
      "summary": "Проблеми виправляються біля джерела, а не відкладаються в беклог, який ніхто не розчищає, і кодова база лишається чистою за замовчуванням, а не завдяки…",
      "content_html": "<p><strong>Ситуація.</strong> Попередження, що накопичуються, непомітно роз&rsquo;їдають якість. Кожна проігнорована діагностика трохи знижує планку, і щойно білд починає видавати їх сорок штук, їх уже ніхто не читає, а реальна проблема сидить у цьому списку на видноті, бо «попередження» перетворилися на фоновий шум. У поліглотній кодовій базі джерел такого шуму ще більше, і йому легше цим скористатися.</p>\n<p><strong>Завдання.</strong> Репозиторію потрібна була одна безкомпромісна планка якості для всіх мов, щоб проблеми виправлялися, а не накопичувалися.</p>\n<p><strong>Дія.</strong> Впроваджено політику нульових попереджень, а стежить за нею інструментарій, — адже політика, що покладається на пильність кожного, програє вже на першому завантаженому тижні. Кожна діагностика лінтера — це помилка: рівня «warn», у якому можна сховатися, просто немає, — і це однаково для всього стеку: Go з golangci‑lint, TypeScript з ESLint, SQL з SQLFluff, Python з Ruff, shell з ShellCheck, Markdown з markdownlint. Inline‑придушення заборонені, тож діагностику не можна замаскувати — проблему треба справді виправити. Pre‑commit- і pre‑push‑хуки запускають лінтери й тести, тож коміт, який вніс би проблему, просто не створюється. Є навіть обмеження на довжину функцій і файлів, щоб модулі не розросталися за межу читабельності.</p>\n<p><strong>Результат.</strong> Проблеми виправляються біля джерела, а не відкладаються в беклог, який ніхто не розчищає, і кодова база лишається чистою за замовчуванням, а не завдяки періодичним героїчним зусиллям. Стандарт однаковий незалежно від мови, і тримає його інструментарій, а не чиясь сила волі, — тому він справді тримається.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "Технічне лідерство",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/",
      "url": "https://engineer.company/uk/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/",
      "title": "Заклала засадничі рішення платформи в тижні після відкриття репозиторію в листопаді 2025 року — поділ на рівні, доступ до даних передусім через базу даних та планку без жодних попереджень — і вони тримаються дев'ять місяців потому.",
      "summary": "Через дев'ять місяців і кілька тисяч комітів усі три тримаються: рівні не розмилися, жоден обробник не звертається до таблиці напряму, а білд і досі не має…",
      "content_html": "<p><strong>Ситуація.</strong> Репозиторій відкрито 25 листопада 2025 року, і в ньому не було нічого. Те, що вирішується в перші кілька тижнів такого проєкту, має непропорційну вагу: поділ на рівні, місце, де дозволено жити бізнес‑логіці, планка якості. Такі рішення дешево ухвалювати на третій день і майже неможливо скасувати на шостий місяць, бо на той момент усе написане відтоді вже на них спирається.</p>\n<p><strong>Завдання.</strong> Засадничі рішення мали бути ухвалені свідомо й рано, причому в такій формі, щоб вони пережили передачу іншим людям і кодовій базі, значно більшій за ту, що існувала на той час.</p>\n<p><strong>Дія.</strong> Основну роботу зробили три рішення. Стек поділено на рівні так, щоб кожна частина мала одну роботу — фронтенд на Next.js, Go API, який валідує й передає далі, рівень функцій PostgreSQL, якому належать бізнес‑правила, — замість того щоб логіка опинялася там, де було зручно того дня. Доступ до даних із самого початку сховано за збереженими функціями, і саме з цього рішення випливає все інше, що стосується бази даних; впровадити його заднім числом означало б переписати кожен обробник. А планку нульових попереджень запроваджено ще до того, як з&rsquo;явилося багато коду, який треба їй підпорядкувати, бо стандарт, уведений на коміті 5 000, — це проєкт із прибирання, тоді як той самий стандарт на коміті 50 — це просто те, як працює репозиторій. Жодне з цих трьох рішень не було легким варіантом на той момент, і всі три коштували темпу в перший місяць.</p>\n<p><strong>Результат.</strong> Через дев&rsquo;ять місяців і кілька тисяч комітів усі три тримаються: рівні не розмилися, жоден обробник не звертається до таблиці напряму, а білд і досі не має жодного попередження. Саме таку перевірку варто застосовувати до засадничого рішення — не чи звучало воно правильно, а чи пережило воно зіткнення з обсягом роботи, що прийшов далі, бо саме в цій точці зручні рішення зазвичай тихо полишають.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "DevOps",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Архітектура платформи",
        "Архітектура рішень",
        "Бази даних",
        "Безпека",
        "Керівництво командою",
        "Технічне лідерство",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Архітектура платформи та рішень",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/",
      "url": "https://engineer.company/uk/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/",
      "title": "Забезпечувала цілодобову підтримку інфраструктури 24/7 для IPTV/OTT‑стрімінгової платформи, адмініструючи ~1 000 серверів та системи клієнтів для глобальних замовників у Китаї, США та Німеччині.",
      "summary": "Платформа лишалася безперервно доступною для глобальної аудиторії, а проблеми виявлялися та усувалися незалежно від того, о котрій годині вони виникали, — ще…",
      "content_html": "<p><strong>Ситуація.</strong> Це була IPTV/OTT‑стримінгова платформа з клієнтами, розкиданими по Китаю, США та Німеччині, а це означало, що тихої години для обслуговування просто не існувало — хтось, десь, завжди дивився. Простій на такій платформі — це не абстрактна метрика; це просто чийсь телевізор, що перестав показувати, і людям байдуже чому.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб тримати інфраструктуру платформи доступною цілодобово — справді цілодобово, а не за принципом «робочі години плюс чергування, на яке ніхто не відповідає».</p>\n<p><strong>Дія.</strong> Підтримка 24/7 забезпечувалася приблизно для тисячі серверів, плюс чимала кількість систем, що належали клієнтам, — їх адміністрували, моніторили, тримали захищеними та налаштованими по всьому стримінговому господарству. Оскільки клієнти перебували у трьох дуже різних часових поясах, поняття «неробочий час» фактично не існувало: проблема о 3‑й ночі за місцевим часом була прайм‑таймом для когось іншого, тож до неї так і ставилися. Значна частина роботи полягала в тому, щоб помітити відхилення до того, як воно переросло в збій, адже на живій стримінговій платформі немає можливості тихо виправити щось постфактум.</p>\n<p><strong>Результат.</strong> Платформа лишалася безперервно доступною для глобальної аудиторії, а проблеми виявлялися та усувалися незалежно від того, о котрій годині вони виникали, — ще до того, як досягали екрана глядача. На сервісі 24/7 у цьому й полягає вся робота: успіх виглядає як відсутність будь‑яких подій, а саме цього і хотіли глядачі.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "Linux та сервери",
        "Інфраструктура",
        "Мережі та VPN",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "IT‑підтримка та helpdesk",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/",
      "url": "https://engineer.company/uk/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/",
      "title": "Забезпечувала безперебійну передачу сигналів IPTV‑стрімінгу між постачальниками та клієнтами, цілодобово моніторячи та підтримуючи стрімінгову мережу й IP‑телефонію.",
      "summary": "Потоки та дзвінки лишалися надійними по всій платформі, а проблеми виявлялися й виправлялися до того, як перетворювалися на збій сервісу, який хтось міг би…",
      "content_html": "<p><strong>Ситуація.</strong> IPTV живе чи гине залежно від того, чи проходить сигнал. Потоки йдуть від постачальників через платформу до клієнтів, і будь‑який розрив у будь‑якій точці цього ланцюга означає чорний екран для когось. Поруч працювала IP‑телефонія з тією самою вимогою: вона просто мала працювати.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб гарантувати безперервність доставлення сигналу та роботи телефонії.</p>\n<p><strong>Дія.</strong> Стримінгову мережу та IP‑телефонію моніторили, усували в них несправності й обслуговували цілодобово. Сенс постійного спостереження в тому, що проблеми стримінгу спершу заявляють про себе деградацією, а вже потім перетворюються на повний обрив — потік, що починає заїкатися, канал, що стає нестабільним, — і якщо стежити уважно, це можна перехопити на етапі заїкання, а не чорного екрана. Тож значна частина роботи полягала в тому, щоб випереджати сигнал, а не реагувати на скарги на нього.</p>\n<p><strong>Результат.</strong> Потоки та дзвінки лишалися надійними по всій платформі, а проблеми виявлялися й виправлялися до того, як перетворювалися на збій сервісу, який хтось міг би помітити. Підтримувати сигнал між постачальниками й кінцевими клієнтами без видимого розриву — це тиха, постійна робота, і саме тихою вона й має бути.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Інфраструктура",
        "Мережі та VPN",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Надійність та моніторинг (SRE)",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/developed-and-maintained-django-web-applications-for-the-84/",
      "url": "https://engineer.company/uk/portfolio/developed-and-maintained-django-web-applications-for-the-84/",
      "title": "Розробляла та підтримувала вебзастосунки на Django для IPTV‑платформи, постачаючи нові функції та покращуючи продуктивність і стабільність.",
      "summary": "Застосунки продовжували набувати можливостей, лишаючись при цьому надійними і для внутрішніх команд, і для клієнтів.",
      "content_html": "<p><strong>Ситуація.</strong> Навколо IPTV‑платформи існували вебзастосунки на Django — саме та частина, на яку люди реально натискали, — і вони мали продовжувати рухатися вперед: нові функції, а також продуктивність і стабільність, яких вимагає платформа, що працює цілодобово.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб ці застосунки лишалися багатофункціональними, швидкими й стабільними.</p>\n<p><strong>Дія.</strong> Вебзастосунки на Django розроблялися й підтримувалися — нові функції створювалися, помилки виправлялися, а робота над продуктивністю та стабільністю велася разом з усією командою, а не в окремому кутку. У чомусь, що безперервно обслуговує клієнтів, стабільність — це не приємний додаток до функцій, а обмеження, якому функції мусять підпорядковуватися. Ефектна функція, через яку все хитається, не варта багато, коли хитатися не можна.</p>\n<p><strong>Результат.</strong> Застосунки продовжували набувати можливостей, лишаючись при цьому надійними і для внутрішніх команд, і для клієнтів. Додавати щось нове, не дестабілізуючи систему, — ось баланс, який тут мав значення, і саме його дотримувалася робота.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Python",
        "Веброзробка",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/",
      "url": "https://engineer.company/uk/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/",
      "title": "Планувала та впроваджувала нову функціональність інфраструктури для внутрішніх і зовнішніх систем, створюючи рішення, достатньо довговічні, щоб працювати роками з мінімальними змінами.",
      "summary": "Системи залишалися функціональними та ефективними ще довго після їх побудови, працюючи роками майже без змін.",
      "content_html": "<p><strong>Ситуація.</strong> У міру зростання організації її внутрішні та зовнішні системи постійно потребували нових можливостей, які додавалися нашвидкуруч. Найпростіший спосіб зробити це — обрати те, що найшвидше сьогодні; проблема простого шляху в тому, що вже за півроку доводиться повертатися й усе переробляти.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб спланувати та побудувати інфраструктурну функціональність, яка справді витримає перевірку часом, — не просто працювати зараз, а продовжувати працювати.</p>\n<p><strong>Дія.</strong> Нову інфраструктурну функціональність було сплановано та впроваджено у внутрішніх і зовнішніх системах з розрахунком на довговічність — саме той тип рішень, які будують один раз і правильно, щоб вони роками працювали з мінімальним втручанням, а не вимагали постійної уваги. Це свідомий вибір щоразу: витратити трохи більше часу на роздуми на старті, щоб не приректи себе на вічне «нянькання» з результатом.</p>\n<p><strong>Результат.</strong> Системи залишалися функціональними та ефективними ще довго після їх побудови, працюючи роками майже без змін. Саме така довговічність і є справжнім мірилом інфраструктурної роботи — зробити щось, що працює сьогодні, може будь‑хто; зробити щось, що тихо продовжує працювати через роки, — завдання значно складніше й цінніше.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Архітектура платформи",
        "Архітектура рішень",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "Архітектура платформи та рішень",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/as-one-of-the-first-hires-designed-and-86/",
      "url": "https://engineer.company/uk/portfolio/as-one-of-the-first-hires-designed-and-86/",
      "title": "Як одна з перших співробітниць, спроєктувала та побудувала всю базову інфраструктуру та супутні процеси з нуля для SaaS‑стартапу в зеленій енергетиці, заклавши фундамент для швидкого зростання.",
      "summary": "Стартап отримав міцну технічну основу, і саме вона дала бізнесу змогу згодом швидко зростати. Бути тим, хто будує таку основу з нуля, — це особлива…",
      "content_html": "<p><strong>Ситуація.</strong> Це був SaaS‑стартап у сфері зеленої енергетики — з перспективною ідеєю, але практично без технічної основи під нею. Прихід на посаду одним із перших співробітників означав той етап, коли підтримувати ще нічого, бо нічого ще не існує, — закладання ґрунту, на якому згодом стоятимуть усі інші.</p>\n<p><strong>Завдання.</strong> Завданням було з нуля побудувати основну інфраструктуру та процеси навколо неї.</p>\n<p><strong>Дія.</strong> Було спроєктовано та побудовано всю базову інфраструктуру й супутні процеси — сервери, мережі, потоки даних, безпеку, операційну складову. У стартапі це означає ухвалення рішень, які потім важко скасувати, тож мета полягала не просто в тому, щоб «щось запрацювало», а в тому, щоб закласти фундамент, здатний витримати вагу швидкого зростання без потреби зривати все й переробляти в момент, коли компанія стане більшою. Ранні інфраструктурні рішення або стають тим, що дає змогу масштабуватися, або тим, що потім рік доводиться розбирати; мета однозначно була в першому.</p>\n<p><strong>Результат.</strong> Стартап отримав міцну технічну основу, і саме вона дала бізнесу змогу згодом швидко зростати. Бути тим, хто будує таку основу з нуля, — це особлива відповідальність: зроби правильно — і ніхто не помітить, зроби неправильно — і помітять усі, — і в цьому випадку основа витримала.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Cloud",
        "DevOps",
        "Архітектура платформи",
        "Архітектура рішень",
        "Безпека",
        "Інфраструктура",
        "Системне адміністрування",
        "DevOps та автоматизація CI/CD",
        "Архітектура платформи та рішень",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/",
      "url": "https://engineer.company/uk/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/",
      "title": "Підтримувала та вдосконалювала застарілий сайт на Hugo, водночас долучаючись до покращень UI/UX основного продукту з управління активами.",
      "summary": "Вебсайт залишався актуальним, а не тихо старів, а зручність використання основного продукту зростала завдяки послідовному, усвідомленому вдосконаленню — тому,…",
      "content_html": "<p><strong>Ситуація.</strong> Існував застарілий вебсайт, побудований на Hugo — генераторі статичних сайтів, — який працював паралельно з основним продуктом компанії, системою управління активами. Вебсайт був тим давнім, усталеним елементом; а реальна цінність була зосереджена в продукті.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб підтримувати сайт у робочому стані й водночас покращувати досвід користування продуктом.</p>\n<p><strong>Дія.</strong> Статичний сайт на Hugo підтримувався й вдосконалювався — залишався актуальним і працездатним, — тоді як покращення UI/UX і зворотний зв&rsquo;язок водночас спрямовувалися в основний продукт управління активами. Розподіл уваги між застарілим сайтом і флагманським продуктом — це насамперед про те, щоб не дати старому занепасти, поки увага прикута до нового; обидва так чи інакше представляли компанію перед кимось, тож обидва мали залишатися в належному стані.</p>\n<p><strong>Результат.</strong> Вебсайт залишався актуальним, а не тихо старів, а зручність використання основного продукту зростала завдяки послідовному, усвідомленому вдосконаленню — тому, яке народжується з реального використання й обдумування продукту, а не з одного великого редизайну.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/designed-a-time-management-and-reporting-system-that-88/",
      "url": "https://engineer.company/uk/portfolio/designed-a-time-management-and-reporting-system-that-88/",
      "title": "Спроєктувала систему управління часом та звітності, яка роками залишалася в промисловій експлуатації без суттєвих змін.",
      "summary": "Система залишалася в продуктивному використанні роками без будь-яких суттєвих змін. Це і є та похвала, яку хочеться почути про внутрішній інструмент, — не те,…",
      "content_html": "<p><strong>Ситуація.</strong> У команди не було надійного способу управляти часом і звітувати про прогрес. Зазвичай це означає, що все тримається на розрізнених таблицях і пам&rsquo;яті, а звітність перетворюється на аврал наприкінці кожного періоду, замість того щоб природно випливати з того, як люди працюють.</p>\n<p><strong>Завдання.</strong> Завданням було побудувати систему для обох цих потреб, яка справді витримає перевірку часом.</p>\n<p><strong>Дія.</strong> Систему управління часом і звітності було спроєктовано під те, як команда працює насправді, а не нав&rsquo;язано якийсь готовий процес, який усі однаково обходитимуть. У цьому весь секрет внутрішніх інструментів — якщо інструмент відповідає реальному робочому процесу, ним користуються; якщо він суперечить робочому процесу, його тихо покидають і повертаються до таблиць. Тож систему було побудовано під реальність, а не під ідеал.</p>\n<p><strong>Результат.</strong> Система залишалася в продуктивному використанні роками без будь‑яких суттєвих змін. Це і є та похвала, яку хочеться почути про внутрішній інструмент, — не те, що він вражав, а те, що він просто продовжував працювати, і його ніколи не доводилося замінювати. Те, що витримує роки щоденного використання без змін, очевидно було побудовано так, щоб підходити ідеально.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Автоматизація та CI/CD",
        "Продукт і вимоги",
        "Технічне лідерство",
        "Управління проєктами",
        "Аналітика даних та BI‑дашборди",
        "Продуктова стратегія та вимоги",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/automated-team-collaboration-password-management-task-and-time-89/",
      "url": "https://engineer.company/uk/portfolio/automated-team-collaboration-password-management-task-and-time-89/",
      "title": "Автоматизувала командну співпрацю, керування паролями, управління завданнями та часом, а також створила напівавтоматичну систему демонстрації проєктів, підвищивши продуктивність команди.",
      "summary": "Операційна ефективність зросла, а команда стала продуктивнішою, оскільки рутинна координація, яка раніше потребувала постійної людської уваги, тепер значною…",
      "content_html": "<p><strong>Ситуація.</strong> Значна частина операційної роботи команди — координація, управління паролями, відстеження завдань і часу — виконувалася вручну, а ручна координація — це тихий податок: його ніколи не помічають, але він постійно з&rsquo;їдає години, які могли б піти на щось корисніше.</p>\n<p><strong>Завдання.</strong> Метою була автоматизація цієї рутинної операційної роботи.</p>\n<p><strong>Дія.</strong> Було автоматизовано ті ділянки, які піддавалися автоматизації, — командну співпрацю, управління паролями, управління завданнями, управління часом, — а зверху додано напівавтоматичну систему презентації проєктів. Ідея в усьому цьому була одна: зняти рутинну координацію з людей, щоб вона виконувалася сама, і дати їм змогу спрямувати вивільнену увагу на роботу, яка справді потребує людини. Система презентації проєктів була тим самим підходом, застосованим до більш видимої частини роботи: зробити представлення результатів переважно автоматичним, а не ручною рутиною щоразу.</p>\n<p><strong>Результат.</strong> Операційна ефективність зросла, а команда стала продуктивнішою, оскільки рутинна координація, яка раніше потребувала постійної людської уваги, тепер значною мірою виконувалася сама. Час, який витікав у рутинні справи, повернувся до реальної роботи.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Технічне лідерство",
        "Управління проєктами",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/",
      "url": "https://engineer.company/uk/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/",
      "title": "Інтегрувала загальнокорпоративну систему керування паролями, посиливши безпеку та оптимізувавши керування доступом.",
      "summary": "Безпека покращилася, а керування доступом стало простішим і послідовнішим у масштабах усієї організації.",
      "content_html": "<p><strong>Ситуація.</strong> Облікові дані оброблялися непослідовно — різні люди зберігали й передавали їх різними, довільними способами, — і саме ця непослідовність і була ризиком безпеки. Рідко йдеться про якийсь драматичний злам; частіше це пароль у повідомленні в чаті, спільний логін, який ніхто не змінює, повільне накопичення дрібних вразливостей.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб централізувати облікові дані та зробити їх безпечними.</p>\n<p><strong>Дія.</strong> Було впроваджено загальнокорпоративну систему управління паролями, завдяки якій зберігання та передача облікових даних відбувалися одним послідовним, безпечним способом замість особистих звичок кожного. Цінність загальнокорпоративного підходу саме в тому, що він не є опційним для окремих людей, — менеджер паролів, яким користується лише половина команди, майже не допомагає, бо ризик живе саме в тій половині, яка ним не користується. Тож мета полягала в тому, щоб зробити безпечний спосіб типовим — і повсюди.</p>\n<p><strong>Результат.</strong> Безпека покращилася, а керування доступом стало простішим і послідовнішим у масштабах усієї організації. Коли всі облікові дані зберігаються в одному керованому місці, цілий клас дрібних, буденних вразливостей просто перестає бути можливим — а це і є більшість того, чим реальна безпека є насправді.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Системне адміністрування",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/drove-client-web-success-by-combining-custom-website-91/",
      "url": "https://engineer.company/uk/portfolio/drove-client-web-success-by-combining-custom-website-91/",
      "title": "Забезпечила успіх клієнтів у вебі, поєднавши розробку та дизайн індивідуальних вебсайтів із SEO, контент‑стратегією та копірайтингом.",
      "summary": "Клієнти отримали вищу видимість і більше залучення — їхні сайти працювали як справжні канали зростання, а не як онлайн-буклети.",
      "content_html": "<p><strong>Ситуація.</strong> Клієнтам насправді потрібен був не вебсайт сам по собі — їм потрібно було те, що вебсайт має для них робити: щоб його знаходили, щоб він приваблював клієнтів, щоб він справді працював як канал. Гарний сайт, який ніхто не може знайти, — це провал, що маскується під успіх.</p>\n<p><strong>Завдання.</strong> Завдання полягало в тому, щоб об&rsquo;єднати розробку та зростання в одну пропозицію, а не просто передати клієнту готовий сайт і побажати удачі.</p>\n<p><strong>Дія.</strong> Було об&rsquo;єднано дві складові — розробку та дизайн вебсайтів на замовлення з одного боку, SEO, контент‑стратегію та копірайтинг з іншого, — щоб клієнт отримував продукт, який був водночас якісно побудований і справді помітний у пошуку. Зазвичай це вважають окремими завданнями, тому й з&rsquo;являються то чудові сайти, яких немає в жодній видачі, то добре оптимізовані сайти, якими неприємно користуватися. Поєднання обох напрямів означало, що сайт із самого початку проєктувався так, щоб його знаходили, а не оптимізувався заднім числом.</p>\n<p><strong>Результат.</strong> Клієнти отримали вищу видимість і більше залучення — їхні сайти працювали як справжні канали зростання, а не як онлайн‑буклети. Саме поєднання розробки та пошукової доступності в одному процесі перетворило вебсайт із витрати на те, що дійсно окупало себе.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Бренд і маркетинг",
        "Веброзробка",
        "Продукт і вимоги",
        "UI/UX‑дизайн та дизайн‑системи",
        "Бренд, маркетинг та SEO",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/performed-data-recovery-across-a-wide-range-of-92/",
      "url": "https://engineer.company/uk/portfolio/performed-data-recovery-across-a-wide-range-of-92/",
      "title": "Виконувала відновлення даних на широкому спектрі носіїв — SD‑картах, HDD, SSD, масивах RAID, зовнішніх накопичувачах та системах Mac.",
      "summary": "Клієнти отримували назад критично важливі дані з пристроїв, які вони вже подумки списали як втрачені, — і це стосувалося всіх поширених типів носіїв.",
      "content_html": "<p><strong>Ситуація.</strong> Люди приходили з носіями, які вийшли з ладу або були пошкоджені, і даними на них, які їм терміново треба було повернути, — а коли хтось несе в майстерню мертвий диск, він зазвичай уже не просто хвилюється, а панікує. Фотографії, бізнес‑файли, єдина копія чогось по‑справжньому важливого.</p>\n<p><strong>Завдання.</strong> Завданням було відновити дані клієнтів, незалежно від того, з яким носієм вони прийшли.</p>\n<p><strong>Дія.</strong> Відновлення даних охоплювало практично всі поширені типи носіїв — SD‑картки, класичні HDD, SSD, масиви RAID, зовнішні диски, системи Mac. Кожен із них виходить з ладу й втрачає дані по‑своєму: SSD — це інша проблема, ніж диск із пластинами, масив RAID — ще одна окрема проблема, а файлова система Mac має свої особливості. Тож робота полягала не менше в знанні правильного підходу для конкретного носія, ніж у володінні якоюсь однією технікою.</p>\n<p><strong>Результат.</strong> Клієнти отримували назад критично важливі дані з пристроїв, які вони вже подумки списали як втрачені, — і це стосувалося всіх поширених типів носіїв. На обличчі людини, якій повертають диск із неушкодженими файлами, з&rsquo;являється особливе полегшення — саме в цьому й полягав сенс роботи, і так було з усім спектром носіїв.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "IT‑підтримка та helpdesk",
        "Ремонт обладнання та відновлення даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/diagnosed-and-repaired-laptop-hardware-screens-hinges-keyboards-93/",
      "url": "https://engineer.company/uk/portfolio/diagnosed-and-repaired-laptop-hardware-screens-hinges-keyboards-93/",
      "title": "Діагностувала та ремонтувала апаратне забезпечення ноутбуків — екрани, петлі, клавіатури, трекпади, материнські плати та живлення — і вирішувала програмні проблеми в Linux, Windows та Mac.",
      "summary": "Пристрої поверталися до власників працездатними й надійними, з вирішеними проблемами і в апаратній, і в програмній частині.",
      "content_html": "<p><strong>Ситуація.</strong> На ремонт приносили ноутбуки з усім спектром типових несправностей — тріснуті екрани, зламані петлі, неробочі клавіатури, трекпади, що відмовляють, несправності материнської плати, проблеми з живленням, — а також із проблемами на боці програмного забезпечення, у Linux, Windows і Mac. По суті, що б не було не так із пристроєм, він зрештою опинявся на робочому столі майстра.</p>\n<p><strong>Завдання.</strong> Завданням було надійно діагностувати й усувати несправності — і саме «надійно» тут ключове слово, адже ремонт ноутбука, який не тримається, — це просто відкладений другий візит.</p>\n<p><strong>Дія.</strong> Апаратну частину ремонтували повністю — екрани, петлі, клавіатури, трекпади, материнські плати, живлення, — причому на рівні материнської плати це справді копітка, ювелірна робота, а програмні проблеми вирішувалися в усіх трьох операційних системах. Справжня майстерність зазвичай саме в діагностиці: ноутбук, який не вмикається, може мати проблему в зарядному пристрої, платі або акумуляторі, і ремонт настільки хороший, наскільки точним було припущення про те, що саме зламалося. Тож основна увага приділялася пошуку реальної причини несправності, перш ніж щось чіпати.</p>\n<p><strong>Результат.</strong> Пристрої поверталися до власників працездатними й надійними, з вирішеними проблемами і в апаратній, і в програмній частині. Ремонт, який тримається, — єдиний вартий уваги, і саме правильна діагностика на старті робила ці ремонти надійними.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "IT‑підтримка та helpdesk",
        "Ремонт обладнання та відновлення даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/",
      "url": "https://engineer.company/uk/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/",
      "title": "Побудувала багаторівневий набір автоматизованих тестів — 981 тест Go, 543 фронтендні та браузерні специфікації, 494 поведінкові тести SQL — з мутаційним тестуванням, property‑based тестами та обов'язковою перевіркою доступності.",
      "summary": "Змінювати щось структурне перестало бути страшно, а це єдине, що не дає кодовій базі такого розміру закам'яніти.",
      "content_html": "<p><strong>Ситуація.</strong> Платформа, що тримає свою бізнес‑логіку в базі даних, має проблему з тестуванням, якої немає в більшості проєктів. Логіка написана не тією мовою, з якою добре працює тестовий фреймворк, — вона в SQL, за фасадом функцій, а SQL — це саме той код, який лишається непокритим, бо тестувати його незручно. Якщо зверху додати API на Go та фронтенд на Next.js, «важливі частини покрито» тихо перетворюється на «покрито ті частини, які було легко покрити».</p>\n<p><strong>Завдання.</strong> Кожен рівень мав отримати перевірку своєї поведінки там, де ця поведінка насправді живе, а не так, щоб усе перевірялося ззовні через браузер.</p>\n<p><strong>Дія.</strong> Чотири рівні отримали чотири види тестів. API на Go несе 981 тестову функцію в 310 файлах. Фронтенд несе 543 spec‑файли Vitest і Playwright, зокрема 48 end‑to‑end файлів і 30 браузерних spec‑файлів. База даних несе 494 файли поведінкових тестів — 116 876 рядків SQL, які перевіряють свої припущення через 6 654 згенеровані винятки, — тож збережена функція тестується в самій базі даних, а не крізь три рівні застосунку над нею. Над ними стоять тести, що тестують тести: мутаційне тестування Stryker навмисно ламає рядок коду й падає, коли цього ніхто не помічає, а fast‑check генерує вхідні дані, які нікому не спало на думку записати. Гейт на axe‑core вимагає нуля порушень WCAG 2.0 і 2.1 рівнів A та AA, тож доступність стає падінням білду, а не знахідкою аудиту через кілька місяців. Пороги покриття рухаються лише вгору. Увесь набір виконується як 10 задач у workflow на 612 рядків.</p>\n<p><strong>Результат.</strong> Змінювати щось структурне перестало бути страшно, а це єдине, що не дає кодовій базі такого розміру закам&rsquo;яніти. Чесна ціна — це час: набір повільний, він оподатковує кожну зміну, і на такому масштабі сам потребує підтримки. Натомість він дає можливість і далі рухатися швидко, і вона варта більше, ніж ті хвилини, які він забирає.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "DevOps",
        "Frontend‑розробка",
        "PostgreSQL",
        "Автоматизація та CI/CD",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/",
      "url": "https://engineer.company/uk/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/",
      "title": "Побудувала механізм перевірок репозиторію — 268 зареєстрованих перевірок коміту, 277 правил лінтингу та 15 власних правил ESLint — плюс 146 тестів самих перевірок, щоб стандарт тримала збірка, а не код‑рев'ю.",
      "summary": "Час код-рев'ю перемістився з механіки на проєктування, бо механічні зауваження вже висловила машина ще до того, як гілку відправили в репозиторій.",
      "content_html": "<p><strong>Ситуація.</strong> Стандарти, записані в contributing‑гайді, — це побажання. З ними всі згодні, а потім настає п&rsquo;ятниця, зміна маленька, і гайд програє. Планка нульових попереджень трималася б лише тоді, коли її тримає щось інше, ніж добра воля, — а лінтери, що постачаються з кожною мовою, навіть близько не дістають до специфічних для проєкту правил, які насправді мають значення: тих, що описують, як має працювати саме ця кодова база.</p>\n<p><strong>Завдання.</strong> Правила, які були важливі для проєкту, мали стати виконуваними, щоб порушення одного з них валило коміт, а не чекало на рецензента, у якого стане часу й пам&rsquo;яті це помітити.</p>\n<p><strong>Дія.</strong> З цього виріс цілий рушій guard‑перевірок. Є 274 скрипти перевірок, 268 з них зареєстровані в commit‑хуках, поруч із 277 JavaScript‑лінтерами та 96 shell- і 17 Python‑валідаторами, які покривають те, щодо чого готовий інструментарій не має жодної думки: що міграцію можна відкотити, що ключ перекладу існує в обох локалях, що зареєстрований маршрут присутній в описі OpenAPI, що ніхто тихцем не додав inline‑придушення. П&rsquo;ятнадцять власних правил ESLint утримують домашні патерни в TypeScript. Одне правило варто назвати окремо: будь‑який коміт із префіксом fix: мусить нести тест, який без цього виправлення падає, — тож виправлена вада лишається виправленою. А оскільки зламана перевірка гірша за її відсутність — вона пропускає все, і ніхто про це не дізнається, — самі guard‑перевірки мають 146 власних тестів.</p>\n<p><strong>Результат.</strong> Час код‑рев&rsquo;ю перемістився з механіки на проєктування, бо механічні зауваження вже висловила машина ще до того, як гілку відправили в репозиторій. Компроміс реальний, і його варто назвати вголос: комітити повільно, а погано написана guard‑перевірка справді дратує, коли її доводиться обходити. Ті 146 тестів існують саме тому, що так уже траплялося.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "Технічне лідерство",
        "DevOps та автоматизація CI/CD",
        "Технічна документація",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-payments-and-entitlements-layer-96/",
      "url": "https://engineer.company/uk/portfolio/built-the-payments-and-entitlements-layer-96/",
      "title": "Побудувала рівень платежів і прав доступу — Stripe поряд із внутрішньозастосунковими покупками Apple і Google — обмеживши каталог, пошук та експорт моделлю доступу з 11 таблиць, яку перевіряє сервер.",
      "summary": "Додавання вітрини тепер зачіпає бік payments і лишає гейти в спокої, а питання підтримки про чийсь доступ має одну таблицю, у яку треба зазирнути, замість…",
      "content_html": "<p><strong>Ситуація.</strong> Гроші — це та частина платформи, до якої нікому не дозволено ставитися недбало. Підписка мусить пережити закінчення строку дії картки, повернення коштів, зміну тарифу, вебхук, що прийшов двічі, і вебхук, що прийшов не в тому порядку. Щойно оплата починає відбуватися на трьох вітринах — карткою у вебі, через Apple в одному app store, через Google в іншому, — з&rsquo;являються три різні версії того, що саме людина купила, а продуктові все одно потрібна одна відповідь на одне запитання: що цій людині дозволено робити просто зараз?</p>\n<p><strong>Завдання.</strong> Приймання грошей і надання прав мали стати двома системами, а не однією, щоб додавання ще однієї вітрини не означало переписування кожного гейта в продукті.</p>\n<p><strong>Дія.</strong> Stripe опрацьовує картки й підписки через 18 файлів Go, а in‑app‑покупки Apple і Google приходять через власну перевірку квитанцій. Усі три сходяться в схемі payments із 9 таблиць і 34 функцій — і на цьому спиняються. Те, про що продукт запитує насправді, — це окрема схема access, 11 таблиць і 34 функції, яка відповідає на «чи можна цьому обліковому запису зробити це?», не знаючи й не цікавлячись, яка саме вітрина за це заплатила. Ця відповідь закриває каталог компаній, пошук і експорт даних, і вона перевіряється сервером повторно на кожен запит, бо прихована кнопка — це ввічливість, а не механізм контролю.</p>\n<p><strong>Результат.</strong> Додавання вітрини тепер зачіпає бік payments і лишає гейти в спокої, а питання підтримки про чийсь доступ має одну таблицю, у яку треба зазирнути, замість трьох. Ціна — це дві схеми там, де меншому продуктові вистачило б однієї, плюс перевірка прав на тих запитах, які інакше були б безкоштовними.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "PostgreSQL",
        "Бази даних",
        "Безпека",
        "Продукт і вимоги",
        "Backend- та API‑розробка",
        "Безпека та керування доступом",
        "Продуктова стратегія та вимоги",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/moved-slow-work-onto-a-river-job-queue-97/",
      "url": "https://engineer.company/uk/portfolio/moved-slow-work-onto-a-river-job-queue-97/",
      "title": "Перенесла повільну роботу зі шляху запиту в чергу завдань River — 15 модулів воркерів, 8 запланованих задач та 20 завдань pg_cron — щоб запит повертався, поки робота за ним триває.",
      "summary": "Запити повертаються швидко, а повільна робота все одно доходить до кінця — з повторними спробами й видимою історією, коли не доходить.",
      "content_html": "<p><strong>Ситуація.</strong> Частині роботи взагалі нема чого відбуватися, поки користувач чекає. Надіслати лист, перебудувати пошуковий індекс, згенерувати документ, перерахувати рейтинги — якщо робити будь‑що з цього всередині запиту, користувач дивиться на спінер заради того, чого ніколи не просив показувати. А якщо робити це в горутині, воно зникає тієї ж миті, коли процес перезапускається, — а він перезапуститься, посеред розгортання, не лишивши й сліду про те, що це взагалі мало статися.</p>\n<p><strong>Завдання.</strong> Фоновій роботі потрібне було довговічне місце для життя: черга, яка переживає перезапуск, повторює невдалу спробу і в яку можна зазирнути, коли щось не сталося.</p>\n<p><strong>Дія.</strong> Вибір упав на River — переважно тому, що він тримає свою чергу в PostgreSQL: база даних і так є авторитетним джерелом даних, тож задача і рядки, яких вона торкається, комітяться або відкочуються разом, і немає другого шматка інфраструктури, який треба запускати й тримати в голові. За ним стоять 15 модулів‑воркерів і 8 запланованих задач. Нижче 20 задач pg_cron виконують ту підтримку, яку базі даних зручніше робити самій: підчищати партиції, ротувати солі, оновлювати агрегати. Усе, що було достатньо повільним, щоб це помітили, перенесено зі шляху запиту на одне з цих двох.</p>\n<p><strong>Результат.</strong> Запити повертаються швидко, а повільна робота все одно доходить до кінця — з повторними спробами й видимою історією, коли не доходить. Тримати чергу в Postgres, а не у виділеному брокері, — це свідоме обмеження: воно не масштабуватиметься вічно, і на якомусь обсязі стає неправильною відповіддю. Для платформи, вузьким місцем якої і так є база даних, на одну рухому частину менше виявилося вартіснішим за запас, яким однаково не скористалися б.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "PostgreSQL",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Backend- та API‑розробка",
        "Надійність та моніторинг (SRE)",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-first-party-error-monitoring-and-tracing-98/",
      "url": "https://engineer.company/uk/portfolio/built-first-party-error-monitoring-and-tracing-98/",
      "title": "Побудувала власний моніторинг помилок та трасування OpenTelemetry замість покупних — очищення payload, виявлення сплесків і регресій, символікацію та синтетичний heartbeat — за 11 операторськими поданнями.",
      "summary": "Помилки перетворюються на чергу, яку хтось може розібрати, а регресія оголошує про себе сама, замість того щоб її знайшов користувач.",
      "content_html": "<p><strong>Ситуація.</strong> Різниця між платформою, яка піднята, і платформою, яка працює, полягає в тому, чи хтось про це дізнається. Помилка, на яку користувач наштовхнувся об одинадцятій вечора, на сторінці, яку ніхто не тестує, лишається невидимою, доки щось не піде й не збере її. Звична відповідь — купити хостований трекер помилок, і це хороша відповідь, — а ще вона означає, що власні помилки платформи, стектрейси й контекст користувача їдуть до третьої сторони.</p>\n<p><strong>Завдання.</strong> Помилки й трейси треба було збирати, групувати й робити придатними до дії так, щоб нутрощі платформи не залишали платформу.</p>\n<p><strong>Дія.</strong> Побудовано дві частини. OpenTelemetry відповідає за трасування через OTLP, тож повільний запит можна простежити наскрізь через фронтенд, API та базу даних, а не здогадуватися про нього. Поруч стоїть власний пайплайн помилок — сервіс errmon і сервіс ingest, — який санітизує payload перед збереженням, групує помилки у повторювані проблеми замість плаского списку, виявляє сплески й регресії з періодом очікування, щоб один невдалий деплой не смикнув когось сорок разів, перетворює мінімізовані стектрейси фронтенду назад на читабельний код і запускає синтетичний heartbeat, щоб довести, що сам пайплайн живий. Усе це осідає в базі даних як події помилок, групи помилок, inbox, латентність API та семпли стеків, а назовні виходить через 11 операторських подань, зокрема одне для service level objectives.</p>\n<p><strong>Результат.</strong> Помилки перетворюються на чергу, яку хтось може розібрати, а регресія оголошує про себе сама, замість того щоб її знайшов користувач. Побудувати замість купити коштувало реального часу й означає, що це ще одна річ на підтримці, — куплений трекер працював би вже того ж дня по обіді. Натомість це дало те, що нічого чутливого не виїжджає назовні, а правила сповіщень підігнані під цю платформу, а не під якусь загальну.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "DevOps",
        "Безпека",
        "Інфраструктура",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/kept-the-schema-honest-across-1022-migrations-99/",
      "url": "https://engineer.company/uk/portfolio/kept-the-schema-honest-across-1022-migrations-99/",
      "title": "Тримала схему узгодженою впродовж 1 022 міграцій за допомогою перевірки CI, яка збирає базу даних обома шляхами — чиста інсталяція та інсталяція плюс усі міграції — і падає, коли вони розходяться.",
      "summary": "Свіже середовище й довговічне — це та сама база даних, і це перевірено, а не припущено. Ціна лягає на того, хто пише міграцію: вона має працювати у відтворенні…",
      "content_html": "<p><strong>Ситуація.</strong> У більшості проєктів схема описана двічі: один раз початковим налаштуванням, яке будує її з нуля, і другий раз накопиченими міграціями, які її виростили. Обидва описи мають давати ту саму базу даних. Ніщо не перевіряє, чи це справді так, тож вони розходяться — і розходження лишається невидимим, доки свіже середовище не почне поводитися інакше, ніж продакшн, зазвичай у найгірший момент.</p>\n<p><strong>Завдання.</strong> Два описи мали бути доказово ідентичними, автоматично, а не такими, у чию ідентичність час від часу вірять.</p>\n<p><strong>Дія.</strong> База даних версіонована як 1 022 міграції, пронумеровані від 036 до 1102, і дисципліна впорядкування навколо них нудна й не підлягає обговоренню. Тримає її CI‑задача, яка на кожну зміну збирає базу даних двічі: один раз зі свіжої початкової схеми, другий — із початкової схеми плюс кожна міграція, відтворена по черзі, — а потім порівнює обидві. Не лише структуру, що є легшою половиною, а й засіяні дані теж, бо міграція, яка неправильно заповнює довідкову таблицю, шкодить рівно так само, як та, що забула колонку, — а в diff схеми потрапляє тільки одна з них. Будь‑яка розбіжність валить білд із виведеною різницею.</p>\n<p><strong>Результат.</strong> Свіже середовище й довговічне — це та сама база даних, і це перевірено, а не припущено. Ціна лягає на того, хто пише міграцію: вона має працювати у відтворенні й має працювати з холодного старту, а це більше роздумів, ніж зазвичай дістається швидкому ALTER. У цьому й суть — альтернатива полягає в тому, щоб дізнатися про це під час відновлення, коли відповідь важлива, а часу її вигадувати вже немає.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "DevOps",
        "PostgreSQL",
        "Бази даних",
        "Міграції та модернізація",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Адміністрування баз даних (DBA)",
        "Міграція та модернізація баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/",
      "url": "https://engineer.company/uk/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/",
      "title": "Побудувала засоби протидії зловживанням за принципом fail‑closed — 22 обмежувачі частоти на Redis, Cloudflare Turnstile, ідемпотентність запитів та прив'язку до origin — щоб платформа відсікала ботів і напливи, а не довіряла тим, хто її викликає.",
      "summary": "Зловживання стає дорогим для того, хто зловживає, і дешевим для платформи, а збій у власному сховищі обмежувача деградує до відмови, а не до відчинених дверей.",
      "content_html": "<p><strong>Ситуація.</strong> Публічний каталог компаній і фахівців стає мішенню того самого дня, коли виходить у світ. Скраперам потрібні дані, спам‑акаунтам — охоплення, а ендпоінтом, обслуговування якого коштує платформі реальних грошей — пошук, експорт, будь‑що, що торкається зовнішнього API, — варто зловживати вже тому, що викликати його безкоштовно. Нічого з цього не є злим наміром, спрямованим саме проти цієї платформи; це фонова погода відкритого інтернету.</p>\n<p><strong>Завдання.</strong> Дорогим і вразливим до зловживань шляхам потрібні були обмеження, які тримають під тиском, зокрема під тиском недоступності власної залежності обмежувача.</p>\n<p><strong>Дія.</strong> Обмежувачів частоти запитів тут 22, і кожен сконструйований під той шлях, який він захищає, замість одного глобального ліміту, бо спроба входу, пошук і масовий експорт стають зловживанням на кардинально різних швидкостях. Стан живе в Redis, тож ліміт спільний для всіх інстансів, а не існує окремо в кожному процесі, звідки його тривіально обійти. Важливе рішення — що відбувається, коли Redis недоступний: обмежувачі закриваються (fail closed). Трафік відхиляється, а не пропускається помахом руки, — це менш зручна відповідь і єдина, яку можна відстояти. Навколо них стоять Cloudflare Turnstile на шляхах, які варто перевіряти челенджем, 351 рядок мідлвару ідемпотентності, щоб повторений запис не перетворився на два, origin‑lock, що відкидає запити, які прийшли не через парадні двері, і власний челендж на самому каталозі.</p>\n<p><strong>Результат.</strong> Зловживання стає дорогим для того, хто зловживає, і дешевим для платформи, а збій у власному сховищі обмежувача деградує до відмови, а не до відчинених дверей. Закриватися при збої справді означає, що проблема з Redis стає проблемою, видимою користувачам, — і це прийнято свідомо, бо альтернатива в тому, що проблема з Redis стає проблемою з рахунками.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Безпека",
        "Мережі та VPN",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Backend- та API‑розробка",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-first-party-product-analytics-in-postgresql-101/",
      "url": "https://engineer.company/uk/portfolio/built-first-party-product-analytics-in-postgresql-101/",
      "title": "Побудувала власну продуктову аналітику в PostgreSQL — 47 функцій над партиціонованими таблицями подій, які самі себе очищають, — псевдонімізовану за ротаційною сіллю та обумовлену згодою відвідувача.",
      "summary": "Питання про те, як користуються продуктом, отримують відповідь із власних таблиць платформи: нічого не залишає її межі, і на сторінці немає жодного тега.",
      "content_html": "<p><strong>Ситуація.</strong> Продуктові рішення потребують цифр, а звичайний спосіб їх отримати — поставити third‑party‑тег на кожну сторінку й дозволити чужим серверам стежити за користувачами. Це швидко, це безкоштовно на малих обсягах, і це означає, що поведінка відвідувачів професійної нетворкінг‑платформи — хто дивився яку компанію, хто що шукав — стає активом, яким володіє рекламний бізнес. Для платформи, користувачі якої — морські фахівці, яких можна ідентифікувати поіменно, це поганий обмін.</p>\n<p><strong>Завдання.</strong> Продуктовій команді потрібні були воронки, retention і дані про події, зібрані у спосіб, за який платформі не соромно й від якого користувач може відмовитися.</p>\n<p><strong>Дія.</strong> Аналітика оселилася в PostgreSQL — у схемі з 7 таблиць і 47 функцій. Таблиці подій партиціоновані — 22 визначення партицій — і самі себе очищають за розкладом, бо ціна власної аналітики не в тому, щоб зібрати події, а в тому, щоб зберігати їх вічно. Ідентичність псевдонімізовано за ротаційною сіллю, тож відвідувача не можна простежити через межу ротації навіть зсередини бази даних; це свідомо встановлена стеля для того, на що ці дані взагалі здатні відповісти. Клієнт знає про стан згоди й не надсилає нічого, доки згоду не дано, замість надсилати, а потім фільтрувати. Воронки конверсії обчислюються в базі даних, поруч із самими даними, а не експортуються кудись назовні, щоб потім бути приєднаними назад.</p>\n<p><strong>Результат.</strong> Питання про те, як користуються продуктом, отримують відповідь із власних таблиць платформи: нічого не залишає її межі, і на сторінці немає жодного тега. Обмеження — це чесна частина: ротація солі коштує когортного аналізу на довгих горизонтах, а дашбордів, які готовий хмарний сервіс дає безкоштовно, тут немає взагалі. Обидва компроміси прийнято свідомо.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "PostgreSQL",
        "SQL",
        "Аналітика даних",
        "Бази даних",
        "Інженерія даних",
        "Оптимізація продуктивності",
        "Data Governance та якість даних",
        "Аналітика даних та BI‑дашборди",
        "Проєктування та моделювання баз даних",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-operator-back-office-for-the-platform-102/",
      "url": "https://engineer.company/uk/portfolio/built-the-operator-back-office-for-the-platform-102/",
      "title": "Побудувала операторський бек‑офіс — близько 40 адміністративних маршрутів та 128 компонентів, що охоплюють заявки на володіння, модерацію, feature flags, кеш і діагностику, — щоб платформою можна було керувати без доступу до бази даних.",
      "summary": "Люди, які керують платформою, справді можуть нею керувати, а кожна дія проходить через ту саму авторизацію й лишає той самий слід, що й будь-яка інша.",
      "content_html": "<p><strong>Ситуація.</strong> Кожна платформа непомітно вирощує другий застосунок, і зазвичай це саме той, якого ніхто не планує. Комусь треба схвалити заявку на володіння, приховати відгук, увімкнути функцію для частини користувачів, очистити кеш або з&rsquo;ясувати, чому один обліковий запис бачить щось дивне. Коли такого застосунку немає, відповіддю стає інженер із консоллю бази даних — а це повільно, ніде не логується і за одну одруківку від інциденту.</p>\n<p><strong>Завдання.</strong> Керувати платформою щодня мало бути можливо без shell, щоб операційна робота належала тому, хто на зміні, а не тому, у кого є облікові дані.</p>\n<p><strong>Дія.</strong> Бек‑офіс склав приблизно 40 адміністративних маршрутів, побудованих зі 128 компонентів, і охоплює роботу такою, якою вона реально надходить: розгляд заявок на володіння компаніями, модерація відгуків і дописів, перемикання feature flags, перегляд і очищення кешів, читання діагностики та звітність, яку просить CEO. Він працює на тій самій дизайн‑системі й тому самому згенерованому API‑клієнті, що й публічний продукт, — і це був вирішальний вибір: внутрішній інструмент, побудований на власному стеку, стає тією частиною, яку ніхто не оновлює, а далі — тією, якій ніхто не довіряє.</p>\n<p><strong>Результат.</strong> Люди, які керують платформою, справді можуть нею керувати, а кожна дія проходить через ту саму авторизацію й лишає той самий слід, що й будь‑яка інша. Це велика поверхня, яку треба тримати протестованою й доступною заради невеликої внутрішньої аудиторії, і ця ціна платиться постійно. Вона все одно менша за альтернативу — інженера, який о дев&rsquo;ятій вечора в неділю набирає UPDATE на продакшні.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "UX / UI‑дизайн",
        "Продукт і вимоги",
        "Системне адміністрування",
        "Full‑Stack продуктова розробка",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-company-ownership-claims-end-to-end-103/",
      "url": "https://engineer.company/uk/portfolio/built-company-ownership-claims-end-to-end-103/",
      "title": "Побудувала наскрізний процес заявок на володіння компанією — користувач заявляє права на компанію, адміністратор ухвалює рішення, а схвалення переписує граф авторизації, який визначає, кому що дозволено редагувати.",
      "summary": "Компанії можуть перебрати й виправити власні записи без того, щоб хтось редагував базу даних вручну, а кожне надання повноважень має названого схвалювача й…",
      "content_html": "<p><strong>Ситуація.</strong> Каталог, наповнений із публічних джерел, має структурну проблему: компанії опинилися в ньому не з власної волі. Рано чи пізно приходить хтось із такої компанії й хоче виправити її запис — а між цією людиною й цим записом немає жодного зв&rsquo;язку, є лише твердження, що зв&rsquo;язок існує. Надати права надто легко — і вашу сторінку редагує конкурент. Надати надто повільно — і каталог лишається неправильним.</p>\n<p><strong>Завдання.</strong> Мав існувати шлях від «це моя компанія» до справжніх повноважень над записом — з людським рішенням посередині й слідом позаду.</p>\n<p><strong>Дія.</strong> Заявки на володіння побудовано наскрізно — 108 комітів і обидва застосунки. Користувач подає заявку з доказами; вона потрапляє в чергу в бек‑офісі; адміністратор розглядає її та схвалює або відхиляє з причиною, яка повертається заявникові. Найцікавіше — що саме робить схвалення: це не прапорець у рядку. Схвалення переписує граф авторизації, тож обліковий запис отримує реальний зв&rsquo;язок з організацією — той самий зв&rsquo;язок, до якого вже звертається кожна перевірка прав на платформі. Воротами є рішення людини, а не гілка в коді, і жодній функції не довелося дізнаватися про заявки, щоб ці ворота поважати.</p>\n<p><strong>Результат.</strong> Компанії можуть перебрати й виправити власні записи без того, щоб хтось редагував базу даних вручну, а кожне надання повноважень має названого схвалювача й прикріплену причину. Людський розгляд є вузьким місцем за задумом; автоматична перевірка доменного імені була б швидшою — і помилялася б саме в тих випадках, які важать найбільше.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Безпека",
        "Продукт і вимоги",
        "Full‑Stack продуктова розробка",
        "Безпека та керування доступом",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/established-a-continuous-security-programme-104/",
      "url": "https://engineer.company/uk/portfolio/established-a-continuous-security-programme-104/",
      "title": "Запровадила безперервну програму безпеки — сканування коду, DAST, перевірки залежностей і вразливостей, генерацію SBOM, пошук секретів та actions, закріплені за SHA, — поряд із 21 письмовим аудитом безпеки.",
      "summary": "Вразливість, оприлюднена в upstream, з'являється як зламана збірка, а не як новина. Реальна ціна — це обсяг знахідок: сканер, який повідомляє про все, привчає…",
      "content_html": "<p><strong>Ситуація.</strong> Робота з безпеки всередині застосунку — Content‑Security‑Policy, ролі бази даних із мінімальними привілеями, повторні перевірки прав — захищає платформу під час виконання. Але вона нічого не каже про те, що саме постачається: чи не підхопила залежність відому вразливість минулого вівторка, чи не потрапили в коміт облікові дані, які потім відкотили, і чи не перетворилася стороння action, закріплена за тегом, непомітно на інший код.</p>\n<p><strong>Завдання.</strong> Безпека ланцюга постачання та коду мала бути безперервною й автоматизованою, щоб її стан був результатом збірки, а не чиєюсь думкою.</p>\n<p><strong>Дія.</strong> Статичний аналіз виконує CodeQL, динамічне тестування проти живого інстансу — ZAP, а залежності Go перевіряє govulncheck. Software bill of materials (SBOM) генерується на кожній збірці за допомогою Anchore та Syft, тож те, що поїхало в продакшн, відоме, а не реконструюється потім. Gitleaks сканує історію на облікові дані. Кожна стороння GitHub Action закріплена за хешем коміту, а не за тегом, — це той неефектний контроль, який не дає перемістити тег у вас під ногами. Dependabot стежить за 6 екосистемами. Поряд з автоматизацією стоїть 21 письмовий аудит безпеки, зокрема модель загроз і оцінка за посібником з тестування OWASP, — адже сканери знаходять класи проблем, які хтось уже описав, а модель загроз — це те місце, де називають проблеми, специфічні саме для цієї платформи.</p>\n<p><strong>Результат.</strong> Вразливість, оприлюднена в upstream, з&rsquo;являється як зламана збірка, а не як новина. Реальна ціна — це обсяг знахідок: сканер, який повідомляє про все, привчає людей себе ігнорувати, і щоб сигнал лишався придатним до використання, потрібне постійне сортування знахідок, а не одноразове налаштування.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Надійність і резервне копіювання",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-loyalty-and-reputation-system-105/",
      "url": "https://engineer.company/uk/portfolio/built-the-loyalty-and-reputation-system-105/",
      "title": "Побудувала систему лояльності та репутації — 67 функцій над реєстром із 31 таблиці, з лігами, бейджами та крамницею обміну — де блокування рядка балансу закриває вікно подвійного витрачання.",
      "summary": "Внесок вимірюється й винагороджується, а баланс — це арифметика, а не наближення. Блокування рядка — повільніша відповідь, і його все одно обрано: конкуренція…",
      "content_html": "<p><strong>Ситуація.</strong> Професійний нетворкінг має проблему холодного старту: платформою варто користуватися тоді, коли нею вже користуються інші, а доти майже немає причин повертатися. Звичний важіль — це система винагород: бали за внесок, статус, що відображає репутацію. Описати її легко, а побудувати підступно, бо щойно бали можна витратити, вони стають грішми, і кожна помилка, якої припускаються з грішми, доступна й тут.</p>\n<p><strong>Завдання.</strong> Внесок мав бути вимірюваним і винагороджуваним, а баланс — таким, який не можна витратити двічі.</p>\n<p><strong>Дія.</strong> Схема лояльності налічує 31 таблицю та 67 функцій, статус — ще 5 таблиць і 32 функції, а поруч стоять схеми discovery й персоналізації, які вирішують, що саме бачить конкретний учасник. Над реєстром надбудовані ліги, бейджі та крамниця обміну, де баланс перетворюється на щось реальне. Найбільше уваги забрав найдавніший баг у світі: перевірити баланс, потім списати його — і два запити, що прийшли одночасно, обидва проходять перевірку. Кожна мутація бере блокування рядка гаманця, перш ніж його прочитати, тож другий запит чекає на завершення першого, а не змагається з ним. І те, що гаманець лежить у тій самій базі даних, що й усе інше, — саме це взагалі робить таке можливим: баланс і те, що на нього куплено, комітяться разом або не комітяться зовсім.</p>\n<p><strong>Результат.</strong> Внесок вимірюється й винагороджується, а баланс — це арифметика, а не наближення. Блокування рядка — повільніша відповідь, і його все одно обрано: конкуренція за гаманець — це черга, а альтернатива — учасник, який витрачає ті самі бали двічі, і хтось, хто потім звіряє це вручну.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "PostgreSQL",
        "SQL",
        "Бази даних",
        "Оптимізація продуктивності",
        "Продукт і вимоги",
        "Backend- та API‑розробка",
        "Продуктова стратегія та вимоги",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-platform-s-social-layer-106/",
      "url": "https://engineer.company/uk/portfolio/built-the-platform-s-social-layer-106/",
      "title": "Побудувала соціальний рівень платформи — дописи, стрічку, групи, згадки, граф підписників та дайджест подій — на тому самому рівні даних, побудованому насамперед на функціях, що й решта продукту.",
      "summary": "У платформи з'явилася причина бути відкритою в день, коли нікому не треба шукати компанію, і з'явилася без паралельного стеку, який довелося б підтримувати.",
      "content_html": "<p><strong>Ситуація.</strong> Каталог компаній — це довідник. Люди зазирають у нього й ідуть. Повертатися на професійну платформу змушує присутність інших людей, а це означає дописи, групи й причину повернутися, яка не зводиться до листа з нагадуванням.</p>\n<p><strong>Завдання.</strong> Соціальний рівень треба було додати так, щоб він не став другою системою з власними правилами, власними дозволами та власним способом зберігати дані.</p>\n<p><strong>Дія.</strong> Дописи, стрічка, групи, згадки, граф підписників і дайджест подій зайшли в продукт за 188 комітів — усе на тому самому рівні даних, побудованому насамперед на функціях, що й решта платформи. Це обмеження зробило більшу частину роботи: граф підписників — це такі самі таблиці й функції, як усе інше, згадка розв&rsquo;язується через ту саму схему identity, яку використовує каталог, а допис успадковує чергу модерації, уже побудовану для відгуків. Нічому тут не знадобилося власне сховище чи власна модель дозволів. Єдине місце, яке чинило опір, — це стрічка, бо ефективно зібрати персоналізовану стрічку подій справді інша задача, ніж дістати рядок, і саме тут робота з персоналізації та discovery виправдовує своє місце.</p>\n<p><strong>Результат.</strong> У платформи з&rsquo;явилася причина бути відкритою в день, коли нікому не треба шукати компанію, і з&rsquo;явилася без паралельного стеку, який довелося б підтримувати. Чи є соціальний рівень правильною інвестицією для морського каталогу — це продуктове питання, а не інженерне: він тут, бо цього попросив продукт, і побудований так само, як усе навколо нього.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Бази даних",
        "Веброзробка",
        "Продукт і вимоги",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Продуктова стратегія та вимоги"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-hiring-marketplace-and-career-workspace-107/",
      "url": "https://engineer.company/uk/portfolio/built-the-hiring-marketplace-and-career-workspace-107/",
      "title": "Побудувала майданчик найму та кар'єрний робочий простір для моряків — 151 збережена функція у 48 таблицях — що охоплюють вакансії, заявки, сертифікати, просування в рангах та підтверджений стаж плавання.",
      "summary": "Вакансію можна зіставити із задокументованою кваліфікацією, а не з назвою посади, яку людина написала про себе сама, — і саме в цьому вся різниця між дошкою…",
      "content_html": "<p><strong>Ситуація.</strong> Комерційний аргумент на користь морської професійної мережі — це найм: компаніям потрібні екіпажі та офіцери, а морякам потрібні посади на суднах. Обидві половини вже існували на платформі, але не в тій формі — компанії були в каталозі, фахівці мали профілі, і ніщо не поєднувало вакансію з людиною, кваліфікованою її закрити. Найскладніше — саме кваліфікація, бо в цій галузі це сертифікати, ранги й задокументований стаж плавання, а не назва посади.</p>\n<p><strong>Завдання.</strong> Вакансії, заявки та перевірювані кваліфікаційні документи моряків потрібно було змоделювати належно, а не як вільний текст у профілі.</p>\n<p><strong>Дія.</strong> Побудовано два домени. Сторона найму налічує 32 таблиці та 118 функцій і охоплює вакансії, заявки, формування короткого списку та погляд роботодавця на весь потік кандидатів. Кар&rsquo;єрний робочий простір несе 16 таблиць і 33 функції, у яких зберігаються сертифікати, просування в рангах і стаж плавання, разом із завантаженням документів і чергою ручної перевірки, щоб кваліфікацію було перевірено, а не просто задекларовано. Саме моделювання просування як графа, а не списку, робить зіставлення корисним: одного рангу можна досягти з іншого за наявності певних сертифікатів і достатнього зафіксованого часу в морі, і саме ця структура дає змогу зіставляти вакансію з кар&rsquo;єрою, а не з ключовим словом. Кар&rsquo;єрний робочий простір постачається за feature flag і ще не випущений повністю; сторона найму вже працює.</p>\n<p><strong>Результат.</strong> Вакансію можна зіставити із задокументованою кваліфікацією, а не з назвою посади, яку людина написала про себе сама, — і саме в цьому вся різниця між дошкою оголошень і інструментом найму в цій галузі. Перевірка є вузьким місцем, і це навмисно: черга ручної перевірки не масштабується так, як масштабувалася б автоматична, а автоматична підтверджувала б кваліфікацію тим, кому її підтверджувати не можна.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Data Governance",
        "Full‑Stack розробка",
        "PostgreSQL",
        "Бази даних",
        "Продукт і вимоги",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Продуктова стратегія та вимоги",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-companys-infrastructure-as-code-108/",
      "url": "https://engineer.company/uk/portfolio/built-the-companys-infrastructure-as-code-108/",
      "title": "Побудувала власну інфраструктуру компанії як 19 плейбуків Ansible і 34 ролі на 12 065 рядках YAML, що зводять живий хост до оголошеного стану, де кожен play ідемпотентний.",
      "summary": "Господарство відтворюється з репозиторію, а ті його частини, які були істинними лише тому, що хтось їх пам'ятав, тепер є твердженнями, що валять прогін.",
      "content_html": "<p><strong>Ситуація.</strong> Engineer ApS керує власним господарством — вебприсутність, git‑форджа, база даних, резервні копії, поштовий транспорт і DNS, — і не було нікого, кому передати експлуатацію. Компанія з однієї людини має ті самі режими відмови, що й велика, і жодного резерву, через що звична відповідь — людина, яка пам&rsquo;ятає, як налаштовано хост, — є найменш доступним варіантом.</p>\n<p><strong>Завдання.</strong> Усе господарство мало бути описане в репозиторії, а не в голові, і описане у формі, що зводить реальний хост до заданого стану, а не документує його.</p>\n<p><strong>Дія.</strong> З цього виросли 19 плейбуків і 34 ролі на 12 065 рядках YAML. Форма важить більше за розмір. Композиція є даними, а не прапорцями: хост належить до групи рівня, чиї змінні оголошують, які ролі він виконує, тож розгортання без жодних аргументів зводить кожен хост до оголошеного стану. Ідемпотентність є контрактом, а не прагненням — зведений хост звітує про нуль змін, і п&rsquo;єса, яка не може цього сказати, не завершена. Чотири простори імен команд тримають обіцянки нарізно: перевірка, що не торкається жодного хоста, звіти, які читають хост і ніколи його не змінюють, розгортання, що змінює хост до відповідності репозиторію, і верифікація, що змінює хост навмисно й повертає вердикт.</p>\n<p><strong>Результат.</strong> Господарство відтворюється з репозиторію, а ті його частини, які були істинними лише тому, що хтось їх пам&rsquo;ятав, тепер є твердженнями, що валять прогін. Ціна реальна: кожна зміна повільніша, ніж редагування файлу на сервері, а зведення, застосоване наполовину, гірше за те, що відмовляється, — саме тому попереду згодом додано попередню перевірочну п&rsquo;єсу. Цей обмін зроблено свідомо, і він себе виправдав.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Архітектура платформи",
        "Документація",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Системне адміністрування",
        "DevOps та автоматизація CI/CD",
        "Infrastructure as Code",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/ran-the-whole-company-on-one-512mb-host-109/",
      "url": "https://engineer.company/uk/portfolio/ran-the-whole-company-on-one-512mb-host-109/",
      "title": "Втримала всю компанію на одному хості з 512 МБ і одним ядром — git‑форж, вебсервер для семи доменів, Tor, два сервери альтернативних протоколів, резервні копії та блокування вторгнень — розглядаючи 464 МБ доступної пам'яті як зобов'язальне архітектурне обмеження.",
      "summary": "Уся компанія працює на машині, що коштує на місяць менше за обід, і задум кращий саме завдяки цій дисципліні, а не просто дешевший.",
      "content_html": "<p><strong>Ситуація.</strong> Робочий хост компанії — це одноядерний хмарний примірник із 512 МБ пам&rsquo;яті та 10 ГБ диска, з яких придатними до вжитку є близько 464 МБ. Усе, що бізнес виконує публічно, стоїть на ньому: вебсервер, що термінує TLS для семи доменів, git‑форджа, onion‑служба Tor, сервер Gemini, сервер Gopher, зашифровані резервні копії та блокування вторгнень. Звична реакція на цей перелік — придбати більшу машину.</p>\n<p><strong>Завдання.</strong> Обмеження мало розглядатися як архітектурний вхідний параметр, а не як проблема, на яку витрачають гроші, бо чесне питання полягало не в тому, чи спрацювала б більша машина, а в тому, чи потрібна вона задуму.</p>\n<p><strong>Дія.</strong> Пам&rsquo;ять стала аргументом, що вирішував суперечки. Немає ані агента моніторингу, ані конвеєра метрик, ані панелі — звітність є витягуванням, сім команд, що читають хост і формують Markdown, нічого не змінюючи й запускаючись лише на прохання. Наглядачем є systemd, а не другий менеджер процесів, накладений поверх нього, а контейнерна площина — це модулі Quadlet під тим самим наглядачем, а не демон із власним. Платформи з вебпанелями відкинуто ще на етапі задуму з тієї самої причини. Коли постало питання, чи витримає хост onion‑службу, відповідь надійшла з доби вимірюваних зразків, а не з думки: доступна пам&rsquo;ять ніколи не опускалася нижче приблизно 310 МБ із 464, підкачування трималося на 2,6 відсотка, а процесор був вільним на 99,7 відсотка.</p>\n<p><strong>Результат.</strong> Уся компанія працює на машині, що коштує на місяць менше за обід, і задум кращий саме завдяки цій дисципліні, а не просто дешевший. Коштувало це запасу для будь‑чого недбалого — пошти навмисно немає на цій машині взагалі — її написано як риштування для встановлення, що чекає на власний хост, бо поштовий сервер потребує запасу, який ця машина вже витратила, і це записано, а не виявлено згодом.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Архітектура платформи",
        "Архітектура рішень",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Системне адміністрування",
        "Infrastructure as Code",
        "Архітектура платформи та рішень",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/",
      "url": "https://engineer.company/uk/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/",
      "title": "Знайшла й закрила три захисти SSH від перебору, які ніколи не працювали: тюрму блокування, що стежила за портом 22, поки демон слухав 1986, обмеження швидкості, затінене ширшим правилом над ним, і дію блокування, чий бінарний файл ніколи не знаходився, тож жодне блокування ніколи не застосовувалося.",
      "summary": "Три види захисту, що не спрацювали жодного разу, тепер працюють, а клас дефектів, до якого вони належать, — засіб контролю, чий режим відмови полягає в тому,…",
      "content_html": "<p><strong>Ситуація.</strong> Огляд захищеності робочого хоста в серпні 2026 року поставив питання, на яке зазвичай дають упевнену відповідь: чи працює захист від перебору паролів SSH. Усі три засоби були налаштовані, усі три з&rsquo;являлися в кожному звіті, який хтось переглядав, і всі три були бездіяльними від дня створення хоста.</p>\n<p><strong>Завдання.</strong> Засоби контролю треба було перевірити проти того, що ядро насправді робить із пакетом, а не проти файлів налаштувань, які описують, що з ним мало б статися.</p>\n<p><strong>Дія.</strong> Читання налаштувань підтвердило б хибну відповідь тричі, тож огляд натомість читав систему в роботі. В&rsquo;язниця блокування вторгнень стежила за портом 22, тоді як демона було перенесено на 1986 під час початкового посилення захисту — кожне блокування, яке вона записувала, називало порт, на якому ніщо не слухало. Обмеження частоти на брандмауері було гіршим у тонший спосіб: правило існувало, і воно стояло нижче ширшого правила, що збігалося першим. Користувацькі правила брандмауера обчислюються згори вниз, і перемагає перший збіг, тож широкий дозвіл над обмеженням частоти робить це обмеження мертвим кодом, який усе одно друкується в кожному переліку стану. Третій засіб був найтихішим із них: дія блокування викликає двійковий файл фільтра пакетів, який система пакунків лише рекомендує, а не вимагає, тож на хості без нього в&rsquo;язниця запускається, рахує та вирішує, а потім зазнає невдачі в ту єдину мить, коли намагається заблокувати. Усі три виправлення були малими. З цього вийшло не виправлення, а два правила, що тепер керують репозиторієм: засіб безпеки дістає твердження, а не коментар, і брандмауер перевіряється за розташуванням правила, а не за його наявністю.</p>\n<p><strong>Результат.</strong> Три види захисту, що не спрацювали жодного разу, тепер працюють, а клас дефектів, до якого вони належать, — засіб контролю, чий режим відмови полягає в тому, що він і далі звітує про справність, — це саме той клас, який тепер покликані ловити перевірки платформи. Усі три були бездіяльними від початкового розгортання. Усі три друкували «справний» скрізь, куди хтось дивився, і саме тому вони протривали.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Моніторинг та observability",
        "Системне адміністрування",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)",
        "Налаштування мереж та VPN"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/hardened-ssh-with-three-stage-validation-111/",
      "url": "https://engineer.company/uk/portfolio/hardened-ssh-with-three-stage-validation-111/",
      "title": "Загартувала SSH до 24 стверджених директив із тристадійною перевіркою — файл‑кандидат, зібрана конфігурація, а тоді власне зчитування демона — після того, як зчитування спіймало робочий сервер на мовчазному перевизначенні двох із двадцяти чотирьох.",
      "summary": "Стан захисту SSH тепер є відповіддю демона, а не заявою репозиторію, і різниця не теоретична — на момент написання перевірки вона вже сягала двох параметрів.",
      "content_html": "<p><strong>Ситуація.</strong> SSH є єдиним інтерактивним шляхом до хоста компанії, і його налаштування пише роль автоматизації, яка місяцями працювала чисто. Звіт про доступ у вересні 2026 року прочитав власні розв&rsquo;язані параметри демона й виявив, що два з них розходяться з тим, що роль писала за кожного окремого зведення.</p>\n<p><strong>Завдання.</strong> Посилення захисту мало стати тим, що підтверджує демон, а не тим, що стверджує репозиторій, бо розрив між цими двома був відкритим уже місяцями, і ніхто цього не помічав.</p>\n<p><strong>Дія.</strong> Причиною був порядок налаштувань. Операційна система постачає власні усталені значення розкоментованими, вище того місця, куди потрапляє файл‑вставка, і для двох згаданих параметрів перемагає перше входження. Виправленням став префікс імені файлу, що сортується попереду постачальницького, — це зміна завбільшки в один символ і саме той різновид, що лишається зламаним, бо нікому не спадає на думку подивитися. Важливіше те, що збудовано навколо неї: три етапи перевірки за кожного зведення. Файл‑кандидат перевіряється на синтаксис перед встановленням, тож хибне налаштування ніколи не дістається хоста. Зібране налаштування перевіряється після встановлення. Потім зчитується власний розв&rsquo;язаний вивід демона, і проти нього стверджується 24 директиви, тож параметр, який записано, але перекрито, валить прогін. Дві директиви навмисно залишено осторонь, обидві тому, що демон їх більше не реалізує, а записувати їх означало б лише вдавати ретельність.</p>\n<p><strong>Результат.</strong> Стан захисту SSH тепер є відповіддю демона, а не заявою репозиторію, і різниця не теоретична — на момент написання перевірки вона вже сягала двох параметрів. Зведення, яке не бачить, чи набув засіб контролю чинності, його не перевірило, а пошук директиви доводить лише те, що її було записано.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Системне адміністрування",
        "Тестування та QA",
        "Infrastructure as Code",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/",
      "url": "https://engineer.company/uk/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/",
      "title": "Довела весь шлях блокування вторгнень на кожному запуску загартування, блокуючи зарезервовану тестову адресу, читаючи отримане правило ядра й знімаючи блокування у гарантованому блоці прибирання, щоб тюрма, яка перестала працювати, валила запуск, а не звітувала про здоров'я.",
      "summary": "Шлях блокування, який перестає працювати, тепер валить зведення замість того, щоб і далі звітувати про справність, — і це єдина властивість, яка мала значення.",
      "content_html": "<p><strong>Ситуація.</strong> Службу блокування вторгнень уже спіймали на блокуванні порту, на якому демон SSH не слухав. Виправлення порту закрило той окремий випадок. Воно нічого не зробило з причиною, чому хиба протривала так довго, а вона в тому, що шлях блокування не має видимої відмови: служба працює, в&rsquo;язниця перелічена як активна, і ніде нічого не каже, чи взагалі якесь блокування дістається ядра.</p>\n<p><strong>Завдання.</strong> Шлях блокування мав випробовуватися за кожного зведення, проти живого набору правил, а не виводитися з того, що служба піднята.</p>\n<p><strong>Дія.</strong> Зведення тепер блокує адресу з блоку, який стандарти резервують для документації, зчитує з ядра отримане правило в фільтрі пакетів і розблоковує її в блоці прибирання, що виконується незалежно від того, чи перевірка пройшла, чи ні. Зарезервований діапазон є несучим вибором — тестова адреса не належить нікому, тож випадкове блокування, що переживе невдалий прогін, не здатне відрізати справжню мережу. Зчитування з ядра є другою половиною: власний вивід стану служби повідомив би про успіх блокування, яке не створило жодного правила, а це і є та сама відмова, яку перевіряють. Поряд із цим бекенд блокування закріплено, а не залишено на визначення службою, а бекенд журналу встановлено на визначення, бо операційна система не постачає традиційного журналу автентифікації, і хибний вибір відмовляє мовчки, стежачи за файлом, який ніколи не з&rsquo;явиться.</p>\n<p><strong>Результат.</strong> Шлях блокування, який перестає працювати, тепер валить зведення замість того, щоб і далі звітувати про справність, — і це єдина властивість, яка мала значення. Це коштує кількох секунд на кожному прогоні й щоразу записує та відкликає правило брандмауера проти робочої системи, що є справжнім втручанням у живу систему і було прийняте на тій підставі, що альтернативу вже було доведено гіршою.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/verified-firewall-rules-by-position-113/",
      "url": "https://engineer.company/uk/portfolio/verified-firewall-rules-by-position-113/",
      "title": "Перевірила правила фаєрвола за позицією, а не за наявністю, читаючи пронумерований перелік правил і живий ланцюг фільтрації пакетів, бо правило, яке існує, — це не правило, до якого доходить хоч один пакет.",
      "summary": "Стан брандмауера тепер перевіряється так, як його переживає пакет. Найкориснішим наслідком була не перевірка, а те, що вона виявила про звітність, яка їй…",
      "content_html": "<p><strong>Ситуація.</strong> Перелік стану брандмауера показує набір правил. Фільтр пакетів обчислює впорядкований список і спиняється на першому збігу. Це різні речі, і різниця невидима в кожному інструменті, що друкує зведення, — саме так хост цілий рік працював з обмеженням частоти, до якого не дійшов жоден пакет, бо воно стояло нижче ширшого правила, що збігалося першим.</p>\n<p><strong>Завдання.</strong> Перевірка брандмауера мала читати розташування, а не належність, бо наявність уже було продемонстровано як таку, що не доводить нічого.</p>\n<p><strong>Дія.</strong> Перевірки тепер читають нумерований перелік правил і живий ланцюжок фільтра та стверджують проти порядку. На кожен порт існує рівно одне правило й завжди з протоколом, бо правило без нього мовчки розширює поверхню. Порт SSH несе обмеження частоти й ніколи дозвіл поруч, бо дозвіл над обмеженням є саме тим затіненням, яке було виявлено. Оголошена публічна поверхня є коротким переліком із п&rsquo;яти портів, який стверджується цілком, а не перевіряється поштучно, тож порт, що з&rsquo;являється без оголошення, валить перевірку, а не лишається поміченим. Звіт з безпеки подає правила в порядку збігу з попередженням на початку розділу, яке пояснює, як його читати, бо наступна людина, що відкриє той файл, інакше прочитає набір.</p>\n<p><strong>Результат.</strong> Стан брандмауера тепер перевіряється так, як його переживає пакет. Найкориснішим наслідком була не перевірка, а те, що вона виявила про звітність, яка їй передувала: кожен причетний інструмент цілий рік друкував обмеження частоти, і друкував правильно, і жодного з них не було спитано про єдине питання, що мало значення.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Тестування та QA",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/",
      "url": "https://engineer.company/uk/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/",
      "title": "Побудувала зашифровані резервні копії поза хостом на restic із обрізанням за терміном зберігання, перевіркою цілісності та щомісячним автоматизованим навчальним відновленням, а тоді проаудитувала позицію відновлення й записала прогалини, замість лишати їх на знаходження під час інциденту.",
      "summary": "Компанія може втратити хост і повернути свої дані, і це речення спирається на відновлення, що відбулося минулого місяця, а не на резервну копію, зроблену…",
      "content_html": "<p><strong>Ситуація.</strong> Усе, що зберігає компанія — git‑репозиторії, база даних, сайт, — стояло на одному хмарному примірнику, чий провайдерський знімок був усією позицією відновлення. Провайдерський знімок — добра річ, щоб її мати, і погана, щоб на неї покладатися: він лежить у тому самому обліковому записі, що й машина, яку він захищає, він не зашифрований тут нікому відомим ключем, і ніхто ніколи з нього не відновлювався.</p>\n<p><strong>Завдання.</strong> Резервні копії мали бути зашифрованими, поза хостом, підрізаними за політикою зберігання і — та частина, яку зазвичай пропускають — справді відновлюваними, за розкладом, без того, щоб хтось про це пам&rsquo;ятав.</p>\n<p><strong>Дія.</strong> Резервне копіювання виконується за таймером systemd: дамп бази даних, де така існує, потім зашифрований знімок із усуненням дублікатів до сховища в іншого провайдера через SFTP, потім підрізання за політикою зберігання, потім перевірка цілісності. Перемикач мертвої руки пінгується лише в разі успіху, і саме ця відмінність робить його тривогою, а не журналом — невдалий прогін не каже нічого, а сказати нічого і є тим, що здіймає тривогу. Окремо щомісяця виконується навчання з відновлення: воно витягує відомий файл із репозиторію та порівнює його, тож перевіряється саме відновлення, а не резервне копіювання. Парольну фразу записано у файл, який читають модулі, а не передано через середовище, бо наглядач обробляє екранування у значеннях середовища, і парольна фраза, що містить зворотну похилу риску, мовчки відрізнялася б від тієї, що створила репозиторій. Згодом позицію відновлення було перевірено й описано, а прогалини, що лишилися, названо в документі, а не залишено на виявлення під час інциденту.</p>\n<p><strong>Результат.</strong> Компанія може втратити хост і повернути свої дані, і це речення спирається на відновлення, що відбулося минулого місяця, а не на резервну копію, зроблену минулої ночі. Найціннішим виходом перевірки був перелік того, що досі не покрито, — саме та частина, про яку зелений звіт про резервне копіювання структурно не здатен нікому сказати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Infrastructure as Code",
        "Надійність та моніторинг (SRE)",
        "Резервне копіювання та відновлення",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-dead-mans-switch-monitoring-115/",
      "url": "https://engineer.company/uk/portfolio/built-dead-mans-switch-monitoring-115/",
      "title": "Побудувала моніторинг із сигналом живучості, який пінгує лише поки пам'ять і диск здорові, тож ослаблений хост здіймає тривогу, замовкаючи, — і спіймала шість імен змінних, що казали «free», де перевірка правильно вимірювала «available», на порядок різні на машині з 464 МБ.",
      "summary": "Хост тепер має тривогу, чий режим відмови — спрацювати, а іменування, яке її знищило б, виправлено.",
      "content_html": "<p><strong>Ситуація.</strong> Хост на 464 МБ, що несе форджу, базу даних і вебсервер, має два реалістичні способи померти: у нього закінчується пам&rsquo;ять або закінчується диск. Жоден із них себе не оголошує. Обидва цілком передбачувані за кілька годин наперед, якщо хтось дивиться, а не дивився ніхто.</p>\n<p><strong>Завдання.</strong> Хостові потрібна була тривога, що працює тоді, коли не працює хост, — а це виключає будь‑що, що має надіслати повідомлення в мить відмови.</p>\n<p><strong>Дія.</strong> Відповіддю є перемикач мертвої руки на таймері. Що п&rsquo;ятнадцять хвилин із розкидом невеликий скрипт вимірює доступну пам&rsquo;ять і вільний диск і пінгує зовнішню службу лише тоді, коли обидва вище своїх порогів. Тиша є сигналом тривоги. Машина, у якої закінчилася пам&rsquo;ять, зникла мережа або яка перестала завантажуватися, дає точнісінько той самий сигнал, що й несправна, — і це правильна поведінка та причина, чому обрано цю форму, а не агента, що звітує про стан. Вимірюється доступна пам&rsquo;ять, а не вільна, і саме ця відмінність обернулася найповчальнішою частиною роботи: скрипт увесь час читав правильний стовпчик, тоді як шість імен змінних довкола нього казали «вільна». На справному Linux‑хості вільної пам&rsquo;яті майже нуль, бо ядро використовує простій пам&rsquo;яті під кеш, тож читач, який звірив би ці імена з порогом у десять відсотків, побачив би дванадцять мегабайтів вільними на машині з 464 МБ, дійшов би висновку, що перевірка зламана, і виправив би її зміною завбільшки в один символ, яка перетворює робочу тривогу на таку, що постійно порушує поріг і яку глушать протягом тижня.</p>\n<p><strong>Результат.</strong> Хост тепер має тривогу, чий режим відмови — спрацювати, а іменування, яке її знищило б, виправлено. Справжнє обмеження перемикача зазначено в його власній документації: він доводить, що машина справна, а не що сайт обслуговує запити, і це різні питання.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Інфраструктура",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Infrastructure as Code",
        "Надійність та моніторинг (SRE)",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/made-ansible-check-mode-tell-the-truth-116/",
      "url": "https://engineer.company/uk/portfolio/made-ansible-check-mode-tell-the-truth-116/",
      "title": "Змусила check mode казати правду на всій платформі, знайшовши шість зондів, які ухвалювали рішення за значенням, якого хост ніколи не давав, бо модуль command в Ansible звітує про успіх під --check, повністю пропускаючи саму команду.",
      "summary": "Пробний прогін тепер або щось вимірює, або каже, що не виміряв, і жодне з цих двох не є тим третім варіантом, який він мав раніше.",
      "content_html": "<p><strong>Ситуація.</strong> Пробний прогін проти робочої системи має бути безпечним способом дізнатися, що зробить зміна. У вересні 2026 року пробний прогін завалився на твердженні, яке просто хибно описувало хост, і порадив операторові встановити прапорець, що послабив би пісочницю безпеки. Пробний прогін не читав хоста. Він прочитав значення, якого хост ніколи не давав, і зробив із нього висновок.</p>\n<p><strong>Завдання.</strong> Кожен зонд, чий результат живить рішення, мав стати чесним у режимі перевірки, а ті, які такими стати не могли, мали сказати про це вголос, а не мовчати.</p>\n<p><strong>Дія.</strong> Причиною є властивість інструмента, яка задокументована і яку легко забути: модуль команд не виконується в режимі перевірки, і те, що він реєструє, не є порожнім результатом — це успіх із порожнім виводом. Будь‑яка умова, що читає той реєстр, отже, вирішує на підставі значення, яке ніколи не вимірювалося, і вирішує в той бік, куди випадково вказує її власна логіка. Обхід усіх зареєстрованих зондів виявив шість таких, і кожен брехав по‑своєму: один звітував, що наглядач приймає кожну директиву модуля, жодного разу того наглядача не спитавши, інший звітував, що робити нічого, на хості з вимкненим брандмауером. Кожному надано одну з двох форм. Зонд, що читає наперед наявний стан, якого прогін не торкався, позначено на виконання навіть у режимі перевірки. Зонд, який виконатися не може, пропускається, і повідомлення називає, що саме не було перевірено, — бо тиша в журналі прогону читається точнісінько як успіх.</p>\n<p><strong>Результат.</strong> Пробний прогін тепер або щось вимірює, або каже, що не виміряв, і жодне з цих двох не є тим третім варіантом, який він мав раніше. Загальне правило потрапило до посібника з розробки тією самою зміною: режим перевірки не має права брехати, а зонд, який не бачить, зобов&rsquo;язаний оголосити свою сліпоту, а не виводити з неї вердикт.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Infrastructure as Code",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/added-a-preflight-play-for-secrets-117/",
      "url": "https://engineer.company/uk/portfolio/added-a-preflight-play-for-secrets-117/",
      "title": "Додала передпольотний play, який виконує той самий код, що й зведення, проти локальних секретів оператора приблизно за секунду, після того як наполовину застосований продакшн‑запуск загинув на дев'ятому завданні з уже записаними на живий хост налаштуваннями swap.",
      "summary": "Секрет, який не розв'язується, тепер коштує двосекундної відмови на ноутбуці замість частково застосованої зміни на живому сервері.",
      "content_html": "<p><strong>Ситуація.</strong> Експлуатаційні секрети щойно було розділено так, щоб кожен хост ніс власний репозиторій резервних копій, парольну фразу та перемикач тривоги. Код репозиторію був правильним. Зашифроване сховище оператора досі тримало попереднє значення для одного хоста, і ніщо не могло побачити цієї розбіжності, бо сховище навмисно є локальним для машини оператора й невидимим для власної перевірки якості репозиторію.</p>\n<p><strong>Завдання.</strong> Цьому класові відмов потрібне було місце, де він міг би відмовляти дешево, бо він щойно відмовив дорого.</p>\n<p><strong>Дія.</strong> Перше зведення після зміни під&rsquo;єдналося до живого хоста, виконало вісім завдань і відмовилося на дев&rsquo;ятому — правильно, але зсередини прогону, що вже записав налаштування підкачування до робочої системи. Наполовину застосоване зведення є гіршою відповіддю за відмову, тож було написано попередню перевірочну п&rsquo;єсу: вона не дістається жодного хоста, виконується локально, не збирає фактів і виконує ті самі два файли завдань, які використовує справжнє зведення, проти сховища оператора. Вона відповідає приблизно за секунду, і розгортання виконує її першою. Несучим рішенням є те, що це той самий код, а не друга реалізація того самого правила, бо перевірка, яка переказує правило іншою мовою, зрештою починає з ним розходитися, і розходиться мовчки. Її написання виявило пастку, яку вона мало не створила: факти, встановлені під час п&rsquo;єси, переживають цю п&rsquo;єсу, тож зчеплення попередньої перевірки та зведення в один виклик передало б справжній ролі парольну фразу, яку попередня перевірка вже розв&rsquo;язала, і перевірка пройшла б на сховищі, що досі було хибним. Це відтворили, перш ніж від цього захистилися, в обох файлах завдань.</p>\n<p><strong>Результат.</strong> Секрет, який не розв&rsquo;язується, тепер коштує двосекундної відмови на ноутбуці замість частково застосованої зміни на живому сервері. Попередню перевірку навмисно не позначено на безумовне виконання й навмисно не серіалізовано, і обидва ці факти записано як рішення, а не як усталені значення.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Infrastructure as Code",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/reconciled-a-dns-zone-declaratively-118/",
      "url": "https://engineer.company/uk/portfolio/reconciled-a-dns-zone-declaratively-118/",
      "title": "Звірила зону DNS із 20 записів декларативно з API Cloudflare, з окремими входами для аудиту та експорту в BIND, і вимкнула проксі CDN назад із міркувань приватності після того, як його побудувала.",
      "summary": "Зона версіонована, порівнювана та експортована, а те єдине рішення, що пішло проти очевидного усталеного вибору, записано разом із його обґрунтуванням, аби…",
      "content_html": "<p><strong>Ситуація.</strong> DNS компанії ніс близько двадцяти записів на вебприсутність, git‑піддомен, два особисті перенаправлення, поштову маршрутизацію через хостованого постачальника скриньок, домен транзакційної відправки та записи автентифікації для обох. Усе це жило у вебконсолі провайдера, а це означає, що поточним станом було те, що залишила по собі остання людина, яка клацала.</p>\n<p><strong>Завдання.</strong> Зона мала стати оголошенням у репозиторії, зі способом порівняти це оголошення з тим, що провайдер насправді віддає.</p>\n<p><strong>Дія.</strong> Зону записано як дані — живі записи, записи застосунків, записи транспортної політики та окремий перелік записів, що очікують на вилучення, і це чесний спосіб зафіксувати видалення, яке ще не сталося. Одна п&rsquo;єса узгоджує її з API провайдера. Ще дві точки входу стоять за явними позначками згоди: перевірка, що звітує про різницю, нічого не змінюючи, і експорт, що виписує зону в стандартному форматі файлу зони, аби її могло прочитати щось, що не є цим репозиторієм. Найцікавішим рішенням було скасування. Пропускання двох вебоблич через мережу доставлення контенту провайдера було збудовано, воно працювало, а потім його вимкнули — бо воно коштує того єдиного речення, заради якого існує сторінка приватності компанії. З проксі попереду інша компанія обробляє адресу кожного відвідувача та кожну URL‑адресу, яку той запитує, раніше за нас, за їхньою політикою, а не за нашою. Для бізнесу, чия відмітна заява полягає в тому, що ніхто не спостерігає, це гірший обмін, ніж атаки, від яких він захищає.</p>\n<p><strong>Результат.</strong> Зона версіонована, порівнювана та експортована, а те єдине рішення, що пішло проти очевидного усталеного вибору, записано разом із його обґрунтуванням, аби ніхто не переглянув його випадково. Шлях перевірки використовується найчастіше, бо знати різницю потрібно частіше, ніж її усувати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Python",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Мережі та VPN",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/",
      "url": "https://engineer.company/uk/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/",
      "title": "Зменшила експозицію пісочниці systemd на кожному юніті, який встановлює сама платформа, — служба сигналу живучості з 9,6 UNSAFE до 1,5, звернений до інтернету git‑форж із 8,3 EXPOSED до 1,5 — і додала перевірку парсером під час зведення, знайшовши директиву з помилкою, яку мовчки ігнорували у трьох шаблонах юнітів.",
      "summary": "Кожен модуль працює з тими правами, які йому потрібні, і без тих, які не потрібні, числа виміряно, а не заявлено, і клас дефектів, у якому одруківка стає…",
      "content_html": "<p><strong>Ситуація.</strong> Тринадцять файлів модулів встановлювалися цим репозиторієм і виконувалися на робочому хості з тими правами, які наглядач дає усталено, а це майже всі. Оцінка захищеності поставила службі перемикача мертвої руки 9,6 і назвала її небезпечною; git‑форджа, обернена до інтернету, дістала 8,3 і була визнана відкритою. Обидва числа були точними, і жодне нічого не спонукало, бо оцінка без прив&rsquo;язаного порога — це число, яке люди привчаються пропускати.</p>\n<p><strong>Завдання.</strong> Кожному модулю потрібна була пісочниця, пропорційна до того, що він насправді робить, а пісочницям потрібна була перевірка, бо режим відмови хибної пісочниці полягає в тому, що модуль запускається, а потім ламається там, де парсер цього не бачить.</p>\n<p><strong>Дія.</strong> Обмеження прав потрапили до кожного шаблону модуля — стеля привілеїв, закріплена на власній стелі модуля, фільтр системних викликів, обмежені родини адрес і пам&rsquo;ять, що є записуваною або виконуваною, але ніколи водночас. Виміряні результати: перемикач мертвої руки пішов з 9,6 на 1,5, форджа з 8,3 на 1,5, а обидва модулі резервного копіювання з 9,6 на 2,3 і 2,5. Їх написання виявило дещо краще за оцінки. Одну директиву було написано з помилкою у трьох шаблонах модулів відтоді, як ті ролі існували, — правдоподібне на вигляд ім&rsquo;я, якого не існує, на що наглядач відповідає записом у журнал про те, що не розпізнає ключ, і все одно запускає модуль. Пошук директиви доводить, що її було записано; лише парсер доводить, що вона набула чинності. Тож роль верифікації тепер проганяє кожен модуль через власний перевіряч наглядача під час зведення й включається кожною роллю, що встановлює модуль. Те, чого це досі не бачить, викладено прямо в тих самих документах: кожна директива, здатна зламати ці модулі, ламає їх під час виконання, а не під час розбору, і оцінка не може сказати, чи доходить скрипт досі до свого останнього рядка.</p>\n<p><strong>Результат.</strong> Кожен модуль працює з тими правами, які йому потрібні, і без тих, які не потрібні, числа виміряно, а не заявлено, і клас дефектів, у якому одруківка стає мовчки відсутнім засобом контролю, тепер валить прогін. Межі вимірювання записано поруч із ним, і саме ця частина стримує наступного читача від надмірної довіри до зеленої смуги.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Контейнери (Docker/Kubernetes)",
        "Тестування та QA",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Контейнеризація та оркестрація",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-seven-read-only-host-reporting-roles-120/",
      "url": "https://engineer.company/uk/portfolio/built-seven-read-only-host-reporting-roles-120/",
      "title": "Побудувала сім ролей звітування лише для читання, які подають живий хост як Markdown — факти, доступ, git, метрики, трафік, безпека та інвентар провайдера — за правилом, що не друкується жодне число, якого запуск не виміряв.",
      "summary": "Господарство можна описати з репозиторію на вимогу, і звіти виявили справжні речі: два мертві засоби безпеки, неоголошений слухаючий порт і спостереження, що…",
      "content_html": "<p><strong>Ситуація.</strong> Хост не мав панелі й не збирався її отримати, бо стек метрик не вміщується в 464 МБ і не вартував би своєї ціни, навіть якби вмістився. Це лишало чесну прогалину: не було способу відповісти на питання на кшталт того, хто має доступ, наскільки виріс цей репозиторій, який вигляд має трафік або чи справді посилення захисту примусово застосовується.</p>\n<p><strong>Завдання.</strong> Ці питання потребували відповідей, які можна виробити на вимогу, які нічого не коштують хостові, поки ніхто не питає, і які ніколи не здатні змінити те, що описують.</p>\n<p><strong>Дія.</strong> Сім ролей лише для читання, кожна з яких подає живий хост у Markdown усередині репозиторію. Знімок фактів, що охоплює операційну систему, обладнання, сховище, мережу, служби, пакунки, слухаючі сокети та завантаження процесора, обчислене з двох зразків власного лічильника ядра. Звіт про доступ, що охоплює облікові записи, обсяг sudo, відбитки ключів, користувачів форджі та ролі бази даних. Git‑звіт для кожного репозиторію. Звіт метрик за зібраними за добу зразками. Звіт про трафік, побудований із замаскованого задля приватності журналу вебсервера. Опис провайдерів на чотирьох провайдерських поверхнях — DNS, два хмарні API та API виділених серверів. І звіт з безпеки, що відповідає, чи посилення захисту примусово застосовується, а не лише налаштоване, друкуючи правила брандмауера в порядку збігу та живий набір правил блокування. Керівним правилом для всіх семи є те, що не друкується жодне число, якого прогін не виміряв, — звіт, який заповнює прогалину правдоподібним числом, гірший за той, що лишає її порожньою, бо вірять саме правдоподібному.</p>\n<p><strong>Результат.</strong> Господарство можна описати з репозиторію на вимогу, і звіти виявили справжні речі: два мертві засоби безпеки, неоголошений слухаючий порт і спостереження, що архів трафіку не старший за той момент, коли хтось востаннє згадав його зібрати. Останнє описано як обмеження з зафіксованою конкретною ціною — шістнадцять днів історії одного сайту, які проротувалися між збираннями і не існують ніде.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Документація",
        "Інфраструктура",
        "Моніторинг та observability",
        "Стейкхолдери та звітність",
        "Надійність та моніторинг (SRE)",
        "Системне адміністрування",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/deployed-the-companys-own-git-forge-121/",
      "url": "https://engineer.company/uk/portfolio/deployed-the-companys-own-git-forge-121/",
      "title": "Розгорнула власний git‑форж компанії на Soft Serve, приватний за замовчуванням і без вебпанелі, з портом SSH, прив'язаним до loopback за хостом‑переходом, і зробила посадкову сторінку перед ним артефактом збірки основного сайту, а не копією, яку тримають руками.",
      "summary": "Компанія тримає власний код на власному обладнанні, а сторінка перед ним успадковує кожну перевірку, яку проходить головний сайт, замість того щоб відходити…",
      "content_html": "<p><strong>Ситуація.</strong> Початковий код компанії жив на сторонній хостинговій службі, що є розумним місцем для нього і поганим для бізнесу, чий аргумент перед клієнтами полягає в тому, що він не передає їхніх даних посередникам. Натомість тримати форджу означає тримати форджу: автентифікація, контроль доступу, сховище, резервні копії та публічне обличчя для всього цього.</p>\n<p><strong>Завдання.</strong> Канонічний git‑сервер треба було підняти на наявному хості, з якнайменшою поверхнею атаки й без вебпанелі адміністрування, і поставити перед ним посадкову сторінку, що не гниє.</p>\n<p><strong>Дія.</strong> Форджа — це єдиний двійковий файл під наглядом операційної системи, встановлений із пакункового репозиторію постачальника, свідомо обраний за те, що він передусім працює через SSH і не має адміністративного вебінтерфейсу: що менше інтерфейсу, то менше треба захищати. Він приватний усталено: анонімний доступ відхиляється, доступ без ключа відхиляється, і кожен оголошений репозиторій позначено як приватний, а не покладено на невідомість. Його слухач SSH прив&rsquo;язується лише до інтерфейсу зворотної петлі на порту 23231 і досяжний ззовні через хост‑перехід, тож оголошена поверхня брандмауера не зростає. Мультиплексор протоколів, що поставив би HTTPS і git‑SSH на один публічний порт, оглядаючи перші байти з&rsquo;єднання, написано й готово за головним вимикачем, і цей вимикач вимкнено: багатокористувацький git через публічний порт поки не потрібен, а слухач, яким ніхто не користується, є поверхнею. Посадкова сторінка перед ним була цікавішою задачею. Вона була рукотворною копією оформлення головного сайту у власному репозиторії, і кожна знайдена між ними відмінність виявилася випадковістю, а не рішенням: шкала розмірів, що подавала словесний знак приблизно на дев&rsquo;ять відсотків завеликим, оголошення шрифту, що зводило дві насиченості до однієї на будь‑якій машині зі встановленою гарнітурою, оздоби, приховані нижче певної ширини, тож відсутні на кожному телефоні, насиченість, використана без постаченого для неї шрифту, і жодного головного орієнтира чи заголовка верхнього рівня на жодній сторінці. П&rsquo;ять із п&rsquo;яти, і жодної видимої на знімку екрана. Копію видалено; посадкову сторінку тепер будують власні шаблони головного сайту й доставляють як артефакт.</p>\n<p><strong>Результат.</strong> Компанія тримає власний код на власному обладнанні, а сторінка перед ним успадковує кожну перевірку, яку проходить головний сайт, замість того щоб відходити від нього так, як здатне побачити лише вимірювання. Розходження досі доступне, і тепер його треба записати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Веброзробка",
        "Інфраструктура",
        "Системне адміністрування",
        "DevOps та автоматизація CI/CD",
        "Infrastructure as Code",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/",
      "url": "https://engineer.company/uk/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/",
      "title": "Розгорнула контейнерний рівень на Podman і Quadlet під systemd, а не на Docker, бо Docker публікує порти контейнерів над власними правилами фаєрвола хоста, — і дала розгортанням непривілейованого користувача з однією фіксованою командою замість root.",
      "summary": "Контейнери працюють під наглядачем, якому вже довіряли, за брандмауером, який уже було оголошено, а звичайний реліз не потребує привілейованого доступу.",
      "content_html": "<p><strong>Ситуація.</strong> Платформі потрібне було місце для запуску контейнерів застосунків. Очевидним вибором був галузевий усталений варіант, і очевидний вибір був хибним для цього хоста в конкретний спосіб: він переписує правила фільтра пакетів ядра та публікує порти контейнерів вище за правила брандмауера, які встановлює роль посилення захисту, тож контейнер тихо стає досяжним з інтернету незалежно від того, що сказали брандмауерові.</p>\n<p><strong>Завдання.</strong> Треба було обрати контейнерну площину, що не обходить брандмауер, не додає другого наглядача поруч із тим, якому вже довіряють, і не вимагає бути root, щоб випустити реліз.</p>\n<p><strong>Дія.</strong> Площиною є бездемонний контейнерний рушій, що керує модулями, згенерованими власним наглядачем операційної системи. Другого менеджера процесів немає: контейнери є службами, вони запускаються так, як запускаються служби, і описані в тій самій декларативній формі, що й усе інше. Контейнери використовують мережу хоста без жодних опублікованих портів, що усуває питання обходу брандмауера, а не пом&rsquo;якшує його. Модулі виконуються на системному рівні, а не безкореневими, і це записано як обмін — так автоматизація лишається простою та звичною, ціною суворішої ізоляції, яку дав би безкореневий режим, і примітка каже, у який бік рухатися, якщо втеча з контейнера колись важитиме більше за простоту автоматизації. Розгортання відокремлено від конфігурування: root один раз налаштовує шлях розгортання, а далі непривілейований користувач перерозгортає, виконуючи один незмінний скрипт через обмежене правило, що дозволяє саме цю команду й жодних аргументів. Зібрати образ, перезапустити службу. Жодної кореневої оболонки, жодних довільних команд.</p>\n<p><strong>Результат.</strong> Контейнери працюють під наглядачем, якому вже довіряли, за брандмауером, який уже було оголошено, а звичайний реліз не потребує привілейованого доступу. Вибір проти усталеного варіанта записано разом із його причиною, і це важить більше за сам вибір — наступній людині кожна стаття, яку вона прочитає, радитиме взяти усталений.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Контейнери (Docker/Kubernetes)",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом",
        "Контейнеризація та оркестрація",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/provisioned-a-second-server-from-code-123/",
      "url": "https://engineer.company/uk/portfolio/provisioned-a-second-server-from-code-123/",
      "title": "Автоматизувала провізіювання другого сервера в другого хмарного провайдера, створивши фаєрвол перед машиною, щоб вона народжувалася за ним, із фаєрволами обох провайдерів, написаними прямо до їхніх REST API, щоб уникнути сторонньої колекції.",
      "summary": "Другий хост можна створити або прийняти повторно з репозиторію, за брандмауером, який уже існує, за ціною, яку зазначає файл.",
      "content_html": "<p><strong>Ситуація.</strong> Для рівня застосунків потрібна була друга машина, в іншого провайдера, ніж перша, і власна історія першої машини була аргументом на користь того, як це зробити: її створювали вручну, а брандмауер додали згодом, що лишає вікно, у якому свіжий хост із усталеною політикою паролів досяжний з інтернету.</p>\n<p><strong>Завдання.</strong> Машина мала створюватися з репозиторію і мала народжуватися за своїм брандмауером, а не набувати його трохи згодом.</p>\n<p><strong>Дія.</strong> Порядок ніс на собі весь задум. П&rsquo;єса брандмауера виконується перед п&rsquo;єсою сервера, тож набір правил існує ще до того, як з&rsquo;явиться що захищати; в іншого провайдера позначення виконується перед хмарним брандмауером, бо брандмауерові, який націлюється на позначки, потрібно, щоб ці позначки спершу існували. Брандмауери обох провайдерів написано безпосередньо проти їхніх REST API через узагальнене HTTP‑завдання, а не через колекцію постачальника, що усуває залежність і її версійний дрейф ціною ручного написання форм запитів. Роль, що створює машину, приймає наявну замість того, щоб її дублювати, якщо та вже є, тож повторний запуск безпечний. Її також задокументовано, в окремому файлі, як єдину роль у репозиторії, що витрачає гроші, — тип примірника, регіон, специфікацію та місячну вартість у євро записано, бо п&rsquo;єса, що комусь виставляє рахунок, має сказати про це там, де це прочитають. Ця ж п&rsquo;єса є тією, яку не можна відрепетирувати звичним способом: узагальнене HTTP‑завдання не оголошує підтримки режиму перевірки, тож пробний прогін пропускає в ній кожне завдання. Репетицію натомість роблять проти п&rsquo;єси брандмауера, що безкоштовно й оборотно.</p>\n<p><strong>Результат.</strong> Другий хост можна створити або прийняти повторно з репозиторію, за брандмауером, який уже існує, за ціною, яку зазначає файл. Те єдине, чого пробний прогін не покриває, названо в тому самому файлі, а не залишено несподіванкою.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Cloud",
        "Python",
        "Автоматизація та CI/CD",
        "Безпека",
        "Інфраструктура",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Налаштування мереж та VPN",
        "Хмарна інфраструктура та міграція"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/",
      "url": "https://engineer.company/uk/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/",
      "title": "Записала правило обсягу в репозиторій після того, як реструктуризація занесла до нього інвентар, дозволи фаєрвола та прозу іншої компанії, — і втримала карантинований залишок під сканером секретів, замість виключити його.",
      "summary": "Межа обсягу є записаним правилом із зазначеною перевіркою, залишки видимі, а не поховані, і та конкретна форма облікових даних, що прослизнула, тепер валить…",
      "content_html": "<p><strong>Ситуація.</strong> Робота, зроблена для іншої компанії, проїхала разом із перебудовою репозиторію та лишилася. Те, що прибуло разом із нею, не було абстрактним: чорновий журнал із живими обліковими даними відкритим текстом, який лежав у дереві повз кожен захист більшу частину історії репозиторію; застарілий інвентар, що називав хост тієї компанії; і файл завдань брандмауера, що відкривав порти шістнадцяти її клієнтським мережам. Нічого з цього не виконувалося. Саме тому воно й вижило — те, що ніде не виконується, більше ніколи не переглядають.</p>\n<p><strong>Завдання.</strong> Межа мала стати правилом із прикріпленою перевіркою, а не наміром, а залишки треба було прибрати так, щоб не просто їх сховати.</p>\n<p><strong>Дія.</strong> Правило тепер є відкривним розділом набору інструкцій репозиторію: цей репозиторій керує інфраструктурою однієї компанії і тільки нею, і хост, інвентар, дозвіл брандмауера, DNS‑зона чи облікові дані іншої сторони йому не належать — навіть вимкнені, закоментовані чи припарковані у файлі, якого не імпортує жоден плейбук. Практичну перевірку записано поруч: чи відповідала б ця компанія за це, якби стосунки скінчилися. Залишки поміщено до карантину в чітко названому каталозі, а не видалено, тож історія лишається читною, і карантин навмисно неповний — два структурні лінтери його пропускають, а сканер секретів, вартовий сховища та перевірка емодзі навмисно й далі його читають, бо саме ці три спіймали б те, що потрапило всередину. Сам витік породив правило лінтера: власний взірець, що позначає облікові дані, передані як прапорець командного рядка, — а це саме та форма, яку мали витеклі дані і яка не збігалася зі стандартним набором правил.</p>\n<p><strong>Результат.</strong> Межа обсягу є записаним правилом із зазначеною перевіркою, залишки видимі, а не поховані, і та конкретна форма облікових даних, що прослизнула, тепер валить коміт. Урок, записаний поруч, є загальним: небезпечний артефакт — не той, що виконується, а той, що не виконується, бо саме його ніхто більше не читає.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Інфраструктура",
        "Data Governance та якість даних",
        "Безпека та керування доступом",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/split-every-operational-secret-per-host-125/",
      "url": "https://engineer.company/uk/portfolio/split-every-operational-secret-per-host-125/",
      "title": "Розділила чотири секрети, що належать окремому хосту, після встановлення, що два хости зі спільним сигналом живучості сповіщають менше, ніж два сигнали, а не більше, і що спільна парольна фраза резервних копій робить два хости одним репозиторієм.",
      "summary": "Секрети є похостовими за побудовою, а два режими відмови, що випливли б зі спільного використання, записано там, де наступна людина редагуватиме файл.",
      "content_html": "<p><strong>Ситуація.</strong> Платформу було збудовано для одного хоста, а невдовзі мало стати два. Кілька експлуатаційних секретів було записано як поодинокі значення саме з цього припущення: один репозиторій резервних копій, одна парольна фраза, один перемикач тривоги. Поширити їх на другий хост, зробивши спільними, — шлях найменшого опору, і він хибний у два окремі способи, обидва з яких відмовляють тихо.</p>\n<p><strong>Завдання.</strong> Кожен секрет мав стати відображенням із ключем за хостом, а причину треба було записати, бо спільна версія має правильний вигляд і нічого не коштує аж до того дня, коли це важить.</p>\n<p><strong>Дія.</strong> Справу вирішили два аргументи, і обидва записано поруч із налаштуванням. Перемикач мертвої руки, спільний для двох хостів, б&rsquo;є на сполох менше, ніж два перемикачі, а не більше: будь‑який хост, що досі пінгує, тримає перевірку зеленою, поки другий мертвий, тож додавання хоста до спільного перемикача активно зменшує покриття того, що вже там був. А рядок репозиторію резервних копій є лише розташуванням — парольна фраза є всім шифруванням, тож два хости зі спільною парольною фразою є не двома репозиторіями зі спільним секретом, а одним репозиторієм із двома каталогами всередині. Кожне значення стало відображенням із ключем за іменем хоста в інвентарі, розв&rsquo;язуваним для кожного хоста спільним файлом завдань, який виконують і зведення, і попередня перевірка. Наявний хост потім названо в усіх чотирьох відображеннях, із його репозиторієм і обома порожніми перемикачами, і це правдивий стан, що тримає дві відкриті ініціативи чесними щодо того, що вони винні операторові половину роботи, а не коду.</p>\n<p><strong>Результат.</strong> Секрети є похостовими за побудовою, а два режими відмови, що випливли б зі спільного використання, записано там, де наступна людина редагуватиме файл. Порожні записи є тією частиною, яку варто зберегти: вони кажуть, що обв&rsquo;язка існує, а значення — ні, і це інше й корисніше твердження, ніж відсутній ключ.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Автоматизація та CI/CD",
        "Архітектура рішень",
        "Безпека",
        "Інфраструктура",
        "Надійність і резервне копіювання",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Надійність та моніторинг (SRE)",
        "Резервне копіювання та відновлення"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-multilingual-static-site-in-hugo-126/",
      "url": "https://engineer.company/uk/portfolio/built-a-multilingual-static-site-in-hugo-126/",
      "title": "Побудувала багатомовний статичний сайт на Hugo зі 108 файлів шаблонів, з яких 53 партіали, що публікує кожну сторінку у чотирьох представленнях з одного дерева контенту трьома мовами, і ще раз під сімома сфокусованими субдоменами, зібраними з того самого дерева.",
      "summary": "Сайт віддає три мови та чотири подання з одного дерева, не має бекенду для атаки й нічого для оплати, а той єдиний шматок JavaScript у ньому тримається…",
      "content_html": "<p><strong>Ситуація.</strong> Компанії потрібен був публічний сайт, що працює трьома мовами, доводить спроможність, а не заявляє про неї, нічого не коштує в експлуатації й нікому не передає своїх відвідувачів. Більшість із цього — звичайні вимоги. Разом вони відкидають майже кожну систему керування вмістом, бо бекенд часу виконання — це те, що треба захищати, латати, оплачувати й пояснювати на сторінці приватності.</p>\n<p><strong>Завдання.</strong> Сайт мав генеруватися цілком під час збирання і все ж поводитися як сучасний — із пошуком, встановлюваний, із стрічками, придатний до друку й читний екранним читачем кожною мовою, якою він виходить.</p>\n<p><strong>Дія.</strong> Це статичний сайт: 108 файлів шаблонів, з яких 53 є частковими шаблонами і 18 — шорткодами, три мови, жодного бекенду часу виконання й один власний скрипт, наданий як обмежений виняток для фільтра портфоліо, чий кожен елемент керування прихований, доки скрипт не запуститься. Спроможність додається під час збирання, а не в браузері, і це продуктове рішення, записане саме як рішення. Кожну сторінку публікують у чотирьох поданнях з одного дерева вмісту — HTML, двійник у Markdown, документ Gemini та пункт меню Gopher, — а головна сторінка додає до цього три стрічки та маніфест встановлюваного застосунку. Таксономій навмисно дві, а не одна, і ця відмінність є несучою: категорія є тематичною позначкою на роботі, послуга є тим, що компанія продає, і злиття їх зробило б каталог переліком навичок замість переліку пропозицій. Те саме дерево потім збирають ще сім разів, по одному на кожен сфокусований субдомен, скеровуючи генератор на інший каталог вмісту, а не відгалужуючи будь‑що.</p>\n<p><strong>Результат.</strong> Сайт віддає три мови та чотири подання з одного дерева, не має бекенду для атаки й нічого для оплати, а той єдиний шматок JavaScript у ньому тримається контракту, який примусово застосовує лінтер. Ціна в тому, що все інтерактивне має розв&rsquo;язуватися під час збирання або ніяк, і це відкинуло кілька речей, що були б легкими із сервером, і є причиною, чому пошуковий індекс оцінили та відклали, а не випустили.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Інтернаціоналізація",
        "Оптимізація продуктивності",
        "Full‑Stack продуктова розробка",
        "Інтернаціоналізація та локалізація",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-22-linter-commit-gate-127/",
      "url": "https://engineer.company/uk/portfolio/built-a-22-linter-commit-gate-127/",
      "title": "Побудувала ворота коміту з 22 однорядкових лінтерів плюс п'ятьох, що заслуговують на абзац, без рівня попереджень і без дозволених вбудованих придушень, з покриттям HTML, CSS, JavaScript, Python, YAML, Markdown, shell, посилань, орфографії, секретів і типографіки.",
      "summary": "Механічні заперечення висуває машина ще до того, як коміт існує, і ця перевірка є єдиним рецензентом, що має цей проєкт.",
      "content_html": "<p><strong>Ситуація.</strong> Посібник для учасників — це набір порад. Усі з ним погоджуються, а потім настає п&rsquo;ятниця, зміна мала, і посібник програє. У проєкті з однієї людини це радше гірше, ніж краще, бо рецензента немає взагалі — єдине, що стоїть між поганою зміною та робочою системою, це людина, яка її написала, у ту мить, коли вона найменш схильна сперечатися сама із собою.</p>\n<p><strong>Завдання.</strong> Стандарти мали стати виконуваними, щоб порушення одного з них валило коміт, а не чекало, доки його помітять.</p>\n<p><strong>Дія.</strong> Виросла перевірка з 22 лінтерів без рівня попереджень: кожна діагностика є помилкою, а сам генератор сайту працює з попередженнями, піднятими до відмов, тож навіть застаріла можливість спиняє збирання. Очевидні присутні — перевірка HTML, CSS, JavaScript, Python, YAML, Markdown, оболонки, орфографії, секретів, мертвих посилань. Цікавими є специфічні для проєкту перевірки, про які жоден готовий інструмент не має думки: що обидві колірні теми фарбують кожну шарувату поверхню однаковою кількістю шарів, що жодну світлину не показано ширшою за половину її вихідних пікселів, що розгорнуте дерево не містить приватного шляху чи імені хоста, що проза дотримується правил тону всіма трьома мовами, що сторінка має двійник у Markdown і чинне подання альтернативним протоколом. Вбудовані придушення заборонено цілком — жодного коментаря ігнорування, жодної директиви вимкнення, жодного обходу хука і жодного перейменування файлу заради ухилення від збігу. Правилом, що тримає це чесним, є те, що наперед наявна відмова не є виправданням: перевірка, що виявляє дефект, якого ніхто не вносив, виправляється тим самим проходом.</p>\n<p><strong>Результат.</strong> Механічні заперечення висуває машина ще до того, як коміт існує, і ця перевірка є єдиним рецензентом, що має цей проєкт. Ціну зазначено, а не приховано: комітити повільно, а погано написаний вартовий справді нестерпний в обході, і саме тому самих вартових згодом підвели під власний форматувальник і власний лінтер.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Frontend‑розробка",
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Продуктова стратегія та вимоги",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/",
      "url": "https://engineer.company/uk/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/",
      "title": "Скоротила керовані браузером ворота якості сайту з 1 636 секунд до 615, плануючи їхні перевірки від найдовшої через пул воркерів, обмежений чотирма смугами, вимірявши, що абеткова черга коштувала 320 секунд проти 224.",
      "summary": "Перевірка пішла з 1 636 секунд на 615, тоді як самі перевірки стали ширшими, а не тоншими — послідовна вартість зросла, а час за годинником упав.",
      "content_html": "<p><strong>Ситуація.</strong> Одинадцять перевірок сайту керують браузером без вікна: розкладка за кожної форми вікна, яку малює дизайн, шкала розмірів, розширення перекладеного тексту, контраст, правила доступності, примусові кольори, розміри маскота, рух, друк у шести комбінаціях паперу, помилки консолі та візуальна регресія. Виконувані по одній, вони брали 1 636 секунд, трохи більш ніж двадцять сім хвилин. Перевірка, що триває двадцять сім хвилин, — це перевірка, яку пропускають, а пропущену перевірку не відрізнити від пройденої.</p>\n<p><strong>Завдання.</strong> Час за годинником мав опуститися настільки, щоб їх запуск був усталеним варіантом, а не рішенням, і жодну з них при цьому не можна було послабити.</p>\n<p><strong>Дія.</strong> Робота почалася з вимірювання. Кожну перевірку заміряно окремо на дванадцятиядерній машині: розкладка на 405 секундах, шрифт на 301, переклад на 282, контраст на 189, доступність на 178 і далі вниз аж до сімнадцяти. Відповідь сформували два висновки. Виконувати всі одразу було повільніше, ніж по чотири за раз, — 265 секунд проти 224, — бо кожна перевірка сама є браузером, що виконує паралельну роботу, і надмірне навантаження машини коштує більше, ніж виграє паралельність. А впорядкування за найдовшим часом обробки спершу перемогло абеткове майже на третину, 224 секунди проти 320, і це класичний результат теорії розкладів, який виявляється тут тому, що перевірки різняться у вартості в двадцять разів. Тож виконавцем є обмежений пул робітників, розмір якого береться з кількості ядер із підлогою в два та стелею в чотири, і який годують найдовшим спершу. Поряд із цим перевірки радше розширили, ніж звузили: вони тепер спільно використовують одну таблицю з двадцяти двох форм вікна, виведену з кожного медіазапиту, який насправді містить таблиця стилів, і це саме лише підняло перевірку розкладки з 95 секунд до 405.</p>\n<p><strong>Результат.</strong> Перевірка пішла з 1 636 секунд на 615, тоді як самі перевірки стали ширшими, а не тоншими — послідовна вартість зросла, а час за годинником упав. Вимірювання є тією частиною, яку варто зберегти: два розумні на слух вибори, виконувати все одразу й виконувати в порядку написання, кожен виявився вимірювано гіршим за альтернативу.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Frontend‑розробка",
        "Python",
        "Автоматизація та CI/CD",
        "Оптимізація продуктивності",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/",
      "url": "https://engineer.company/uk/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/",
      "title": "Замінила 27 відтворених розмірів шрифту, чиї найближчі сусіди різнилися на 0,6%, шестикроковою шкалою Major Third і написала лінтер, який валить двадцять восьмий.",
      "summary": "Шість розмірів там, де було двадцять сім, з оголошеним співвідношенням, оголошеною мірою та перевіркою, що відхиляє наступне незаплановане значення.",
      "content_html": "<p><strong>Ситуація.</strong> Вимірювання поданого тексту сайту виявило двадцять сім різних розмірів шрифту в ужитку. Кілька з них розділяв менш ніж один відсоток — п&rsquo;ять значень між 0,8 і 0,85 від розміру основного тексту були живими одночасно, а це різниця, якої жоден читач не здатен відчути і до якої кожен наступний редактор додасть свою. Два заголовки таблиця стилів не розмічала за розміром узагалі, і вони провалювалися до власних усталених значень браузера, у співвідношення 1,33, що не відповідало нічому іншому на сторінці.</p>\n<p><strong>Завдання.</strong> Розміри мали стати шкалою з оголошеним співвідношенням, і щось мало завадити появі двадцять восьмого.</p>\n<p><strong>Дія.</strong> Шкалою є велика терція зі співвідношенням 1,25, шість іменованих щаблів від дрібного шрифту до плакатного, кожен із яких є токеном, а не значенням. Заголовки явно накладено на щаблі замість успадкування того, що думає браузер, і саме це виправило ті два, що не мали власного розміру. Підлогу встановлено лише для найнижчого щабля, тож дрібний шрифт лишається читним на телефоні без прив&rsquo;язування всієї шкали. Логотипи звільнено за іменем, а не випадково. Лінтер є тією частиною, що тримає це разом: він подає сайт і валить збирання на двадцять восьмому різному розмірі. Він уже двічі виправдав своє місце — спіймав заголовок, що прибув на 1,17 від розміру основного тексту, а це не щабель нічого, і назвав співвідношення в повідомленні про відмову; і спіймав вбудований код на 0,9, а це саме той різновид значення, заради запобігання якому шкала й існує. Поряд зі шкалою пішла міра приблизно у сімдесят два символи, що замінила успадковану фіксовану ширину, яка давала дев&rsquo;яносто один символ на сторінці відгуку і сто десять на сторінці контактів.</p>\n<p><strong>Результат.</strong> Шість розмірів там, де було двадцять сім, з оголошеним співвідношенням, оголошеною мірою та перевіркою, що відхиляє наступне незаплановане значення. Обмеження реальне й подеколи незручне: дизайн, що хоче розмір між двома щаблями, мусить перейти на щабель або доводити потребу змінити шкалу, і цю суперечку вже не раз вели й програвали.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Дизайн‑системи та UI",
        "Документація",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Бренд, маркетинг та SEO"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/",
      "url": "https://engineer.company/uk/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/",
      "title": "Знайшла й виправила 11 дефектів доступності, які браузер звітував здоровими: вісім посилань підвалу, що лишалися в порядку табуляції за pointer‑events, шкалу прокрутки, яка обрізала колофон на трьох сторінках, і механізм правил, що виконував 70 зі своїх 105 правил.",
      "summary": "Одинадцять дефектів виправлено і, що корисніше, чотири правила, які їх переживуть: вартовий, що перевіряє одну вісь, захищає одну вісь; набір правил, що не…",
      "content_html": "<p><strong>Ситуація.</strong> Сайт проходив свої автоматичні правила доступності. Він також мав одинадцять дефектів, яких ті правила не бачили, бо кожен із них був властивістю того, як сторінка подається, а не того, що казала розмітка, — саме той різновид, який валідатор звітує як справний і на який користувач клавіатури натрапляє за секунди.</p>\n<p><strong>Завдання.</strong> Дефекти треба було знайти, виправити та описати як реєстр із правилом, яке породив кожен із них, щоб закривався клас дефектів, а не окремий випадок.</p>\n<p><strong>Дія.</strong> Вони поділилися на три групи. Розміри: ключове слово таблиці стилів, ужите так, ніби воно відносне, прив&rsquo;язало цілу ділянку до шістнадцяти пікселів, тоді як основний текст сягав двадцяти двох; елемент нижнього індексу вжито у значенні «менший»; зменшення тексту подовжило рядок так, що заголовок сягнув дев&rsquo;яноста шести символів; а виміряна стеля висоти була переросла саме тим перевизначенням відступів, підтримку якого сайт заявляє. Фокус і обрізання: вісім посилань підвалу лишалися в порядку табуляції за властивістю, що прибирає взаємодію вказівником і більш нічого; правило переповнення створило контейнер прокручування, якого ніхто не хотів; а анімація, керована прокручуванням, яка просто неактивна на сторінці, надто короткій для прокручування, назавжди обрізала підвал на трьох сторінках. І два дефекти в самих вартових, які варто назвати окремо, — кожна форма вікна, яку відкривала перевірка розкладки, мала дев&rsquo;ятсот пікселів заввишки, тож телефон у альбомній орієнтації на 852 на 393 давав сім пікселів між двома елементами, і жодна перевірка туди ніколи не дивилася; а рушій правил виконував сімдесят зі своїх ста п&rsquo;яти правил, тож правила, яке спіймало б відсутній орієнтир, у наборі не було.</p>\n<p><strong>Результат.</strong> Одинадцять дефектів виправлено і, що корисніше, чотири правила, які їх переживуть: вартовий, що перевіряє одну вісь, захищає одну вісь; набір правил, що не містить правила, не може його примусово застосувати; висота є виміром, тож перевіряйте її; і доводьте видимість у пікселях, а не в документі. Коли перевірку розкладки належно відкрили заново, вона провалилася сто двадцять вісім разів трьома мовами, зокрема на вікні завбільшки з телефон, де завершальний рядок головного блоку сидів на двадцять один піксель нижче згину.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/",
      "url": "https://engineer.company/uk/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/",
      "title": "Згенерувала 495 сторінок досягнень трьома мовами з експорту SQLite лише для читання, де адресу сторінки авторовано як дані, тож виправлення речення більше не пересувало сторінку й не ламало посилання.",
      "summary": "Чотириста дев'яносто п'ять сторінок генерується з одного джерела, виправлення твердження нічого не коштує, а адреси, які цей сайт колись публікував, і далі…",
      "content_html": "<p><strong>Ситуація.</strong> Вміст портфоліо компанії створюється в окремій базі даних — тій самій, що виробляє CV, — і вебсайт має публікувати його як сторінки, трьома мовами, не даючи двом копіям розійтися. Наївний підхід, писати сторінки вручну й тримати їх у злагоді, ламається на першому ж виправленні.</p>\n<p><strong>Завдання.</strong> Вебсайт мав генерувати свій вміст із бази даних як вхідні дані збирання, з адресами сторінок, що переживають переписування речень на них.</p>\n<p><strong>Дія.</strong> Експортер читає базу даних лише для читання й пише по одній сторінці на досягнення на мову — 495 сторінок — плюс дані таксономії та послуг, потрібні шаблонам. Він використовує лише стандартну бібліотеку, тож збирання сайту не залежить від середовища генератора, а закомічений вивід означає, що сайт збирається самостійно. Найбільш наслідкове рішення в ньому стосується адрес. Раніше сайт виводив URL сторінки з перших слів її англійського твердження, тож виправлення речення мовчки переносило сторінку й ламало кожне посилання на неї — сайт, чиїм аргументом на власну користь є те, що він виправляє речі, штрафував себе мертвим посиланням щоразу, коли це робив. Адресу тепер створюють як дані: по одному рядку на адресу на досягнення, перша є поточною, а кожна наступна є відставленою адресою, яку сайт видає як перенаправлення. З тієї самої роботи записано ще дві пастки. Порівняння періоду з текстовим стовпчиком мовчки збіглося з усіма тридцятьма двома рядками через те, як база даних призначає спорідненість типів у порівнянні. І перелік мов тепер є єдиною віссю, з якої виводять і цикл запису, і файли даних, і запити, тож додати четверту мову — це один запис у відображенні, а не пошук.</p>\n<p><strong>Результат.</strong> Чотириста дев&rsquo;яносто п&rsquo;ять сторінок генерується з одного джерела, виправлення твердження нічого не коштує, а адреси, які цей сайт колись публікував, і далі відповідають. Експортер також володіє рівно одним рішенням про подання — тим, як послуги групуються в тематичні розділи, — і це навмисно: усе інше, що він пише, належить базі даних, а заголовок групи без якоїсь мови валить експорт, а не подає англійську поверх перекладеного вмісту.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Python",
        "SQL",
        "Бази даних",
        "Веброзробка",
        "Інтернаціоналізація",
        "Пайплайни даних (ETL/ELT)",
        "Бренд, маркетинг та SEO",
        "Інтернаціоналізація та локалізація",
        "Розробка вебсайтів та CMS",
        "Розробка пайплайнів даних (ETL/ELT)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/closed-the-colour-system-at-28-colours-133/",
      "url": "https://engineer.company/uk/portfolio/closed-the-colour-system-at-28-colours-133/",
      "title": "Закрила систему кольорів на 28 задокументованих кольорах із лінтером, який валить значення, намальоване але незадокументоване, задокументоване але ненамальоване, хибно виміряне, переписане як літерал або в межах перцептивної відстані 0,02 від уже наявного.",
      "summary": "Палітра є замкненим виміряним набором, що не може тихо зростати, а два майже однакові написання, які до цього спонукали, зникли.",
      "content_html": "<p><strong>Ситуація.</strong> Колір на сайті з темною темою за усталеним вибором, світлою темою, таблицею стилів для друку, режимом примусових кольорів та ілюстрованим брендом сам собою не лишається малим набором. Він уже почав розходитися так, як завжди: два написання того самого кольору стояли досить близько, щоб ніхто не міг їх розрізнити, значення були перевведені як літерали поруч із токенами, що їх визначали, а задокументовані кольори не фарбували нічого.</p>\n<p><strong>Завдання.</strong> Палітра мала стати замкненим набором із оголошеним порогом розрізненності, і щось мало примусово тримати цю замкненість.</p>\n<p><strong>Дія.</strong> Двадцять вісім кольорів, кожен задокументований із коефіцієнтом контрасту, який він показує на поверхні, де з&rsquo;являється, та одинадцять брендових значень, оголошених один раз як токени. Поріг є числовим, а не редакційним: два кольори, ближчі за перцептивну відстань 0,02 в однорідному колірному просторі, є одним кольором із двома написаннями. Лінтер валить збирання п&rsquo;ятьма різними способами — значення пофарбоване, але незадокументоване; задокументоване, але непофарбоване; записане з хибним коефіцієнтом; у межах порога від того, що вже є; або брендове значення, переписане як літерал. Він одразу знайшов два: колір теми, що існував у двох написаннях на відстані 0,018, і колір тла, що заміняв стіну, від якої стояв на 0,021. Прозорість використовує відносний колірний синтаксис, а не функцію змішування, саме тому, що вартовий не бачить крізь суміш, а палітрний вартовий, якого можна обійти, не є вартовим. Правило, що йде з цим, коротке: змінюйте токен, а не правило, додавайте колір лише тоді, коли жоден не пасує, і ніколи не знижуйте задокументований коефіцієнт, щоб дизайн запрацював.</p>\n<p><strong>Результат.</strong> Палітра є замкненим виміряним набором, що не може тихо зростати, а два майже однакові написання, які до цього спонукали, зникли. Це обмеження, що подеколи каже ні: дизайн, який хоче трохи інший синій, мусить узяти той, що існує, або обґрунтувати двадцять дев&rsquo;ятий колір, і це обґрунтування має містити коефіцієнт.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Дизайн‑системи та UI",
        "Документація",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Бренд, маркетинг та SEO"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/found-the-light-theme-missing-an-overlay-layer-134/",
      "url": "https://engineer.company/uk/portfolio/found-the-light-theme-missing-an-overlay-layer-134/",
      "title": "Виявила, що світлій темі бракувало повносторінкового шару накладання від самого дня її написання, стверджуючи, що обидві теми малюють кожну шарувату поверхню однаковою кількістю шарів.",
      "summary": "Шар, відсутній в одній темі, тепер валить коміт, а той, що був відсутнім від дня написання, пофарбовано.",
      "content_html": "<p><strong>Ситуація.</strong> Сайт постачає дві колірні теми. Темна є усталеною і на неї дивляться постійно; світла є перевизначенням, що з&rsquo;являється лише за системною вподобою, а це означає, що її бачать значно рідше і ніхто з тих, хто її перевіряє. Паритет тем є класом дефектів, у якому поверхню будують один раз і переказують один раз, а переказ тихо губить шар.</p>\n<p><strong>Завдання.</strong> Паритетові потрібне було твердження, бо єдиною альтернативою є людина, яка пам&rsquo;ятає перемкнути вподобу й подивитися.</p>\n<p><strong>Дія.</strong> Перевірка мала й структурна: для кожної шаруватої поверхні порахувати шари, які фарбує кожна тема, і завалити, коли числа різняться. Вона не порівнює вигляд — теми й мають виглядати по‑різному, — вона порівнює склад, а це та річ, що має бути однаковою. Вона знайшла дефект на першому ж прогоні. Повносторінкова обкладинка сайту має три шари в темній темі, візерунок граней над затінювачем над стіною, а світла тема переказала це двома. Накладення граней було відсутнім у світлій темі від дня її написання, і ніщо про це не сказало, бо сторінка без одного з трьох шарів тла має вигляд дизайнерського рішення, а не вади. Виправленням було одне правило; опис, зроблений згодом, зафіксував, чого накладення коштує в контрасті, тож додавання виміряно, а не вважається безкоштовним.</p>\n<p><strong>Результат.</strong> Шар, відсутній в одній темі, тепер валить коміт, а той, що був відсутнім від дня написання, пофарбовано. Це і є форма дефекту, на яку націлено весь підхід із перевірками: нічого не було зламано, нічого не давало помилки, сторінка подавалася правильно, і вона була хибною місяцями.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Дизайн‑системи та UI",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/made-reduced-motion-honest-135/",
      "url": "https://engineer.company/uk/portfolio/made-reduced-motion-honest-135/",
      "title": "Зробила зменшений рух чесним, знайшовши одинадцять селекторів, які досі анімувалися під цією настройкою, бо універсальне правило transition‑none програє за специфічністю будь‑якому правилу з класом.",
      "summary": "Уподобу шанують насправді, а не за наміром, і одинадцять живих анімацій, які суцільне правило нібито покривало, покрито справді.",
      "content_html": "<p><strong>Ситуація.</strong> Сайт шанував уподобу зменшеного руху одним правилом, що вимикало кожен перехід. Воно мало вигляд завершеного, воно проходить лінтер чисто, і за емульованої вподоби зменшеного руху одинадцять селекторів усе одно анімувалися.</p>\n<p><strong>Завдання.</strong> Уподобу треба було шанувати насправді, а причина, чому очевидне правило не спрацювало, мала стати тим, чого наступна людина не зможе повторити.</p>\n<p><strong>Дія.</strong> Причиною є специфічність. Універсальне правило набирає найнижчий бал у каскаді й програє будь‑якому правилу з класом, тож суцільне вимкнення переходів програє кожній продуманій анімації на сторінці — а це і є кожна анімація, яку варто вимикати. Виправлення було структурним, а не латкою: усе, що рухається, тепер живе в одній пізній частині таблиці стилів, а лінтер валить перехідне перетворення будь‑де інде. Розрізнення, яке проводить правило, є навмисним і вужчим за очевидне: зменшуйте рух, а не колір. Згасання кольору не є рухом, і його вимкнення робить інтерфейси на відчуття зламаними для людей, які цього не просили, тож перехід, що перелічує колірні властивості, проходить, а перехід на русі — ні. Рух також зобов&rsquo;язаний виражатися як перехід, а не як анімація за ключовими кадрами, бо перший тривіально скасовується, а друга — ні. З тієї самої роботи вийшли дві суміжні пастки, записані з вимірюваннями: оздоба меню проходила тридцять один градус із шістдесятиградусного повороту, перш ніж стати наполовину видимою, і оскільки форма періодична, півповорот має однаковий вигляд за третину вартості; і п&rsquo;ять різних властивостей кожна робить елемент вмісним блоком для всього, спозиційованого відносно вікна перегляду, що мовчки зменшило шар закривання до частки екрана.</p>\n<p><strong>Результат.</strong> Уподобу шанують насправді, а не за наміром, і одинадцять живих анімацій, які суцільне правило нібито покривало, покрито справді. Загальний урок записано на початку того документа: правило, що програє за специфічністю, відмовляє мовчки, і кожен звіт називає це якось інакше.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-637-line-print-stylesheet-136/",
      "url": "https://engineer.company/uk/portfolio/built-a-637-line-print-stylesheet-136/",
      "title": "Побудувала друкований стиль на 637 рядків проти чотирьох задокументованих поведінок рушія відтворення, зокрема вбудованих заголовків, які друкувалися білим по білому для будь‑якого читача, чий браузер надавав перевагу темному.",
      "summary": "Сайт друкується на невідомому папері в обох темах, а чотири види поведінки рушіїв записано разом із дефектом, який спричинив кожен.",
      "content_html": "<p><strong>Ситуація.</strong> Кейси сайту є тим артефактом, який хтось роздруковує й несе на зустріч. Це робить папір справжнім виходом, а не люб&rsquo;язністю, а папір є іншим носієм, ніж вузький екран — розмір паперу читача невідомий, орієнтація читача невідома, а поведінка браузера під час друку різниться між рушіями так, як жодний екранний перегляд не покаже.</p>\n<p><strong>Завдання.</strong> Сайт мав друкуватися правильно на невідомому папері, в обох колірних темах, без окремого документа, який довелося б підтримувати поруч із вебверсією.</p>\n<p><strong>Дія.</strong> Це одна таблиця стилів на 637 рядків з єдиним правилом сторінки й одним блоком друку. Правило сторінки задає поле й навмисно не задає розміру паперу, тож те, що читач обере в діалозі, проходить наскрізь, і все інше до цього пристосовується. Кореневий розмір шрифту закріплено в пунктах, тож кожне відносне вимірювання має фізичний якір, а одну міру приблизно у сімдесят два символи застосовано до чотирьох блоків верхнього рівня — і це аркуш перемагає дизайн, бо альбомна сторінка інакше розганяла б рядок приблизно до ста десяти символів. Чотири види поведінки рушіїв задокументовано як пастки, і кожен спричинив справжній дефект. Одиниці вікна перегляду розв&rsquo;язуються в коробку сторінки в одному рушії й у вікно в іншому, тож сторінка, надрукована з широкого вікна, має третину кожного рядка обрізаною в другому. Елементи з фіксованим положенням малюються на кожному аркуші, тож декоративні прибрано, а два з них перепризначено на бланк і колофон. Палітра усталено бере білий текст, бо усталеною темою є темна, і це друкувало чотири підзаголовки розділів білим по білому — слова просто були відсутні. А сторінковий носій не може розділити гнучку чи сіткову коробку, що дало порожній перший аркуш на сторінці досягнення. Це покриває перевірка з шести частин, що випробовує шість комбінацій паперу й орієнтації, обидві вподоби колірної схеми та справжню кількість сторінок проти тієї, яку передбачає висота вмісту.</p>\n<p><strong>Результат.</strong> Сайт друкується на невідомому папері в обох темах, а чотири види поведінки рушіїв записано разом із дефектом, який спричинив кожен. Відомі межі записано, а не приховано: немає ні номерів сторінок, ні колонтитулів, один рушій ігнорує контроль висячих рядків, а буквиці не є універсальними. Одного разу випадковий термінатор коментаря змусив лінтер CSS проковтнути ціле правило і двічі пройти чисто — помітила це лише перевірка друку.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Документація",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/mirrored-the-site-to-gemini-and-gopher-137/",
      "url": "https://engineer.company/uk/portfolio/mirrored-the-site-to-gemini-and-gopher-137/",
      "title": "Віддзеркалила весь сайт як 777 документів Gemini і 777 документів Gopher з того самого розгорнутого дерева, з нульовою зміною байтів у HTML.",
      "summary": "Сайт читний чотирма протоколами з одного збирання, по 777 документів на кожен і з нульовою зміною HTML, а альтернативні подання коштують приблизно дванадцять…",
      "content_html": "<p><strong>Ситуація.</strong> Сайт статичний, не має ні стеження, ні бекенду часу виконання, і його аргумент полягає в тому, що документові не потрібен мегабайт JavaScript, аби його прочитали. Цей аргумент легко висловити й важко продемонструвати. Два невеликі інтернет‑протоколи демонструють його безпосередньо, бо жоден із них узагалі не здатен нести скрипт.</p>\n<p><strong>Завдання.</strong> Увесь сайт мав публікуватися через Gemini і Gopher із того самого вмісту, без другого дерева вмісту й без змін у HTML.</p>\n<p><strong>Дія.</strong> Обидва є форматами виводу того самого збирання, а не окремим конвеєром. Генераторові сайту надали власні типи носіїв і формати виводу, і кожна сторінка, розділ та термін таксономії дістали ще по два подання поруч зі своїм HTML і двійником у Markdown. Результатом є 777 документів Gemini і 777 меню Gopher, вироблені з того самого джерела, розгорнуті в те саме дерево й віддавані двома невеликими демонами на тому самому хості. Дві властивості зробили це вартим роботи, а не дивиною. Обидва формати позначено як неальтернативні подання, тож у HTML не змінилося нічого — жодного байта, і це виміряли, а не припустили. А формат Gopher не має способу вкласти посилання всередину речення, бо рядок меню є полями, розділеними табуляціями, тож прозу жорстко переносять на шістдесят восьмому стовпчику під час збирання; це обмеження вигострило письмо так, як HTML ніколи не вимагав. Поруч із ними стоїть onion‑дзеркало Tor, і це єдине публічне обличчя, яке платформа могла додати, не відкриваючи порту брандмауера, бо демон додзвонюється назовні, а всередину не дзвонить ніхто.</p>\n<p><strong>Результат.</strong> Сайт читний чотирма протоколами з одного збирання, по 777 документів на кожен і з нульовою зміною HTML, а альтернативні подання коштують приблизно дванадцять відсотків від власної ваги HTML на диску. Лише один із чотирьох вимірюється щодо трафіку, і це зазначено у власному документі статистики платформи, а не тихо проігноровано.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Автоматизація та CI/CD",
        "Веброзробка",
        "Інтернаціоналізація",
        "Інфраструктура",
        "DevOps та автоматизація CI/CD",
        "Інтернаціоналізація та локалізація",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/",
      "url": "https://engineer.company/uk/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/",
      "title": "Замінила 963 анонімні блоки структурованих даних, які переповідали компанію 1 671 раз, одним пов'язаним графом із 16 типів, викарбуваним зі стабільних ідентифікаторів походження.",
      "summary": "Один граф зі стабільною тотожністю замінює 963 анонімні переказування, і сторінки несуть менше, а не більше.",
      "content_html": "<p><strong>Ситуація.</strong> Сайт видавав структуровані дані так, як це робить більшість сайтів: по блоку на сторінку, і кожен описував організацію заново з нуля. На весь сайт це дало 963 блоки, що переказували ту саму компанію 1 671 раз, анонімно — жодного стабільного ідентифікатора ніде, тож ніщо із тих, хто це споживає, не могло сказати, що організація на одній сторінці є організацією на іншій.</p>\n<p><strong>Завдання.</strong> Структуровані дані мали стати одним графом зі стабільною тотожністю, а не купою блоків, що випадково містять ті самі слова.</p>\n<p><strong>Дія.</strong> Ідентифікатори тепер карбують із джерела сайту — один для організації, один для сайту, один для особи, — і кожен блок посилається на них, а не переказує їхній вміст. Ідентифікатори є спільними для джерела, а не окремими для кожної мови, бо компанія є тією самою компанією й данською. У грі шістнадцять типів, що охоплюють каталог послуг і його пропозиції, відгуки та роботу, яку вони описують, добірки та їхні навігаційні ланцюжки. Два рішення втримали вагу. Сторінки переліків публікують свої елементи лише за URL, а не вбудовують їх, і це виміряли: назвати їх на індексі портфоліо означало б 107 повних тверджень і зростання стиснутої сторінки на 52 відсотки. А перевірка, що це стереже, не просто підтверджує синтаксис — вона стверджує, що кожен блок розбирається, що кожен ідентифікатор розв&rsquo;язується і що кожну URL‑адресу, яку називає граф, справді було зібрано, тож граф, що вказує на неіснуючу сторінку, валить перевірку.</p>\n<p><strong>Результат.</strong> Один граф зі стабільною тотожністю замінює 963 анонімні переказування, і сторінки несуть менше, а не більше. Вимірювання, з якого почалася робота, варто тримати в голові: сайт видавав той самий опис організації 1 671 раз, і ніщо не могло їх поєднати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Data Governance",
        "Frontend‑розробка",
        "Автоматизація та CI/CD",
        "Бренд і маркетинг",
        "Веброзробка",
        "Data Governance та якість даних",
        "Бренд, маркетинг та SEO",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/",
      "url": "https://engineer.company/uk/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/",
      "title": "Скоротила пакунок стилів із 87 КБ до 31 КБ, вийнявши з нього шрифт у base64, і відкинула 756 КБ у 22 файлах, які публікувалися при кожному розгортанні й на які ніщо не посилалося.",
      "summary": "Пакет важить 31 КБ замість 87, 756 КБ мертвих ресурсів перестали розгортатися, і за кожним рішенням стоїть вимірювання — зокрема за тим, що пішло в інший бік,…",
      "content_html": "<p><strong>Ситуація.</strong> Пакет таблиць стилів сайту важив 87 КБ, а для документного сайту без фреймворку це більша частина ваги сторінки, витрачена ще до прибуття будь‑якого вмісту. Сайт до того ж публікував каталог піктограм за кожного розгортання, згенерований один раз і відтоді ні з чого не згаданий.</p>\n<p><strong>Завдання.</strong> Вага мала впасти без зміни дизайну, і мала впасти з причини, на яку можна вказати, а не через загальне прибирання.</p>\n<p><strong>Дія.</strong> Спершу вимірювання. Дві третини найбільшої таблиці стилів були одним шрифтом, закодованим у base64, — приблизно 56 КБ тексту, що кодували приблизно 42 КБ шрифту, — вбудованим заради виграшу в першому промальовуванні, який попередньо завантажений зовнішній файл дає й так, і оплачуваним на кожній сторінці незалежно від того, чи потрібна була та вага. Його вилучення забрало цей файл з 84 КБ до 28, а весь пакет з 87 до 31. Три насиченості шрифту натомість попередньо завантажуються, і третя приєдналася до переліку лише тоді, коли польові дані показали, що вона закриває найдовший критичний ланцюжок, а не тому, що три звучить завершено. Окремо перевірка того, що розгортання насправді публікувало, виявила двадцять одну згенеровану піктограму та дублікат файлу налаштувань, 756 КБ, що вивантажувалися щоразу й не згадувалися нізвідки; а власний файл піктограм сайту впав із 145 КБ до 15. Сучасний формат зображень оцінили для знака бренду, виміряли й відхилили — він вийшов більшим, а механізм вибору бере за порядком, а не за розміром, тож сучасний браузер брав би скрізь важчий файл. Дві перевірки тепер тримають межу: жодну світлину не можна показувати ширшою за половину її вихідних пікселів, і кожну ілюстрацію треба публікувати в розмірі, який підтримують її власні пікселі і за звичайної, і за високої щільності.</p>\n<p><strong>Результат.</strong> Пакет важить 31 КБ замість 87, 756 КБ мертвих ресурсів перестали розгортатися, і за кожним рішенням стоїть вимірювання — зокрема за тим, що пішло в інший бік, і це корисніший запис із двох.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Автоматизація та CI/CD",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Оптимізація продуктивності",
        "Бренд, маркетинг та SEO",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/",
      "url": "https://engineer.company/uk/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/",
      "title": "Виправила мапу сайту, де 172 з 176 URL мали одну позначку часу зміни, взявши дату з історії git після встановлення, що експорт переписує кожен файл при кожному запуску.",
      "summary": "Повторна синхронізація після місяця редагування вмісту тепер торкається восьми файлів зі 186 замість усіх, і мапа сайту каже щось правдиве.",
      "content_html": "<p><strong>Ситуація.</strong> Мапа сайту казала пошуковим системам, що 172 з його 176 сторінок востаннє змінилися тієї самої миті. Це не тонка неточність — дата зміни є обіцянкою повзунові, що вміст сторінки змінився, і сайт, який дає цю обіцянку 172 рази одночасно, або каже правду про повне переписування, або не каже нікому нічого корисного.</p>\n<p><strong>Завдання.</strong> Дати мали описувати вміст, а не файл, не вигадуючи точності, якої репозиторій не має.</p>\n<p><strong>Дія.</strong> Причиною було те, що дата бралася з часу зміни файлу, а експорт вмісту переписує кожен файл за кожного прогону, тож одна синхронізація штампувала весь корпус. Виправлення переносить джерело до історії версій, із ланцюжком запасних варіантів, що пробує спершу явне поле, потім історію комітів, потім файл. Пастка в цьому виправленні варта запису: буквальна назва поля має з&rsquo;явитися в переліку, інакше генератор ніколи його не прочитає, тож налаштування, що на вигляд віддає перевагу авторській даті, але пропускає назву, мовчки ігнорує кожну авторську дату. З тієї самої роботи вийшли ще два рішення про дати. База даних тепер несе, коли кожен запис було написано й востаннє переглянуто, і це навмисно тримають окремо від того, коли відбулася сама робота, — вони віддалені на роки, і злиття їх датувало б сторінку, написану цього року, десятиліттям тому. А рядки в тому файлі є необов&rsquo;язковими, і нічого не виводиться, бо власна історія репозиторію починається пізніше за вміст: відсутня дата лишає поле порожнім, а не фіксує міграцію, за принципом, що точне хибне число гірше за відсутнє, бо вірять саме хибному.</p>\n<p><strong>Результат.</strong> Повторна синхронізація після місяця редагування вмісту тепер торкається восьми файлів зі 186 замість усіх, і мапа сайту каже щось правдиве. Загальне правило потрапило до документа з метаданими поруч, бо та сама пастка стосується кожного поля, що має ланцюжок запасних варіантів.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Python",
        "Автоматизація та CI/CD",
        "Бренд і маркетинг",
        "Веброзробка",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Бренд, маркетинг та SEO",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/ran-development-as-49-written-initiatives-141/",
      "url": "https://engineer.company/uk/portfolio/ran-development-as-49-written-initiatives-141/",
      "title": "Провела розробку сайту як 51 письмову ініціативу у 54 документах планів, кожен зі своїми відкритими пунктами, вимірами та рішеннями, від яких відмовився, — включно з шістьма з восьми висновків щодо готовності до агентів, відхиленими із записаною причиною.",
      "summary": "П'ятдесят одне рішення із прикріпленим обґрунтуванням, приблизно три чверті закритих, і відхилені так само видобувні, як прийняті.",
      "content_html": "<p><strong>Ситуація.</strong> Компанія з однієї людини не має ані планувальної наради, ані впорядкування беклогу, ані нікого, хто б не погодився з рішенням. Натомість вона має сильну схильність робити ту роботу, яка наразі цікава, і жодного запису згодом про те, чому щось було обрано, — а це стає проблемою першого ж разу, коли рішення треба переглянути чи обстояти.</p>\n<p><strong>Завдання.</strong> Розробці сайту потрібен був письмовий запис на кожну ініціативу, що переживає перечитування через місяці й охоплює як відхилені, так і збудовані.</p>\n<p><strong>Дія.</strong> П&rsquo;ятдесят одна ініціатива у п&rsquo;ятдесяти чотирьох пронумерованих і проіндексованих планових документах, кожен із яких несе проблему, зроблені вимірювання, рішення та його відкриті пункти. Це не підсумки, написані згодом. Вони тримають числа, що вирішили суперечку, — вимірювання розкладу, які сформували виконавця перевірок, формат зображень, який випробували й відхилили, бо він вийшов більшим, цінову драбину, підтверджену власником, перевірку, що виявила, як сайт доводить спроможність на 371 сторінці, ніде не зазначаючи ані ціни, ані форми співпраці, ані мінімуму. Відхилені висновки дістають те саме поводження, що й прийняті: огляд готовності до роботи з агентами дав вісім висновків, і шість відхилено, кожен із зафіксованим вердиктом, саме для того, щоб пізніша автоматична порада не могла тихо скасувати записане рішення. Дошка стану читає позначки плану, а не його прозу, бо проза каже «готово», а позначки кажуть, що відкрито. Ця відмінність не була теоретичною — лінтер документації згодом виявив шість планів, позначених готовими, які несли непозначені пункти.</p>\n<p><strong>Результат.</strong> П&rsquo;ятдесят одне рішення із прикріпленим обґрунтуванням, приблизно три чверті закритих, і відхилені так само видобувні, як прийняті. Коштує це того, що кожна ініціатива має опис, а це справжній податок на малу роботу, і подеколи це означало, що запис довший за зміну, яку він описує.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "Документація",
        "Продукт і вимоги",
        "Стейкхолдери та звітність",
        "Технічне лідерство",
        "Управління проєктами",
        "Продуктова стратегія та вимоги",
        "Технічна документація",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/put-the-documentation-under-its-own-linter-142/",
      "url": "https://engineer.company/uk/portfolio/put-the-documentation-under-its-own-linter-142/",
      "title": "Поставила документацію під власний лінтер — побюджетний ліміт рядків на файл, який лише знижується, вимогу індексу та перевірку справжніх шляхів, — який знайшов шість із дев'яти планів, позначених виконаними, попри невідмічені пункти, і чотирнадцять завдань, що блокували кожен коміт, не згаданих у жодному документі.",
      "summary": "Двадцять шість документів загальним обсягом приблизно 2 666 дієвих рядків, кожен під бюджетом, що не може зрости, з кожним шляхом і символом, які вони…",
      "content_html": "<p><strong>Ситуація.</strong> Репозиторій керує собою письмовими інструкціями — двадцять шість документів, що охоплюють політику якості, систему дизайну, доступність, друк, метадані, переклад і git. Інструкції мають своєрідний взірець занепаду: вони довшають, вони відходять від коду, вони починають посилатися на файли, які перемістилися, і на певному розмірі їх перестають читати. Непрочитане правило не є правилом.</p>\n<p><strong>Завдання.</strong> Документація потребувала того самого поводження, що й код, — лінтера з межами, які валять, а не радять.</p>\n<p><strong>Дія.</strong> Вісім політик, кожна механічна. Жорстка стеля довжини документа й м&rsquo;якша, що попереджає. Пофайловий бюджет рядків, що рухається лише вниз, тож документ може зменшитися й не може вирости назад. Вимога індексу понад певний поріг і індексу розділів понад менший. Правило розташування про те, який документ володіє якою темою. Чинність посилань. Чесність планів — стан, який заявляє план, має відповідати його власним позначкам. Правило, що кожне завдання, яке стереже коміт, названо в якомусь документі. І перевірка справжності шляхів: кожен шлях із каталогом і кожен символ коду, який називає документ, справді існує. Перший прогін був аргументом на користь усієї вправи: шість планів, позначених готовими, які несли непозначені пункти, чотирнадцять завдань, що стерегли кожен коміт і не були названі в жодному документі, три зламані посилання, один осиротілий документ і три мертві шляхи у п&rsquo;яти документах. Бюджет потім відмовив власному авторові — запис підсумку цієї роботи до документа з розробки виштовхнув його за межу, і саме так з&rsquo;явився окремий документ, а це і є політика, що працює точнісінько як задумано.</p>\n<p><strong>Результат.</strong> Двадцять шість документів загальним обсягом приблизно 2 666 дієвих рядків, кожен під бюджетом, що не може зрости, з кожним шляхом і символом, які вони називають, звіреними з деревом. Незручний висновок вартий повторення: чотирнадцять перевірок стерегли кожен окремий коміт, не з&rsquo;являючись у жодному документі, тож правила, які примусово застосовувала машина, і правила, які читали люди, вже розійшлися.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "Технічне лідерство",
        "Управління проєктами",
        "Технічна документація",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/brought-the-quality-gate-code-under-a-linter-143/",
      "url": "https://engineer.company/uk/portfolio/brought-the-quality-gate-code-under-a-linter-143/",
      "title": "Підвела 10 242 рядки JavaScript воріт якості під форматувальник і лінтер, встановивши, що це найбільший обсяг коду в репозиторії й єдиний, якого ніщо не читало, виправила 13 знахідок і не придушила жодної.",
      "summary": "Найбільший і найбільш несучий код у репозиторії тепер відформатовано, перевірено лінтером і перевірячем типів, із тринадцятьма виправленими висновками й нулем…",
      "content_html": "<p><strong>Ситуація.</strong> Перевірка якості сайту — це тридцять два скрипти загальним обсягом 10 242 рядки JavaScript. Це був із великим відривом найбільший масив коду в репозиторії, і це був єдиний масив коду, якого ніщо не читало — ані форматувальник, ані лінтер, ані перевірка типів. Програми, що примусово застосовували кожне правило в проєкті, були єдиними програмами, на які не поширювалося жодне з них.</p>\n<p><strong>Завдання.</strong> Перевіряльників треба було підвести під той стандарт, заради примусового застосування якого вони існують, і форматувальник треба було припасувати до них, а не навпаки.</p>\n<p><strong>Дія.</strong> Форматувальник ішов першим, і ширина відступу була цікавим рішенням. Усталеним значенням репозиторію є чотири пробіли; за чотирьох пробілів форматувальник переписав би 2 173 рядки найбільшого перевіряльника. Перевизначення на два пробіли для цих файлів звело це до 38 рядків справжнього розходження. Записаний із цим принцип полягає в тому, що форматувальник припасовують до коду, а не код до форматувальника — переформатування двох тисяч рядків заради вподобання знищує здатність читати історію файлу. Далі лінтер, що дав тринадцять справжніх висновків, усі виправлено й жодного не придушено. Перевіряльники на Python дістали те саме поводження через перевіряч типів, налаштований на середню суворість із тридцятьма окремими правилами суворого рівня, увімкненими понад це й обраними за вимірюванням: за цього налаштування дерево мовчить, і з тридцяти кандидатів двадцять дев&rsquo;ять уже мовчали, а один спрацював — і його виправили, а не звільнили. Перевіряч типів знайшов два справжні дефекти, які лінтер пропустив чистими, обидва про форму значення, а не про його синтаксис.</p>\n<p><strong>Результат.</strong> Найбільший і найбільш несучий код у репозиторії тепер відформатовано, перевірено лінтером і перевірячем типів, із тринадцятьма виправленими висновками й нулем придушень. Причина, чому це важить більше, ніж підказує кількість рядків, зазначена в плані: дефект у таблиці стилів сайту виявляється як сторінка, що виглядає хибно, а дефект у перевіряльнику виявляється як перевірка, що проходить тоді, коли не мала б.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Frontend‑розробка",
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/",
      "url": "https://engineer.company/uk/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/",
      "title": "Побудувала на Python генератор CV, рекомендацій, портфоліо та супровідних листів на основі бази даних — 41 модуль, 10 580 рядків — що відтворює шість форматів виводу з одного джерела SQLite на 23 таблиці, зібраного ідемпотентним конвеєром із 19 кроків.",
      "summary": "Шість форматів, три мови й п'ять тем виходять з однієї бази даних, а виправлене речення виправляють один раз.",
      "content_html": "<p><strong>Ситуація.</strong> CV, аркуш рекомендацій, портфоліо та супровідний лист — це ті самі факти, впорядковані чотирма способами, і тримати їх як чотири документи означає робити кожне виправлення чотири рази, а зрештою не робити. Три мови множать це на три. Режим відмови полягає не в тому, що документ хибний; він у тому, що два документи розходяться, і ніщо не каже, який із них поточний.</p>\n<p><strong>Завдання.</strong> Одне джерело фактів мало виробляти кожен документ, кожною мовою, у кожному форматі, з упорядкуванням, яке вирішує код, а не той, хто останнім редагував файл.</p>\n<p><strong>Дія.</strong> Джерелом є база даних SQLite із двадцяти трьох таблиць — досягнення, посади, компанії, регіони, категорії, послуги, профілі, рекомендації, резюме, — зібрана конвеєром із дев&rsquo;ятнадцяти кроків, що йде від порожнього файлу до повної бази даних однією командою. Кроки впорядковано, і кожен написано так, щоб його було безпечно повторювати, тож конвеєр можна виконати проти наявної бази даних, не дублюючи жодного рядка. Сорок один модуль Python загальним обсягом 10 580 рядків подають із неї шість вихідних форматів: HTML, PDF у двох варіантах, звичайний текст, Markdown і JSON, через шість шаблонів Jinja і вісім таблиць стилів. Залежності часу виконання втримано рівно на двох, шаблонний рушій і рендерер PDF, з тим аргументом, що генератор документів, який не вдасться встановити за п&rsquo;ять років, нічого не зберіг. Націлювання є повноцінним поняттям, а не ручним редагуванням: профіль обирає, які досягнення з&rsquo;являються і в якому порядку, тож документ, спрямований на один різновид читача, є запитом, а не копією.</p>\n<p><strong>Результат.</strong> Шість форматів, три мови й п&rsquo;ять тем виходять з однієї бази даних, а виправлене речення виправляють один раз. Ціна в тому, що система тепер є єдиним способом виробити документ — більше немає файлу, який можна поспіхом відкрити й відредагувати, а додати мову означає додати її скрізь, перш ніж узагалі щось збереться.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Full‑Stack розробка",
        "Python",
        "SQL",
        "Автоматизація та CI/CD",
        "Архітектура рішень",
        "Бази даних",
        "Інтернаціоналізація",
        "Backend- та API‑розробка",
        "Full‑Stack продуктова розробка",
        "Архітектура платформи та рішень",
        "Інтернаціоналізація та локалізація",
        "Проєктування та моделювання баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/",
      "url": "https://engineer.company/uk/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/",
      "title": "Втримала генератор на 981 тестовому випадку із порогом покриття гілок 92% і попередженнями як помилками та ствердила ідемпотентність, запустивши весь конвеєр збірки двічі з порожнього файлу й вимагаючи, щоб другий прохід нічого не змінив.",
      "summary": "Конвеєр можна повторно виконати проти живої бази даних без страху, і саме це взагалі уможливлює поступову роботу з вмістом.",
      "content_html": "<p><strong>Ситуація.</strong> Генератор, що збирає базу даних з нуля, має особливий різновид вади: він працює першого разу й псує другого. Кроки, що вставляють без перевірки, кроки, що залежать від порядку виводу попереднього кроку, кроки, безпечні поодинці й не разом. Нічого з цього не виявляється в тесті, що починає з нічого й виконується один раз.</p>\n<p><strong>Завдання.</strong> Збирання треба було довести як повторюване, а не просто робоче, а набір тестів мав бути достатньо великим і суворим, щоб регресія не змогла тихо крізь нього пройти.</p>\n<p><strong>Дія.</strong> Тест ідемпотентності є прямолінійним і найкориснішим: зібрати всю базу даних із порожнього файлу, зробити знімок, виконати весь дев&rsquo;ятнадцятикроковий конвеєр знову поверх результату й вимагати, щоб другий прохід нічого не змінив. Кількості рядків, вміст та ідентифікатори мають збігатися. Довкола нього стоять 383 тестові функції — 981 випадок, коли параметризовані розгортаються, — у сорока п&rsquo;яти файлах і 7 944 рядках, що охоплюють конвеєр, рендерери, завантажувачі вмісту, логіку націлювання та перевіряльників. Покриття гілок несе підлогу в дев&rsquo;яносто два відсотки, примусово застосовану в збиранні, а не подану в підсумку, і набір наразі показує близько 95 відсотків, тож підлога має запас і не є декоративною. Попередження налаштовано як відмови, і саме це налаштування на практиці важить найбільше — сповіщення про застарілість, що друкується два роки, є сповіщенням, якого ніхто не читає, а прогін, що перетворює його на червоний тест, є тим прогоном, після якого його виправлять.</p>\n<p><strong>Результат.</strong> Конвеєр можна повторно виконати проти живої бази даних без страху, і саме це взагалі уможливлює поступову роботу з вмістом. Підлога є підлогою, а не ціллю, і варто сказати, що дев&rsquo;яносто два відсотки покриття гілок усе одно лишають гілки, якими ніщо ніколи не проходило, — число обмежує ризик, а не усуває його, і два дефекти, знайдені в проєкті згодом, були в коді, який звіт про покриття показував як покритий.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Python",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/",
      "url": "https://engineer.company/uk/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/",
      "title": "Встановила відповідність PDF/UA‑1 на дев'яти документах за 106 зі 106 правил і виявила, що архівний варіант валить одне правило зі 146 — майже‑успіх, який читається як успіх для будь‑кого, хто не запускає валідатор.",
      "summary": "Відповідність доступності доведено на повний бал, а архівну заяву висловлено чесно як майже влучання із названою конкретною прогалиною.",
      "content_html": "<p><strong>Ситуація.</strong> PDF, що має правильний вигляд на екрані, не каже нічого про те, чи здатен його прочитати екранний читач, чи утворюють його заголовки структуру, чи оголошено його мову і чи відкриється він ще за двадцять років. Відповідність доступного PDF і архівного PDF є двома машинно перевірюваними стандартами, а документ, якого ніколи не проганяли через валідатор, є документом, що робить неперевірену заяву.</p>\n<p><strong>Завдання.</strong> Згенеровані документи треба було зміряти проти обох стандартів, із результатом, записаним як число, а не як намір.</p>\n<p><strong>Дія.</strong> Дев&rsquo;ять документів — CV у своїх варіантах, аркуш рекомендацій, портфоліо та супровідний лист, у різних мовах — прогнали через незалежний валідатор окремо для профілю доступності й архівного профілю. Профіль доступності проходить на 106 зі 106 правил, і це вимагало тегованої структури, оголошеної мови документа, альтернативного тексту на кожній недекоративній графіці, справжнього заголовка в метаданих і явного порядку читання замість того, який випадково дає розкладка. Архівний профіль дає цікавіший результат: він валить рівно одне правило зі 146. Це та форма результату, яку легко подати хибно. Сто сорок п&rsquo;ять пройдених у підсумку читається як відповідність, і це не відповідність; це документ, який відхилить система, що застосовує стандарт. Правило, яке не проходить, записано разом із тим, що воно є і чому його не закрито, а не заокруглено геть.</p>\n<p><strong>Результат.</strong> Відповідність доступності доведено на повний бал, а архівну заяву висловлено чесно як майже влучання із названою конкретною прогалиною. Межа, про яку варто сказати прямо, полягає в тому, що обидва числа походять від одного валідатора; інша реалізація може не погодитися, а правило, що проходить, є лише свідченням того, що цьому перевіряльникові не було чого про нього сказати.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Python",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Веброзробка",
        "Документація",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Розробка вебсайтів та CMS",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/enabled-every-python-linter-rule-as-an-error-147/",
      "url": "https://engineer.company/uk/portfolio/enabled-every-python-linter-rule-as-an-error-147/",
      "title": "Обрала кожне правило, яке має лінтер Python, як помилку й опрацювала 1 815 знахідок до нуля, де кожен із небагатьох винятків несе письмову причину, а два з них підперті перевіркою, а не коментарем.",
      "summary": "Лінтер працює на повну силу з нулем висновків, і кожне відхилення задокументовано в тому рядку, де його взято.",
      "content_html": "<p><strong>Ситуація.</strong> Більшість проєктів обирає зручну підмножину правил свого лінтера, і цю підмножину обирають ті правила, що мовчали того дня, коли його налаштовували. Це робить налаштування записом наявних звичок коду, а не стандартом, якого код дотримується, і кожне лишене вимкненим правило є класом дефектів, про який нікому ніколи не скажуть.</p>\n<p><strong>Завдання.</strong> Усталений вибір треба було обернути — кожне правило, яке реалізує інструмент, увімкнене як помилка, — а отриманий доробок відпрацювати до нуля, а не виторгувати вниз, вимикаючи правила назад.</p>\n<p><strong>Дія.</strong> Вибір повного набору правил дав 1 815 висновків на першому прогоні. Їх опрацьовували за категоріями, а не за файлами, бо категорії про щось кажуть: невживані аргументи та затінені вбудовані імена є шумом, а категорія безпеки, категорія змінюваних усталених значень і категорія обробки винятків кожна вказувала на справжню поведінку. Справжні несумісності існують — форматувальник і лінтер можуть розходитися щодо того самого рядка, а кілька правил суперечать власним свідомим виборам проєкту, — і кожне з невеликої кількості звільнень несе письмову причину в тому місці, де звільнення береться, і каже, чого хотіло правило й чому цей код робить інакше. Два з них ідуть далі й підперті перевіркою, а не коментарем, тож звільнення не може тихо розширитися: правило вимкнено, а тест стверджує саме ту властивість, яку правило примусово застосувало б. Поряд працює перевірка типів у суворому режимі, а це окремий і жорсткіший стандарт, і саме вона спіймала дефекти, яких лінтер не бачив, бо вони про те, чим значення є, а не про те, як його записано.</p>\n<p><strong>Результат.</strong> Лінтер працює на повну силу з нулем висновків, і кожне відхилення задокументовано в тому рядку, де його взято. Ціна реальна й варта називання: найсуворіше налаштування дає висновки, на які щиро не варто зважати, і хтось має ухвалювати це рішення 1 815 разів, а не один раз.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/vendored-a-qr-encoder-in-522-lines-148/",
      "url": "https://engineer.company/uk/portfolio/vendored-a-qr-encoder-in-522-lines-148/",
      "title": "Вбудувала кодувальник QR — Ріда‑Соломона над GF(256), фіксоване розташування модулів, вісім шаблонів маски — на 522 рядках, замість брати третю залежність часу виконання, і перевірила його, зчитавши готову матрицю незалежно написаним декодером.",
      "summary": "Кількість залежностей часу виконання лишилася на двох, а кодувальник є єдиним вкладеним компонентом у проєкті.",
      "content_html": "<p><strong>Ситуація.</strong> Документам потрібен був QR‑код із посиланням на онлайнову версію. Кожна доступна бібліотека це вміє, і взяти одну з них означало б додати третю залежність часу виконання до проєкту, що свідомо тримався двох — шаблонного рушія й рендерера PDF — з тим аргументом, що генератор документів має встановлюватися й через багато років.</p>\n<p><strong>Завдання.</strong> Треба було або прийняти залежність, або реалізувати формат, і реалізацію треба було довести як правильну, а не просто таку, що дає щось квадратне й чорне.</p>\n<p><strong>Дія.</strong> Кодувальник має 522 рядки й реалізує ті частини специфікації, які насправді потрібні для цього вжитку: кодування в байтовому режимі, виправлення помилок за Ридом‑Соломоном над полем Галуа з 256 елементів із твірним многочленом, побудованим у потрібному степені, фіксовану розкладку модулів із її пошуковими взірцями, часовими взірцями та взірцями вирівнювання, інформацію про формат і версію, а також усі вісім взірців маскування даних, оцінених за чотирма штрафними правилами специфікації, тож обирається маска з найнижчим балом, а не стала. Саме перевірка зробила це захисним. Випробовувати кодувальник проти його власної логіки не доводить нічого, тож готову матрицю модулів зчитує назад декодувальник, написаний незалежно за порядком читання зі специфікації, і тест стверджує, що декодований рядок дорівнює вхідному. Це перетворює «воно дає правдоподібне зображення» на «воно дає код, що декодується в правильну URL‑адресу», і це перевіряють за кожного прогону, а не один раз оком і телефоном.</p>\n<p><strong>Результат.</strong> Кількість залежностей часу виконання лишилася на двох, а кодувальник є єдиним вкладеним компонентом у проєкті. Слід сказати прямо, що це не універсальна реалізація — вона підтримує ті режими й версії, які використовують документи, і нічого більше, а чесним обґрунтуванням є бюджет залежностей, а не якась заява, що результат кращий за зрілу бібліотеку.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Python",
        "Документація",
        "Оптимізація продуктивності",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "Архітектура платформи та рішень"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/wrote-tests-for-the-checkers-themselves-149/",
      "url": "https://engineer.company/uk/portfolio/wrote-tests-for-the-checkers-themselves-149/",
      "title": "Написала тести для самих перевірок після встановлення, що перевірка, якій дають лише чистий вхід, одного дня відзвітує чисто, бо нічого не прочитала, — підклавши помилку правопису, щоб підтвердити, що перевірка орфографії її знаходить, і взявши діапазон ідентифікаторів із бази даних, а не з числа в тесті.",
      "summary": "Кожен перевіряльник у проєкті тепер має тест, що доводить його падіння на поганих вхідних даних, а твердження про діапазон читаються з джерела істини.",
      "content_html": "<p><strong>Ситуація.</strong> Проєкт проганяє набір власних перевіряльників над власним вмістом — перевірку орфографії, перевірку діапазону ідентифікаторів, перевірку голосу, перевірку узгодженості чисел. Кожен із них місяцями показував зелене. Перевіряльник, що бачив лише чисті вхідні дані й лише звітував про чистоту, не відрізнити від перевіряльника, що не читає нічого, і в наборі не було тесту, здатного розрізнити цих двох.</p>\n<p><strong>Завдання.</strong> Перевіряльників треба було змусити довести, що вони здатні завалитися, а фікстури, проти яких вони перевіряють, мали перестати бути рукотворними копіями того, що вони описують.</p>\n<p><strong>Дія.</strong> Взірцем, застосованим усюди, є посадити саме той дефект, заради пошуку якого перевіряльник існує, і вимагати, щоб перевіряльник його знайшов. Перевірці орфографії згодовують навмисно неправильно написане слово, і тест валиться, якщо прогін повертається чистим. Перевірці голосу згодовують прозу в першій особі, і вона має її відхилити. Перевірці модних слів згодовують заборонене слово. Кожне з цього є маленьким тестом, і кожен закрив справжню сліпу пляму, бо два перевіряльники, як виявилося, читали вужчий набір файлів, ніж заявляла їхня документація, і мовчки пропускали вміст. Друга зміна стосується того, звідки тест бере свої очікування: перевірка діапазону ідентифікаторів раніше порівнювала з числом, записаним у тестовому файлі, а це означало, що кожне додавання вмісту вимагало редагування тесту, і редактор, який оновив число, не подивившись, вимикав перевірку. Тепер вона виводить діапазон із бази даних, тож перевірка описує дані, а не застарілий спогад про них.</p>\n<p><strong>Результат.</strong> Кожен перевіряльник у проєкті тепер має тест, що доводить його падіння на поганих вхідних даних, а твердження про діапазон читаються з джерела істини. Незручним є те, що це виявило: зелена перевірка була беззмістовною щонайменше у двох місцях протягом невідомого часу, і немає способу дізнатися заднім числом, що крізь неї пройшло.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "Python",
        "Автоматизація та CI/CD",
        "Бази даних",
        "Тестування та QA",
        "Data Governance та якість даних",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/",
      "url": "https://engineer.company/uk/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/",
      "title": "Виявила, що хуки коміту та ворота якості виконують різні перевірки, поки документ обіцяв, що вони однакові, порівнявши два переліки в тесті, — п'ять, які виконувалися лише вручну, були тими, що читали прозу CV.",
      "summary": "Хук і повна перевірка доведено виконують ті самі перевірки, а перевірки прози тепер виконуються за кожного коміту.",
      "content_html": "<p><strong>Ситуація.</strong> Проєкт мав хук на коміт, що виконує перевірки до прийняття коміту, і повну перевірку якості, яку запускають на вимогу. Документ стверджував, що хук виконує ту перевірку, тож ніщо не могло потрапити до історії, не пройшовши всього. Обидва переліки підтримувалися вручну, у двох різних файлах, і ніщо їх не порівнювало.</p>\n<p><strong>Завдання.</strong> Заяву треба було перетворити на твердження, а це означало перелічити обидві множини програмно й валитися, коли вони розходяться.</p>\n<p><strong>Дія.</strong> Тест читає налаштування хука та визначення завдань перевірки, розв&rsquo;язує кожне з них у множину перевірок, які воно насправді викликає, і порівнює. Вони не збіглися. П&rsquo;ять перевірок існували лише в повній перевірці й ніколи не виконувалися на коміті, і ці п&rsquo;ять не були випадковими — це були ті, що читають саму прозу CV: перевірка голосу, яка тримає відгуки безособовими, перевірка модних слів, перевірка узгодженості чисел між мовами, перевірка нотації та перевірка орфографії вмісту. Інакше кажучи, кожна перевірка, що захищає код, виконувалася автоматично, а кожна перевірка, що захищає письмо, виконувалася лише тоді, коли хтось згадував. Оскільки письмо є всім продуктом, вразливість була оберненою щодо того, де її хтось припустив би. Виправленням було внести ці п&rsquo;ять до хука, що вимагало зробити дві з них досить швидкими, аби пережити бюджет часу до коміту, а потім лишити тест порівняння на місці, щоб два переліки більше не могли розійтися. Документ, що описував намір, тепер описує щось примусово застосоване.</p>\n<p><strong>Результат.</strong> Хук і повна перевірка доведено виконують ті самі перевірки, а перевірки прози тепер виконуються за кожного коміту. Компромісом є час виконання хука на коміт, який зріс і зростатиме далі, поки зростає вміст, і існує точка, у якій повільний хук починають обходити, — тож у цього виправлення є термін придатності, вимірюваний тим, як довго перевірки лишатимуться швидкими.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Технічна документація",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/rehearsed-the-forge-side-ci-hook-151/",
      "url": "https://engineer.company/uk/portfolio/rehearsed-the-forge-side-ci-hook-151/",
      "title": "Відрепетирувала CI‑хук на боці форжу й знайшла два дефекти, недосяжні читанням файлу: запасний варіант, який клав нерозв'язний аргумент на вхід хука, і власну змінну середовища git, яка йшла за воротами у checkout і робила 19 тестів червоними.",
      "summary": "Хук працює на обох шляхах, і обидва дефекти знайдено раніше, ніж їх зустрів справжній пуш. Обмеження в тому, що репетиція все одно є симуляцією: вона доводить,…",
      "content_html": "<p><strong>Ситуація.</strong> Самостійно розміщена git‑форджа приймає пуші й може виконати хук на боці сервера, аби відхилити роботу, що не проходить перевірку. Хук на боці сервера є тим єдиним шматком автоматизації, який не можна випробувати, запустивши його локально: він виконується в голому репозиторії, без робочого дерева, у середовищі, яке задає форджа, читаючи запушені посилання зі свого стандартного входу. Прочитати скрипт і виснувати, що він правильний, — це здогад.</p>\n<p><strong>Завдання.</strong> Хук треба було відрепетирувати проти справжнього голого репозиторію та справжнього пушу, перш ніж йому довіряти, а не розгорнути й дізнатися.</p>\n<p><strong>Дія.</strong> Репетиція створює голий репозиторій, встановлює хук, клонує його, комітить, пушить і стверджує і на шляху прийняття, і на шляху відхилення. Вона знайшла два дефекти, жоден із яких не був видимий у файлі. Першим був запасний варіант в обробці аргументів: коли хук не міг визначити посилання, він підставляв заповнювач, що не був розв&rsquo;язуваним об&rsquo;єктом, і оскільки значення приходить на стандартний вхід хука, а не як параметр, відмова спливала як неспоріднена помилка значно нижче. Другий вартий запам&rsquo;ятовування. Git експортує змінну середовища, що називає каталог репозиторію, коли викликає хук, і цю змінну успадковує все, що хук запускає. Перевірка вивантажує запушену ревізію й виконує в ній набір тестів, а набір тестів успадкував вказівник на голий репозиторій — тож дев&rsquo;ятнадцять тестів, що торкаються git, розв&rsquo;язувалися проти хибного репозиторію й почервоніли на коді, що був правильним. Середовище треба очищати на межі, і ця межа невидима, доки річ насправді не запустять.</p>\n<p><strong>Результат.</strong> Хук працює на обох шляхах, і обидва дефекти знайдено раніше, ніж їх зустрів справжній пуш. Обмеження в тому, що репетиція все одно є симуляцією: вона доводить, що хук переживає одну форму пушу, а форджа в роботі бачить пуші, яких ця репетиція не конструює, зокрема примусові оновлення та видалення гілок.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Linux та сервери",
        "Python",
        "Автоматизація та CI/CD",
        "Інфраструктура",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Infrastructure as Code",
        "Системне адміністрування"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/moved-every-user-facing-string-into-a-content-tree-152/",
      "url": "https://engineer.company/uk/portfolio/moved-every-user-facing-string-into-a-content-tree-152/",
      "title": "Перенесла кожен рядок, звернений до користувача, з Python у дерево контенту з 874 файлів трьома мовами, знайшовши мертві переклади, чиєї мертвості ніхто не бачив, і перевірку, яка мовчки оцінювала третину досягнень.",
      "summary": "Прозу тепер можна редагувати, не торкаючись коду, і порівнювати між мовами підрахунком. Ціною є те, що додавання мови тепер однозначне, а не поступове — дерево…",
      "content_html": "<p><strong>Ситуація.</strong> Кожен рядок генератора, звернений до користувача, — кожне досягнення, кожен відгук, кожен заголовок розділу, кожне резюме, трьома мовами — жив усередині коду на Python. Це робить редагування речення зміною коду, робить перегляд перекладу різницею проти коду й унеможливлює побачити з першого погляду, чи мова повна. Це також ховає той режим відмови, що має значення: переклад може бути присутнім, хибним і недосяжним водночас.</p>\n<p><strong>Завдання.</strong> Рядки треба було винести з коду до дерева вмісту, яке можна перерахувати, порівняти між мовами й перевірити, не запускаючи рендерера.</p>\n<p><strong>Дія.</strong> Результатом є 874 файли у каталозі вмісту, впорядкованих за видом, а потім за мовою: досягнення, відгуки, резюме, посади, компанії, регіони, категорії, послуги, профілі, рекомендації та фрагменти супровідних листів. Файли з полями через табуляцію, де одиницею є рядок з ідентифікатором, і окремі файли, де одиницею є абзац. Завантажувач читає їх під час збирання, і база даних збирається з них, тож дерево є джерелом, а база даних — похідною. Два висновки вийшли безпосередньо зі здатності рахувати. Деякі перекладені рядки більше не мали жодного англійського відповідника — мертві записи, яких ніщо не подавало і яких ніхто не міг би помітити, доки вони були вкладені в код, бо непосиланий ключ словника має точнісінько такий вигляд, як посиланий. А перевірка вмісту, що мала оцінювати кожне досягнення, читала лише ту підмножину, яку могла розв&rsquo;язати, оцінювала тридцять сім із дев&rsquo;яноста трьох і звітувала про успіх. Перетворення корпусу на каталог зробило обидва ці факти видимими як розбіжність у кількості файлів.</p>\n<p><strong>Результат.</strong> Прозу тепер можна редагувати, не торкаючись коду, і порівнювати між мовами підрахунком. Ціною є те, що додавання мови тепер однозначне, а не поступове — дерево робить неповну мову очевидною, і в цьому вся суть, але це також означає, що часткові переклади не можна тихо випускати, поки їх доробляють.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Data Governance",
        "Python",
        "Документація",
        "Інтернаціоналізація",
        "Міграції та модернізація",
        "Backend- та API‑розробка",
        "Data Governance та якість даних",
        "Інтернаціоналізація та локалізація",
        "Міграція та модернізація баз даних"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-cross-language-figure-and-notation-check-153/",
      "url": "https://engineer.company/uk/portfolio/built-a-cross-language-figure-and-notation-check-153/",
      "title": "Побудувала міжмовну перевірку контенту, яка валиться, коли переклад губить число, вказане англійською, і коли мова вживає нотацію, якої не вживає, — знайшовши два данські описи без метрики і шістнадцять українських фрагментів, що цитували на англійський лад.",
      "summary": "Вісімнадцять справжніх дефектів закрито, а разом із ними закрито й клас, бо кожен майбутній переклад порівнюється зі своїм англійським джерелом, перш ніж його…",
      "content_html": "<p><strong>Ситуація.</strong> Найшкідливіший різновид помилки перекладу в CV — не незграбна фраза. Це число, що зникає. Англійське речення, що заявляє п&rsquo;ятдесятикратне поліпшення, перекладене реченням, яке каже «значно», є заявою, тихо відкликаною на одному ринку й збереженою на іншому, — і жодна перевірка орфографії, граматики чи людське читання самої лише цільової мови цього ніколи не помітить, бо перекладене речення є цілком доброю прозою.</p>\n<p><strong>Завдання.</strong> Потрібна була перевірка, що читає мови одна проти одної, а не кожну окремо, на тих двох речах, які мають пережити переклад: числа й нотація, якою кожна мова їх записує.</p>\n<p><strong>Дія.</strong> Перевірка чисел витягує кожне число, відсоток, множник та одиницю з англійського рядка й вимагає, щоб кожне з них з&rsquo;явилося в кожному перекладі того рядка, з формами множників, зіставленими для кожної мови окремо, а не збіганими буквально: англійська форма «у п&rsquo;ятдесят разів» відповідає певній данській і певній українській вимові, і перевірка знає це зіставлення, а не вимагає самих лише цифр. Перевірка нотації є її дзеркалом: кожна мова має конвенції, які мусить вживати, і конвенції, яких вживати не має, зокрема десяткові розділювачі, групування тисяч і лапки. Українська бере лапки‑ялинки; англійські подвійні лапки в українському реченні є так само хибними, як пропущене число, і їх набагато легше внести копіюванням. Перший повний прогін виявив два данські описи, де показник, присутній в англійській, було втрачено, і шістнадцять українських фрагментів із лапками в англійському стилі.</p>\n<p><strong>Результат.</strong> Вісімнадцять справжніх дефектів закрито, а разом із ними закрито й клас, бо кожен майбутній переклад порівнюється зі своїм англійським джерелом, перш ніж його можна закомітити. Чого перевірка не вміє, так це судити про зміст: вона доводить, що число вижило і що пунктуація рідна, а переклад, що зберігає кожне число й водночас перевертає заяву навпаки, проходить її без зауважень.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Інтернаціоналізація",
        "Тестування та QA",
        "Data Governance та якість даних",
        "Інтернаціоналізація та локалізація",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/",
      "url": "https://engineer.company/uk/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/",
      "title": "Побудувала нативний клієнт обміну повідомленнями для macOS на Swift 6 і SwiftUI — 11 141 рядок у 53 файлах — поверх C‑інтерфейсу ядра на Rust, злінкованого як статичний архів із зафіксованої ревізії.",
      "summary": "Рідний клієнт, що запускається як програма для Mac, використовує власні матеріали та елементи керування платформи й не несе вбудованого браузера.",
      "content_html": "<p><strong>Ситуація.</strong> Протокол обміну повідомленнями мав добре випробуване ядро, написане на Rust, і клієнти на кількох платформах, але настільний досвід на macOS був кросплатформною оболонкою — він не мав вигляду програми для Mac, не поводився як така й ніс середовище виконання, якого рідній програмі не потрібно. Ядро відкриває свою спроможність через C‑інтерфейс, а це означає, що будь‑яка мова, здатна викликати C, може на ньому будувати, і Swift здатен.</p>\n<p><strong>Завдання.</strong> Рідного клієнта треба було збудувати безпосередньо на тому C‑інтерфейсі, поточною мовою платформи та її поточним інтерфейсним каркасом, із ядром, вкомпонованим усередину, а не постаченим поруч.</p>\n<p><strong>Дія.</strong> Програма має 11 141 рядок Swift у п&rsquo;ятдесяти трьох файлах у цілі застосунку, збудована на SwiftUI з ядром, вкомпонованим як статичний архів, зібраний із закріпленої висхідної ревізії. Закріплення ревізії, а не стеження за гілкою, є тим рішенням, що робить збирання відтворюваним: C‑інтерфейс є контрактом, і рухоме ядро змінює контракт, не змінюючи жодного рядка Swift. Шарування тримає небезпечну поверхню малою — тонка обгортка володіє кожним вказівником і кожним рядком, що перетинає межу, моделі над нею є звичайними значеннями Swift, а інтерфейсний шар ніколи не бачить сирого вказівника. Усе, що повертає C‑інтерфейс, має правило володіння, і помилитися в одному з них означає або витік, або аварію без жодного попередження компілятора між ними, тож саме в обгортці живе вся дисципліна пам&rsquo;яті проєкту. Збиранням керує виконавець завдань із п&rsquo;ятдесятьма шістьма цілями, що охоплюють компіляцію ядра, збирання Swift, набори тестів, лінтери та пакування.</p>\n<p><strong>Результат.</strong> Рідний клієнт, що запускається як програма для Mac, використовує власні матеріали та елементи керування платформи й не несе вбудованого браузера. Те, чого не зроблено, слід зазначити: це не випущений реліз. Немає ні нотаризованого розповсюдження, ні каналу оновлень, і в інтерфейсі одна мова, тож це радше робоча програма, ніж продукт, який хтось інший використовує.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Frontend‑розробка",
        "Full‑Stack розробка",
        "UX / UI‑дизайн",
        "Архітектура рішень",
        "Дизайн‑системи та UI",
        "Full‑Stack продуктова розробка",
        "UI/UX‑дизайн та дизайн‑системи",
        "Архітектура платформи та рішень"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/",
      "url": "https://engineer.company/uk/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/",
      "title": "Спинила застосунок, що наповнював пам'ять зі швидкістю 41 МБ за секунду — зафіксовані 111 ГБ стиснених сторінок на машині з 36 ГБ, — обмеживши кожен потік подій, підписуючись за типом події та поклавши бюджет швидкості на журналювання, що звело 610 996 рядків журналу до 1 411.",
      "summary": "Пам'ять лишається рівною під тривалим навантаженням, і той самий сеанс, що давав 610 996 рядків журналу, дає 1 411.",
      "content_html": "<p><strong>Ситуація.</strong> Програма наповнювала пам&rsquo;ять, доки операційна система її не вбивала. Зафіксований інцидент сягнув 111 ГБ стиснутих сторінок на машині з 36 ГБ, зростаючи приблизно на 41 МБ за секунду, а файл журналу за один короткий сеанс тримав 610 996 рядків. Машина в такому стані не повільна, вона непридатна — вбивство приходить після того, як підкачування вже змусило все інше на робочому столі перестати відповідати.</p>\n<p><strong>Завдання.</strong> Зростання треба було знайти, а не вгадати, і кожному необмеженому шляху треба було дати межу, бо одна обмежена черга поруч із трьома необмеженими не є виправленням.</p>\n<p><strong>Дія.</strong> Причин‑множників було три, і саме множення пояснює, чому це відбувалося так швидко. Потік подій із ядра споживався без жодної межі, тож події надходили швидше, ніж інтерфейс міг їх застосувати, і доробок утримувався, а не відкидався. Кожен передплатник отримував кожну подію й фільтрував після цього, тож вартість однієї події множилася на кількість слухачів, і фільтрування кожного слухача виділяло пам&rsquo;ять. А журналювання було небюджетованим, тож кожна подія породжувала рядки журналу — і це складений доданок, бо обсяг журналювання був пропорційним до обсягу того, що йшло не так. Виправлення взялося за всі три: обмежені буфери з явною політикою того, що стається за їх заповнення, передплата за типом події, тож слухача будять лише для подій, яких він хоче, і бюджет швидкості на журналювання, що згортає повтори, а не пише кожен. Регресійний тест жене високу швидкість подій і стверджує, що стеля пам&rsquo;яті тримається, тож межа є властивістю збирання, а не коментарем.</p>\n<p><strong>Результат.</strong> Пам&rsquo;ять лишається рівною під тривалим навантаженням, і той самий сеанс, що давав 610 996 рядків журналу, дає 1 411. Чесним зауваженням є те, що бюджет швидкості на журналювання відкидає інформацію: коли щось іде не так швидко, запис про це тепер навмисно неповний, і це обмін, зроблений свідомо проти альтернативи, якою є машина, що спиняється.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "Архітектура рішень",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Тестування та QA",
        "Архітектура платформи та рішень",
        "Надійність та моніторинг (SRE)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/",
      "url": "https://engineer.company/uk/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/",
      "title": "Прийняла повну сувору паралельність Swift 6 без акторів, перекинувши місток від блокувального циклу подій C до головного актора через одного виробника, одного споживача й один порядок — після встановлення, що задача на подію губить порядок, від якого залежить інтерфейс.",
      "summary": "Програма компілюється за повної суворої перевірки паралельності без придушень, а впорядкованість подій є структурною властивістю, а не сподіванням.",
      "content_html": "<p><strong>Ситуація.</strong> Повна сувора перевірка паралельності у Swift 6 перетворює гонитви за даними на помилки компіляції замість переривчастих аварій. Впроваджувати її проти бібліотеки на C — саме там, де стає важко: цикл подій ядра є блокувальним викликом, що має вічно виконуватися поза головним потоком, а значення, які він повертає, є вказівниками без жодних гарантій щодо паралельності. Компілятор не може міркувати про це все й відхилятиме всі, доки межу не буде описано явно.</p>\n<p><strong>Завдання.</strong> Повну перевірку треба було ввімкнути без жодних запасних лазівок, а це означало спроєктувати перехід від блокувального циклу на C до головного актора, а не обставляти його анотаціями.</p>\n<p><strong>Дія.</strong> Очевидним підходом є актор на підсистему, і його відкинули за вимірюванням, а не за смаком. Породження задачі на кожну вхідну подію дозволяє середовищу виконання планувати їх у будь‑якому порядку, а потік подій ядра є впорядкованим — подія «повідомлення змінено», що обганяє подію «повідомлення створено», на яку вона посилається, дає інтерфейс, що показує редагування чогось, чого ще не існує. Повторний вхід в актора робить це гіршим, а не кращим, бо актор може призупинитися посеред методу й обробити інший виклик. Те, що це замінило, є навмисно простим: один потік‑виробник, що володіє блокувальним циклом, один споживач, одна черга між ними та єдиний стрибок на головного актора наприкінці. Порядок зберігається, бо шлях рівно один і ніщо нічого не обганяє. Небезпечні типи, що перетинають цю межу, загорнуто в типи, чию потокобезпеку стверджують на обгортці, а не припускають, і твердження задокументовано разом із тим, чому воно чинне: вказівником володіє один потік, і його копіюють, перш ніж передати.</p>\n<p><strong>Результат.</strong> Програма компілюється за повної суворої перевірки паралельності без придушень, а впорядкованість подій є структурною властивістю, а не сподіванням. Ціною є те, що задум менш паралельний, ніж міг би бути: усе стікається через одного споживача, і якщо той споживач колись стане вузьким місцем, виправлення вимагатиме заново вивести, які події можна безпечно переставляти, а це саме той аналіз, якого це дозволило уникнути.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Backend‑розробка",
        "Frontend‑розробка",
        "Архітектура рішень",
        "Надійність і резервне копіювання",
        "Оптимізація продуктивності",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "Архітектура платформи та рішень",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/",
      "url": "https://engineer.company/uk/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/",
      "title": "Написала парсер, який читає справжній C‑заголовок на 7 308 рядків і перевіряє кожне місце виклику, кожну константу переліку й те, що кожен клас‑власник вказівника є final, після того як рукописний заголовок‑заглушка дозволив викликам до трьох вилучених функцій скомпілюватися, злінкуватися й впасти.",
      "summary": "Клас дефектів, що спричинив початкову аварію, не може повторитися, бо застаріле посилання тепер є відмовою збирання, а не відмовою під час виконання.",
      "content_html": "<p><strong>Ситуація.</strong> На початку проєкту C‑інтерфейс представляв рукописний заголовний файл, що описував функції, яких очікувала програма. Той заголовок компілювався, програма зв&rsquo;язувалася, а виклики трьох функцій, яких у ядрі більше не існувало, доходили до моменту виклику й аварійно завершувалися. І компілятор, і компонувальник задовольнилися описом бібліотеки замість самої бібліотеки, а розрив виявився лише під час виконання.</p>\n<p><strong>Завдання.</strong> Справжній заголовок — 7 308 рядків і 268 оголошень — мав стати авторитетом, і кожне його використання в коді Swift треба було звіряти з ним автоматично, а не переглядом.</p>\n<p><strong>Дія.</strong> Перевіркою є розбирач, що читає справжній висхідний заголовок і будує множину функцій, констант переліку й типів, які той оголошує, а потім читає код Swift і розв&rsquo;язує кожне місце виклику та кожне посилання на константу проти цієї множини. Виклик функції, якої заголовок не оголошує, валить збирання. Посилання на константу переліку, яку перейменували, валить збирання. Поточне число — 132 з 268 оголошень, на які є посилання, і знати, які 136 не використовуються, саме собою корисно, бо це каже точно, якої частини ядра клієнт не досяг. Розбирач також примусово застосовує правило, якого не може компілятор: кожен клас Swift, що володіє вказівником у ядро, має бути фінальним. Нефінальний клас, що володіє вказівником, можна успадкувати, а підклас, що перевизначає деініціалізацію або додає власний час життя, змінює момент звільнення вказівника — використання після звільнення без жодного небезпечного ключового слова поблизу. Правило перевіряють за іменем по всьому дереву.</p>\n<p><strong>Результат.</strong> Клас дефектів, що спричинив початкову аварію, не може повторитися, бо застаріле посилання тепер є відмовою збирання, а не відмовою під час виконання. Обмеженням є те, що розбирач розуміє оголошення заголовка, а не його семантику: він доводить, що функція існує з відповідним іменем, а функція, чиє значення чи правило володіння змінилося вище за течією зі збереженням сигнатури, проходить без зауважень.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/took-the-test-suite-under-nine-seconds-158/",
      "url": "https://engineer.company/uk/portfolio/took-the-test-suite-under-nine-seconds-158/",
      "title": "Звела набір тестів із шести тестів понад межу в шістдесят секунд до 135 успішних за 8,9 секунди, профілюючи головний потік і прибравши два виклики, всередині яких він сидів у 3 989 із 4 017 вибірок.",
      "summary": "Набір пішов із шести тестів понад шістдесят секунд — 74 секунди за годинником — до 135 тестів, що проходять за 8,9, і це вкладає його у вікно, в якому він…",
      "content_html": "<p><strong>Ситуація.</strong> Набір тестів мав межу в шістдесят секунд, і шість тестів були понад неї. Набір тестів, що триває понад хвилину, перестають запускати перед кожною зміною, а набір, який не запускають перед кожною зміною, є звітом про минуле. Інстинкт у цій ситуації — підняти межу, а піднімання межі є тим, як набір доходить до десяти хвилин.</p>\n<p><strong>Завдання.</strong> Час треба було знайти, а не закласти в бюджет, а це означало профілювати набір замість міркувати, які тести мають дорогий вигляд.</p>\n<p><strong>Дія.</strong> Профіль знімали з головного потоку, поки набір виконувався, і результат суперечив здогаду. Головний потік сидів усередині двох викликів у 3 989 зразках із 4 017 — тож повільними були не ті тести, що робили найбільше роботи, і майже кожен тест проходив через ті самі два місця. Першим було фіксоване очікування, вжите, щоб дати асинхронній роботі влягтися перед твердженням, — по суті сон, оплачуваний кожним тестом, що торкався шляху подій, незалежно від того, чи робота вже скінчилася. Його замінили на очікування самої умови з тайм‑аутом, тож тест, готовий за п&rsquo;ять мілісекунд, бере п&rsquo;ять мілісекунд, і повне очікування платить лише той тест, що справді застряг. Другим було налаштування на кожен тест, що щоразу перебудовувало дорогу фікстуру, тоді як фікстура була лише для читання й могла будуватися один раз на весь набір. Жодне з них не було в тесті, який хтось назвав би повільним; обидва були в спільному шляху, і саме тому весь набір був рівномірно повільним, а не кілька тестів були викидами.</p>\n<p><strong>Результат.</strong> Набір пішов із шести тестів понад шістдесят секунд — 74 секунди за годинником — до 135 тестів, що проходять за 8,9, і це вкладає його у вікно, в якому він виконується за кожного збереження. Застереження в тому, що спільна фікстура лише для читання тепер є точкою зчеплення: тест, що його змінить, дасть падіння в іншому тесті, і швидкість набору залежить від дисципліни, якої компілятор не примушує.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "DevOps",
        "Автоматизація та CI/CD",
        "Оптимізація продуктивності",
        "Тестування та QA",
        "DevOps та автоматизація CI/CD",
        "Технічне лідерство та консалтинг"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/",
      "url": "https://engineer.company/uk/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/",
      "title": "Назвала кожен суто піктограмний елемент керування в інтерфейсі для зчитувачів екрана після того, як кнопка надсилання оголошувалася як «arrow up circle, button», і написала лінтер, що вимагає підпис у межах восьми рядків від піктограми.",
      "summary": "Усі сімнадцять елементів керування оголошують свою функцію, і вісімнадцятий не можна додати без неї.",
      "content_html": "<p><strong>Ситуація.</strong> Інтерфейс використовував системні символи для своїх елементів керування, а символ без мітки доступності екранний читач озвучує його власним внутрішнім іменем. Кнопка надсилання оголошувалася як «стрілка вгору коло, кнопка». Так само робив кожен інший елемент керування лише з піктограмою в програмі, кожен по‑своєму — сімнадцять із них описували власний малюнок замість своєї функції.</p>\n<p><strong>Завдання.</strong> Кожен елемент керування лише з піктограмою потребував мітки, що описує, що він робить, і виправлення мало прийти з перевіркою, бо наступна додана піктограма інакше внесла б дефект назад негайно.</p>\n<p><strong>Дія.</strong> Кожному із сімнадцяти надали мітку, що називає дію, а не форму, і там, де значення елемента залежить від стану, мітка йде за станом, а не є сталою. Перевірка є тією частиною, яку варто описати, бо загального правила «чи це доступно» для цього не існує. Лінтер шукає конструкцію, що створює елемент керування лише з піктограмою, і далі вимагає мітки доступності в межах восьми рядків від неї. Вісім рядків є навмисно грубою евристикою, і її обрано вимірюванням: вона достатньо довга, щоб охопити кожен законний спосіб, яким кодова база пише один із цих елементів разом із його модифікаторами, і достатньо коротка, щоб мітка, приєднана до іншого подання нижче, її випадково не задовольнила. Точне правило тут мало б розуміти ланцюжки модифікаторів SwiftUI як дерево, а дешеве правило близькості ловить справжню помилку — а це не хибно підписаний елемент, це непідписаний.</p>\n<p><strong>Результат.</strong> Усі сімнадцять елементів керування оголошують свою функцію, і вісімнадцятий не можна додати без неї. Неточність правила є реальною й зазначена там, де його визначено: його може задовольнити мітка на сусідньому поданні, тож воно доводить, що мітка існує поруч, а не що мітка правильна, і для правильності досі потрібно, щоб хтось її послухав.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Дизайн‑системи та UI",
        "Документація",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-a-48-token-design-system-160/",
      "url": "https://engineer.company/uk/portfolio/built-a-48-token-design-system-160/",
      "title": "Побудувала систему дизайну на 48 токенів поверх власного скляного матеріалу платформи й написала лінтер, який відхиляє магічне число, жорстко задений розмір шрифту чи анімацію, що ігнорує настройку зменшеного руху.",
      "summary": "Сорок вісім токенів описують увесь інтерфейс, вигляд іде за системою, і жодне з трьох руйнувань не можна закомітити.",
      "content_html": "<p><strong>Ситуація.</strong> Інтерфейс, збудований додаванням подань, накопичує значення: радіус заокруглення тут, шрифт у чотирнадцять пунктів там, анімація на дві десятих секунди десь іще. Кожне окремо є розумним, а разом вони є дизайном, якого не можна змінити, бо не існує такої речі, як «радіус заокруглення», щоб її змінити, — їх сорок, злегка різних, розсипаних по п&rsquo;ятдесяти файлах.</p>\n<p><strong>Завдання.</strong> Візуальний словник треба було скоротити до іменованої множини, вираженої проти власного матеріалу платформи, а не винайденої заново, і захищеної перевіркою, щоб він лишався скороченим.</p>\n<p><strong>Дія.</strong> Системою є сорок вісім токенів у шести групах: відступи, типографіка, колір, радіус, підняття та рух. Колір і матеріал збудовано на семантичних кольорах платформи та її скляному матеріалі, а не на сталих значеннях, і саме це змушує інтерфейс іти за системним виглядом, акцентним кольором і налаштуваннями контрасту без жодного коду, що за ними стежить. Типографіка відображається на текстові стилі платформи, тож вона масштабується з уподобою розміру в користувача замість прив&rsquo;язки до пунктового значення. Лінтер відхиляє три речі: числовий літерал там, де належить токен відступу чи радіуса, жорстко заданий кегль будь‑де і анімацію, оголошену без шанування уподоби зменшеного руху. Третя є тією, що інакше руйнувалася б найшвидше, бо анімацію додають у мить наведення блиску, і саме перевірку уподоби пропускають — тож правило робить саму анімацію неможливою для написання без неї, а не просить когось пам&rsquo;ятати.</p>\n<p><strong>Результат.</strong> Сорок вісім токенів описують увесь інтерфейс, вигляд іде за системою, і жодне з трьох руйнувань не можна закомітити. Межею є те, що система токенів обмежує узгодженість, а не якість, — тепер усе пасує одне до одного, а пасувати не те саме, що бути добре спроєктованим, і це судження не виносить жоден лінтер у цьому проєкті.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Дизайн‑системи та UI",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Бренд, маркетинг та SEO"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/reached-the-unused-half-of-the-messaging-core-161/",
      "url": "https://engineer.company/uk/portfolio/reached-the-unused-half-of-the-messaging-core-161/",
      "title": "Дістала ту половину ядра обміну повідомленнями, якої застосунок ніколи не використовував, — передавання резервної копії, зникомі повідомлення, редагування та повторне надсилання, підтверджені запрошення, проксі та політику шифрування, — ведучи кожен тест проти справжньої бібліотеки без заглушок.",
      "summary": "Раніше недосяжну половину ядра тепер ганяють тести проти справжньої бібліотеки, а обгортка несе найвищу підлогу в проєкті.",
      "content_html": "<p><strong>Ситуація.</strong> Клієнт використовував приблизно половину того, що пропонує ядро обміну повідомленнями. Невикористана половина не була маловідомою — перенесення резервних копій між пристроями, зникомі повідомлення, редагування та повторне надсилання повідомлень, перевірені запрошувальні посилання, налаштування проксі та політика шифрування для розмови. Кожне з цього є можливістю, якої очікував би користувач, і кожне було невипробуваною ділянкою C‑інтерфейсу, а це небезпечніший факт, бо невипробувана ділянка C‑інтерфейсу — саме там, де живуть помилки володіння.</p>\n<p><strong>Завдання.</strong> Недосяжну спроможність треба було задіяти й покрити, і тести мали виконуватися проти справжньої бібліотеки, а не проти заміщувача.</p>\n<p><strong>Дія.</strong> Прийнятим правилом було жодних імітацій для ядра. Імітація C‑інтерфейсу кодує переконання розробника про те, що робить бібліотека, а кожен вартий пошуку дефект тут є місцем, де це переконання хибне, — тож пройдений тест на імітації є свідченням про імітацію. Натомість тести створюють справжні облікові записи в тимчасових каталогах, ганяють справжню бібліотеку і стверджують про те, що вона насправді повертає, і кожен набір прибирає власний стан. Саме це зробило покриття змістовним: задіяти перенесення резервних копій означало обробити машину станів справжнього перенесення та її шляхи відмов, а задіяти перевірені запрошення означало сконструювати справжній формат посилання й дати бібліотеці його розібрати. Підлоги покриття задано на кожен шар окремо, а не одним числом: вісімдесят чотири відсотки для обгортки ядра, сімдесят п&rsquo;ять для допоміжних функцій і шістдесят п&rsquo;ять для моделей, з тим міркуванням, що шар, який торкається сирих вказівників, слід тримати найвище, а модель, яка здебільшого складається зі збережених властивостей, не варто набивати тестами заради середнього.</p>\n<p><strong>Результат.</strong> Раніше недосяжну половину ядра тепер ганяють тести проти справжньої бібліотеки, а обгортка несе найвищу підлогу в проєкті. Ціною є швидкість і передбачуваність: тести проти справжньої бібліотеки повільніші за імітації, і вони можуть падати з причин середовища, а це ціна за їхню здатність падати зі справжніх.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "API та інтеграції",
        "Backend‑розробка",
        "Автоматизація та CI/CD",
        "Безпека",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Backend- та API‑розробка",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/",
      "url": "https://engineer.company/uk/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/",
      "title": "Переписала повідомлення про помилки застосунку за письмовим стандартом тону після того, як відмовлений вхід звинуватив користувача в друкарській помилці, тоді як провайдер насправді вимагав пароль для застосунку, і покрила це тестом, який називає провайдера.",
      "summary": "Поверхня помилок дотримується зазначеного стандарту, а випадок, що до нього спонукав, покрито тестом, який падає на старому тексті.",
      "content_html": "<p><strong>Ситуація.</strong> Вхід до великого поштового провайдера не вдався, і програма сказала користувачеві, що його пароль хибний. Він не був хибним. Той провайдер вимагає окремого пароля застосунку для сторонніх клієнтів і відхиляє пароль облікового запису незалежно від того, наскільки ретельно його набрано. Повідомлення відправило користувача перенабирати те, що ніколи не могло спрацювати, а справжня вказівка — піти й створити інший різновид пароля — не з&rsquo;являлася ніде.</p>\n<p><strong>Завдання.</strong> Повідомлення про помилки треба було переписати за письмовим стандартом, а не латати по одному, бо це було видимим випадком звички, що проходила крізь усі них.</p>\n<p><strong>Дія.</strong> Стандарт має три вимоги: скажи, що сталося, ніколи не натякай, що користувач зробив щось не так, коли причина деінде, і дай наступну дію, коли така є. Застосований до всієї поверхні помилок, він показав, що більшість повідомлень порушує щонайменше одну — кілька були рядком помилки нижчої бібліотеки, пропущеним наскрізь, а він описує стан для програміста, а не ситуацію для людини. Випадок із провайдером переписали так, щоб назвати провайдера, зазначити, що він вимагає окремого пароля застосунку для інших клієнтів, і сказати, де такий створити. Тест є тим, що не дає цьому повернутися, і він навмисно конкретний: він жене невдалий вхід проти того провайдера й стверджує, що повідомлення містить ім&rsquo;я провайдера та вислів, що описує потрібний тип облікових даних. Тест, що стверджував би лише появу якоїсь помилки, пройшов би й на початковому хибному повідомленні, тож твердження стоїть на вмісті, а це єдина частина, що колись була зламана.</p>\n<p><strong>Результат.</strong> Поверхня помилок дотримується зазначеного стандарту, а випадок, що до нього спонукав, покрито тестом, який падає на старому тексті. Нерозв&rsquo;язаним лишається масштаб: стандарт примусово тримають переглядом і одним тестом на одне повідомлення, а інші провайдери зі своїми особливими вимогами не мають рівноцінного тесту, тож клас задокументовано, а не закрито.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Frontend‑розробка",
        "UX / UI‑дизайн",
        "Безпека",
        "Документація",
        "Продукт і вимоги",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Продуктова стратегія та вимоги",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/audited-644-rust-crates-for-licence-compatibility-163/",
      "url": "https://engineer.company/uk/portfolio/audited-644-rust-crates-for-licence-compatibility-163/",
      "title": "Проаудитувала 644 крейти Rust на сумісність ліцензій при кожній збірці й довела, що перевірка спрацьовує, переписавши ліцензію одного крейта й перемістивши зафіксовану ревізію ядра без перегенерації.",
      "summary": "Становище щодо поширення перевіряють за кожного збирання, і про перевірку відомо, що вона працює, бо її змусили впасти, а не бо вона ніколи нічого не сказала.",
      "content_html": "<p><strong>Ситуація.</strong> Вкомпонувати ядро на Rust у програму, яку випускають, означає випускати все, від чого те ядро залежить. Граф залежностей налічує 644 крейти. Кожен несе ліцензію, деякі несуть більш ніж одну, а єдиний копілефтний крейт, що прибуває на три рівні нижче через рутинне підняття версії, змінює те, за якими умовами можна поширювати програму в цілому, — мовчки, у файлі блокування, якого ніхто не читає рядок за рядком.</p>\n<p><strong>Завдання.</strong> Ліцензійне становище треба було перевіряти за кожного збирання, а не переглянути один раз, з явним переліком дозволеного, щоб зміна в графі була відмовою збирання, а не відкриттям, яке хтось зробить згодом.</p>\n<p><strong>Дія.</strong> Перевірка розв&rsquo;язує повний транзитивний граф і звіряє ліцензійний вираз кожного крейта з переліком умов, які проєкт приймає, належно обчислюючи булеві вирази — крейт, що пропонує вибір із двох ліцензій, прийнятний, якщо в переліку є будь‑яка з них, а крейт, що вимагає обох, прийнятний, лише якщо в переліку є обидві. Усе, що не збіглося, валить збирання, а не попереджає, і додавання умови до переліку дозволеного є свідомим редагуванням із причиною. Перевірку, що ніколи не падала, не відрізнити від тієї, що падати не здатна, тож її змусили впасти навмисно, двічі. Один раз переписавши ліцензійний вираз крейта на те, чого перелік не приймає, а це є формою крейта, що змінює свої умови вище за течією між версіями, — випадок, якого не ловить жоден людський перегляд, бо сам крейт не новий. Один раз зсунувши закріплену ревізію ядра без перегенерації перевірки, а це є формою підняття ядра, що тихо приносить із собою нову залежність. Обидві провокації завалили збирання, як і задумано, і перевірку лишили на місці, а не розширили.</p>\n<p><strong>Результат.</strong> Становище щодо поширення перевіряють за кожного збирання, і про перевірку відомо, що вона працює, бо її змусили впасти, а не бо вона ніколи нічого не сказала. До того, як вона з&rsquo;явилася, і пакет, і файл ліцензії, і власний README проєкту робили заяву про 644 крейти, якої ніщо не перевіряло. Межа точна, і її не слід перебільшувати: перевірка читає оголошені ліцензійні метадані, а метадані можуть бути хибними чи неповними. Вона не доводить нічого про крейт, що оголошує себе хибно, і вона не є юридичною порадою.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Data Governance",
        "DevOps",
        "Автоматизація та CI/CD",
        "Безпека",
        "Документація",
        "Data Governance та якість даних",
        "DevOps та автоматизація CI/CD",
        "Безпека та керування доступом"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/built-the-visual-identity-from-two-drawings-164/",
      "url": "https://engineer.company/uk/portfolio/built-the-visual-identity-from-two-drawings-164/",
      "title": "Побудувала набори піктограм і фавіконів компанії з двох рукотворних малюнків, де кожен похідний ресурс перегенеровується скриптом, а перевірка валиться, коли похідний файл закомічено раніше за своє джерело.",
      "summary": "Два малюнки виробляють кожну опубліковану піктограму, перегенерація є однією командою, а застарілий ресурс валить збирання.",
      "content_html": "<p><strong>Ситуація.</strong> Візуальну ідентичність малої компанії зазвичай купують, генерують або збирають зі стокових матеріалів, і результатом є ідентичність, що не належить нікому. Альтернативна проблема гірша: рукотворна графіка, що існує лише як експортовані файли, де вихідний малюнок втрачено, експорти редагують безпосередньо, і протягом року версії в ужитку розходяться між собою, а оригіналу, який це владнав би, не лишилося.</p>\n<p><strong>Завдання.</strong> Ідентичність треба було намалювати, а не роздобути, і конвеєр від малюнка до опублікованого ресурсу мав бути відтворюваним, щоб кожен файл на сайті виводився, а не зберігався.</p>\n<p><strong>Дія.</strong> В основі згенерованого зображального матеріалу лежать два рукотворні малюнки — знак компанії та шестірня, що стала фавіконом, — і кожну піктограму, яку публікує сайт, вироблено з них. Знак є растровим малюнком; шестірня є вектором. З них скрипти виробляють кожну похідну форму: набір favicon у потрібних розмірах, дотикові піктограми, зображення для соціальних попереднів, адаптивні растрові варіанти в кожній ширині й у кожному сучасному форматі та версії для конкретних тем. Генерація є завданням, яке може виконати будь‑хто, тож питання «звідки взявся цей файл» має відповідь, що є командою. Перевірка застарілості є тим шматком, що тримає це разом: вона порівнює час зміни кожного похідного ресурсу з його джерелом і падає, коли похідний файл старіший, і це ловить саме ту відмову, задля запобігання якій цей задум існує, — хтось редагує джерело, забуває перегенерувати, і опублікований сайт далі показує графіку, що більше не відповідає оригіналові. Правило, що похідні файли ніколи не редагують вручну, зазначено там, де живуть джерела.</p>\n<p><strong>Результат.</strong> Два малюнки виробляють кожну опубліковану піктограму, перегенерація є однією командою, а застарілий ресурс валить збирання. Компромісом є жорстка залежність від набору інструментів: похідні файли закомічено, тож сайт збирається будь‑де, але зміна ідентичності вимагає, щоб генераційне знаряддя досі працювало, а вихідний формат, який перестане читатися, забере всю ідентичність із собою.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "UX / UI‑дизайн",
        "Автоматизація та CI/CD",
        "Бренд і маркетинг",
        "Веброзробка",
        "Дизайн‑системи та UI",
        "Тестування та QA",
        "UI/UX‑дизайн та дизайн‑системи",
        "Бренд, маркетинг та SEO",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/held-five-repositories-to-one-history-standard-165/",
      "url": "https://engineer.company/uk/portfolio/held-five-repositories-to-one-history-standard-165/",
      "title": "Втримала чотири репозиторії на одному стандарті історії — конвенційному, без емодзі, без рядків атрибуції, із примусом через хук повідомлення коміту — поряд із 48 документами інструкцій, що керують тим, як виконується робота.",
      "summary": "Чотири репозиторії поділяють один формат історії та одну структуру інструкцій, обидва примусово застосовані хуками, а не дисципліною.",
      "content_html": "<p><strong>Ситуація.</strong> Чотири репозиторії, збудовані за вісімнадцять місяців однією людиною, — це та ситуація, у якій процес найлегше пропустити, бо немає з ким координуватися, а ціну нечитної історії цілком платить майбутнє я, яке ще не скаржилося. Це також та ситуація, у якій неузгоджена історія найімовірніша, бо кожен репозиторій може зісковзнути у власні звички без нічого, що тягнуло б їх докупи.</p>\n<p><strong>Завдання.</strong> Один стандарт для історії та один стандарт для інструкцій мали діяти в кожному репозиторії, де пишеться робота, і його треба було примусово застосовувати машинно, а не пам&rsquo;ятати.</p>\n<p><strong>Дія.</strong> Стандартом комітів є конвенційний префікс, що називає різновид зміни, і область, тема під сталою довжиною, жодних емодзі й жодних рядків приписування будь‑якого штибу — останнє тому, що рядок, який дякує інструментові, не є фактом про зміну, а історія існує для фактів про зміни. Хук на повідомлення коміту відхиляє все, що не відповідає, у кожному репозиторії, що несе роботу, тож стандарт є властивістю репозиторію, а не того, хто комітить. Розподіл у найбільшому репозиторії показує, чим робота була насправді: 156 комітів із можливостями, 133 виправлення, 128 документації, 81 господарський, 26 переробок, 20 стилю, 5 продуктивності та 3 тестові. Документація достатньо близька до виправлень, щоб це помітити, і це наслідок другої половини всього цього — 48 інструкційних документів у чотирьох, кожен покриває одну область, кожен написано як правила, а не опис, і всі досяжні з єдиного вхідного документа на репозиторій, тож є одне місце, з якого почати. Лінтер документації примусово застосовує пофайлові бюджети розміру та належність до індексу, тож набір лишається придатним для навігації, а не розростається в архів.</p>\n<p><strong>Результат.</strong> Чотири репозиторії поділяють один формат історії та одну структуру інструкцій, обидва примусово застосовані хуками, а не дисципліною. Чого це не робить, так це не робить історію доброю: формат перевіряють, а вміст — ні, тож тема, що відповідає формату й не описує нічого, проходить точнісінько так само добре, як та, що пояснює зміну.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Agile та Scrum",
        "DevOps",
        "Автоматизація та CI/CD",
        "Документація",
        "Технічне лідерство",
        "Управління проєктами",
        "DevOps та автоматизація CI/CD",
        "Технічна документація",
        "Технічне лідерство та консалтинг",
        "Управління проєктами (Agile)"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/made-six-collectors-state-what-they-never-read-167/",
      "url": "https://engineer.company/uk/portfolio/made-six-collectors-state-what-they-never-read-167/",
      "title": "Змусила шість збирачів звітів повідомляти ту частину свого входу, яку вони так і не прочитали — файли, що лишилися закритими, непроінстальовані проби, нерозпізнані рядки журналу, — і підігнала пороги до 116 виміряних зразків, з'ясувавши, що сліпий збір і здоровий хост дають ту саму сторінку.",
      "summary": "Сторінка чисел цієї платформи тепер несе власні сліпі зони поряд зі своїми знахідками. Жоден із самовимірів не є ґейтом, і це сказано, а не мається на увазі:…",
      "content_html": "<p><strong>Ситуація.</strong> Шість збирачів лише для читання перетворювали живий хост на Markdown, і жоден із них не фіксував ані власного часу роботи, ані файлів, які не зміг відкрити, ані вхідних даних, які пропустив. Кілька мали шляхи помилок, що ковтали помилку цілком, а це дає певну й небезпечну форму звіту: сторінку чисел, яка виглядає повною та здоровою незалежно від того, чи щось узагалі було прочитано. Згорнутий журнал, що надходить обрізаним, прибирає весь свій проміжок з кожного числа на сторінці, а тиждень відсутнього трафіку читається точно як тихий тиждень. Дзеркало, чий демон змінив формат журналу, дає той самий нуль, що й дзеркало, якого ніхто не відвідував. Кожна проба у звіті безпеки стоїть за перевіркою наявності інструмента, тож хост без інструментів фаєрвола, сокетів і блокувань не показував ані правил, ані сокетів, ані в&rsquo;язниць &ndash; візуальний підпис замкненого хоста, а насправді сліпого.</p>\n<p><strong>Завдання.</strong> Дві речі мали стати неможливими для сплутування зі здоров&rsquo;ям. Звіт мав казати, що вважається поганим, а не лишати це на людину, і кожен збирач мав казати, скільки коштував його власний збір і якої частки свого входу він не зміг використати.</p>\n<p><strong>Дія.</strong> Пороги підігнали до 116 зразків, які звіт метрик уже виміряв, і ніколи до здогадки, а поряд із межами записали спостережені діапазони. Оцінювання знаходить кожен стовпець за іменем, а не за позицією, і відмовляється оцінювати рядок, у якому кількість значень не збігається з кількістю підписів, &ndash; саме це захищає його від зміни формату годинника, що зсуває кожен підпис на один. Далі звіт розрізняє три наслідки замість двох: порушення, відсутність порушення і неоцінено, бо ніщо цього не виміряло. З боку збору кожен тепер повідомляє свій час роботи і свою сліпоту &ndash; файли прочитані проти файлів нечитних, рядки журналу прочитані проти рядків розпізнаних, репозиторії, які git відмовився читати, пораховані, а не показані нулем, джерела опитані проти джерел, що відповіли, проби запитані проти проб непроінстальованих, &ndash; і кожен такий рядок друкується навіть тоді, коли відповідь нуль, бо рядок, що зникає, коли порожній, &ndash; це та сама тиша в іншій формі. Кожен шаблон отримав явну гілку для виводу, написаного збирачем, старшим за нього самого.</p>\n<p><strong>Результат.</strong> Сторінка чисел цієї платформи тепер несе власні сліпі зони поряд зі своїми знахідками. Жоден із самовимірів не є ґейтом, і це сказано, а не мається на увазі: до часу роботи збирача не підігнано жодної межі, тож збір, що подвоївся, видно, і він нікого не спинить, а щоб підігнати таку межу, потрібна база з реального хоста, якої ця робота свідомо не вигадувала. Наявні межі &ndash; це денні середні, тож хост, що торкається стелі на хвилину, тут нічого не перетинає: це ловить перемикач кожні чверть години, жоден не замінює іншого, і обидва звіти кажуть про це на сторінці.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Python",
        "Автоматизація та CI/CD",
        "Документація",
        "Моніторинг та observability",
        "Надійність і резервне копіювання",
        "Тестування та QA",
        "Надійність та моніторинг (SRE)",
        "Системне адміністрування",
        "Технічна документація"
      ]
    },
    {
      "id": "https://engineer.company/uk/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/",
      "url": "https://engineer.company/uk/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/",
      "title": "Опублікувала сайт як onion‑дзеркало в Tor на читабельній адресі, що починається з engineer, з ключем, згенерованим поза хостом, тож він ніколи не потрапив ні до цього репозиторію, ні на ноутбук, і лишила ці двері єдиними з чотирьох, які ніколи не рахують.",
      "summary": "Сайт має четверо дверей до однієї збірки, і ці -- єдині, яких ніколи не рахують. Запити Gemini та з'єднання Gopher підраховують щодня без адреси й без шляху; в…",
      "content_html": "<p><strong>Ситуація.</strong> Сайт уже відповідав на трьох протоколах з однієї збірки. Читач, якому треба було дістатися до нього, не виказуючи, що він дістався, усе ще робив гак через вихідний вузол до звичайної адреси, а це слабше за власні двері. Очевидне заперечення проти четвертих дверей &ndash; це фаєрвол, і воно не діє: демон анонімності виходить у мережу, будуючи вихідні ланцюги, тож ніхто не дзвонить усередину, жоден порт не відкривається, і жодному з двох шарів фаєрвола нема чого узгоджувати.</p>\n<p><strong>Завдання.</strong> Дзеркало мало віддавати ті самі сторінки, що й звичайна адреса, бути опублікованим там, де опубліковані інші дзеркала, нести адресу, яку людина може прочитати вголос, а не випадковий рядок, і ніколи не дозволити приватному ключу, який і є адресою, торкнутися цього репозиторію чи ноутбука.</p>\n<p><strong>Дія.</strong> Роль встановлює демон із власного пакета дистрибутива, пише конфігурацію з вимкненим вихідним портом проксі й відмовляється перезаписувати особу, якої не генерувала, &ndash; тож ключ, покладений рукою, просто використовується. Читабельну адресу не можна обрати, лише знайти: адреса &ndash; це відкритий ключ у base32, тож префікс купують, генеруючи пари ключів, доки одна з них випадково не закодує потрібні літери, і кожен символ коштує в тридцять два рази більше за попередній. Куплений префікс читається як власна назва компанії. Адреса &ndash; це оголошене значення в інвентарі, і кожне зведення стверджує, що справжній файл особи на хості збігається з ним, тож підмінений ключ зі застарілим оголошенням валить запуск, а не мовчить. Ключ ловлять обидві сторожі секретів, після того як було виміряно, що очевидний шаблон для файлу ключа збігається з ключем розгортання й проминає цей. Виведення з обігу випадкової адреси, з якою дзеркало вийшло, було поетапним переходом, а не перемикачем, тож опублікована адреса працювала, доки публікувалася читабельна. Крок, що видавався останнім, ним не був: ключ ліг правильно, а зведення повідомило про відсутність змін, бо ніщо ще не називало нову теку, тож нова адреса так і не була опублікована &ndash; тепер роль валиться на особі на диску, якої не називає жодна служба.</p>\n<p><strong>Результат.</strong> Сайт має четверо дверей до однієї збірки, і ці &ndash; єдині, яких ніколи не рахують. Запити Gemini та з&rsquo;єднання Gopher підраховують щодня без адреси й без шляху; в onion немає лічильника й немає прапорця, щоб його додати, бо порахувати там читача &ndash; це саме те єдине, заради запобігання чому протокол існує, і сліпота тут ціна позиції, а не прогалина у звітності. Дзеркало окупилося ще й як друга думка: його перші читачі сиділи на іншому рушії браузера, який не реалізує керовану прокруткою анімацію, на яку спирався колофон, тож кожен із них отримав колофон, намальований поверх головної сторінки. Це був справжній дефект звичайного сайту, знайдений аудиторією, яка не мала іншого способу про нього повідомити.</p>\n",
      "date_published": "2026-09-26T15:39:58+02:00",
      "date_modified": "2026-09-26T15:39:58+02:00",
      "language": "uk",
      "tags": [
        "Linux та сервери",
        "Безпека",
        "Веброзробка",
        "Інфраструктура",
        "Системне адміністрування",
        "Infrastructure as Code",
        "Безпека та керування доступом",
        "Розробка вебсайтів та CMS"
      ]
    },
    {
      "id": "https://engineer.company/uk/notes/solana-mobile-wallet-deeplinks/",
      "url": "https://engineer.company/uk/notes/solana-mobile-wallet-deeplinks/",
      "title": "Як відкрити dApp у мобільних гаманцях Solana",
      "summary": "Чому browse-deeplinks до Phantom, Solflare і Backpack не спрацьовують на мобільних, і точні формати, правила запуску та виправлення, які змушують їх працювати.",
      "content_html": "<p>React-dApp, побудований на <code>@solana/wallet-adapter-react</code>, без проблем\nпід&rsquo;єднує десктопні гаманці, але на телефоні той самий потік розсипається:\nгаманець має відкрити dApp у власному вбудованому браузері, а deeplinks, які\nмали б це зробити, просто мовчки не спрацьовують. Backpack виводить на\nсторінку «завантажте застосунок»; Solflare відкриває застосунок, але ніколи —\nсайт; здається, що не працює жоден варіант. Ми розібрали проблему на частини,\nі виявилося, що це чотири окремі проблеми з одним спільним симптомом.</p>\n<h2 id=\"чотири-проблеми\">Чотири проблеми</h2>\n\n<ul>\n<li><strong>Посилання для Backpack було сформоване неправильно.</strong> Єдиний\nзадокументований формат —\n<code>https://backpack.app/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code>: універсальне посилання\nіз цільовим URL у шляху та обов&rsquo;язковим <code>ref</code>. Здогадка з власною схемою на\nкшталт <code>backpack://ul/v1/browse?url=...</code> не збігається з жодним маршрутом,\nякий реєструє застосунок, тож користувач опиняється на сторінці встановлення\nгаманця.</li>\n<li><strong>Solflare теж потребує свого універсального посилання:</strong>\n<code>https://solflare.com/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code>, а не голої схеми\n<code>solflare://</code>. Гола схема може запустити застосунок, не спрямувавши його —\nа це саме те, що «застосунок відкривається, але вкладку із сайтом\nдоводиться відкривати вручну».</li>\n<li><strong>Обидва параметри мають бути закодовані.</strong> <code>url</code> — це повна абсолютна\nадреса dApp, а <code>ref</code> — origin, який робить запит; кожен проходить через\n<code>encodeURIComponent</code>. Незакодований <code>?</code> або <code>&amp;</code> у цілі псує розбір, і\nгаманець відкривається на своєму головному екрані замість вкладки браузера.</li>\n<li><strong>Спосіб запуску важить не менше за саме посилання.</strong> Універсальні посилання\nперемикають застосунки лише під час навігації, якій довіряє операційна\nсистема — і вони навмисно не роблять нічого, коли їх вставляють в адресний\nрядок, і саме так цілком коректне посилання «не працює» під час тестування.</li>\n</ul>\n<h2 id=\"задокументовані-формати\">Задокументовані формати</h2>\n\n<ul>\n<li>Phantom: <code>https://phantom.app/ul/browse/&lt;url&gt;?ref=&lt;ref&gt;</code> — саме тут без\n<code>/v1</code>.</li>\n<li>Solflare: <code>https://solflare.com/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code></li>\n<li>Backpack: <code>https://backpack.app/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code></li>\n</ul>\n<p>Один шаблон покриває всі три:</p>\n<pre tabindex=\"0\"><code>const WALLET_BROWSE = {\n  phantom: (url, ref) =&gt;\n    `https://phantom.app/ul/browse/${url}?ref=${ref}`,\n  solflare: (url, ref) =&gt;\n    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,\n  backpack: (url, ref) =&gt;\n    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,\n};\n\nfunction walletBrowseLink(\n  walletName,\n  targetUrl = window.location.href,\n) {\n  const build = WALLET_BROWSE[walletName.toLowerCase()];\n  if (!build) return null;\n  return build(\n    encodeURIComponent(targetUrl),\n    encodeURIComponent(window.location.origin),\n  );\n}\n</code></pre><h2 id=\"як-запустити-посилання-щоб-ios-та-android-його-прийняли\">Як запустити посилання, щоб iOS та Android його прийняли</h2>\n\n<ul>\n<li><strong>Рендерте справжній якір, обчислений заздалегідь.</strong> Звичайний\n<code>&lt;a href={walletBrowseLink('phantom')}&gt;</code> — найнадійніший спосіб запуску на\nобох платформах.</li>\n<li><strong>Якщо це має бути програмно</strong>, присвоюйте <code>window.location.href</code> синхронно\nвсередині обробника натискання — без <code>await</code>, без <code>fetch</code>, без <code>setTimeout</code>\nперед цим. Після асинхронної роботи контекст жесту втрачено, і iOS\nвідкочується до вебсайту гаманця. Ніколи не використовуйте <code>window.open</code>.</li>\n<li><strong>Ніколи не тестуйте вставлянням в адресний рядок.</strong> Універсальні посилання\nнавмисно там не спрацьовують; тестуйте посиланням, на яке натискають, або\nQR-кодом, який сканує камера.</li>\n<li><strong>Зважайте на webview месенджерів.</strong> Відкриті у вбудованому браузері\nTelegram або Instagram, універсальні посилання часто просто поглинаються, і\nнатомість завантажується звичайний вебсайт гаманця. Визначення за\nuser-agent — у кращому разі евристика, тож дайте користувачам ще й видимий\nзапасний вихід: «відкрийте в Safari чи Chrome, а тоді під&rsquo;єднайтеся».</li>\n</ul>\n<h2 id=\"ґрунтовніше-виправлення-на-android\">Ґрунтовніше виправлення на Android</h2>\n\n<p>Саморобні deeplinks — це історія про iOS. На Android Mobile Wallet Adapter від\nSolana Mobile дає dApp, що працює в мобільному браузері, під&rsquo;єднатися прямо до\nвстановленого застосунку гаманця, узагалі без гаку через вбудований браузер.\nСвіжі версії <code>@solana/wallet-adapter-react</code> реєструють мобільний адаптер\nавтоматично, тож оновлення пакетів wallet-adapter може полагодити Android саме\nсобою. Цільова архітектура: Mobile Wallet Adapter на Android, універсальні\nbrowse-посилання на iOS, де Apple не дозволяє нічого рівноцінного.</p>\n<h2 id=\"перевірка-на-пристрої\">Перевірка на пристрої</h2>\n\n<ol>\n<li>Справжній пристрій, встановлений гаманець, посилання відкрито із системного\nбраузера — не з месенджера.</li>\n<li>Натисніть відрендерене посилання або відскануйте QR-код; ніколи не\nвставляйте в адресний рядок.</li>\n<li>Переконайтеся, що гаманець відкривається і dApp завантажується у вкладці\nйого вбудованого браузера — саме друга половина і ламається.</li>\n<li>Повторіть без встановленого гаманця: універсальне посилання має деградувати\nдо вебсайту гаманця. Якщо ця сторінка з&rsquo;являється, коли застосунок\nвстановлено, — посилання або спосіб запуску все ще неправильні.</li>\n<li>Потім перевірте шлях через месенджер і додайте підказку «відкрийте у\nбраузері», якщо там не спрацьовує.</li>\n</ol>\n<h2 id=\"джерела\">Джерела</h2>\n\n<ul>\n<li><a href=\"https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android\">Phantom: deeplinks на iOS та Android</a></li>\n<li><a href=\"https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse\">Solflare: Browse-deeplink</a></li>\n<li><a href=\"https://docs.backpack.app/deeplinks/other-methods/browse\">Backpack: Browse-deeplink</a></li>\n<li><a href=\"https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps\">Solana Mobile: Mobile Wallet Adapter</a></li>\n</ul>\n",
      "date_published": "2026-08-10T00:00:00Z",
      "date_modified": "2026-09-15T22:17:14+02:00",
      "language": "uk"
    }
  ]
}