CV Hub
Автор и разработчик · 2026

CV Hub

Резюме как код. Профессиональная идентичность как воспроизводимая версионируемая система.

Platforms
  • Web
  • GitHub Pages
Stack
  • Astro
  • TypeScript
  • YAML
  • Playwright
  • docx.js
  • Canvas
  • GitHub Actions
Главная страница CV Hub

Обзор

CV Hub — это не шаблон портфолио. Это система. Проект переосмысляет резюме как инженерный артефакт — версионируемый, воспроизводимый и развёртываемый. Вместо того чтобы поддерживать разрозненные представления в LinkedIn, PDF, Notion и на сайтах-портфолио, CV Hub вводит единый декларативный источник правды — YAML-файл, который управляет всем пайплайном вывода. Результат — полностью автоматизированная система, где одно изменение согласованно расходится по всем форматам и всем ролевым вариациям. Сама страница, которую вы читаете, — часть этой системы: этот кейс собран из блочного YAML-документа тем же движком, что строит резюме.


Проблема

С точки зрения систем традиционные резюме фундаментально сломаны. Они: - дублируются между платформами - синхронизируются вручную - зависят от контекста (DevOps vs Backend vs GameDev) - не находятся под версионным контролем - не воспроизводимы Это ведёт к рассинхрону, несогласованности и заметным накладным расходам на поддержку. С инженерной точки зрения это эквивалентно запуску нескольких несинхронизированных окружений без единого источника правды.


Решение

CV Hub применяет инфраструктурные принципы к персональным данным. Базовая идея проста: опиши один раз → сгенерируй всё → разверни автоматически. Один YAML-файл становится: - живым сайтом - артефактами PDF, DOCX и TXT - несколькими ролевыми версиями резюме - версионируемым профилем под контролем Git Система устраняет дублирование и обеспечивает согласованность by design.


Мультипрофильная система

Архитектура base + delta

Ролевые резюме генерируются по двухслойной модели: базовое CV плюс дельта-переопределения на каждый профиль. Это даёт точный контроль над позиционированием без дублирования данных.

Пайплайн слияния профилей

Как работают профили

Каждый профиль объявляется один раз в `profiles.yml` — id, URL-slug и ключ spec. На этапе сборки `merge.mjs` проходит по каждой комбинации профиль × язык и создаёт нормализованный артефакт на пару. Слияние намеренно явное, а не магическое: - Скалярные и списочные поля дельты целиком заменяют базовое значение. - Записи опыта сопоставляются по названию компании — дельта-запись, в которой указана только компания, наследует базовую и переопределяет лишь те поля, что задала. - Список опыта профиля полностью определяет свой упорядоченный набор, так что каждая роль курирует ровно ту историю, которая ей релевантна. Вывод детерминирован: один и тот же источник всегда даёт одни и те же артефакты, а гард на этапе сборки следит, чтобы routing-slug профиля и его file-spec ключ не расходились — страница профиля никогда не разъедется с его CV и файлами для скачивания.


Интернационализация

Языки — это ось первого класса, а не довесок. Система рендерит матрицу N профилей × N языков из единой базы контента. - Реестр `languages.yml` задаёт доступные языки и язык по умолчанию; переключатель языка в шапке генерируется из него. - Каждая строка интерфейса живёт в `translations.yaml` и резолвится через небольшой хелпер `makeT()` с цепочкой фоллбэка: запрошенный язык → английский → сам ключ, так что отсутствующий перевод деградирует мягко, а не ломает страницу. - Маршрутизация полностью статическая. `[...slug].astro` выпускает по странице на каждую комбинацию профиль × язык, а главная на языке по умолчанию остаётся на чистом корневом пути. Китайские переводы уже лежат в слое контента и готовы к включению добавлением одной строки в реестр языков.


Что я построил

  • Static-first архитектура с нулём клиентского JavaScript по умолчанию
  • YAML как единый источник правды для всех данных резюме
  • Мультипрофильная система (DevOps, GameDev и т.д.) через детерминированный пайплайн слияния
  • Поддержка нескольких языков с мягкой цепочкой фоллбэка
  • Автоматическая генерация документов (PDF через Playwright, DOCX/TXT через docx.js)
  • Блочный движок кейсов, на котором работают эти Deep Dive страницы
  • Четыре взаимозаменяемых анимированных фоновых компонента (CSS и Canvas)
  • Переключение тем через URL с шарингом состояния
  • Полностью автоматизированный CI/CD на GitHub Actions с алертами в Telegram
  • Динамическая конфигурация по окружению (siteUrl из GITHUB_REPOSITORY)

Архитектура

Система построена как детерминированный пайплайн. Слой данных: - YAML-файлы (базовое CV + дельты профилей, проекты showcase, кейсы, переводы, changelog) Слой обработки: - merge.mjs → нормализованные артефакты на каждый профиль и язык - генераторы документов → создают PDF / DOCX / TXT из этих артефактов Слой представления: - статическая сборка Astro → предрендеренный HTML, контент валидируется типизированными схемами Развёртывание: - GitHub Actions → неизменяемая сборка → GitHub Pages Никакого runtime-сервера. Никакого скрытого состояния. Никакой базы данных. Каждый вывод воспроизводим из исходника, а форма контента проверяется Zod-схемами ещё до сборки страниц.


Динамические фоны

Атмосферу сайта создаёт небольшая библиотека взаимозаменяемых фоновых компонентов. Активен всегда один — они спроектированы как drop-in палитра, каждый самодостаточен и настраивается через ту же систему дизайн-токенов, что и остальная стилизация. Семейства два: CSS-слой, который почти ничего не стоит, и набор Canvas-рендереров, вдохновлённых интерфейсом PlayStation XMB. Каждый показан ниже.

AnimatedBackground — по умолчанию

Чистый CSS · ноль JavaScript

Четыре крупных орба из радиальных градиентов дрейфуют за контентом, поверх — тонкий слой шума. Это полностью CSS — без JavaScript, без canvas, без работы в основном потоке. Это и самый оптимизированный фон: keyframes анимируют только смещение (без scale), поэтому браузер кеширует каждый размытый орб как текстуру и просто двигает её, а не пересчитывает blur 60px каждый кадр. Весь слой отключается ниже 768px и уважает `prefers-reduced-motion`.

AnimatedBackground — дрейфующие размытые орбы

GalaxyBackground

Canvas · requestAnimationFrame

Звёздное поле на canvas с медленным параллакс-дрейфом, подкрашенное под акцент активной темы. Более тяжёлый, кинематографичный вариант — когда атмосфера важнее стоимости простоя.

GalaxyBackground — звёздное поле

PlayStationWaves

Canvas · заливные волны в духе XMB

Заливные синусоиды, наслоённые как меню PlayStation XMB, со сдвигом оттенка по времени суток и недетерминированной стартовой позицией (сид от таймстампа) — так что два запуска не выглядят одинаково. Около 18 пропсов открывают число волн, скорость, амплитуду, цвет и качество отрисовки.

PlayStationWaves — заливные синусоидальные волны

WaveLines

Canvas · светящиеся линии в духе XMB

Штриховой родственник PlayStationWaves: светящиеся линии, симметрично расположенные вокруг центральной оси. Свечение каждой линии композитится на собственном offscreen-canvas — чтобы обойти тонкий баг, где общая маска `destination-in` съедала альфу фона по краям.

WaveLines — светящиеся штриховые линии

Инженерия производительности фонов

Красивые фоны легко сделать тормозящими, поэтому они рассматриваются как отдельная поверхность производительности. - CSS-орбы избегают пересчёта blur каждый кадр, анимируя только трансформации. - Полноэкранный градиент живёт на fixed-псевдоэлементе вместо `background-attachment: fixed`, поэтому не перерисовывается при скролле. - Полноэкранный проход `mix-blend-mode` был убран, как только подтвердилось: при своей прозрачности он невидим, но дорог каждый кадр. - Каждый анимированный фон отключается на маленьких экранах и уважает reduced-motion. Итог: насыщенное движение на мощных десктопах и спокойный, дешёвый рендер на всём остальном.


Темы

Темизация — это набор CSS-переменных поверх токен-базы. Тема выбирается параметром `?theme=` в URL и применяется крошечным инлайн-скриптом, что делает состояние шарящимся: отправь ссылку — и получатель увидит ровно ту палитру, что выбрал ты.

Варианты тем
Frosted, Light, Nordic, Peachy — управляются через URL-параметр

Пайплайн экспорта документов

Тот же смерженный YAML, что рендерит сайт, генерирует и файлы для скачивания — так веб- и офлайн-версии не могут разойтись. - PDF получается рендерингом print-вёрстки в headless Chromium через Playwright — пиксель-в-пиксель с сайтом. - DOCX собирается программно через docx.js — это настоящий редактируемый документ Word, а не скриншот. - TXT отдаётся как чистый текстовый фоллбэк для ATS-систем и копипаста. Каждая пара профиль × язык получает свой набор файлов, генерируемых в CI и подключённых прямо на соответствующей странице.


CI/CD и автоматизация

Релиз — это один `git push`. - GitHub Actions гоняет весь пайплайн на каждый push в main: merge → генерация документов → рендер PDF → статическая сборка → деплой на Pages. - Бинарь Playwright Chromium кешируется по хешу lockfile, экономя около двух минут на холодном деплое. - Telegram-бот сообщает результат — успех, провал сборки или провал деплоя — с веткой и коротким SHA коммита, молча деградируя, если секреты не настроены. - `siteUrl` и base-путь выводятся из `GITHUB_REPOSITORY`, так что форк собирается и деплоится корректно без всякой конфигурации. - Sitemap, покрывающий каждый маршрут профиль × язык, генерируется на сборке, с соответствующим robots.txt.


Инженерия производительности

Производительность измеряется, а не предполагается. - Статический предрендеренный HTML без стоимости гидратации по умолчанию. - Первая обложка Showcase с реальной картинкой грузится eager с высоким приоритетом, остальные остаются lazy — намеренная оптимизация LCP. - Композитинг при скролле был профилирован, дорогие слои (перерисовка fixed-градиента, полноэкранный blend-проход) убраны. - Итог: Lighthouse 100 Performance / 100 Accessibility / 100 SEO, с движением, которое остаётся плавным на слабом железе.


Движок Showcase

Портфолио-половина сайта — та же идея, применённая рекурсивно. Проекты объявляются YAML-списком, и каждый может нести полноценный Deep Dive кейс — как этот — собранный из небольшого набора контент-блоков: text, image, divider и links. Блоки валидируются типизированной схемой и рендерятся отдельными компонентами, а значит длинный редакторский кейс пишется целиком в данных, без какого-либо кастомного кода страницы. Ведёт себя как контролируемая статическая альтернатива странице Notion: портативно, версионируемо и быстро.


Инженерные решения

  • Astro вместо SPA-фреймворков — чтобы убрать лишний рантайм и стоимость гидратации
  • Статическая генерация — ради гарантии производительности и предсказуемости
  • YAML вместо CMS — ради полного контроля и Git-нативного версионирования
  • Состояние через URL вместо localStorage — ради шаринга и прозрачности
  • Явные дельта-файлы вместо неявных переопределений — чтобы изменения были наблюдаемы
  • Типизированные схемы контента — чтобы кривые данные роняли сборку, а не браузер

DevOps-подход

Проект относится к резюме как к build-артефакту. Ключевые принципы: - версионирование на Git - неизменяемые сборки - автоматизация CI/CD - развёртывание, независимое от окружения - нулевые runtime-зависимости Каждый коммит порождает полностью согласованное, развёртываемое состояние системы.


Компромиссы

  • Нет CMS — намеренный компромисс ради контроля и прозрачности
  • Нет бэкенда — чисто статическая архитектура
  • Ручное создание дельт для профилей — явность вместо неявной сложности
  • Canvas-фоны дороже CSS-дефолта — поэтому один по умолчанию, остальные по выбору
  • Ограниченная гибкость в рантайме в пользу детерминизма

Результат

  • Одна правка перегенерирует все форматы по всем профилям и языкам
  • Полностью статический деплой с нулевой стоимостью инфраструктуры
  • Готовая к форку система, не требующая конфигурации
  • Lighthouse: 100 Performance / 100 Accessibility / 100 SEO
  • Предсказуемый, воспроизводимый вывод между окружениями

Выводы

CV Hub показывает, что даже нетрадиционные домены вроде резюме выигрывают от инженерной строгости. Применяя принципы системного дизайна — единый источник правды, детерминированные пайплайны и автоматизацию — проект превращает статический документ в масштабируемую, поддерживаемую систему. Этот подход обобщается за пределы резюме на любой домен, где важны согласованность данных, воспроизводимость и вывод в несколько форматов.