И такое бывает
И такое бывает

Что-то пошло не так

Когда работаешь в IT больше десяти лет, жизнь постепенно становится предсказуемой. Ты просто делаешь свою работу: делаешь крутые продукты, отстаиваешь решения, выступаешь на конференциях. Кажется, что так будет всегда, и на рынок труда ты посматриваешь с легким равнодушием.

Но жизнь умеет удивлять. Кого-то внезапно настигают сокращения. В моем случае это было отстаивание границ, после которого стало понятно: нам с компанией больше не по пути. И вот ты обновляешь статус на «Открыт к предложениям».

Казалось бы, с солидным опытом найти работу, дело пары недель. Собираешь всю свою карьеру в аккуратный "универсальный" PDF на одну страницу. Рассылаешь свое классическое резюме по знакомым в ожидании приглашений на интервью. А потом что-то идет не так, как обычно. В ответ получаешь отказы еще до этапа знакомства с нанимающим менеджером.

Одно из сообщений с отказом, до общения даже с HR
Одно из сообщений с отказом, до общения даже с HR

Это звучит абсурдно. Я буквально преподаю в вузах и создавал образовательные программы, но эйчар этого не увидел.

Проблема оказалась неожиданной. За карьеру успеваешь поделать кучу всего. Часть этого опыта идеально ложится в требования конкретной вакансии. Но весь опыт физически невозможно уместить в классическое резюме.

Негласное правило рынка: резюме должно занимать одну, максимум две страницы. Если попытаться впихнуть туда все проекты за десятилетие, получится мемуар. С другой стороны, если сделать универсальную "выжимку", она получается слишком пресной. В ней теряются те специфические ключевые слова и фокусные достижения, которые ищут алгоритмы скрининга и рекрутеры.

Получается замкнутый круг. Чтобы пройти первичный фильтр, резюме должно быть заточено строго под вакансию. Но переписывать PDF руками под каждый отклик, судорожно вспоминая, в каком году и на сколько процентов ты поднял нужную метрику - это боль.

И тут пришло озарение: подход к хранению карьерного опыта изначально ошибочен. Опыт не должен быть одностраничным резюме.

Я решил написать свой инструмент. CMS для управления профессиональным опытом, которая под капотом использует LLM для сборки идеального CV под требования конкретной вакансии.

пример заполненного опыта
пример заполненного опыта

В чем суть?

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

Проблема кроется в самом источнике. Входные данные уже обрезаны вами же при составлении того самого одностраничника. Если в исходном загруженном файле нет кейса про запуск биллинга, никакой алгоритм его оттуда не достанет. Модель может только переформулировать существующий текст и насыпать ИИ-слопа.

Я решил пересобрать саму модель данных. Резюме больше не должно быть монолитным документом.

Я разделил опыт на следующие сущности:

  • job выступает как контекст (название компании, ваша роль, период работы).

  • highlight выступает как атом опыта (конкретное достижение, запущенный проект, зона ответственности или пройденное обучение).

  • У каждого highlight есть свои теги: домены, скиллы, ключевые слова и оцифрованные метрики.

Под конкретную вакансию система выбирает релевантные атомы за всю вашу карьеру и собирает идеальную версию CV. Именно это дает выигрыш в качестве конверсии на скрининге.

Быстрый прототип внезапно стал продуктом

Изначальная идея была формата «сейчас по-быстрому накину n8n-воркфлоу» (давно хотел углубиться и собрать что-то сложнее простого телеграм бота), но очень быстро переросла в полноценный продукт, так как понадобился UI чтобы разгребать ошибки LLM на разных этапах.

Сценарии которые я реализовал:

  • Работает без регистрации. Пользователь открывает UI, вводит свой опыт, а данные живут локально в браузере. Порог входа нулевой.

  • Пользователь вложил время в заполнение данных и хочет сохранить их. Работает логин через GitHub или Google, происходит автоматическая миграция локальных данных в облако. Теперь пользователь не потеряет свои данные.

  • Для адаптации в n8n уходит только то, что нужно для сборки резюме. URL вебхука хранится только в браузере пользователя: я не могу вызвать ваш пайплайн без вашего доступа, и не вижу ваш ключ.

  • После генерации нужно быстро дожать документ. ��аботает редактирование прямо в UI, удаление лишних позиций в один клик и моментальный экспорт в PDF без сторонних конструкторов.

Стек технологий собрался следующий: Next.js для интерфейса и серверной логики, Turso для баз данных (работает и без него локально), n8n для вызовов к моделям.

Режимы хранения переключаются через абстрактный DataLayer, поэтому пользователь вообще не думает, где сейчас лежат его байты.

упрощенная схема генерации резюме в production
упрощенная схема генерации резюме в production

Turso был выбран, потому что давно хотелось его попробовать + у него есть простой http api для запросов, и с точки зрения безопасности реализовал так, что у каждого пользователя своя бд.

Изначально хотел строить полноценный RAG пайплайн в n8n, но оказалось, что простой вызов одного промпта с нужными данными дает вполне хороший результат.

Как я писал код чужими руками

С каким выражением лица я читаю блок про оценку сроков от Claude
С каким выражением лица я читаю блок про оценку сроков от Claude

Я менеджер, а не разработчик (но код читать и править умею). Поэтому вооружился Claude Code.

Всего ушло 163 промпта (половина из которых "да, коммить и пуш").

Вот три практичных лайфхака, которые сэкономили мне кучу нервов:

Сначала спецификация, потом код

Я стартую не в Claude Code, а в ChatGPT/Claude: задаю вводные и прошу набросать PRD. (Я пробовал специальные сервисы для этого, особого смысла в них не увидел)

Когда PRD меня устраивает, фиксирую архитектуру и правила работы агента (AGENTS.MD), и только потом иду в клод и начинаю с чтения этих документов.

И в целом я перестал давать команды формата «запили мне вот такую фичу». Вместо этого я заставлял агента работать аналитиком.

Например, я просил спроектировать UI/UX и сохранить результат в файл UIUX.md. Или подготовить план генерации n8n workflow в документ logic.md. Затем я вычитывал эти Markdown файлы, правил логику, и только после согласования PRD разрешал агенту приступать к написанию кода по зафиксированному документу.

MCP тулзы экономят время

Когда я уперся в интеграцию с n8n, я перестал гуглить документацию руками. Я просто подключил n8n MCP + скилы к нему и целенаправленно дергал их для того чтобы Claude самостоятельно правил ошибки в workflow. Агент сам читал документацию, находил рабочие паттерны, прогонял получившийся workflow.

YOLO режим в песочнице

без YOLO сложно отойти от терминала
без YOLO сложно отойти от терминала

Чтобы не "сидеть над терминалом, медитируя на строчки вызова тулзов" в ожидании, когда он попросит дополнительный пермишн, а заниматься другими задачами параллельно я собрал изолированную песочницу.

Это отдельный Docker контейнер на VPS, где я запускал агента с флагом --dangerously-skip-permissions.

Идея простая и эффективная: агент получает полную свободу действий в «опасном» режиме, но строго внутри изоляции. Обязательный git-контроль всех изменений позволял мне откатить любой мусор, если клода уносило в дебри. Безопасность обеспечена на уровне контейнера, а скорость разработки возрастает кратно.

Риск, который остаётся - он сожрет все токены в сессии и придется ждать 5 часов чтобы продолжить, но с таким я сталкивался только один раз в этом проекте.

Промпт

Самая важная часть всего проекта это правдивость выходного документа. Я использую reasoning модели последнего поколения (конкретно gpt-5.2 через OpenRouter). И они уже очень хорошо справляются с поставленной задачей.

На всякий случай я сделал простой редактор готового резюме перед его загрузкой.

Для этого заложены два правила.

Правило первое: ничего лишнего в промпт.

Телефон, почта, ссылки на Telegram, LinkedIn и GitHub не нужны языковой модели для оптимизации буллитов вашего опыта. Больше контекста означает худшие ответы, высокий риск галлюцинаций, больше токенов и долгое ожидание. Поэтому персональные данные вообще не уезжают в LLM.

Правило второе: строгие директивы в системном промпте.

В промпте у меня жестко зафиксированы правила которые я ожидаю от LLM.

#### STRICT RULES - NEVER VIOLATE:
- NEVER fabricate job titles, companies, degrees, certifications, or achievements
- NEVER invent metrics, numbers, or achievements not present in the data
- NEVER use the em dash symbol, the word "delve", or other common LLM text markers
- NEVER drop work experience or achievements unless they clearly decrease fit
- You CAN add related technologies plausible from context (Python user = pip, venv)
- You CAN add umbrella terms inferable from context: "NLP" if they did text processing
- You CAN rephrase metrics with same values: "1% - 10%" to "1-10%"
- You CAN reorder and emphasize existing content for relevance
- Do NOT cut critical content (work experience, education) if you can cut something else

Категорически запрещено выдумывать должности, компании и любые метрики, которых не было в исходных данных. Отдельно запрещено использовать бесячие маркеры машинно-сгенерированного текста и вырезать критичный контент ради сокращения объема.

Вот так выглядит оптимизированное резюме для нашего John Doe
Вот так выглядит оптимизированное резюме для нашего John Doe

Сколько это стоит?

Я проектировал проект так, чтобы порог входа был минимальным, а сам проект не требовал регулярных вливаний денег. UI бесплатно крутится на Vercel, базы данных живут в бесплатных лимитах Turso, а триала в n8n Cloud достаточно чтобы откликнуться на сотни вакансий.

Я плачу только за токены API через OpenRouter. По моим личным тестам один прогон gpt-5.2 обходится примерно в 5 центов.

Откуда взять данные для заполнения опыта

На эту идею меня натолкнул мой друг: чтобы максимально полно собрать свой опыт, иногда достаточно просто проговорить его вслух с кем-то со стороны.

Для этого я включил voice mode в приложении ChatGPT и примерно час обсуждал с ним свой карьерный путь. Если честно, сам диалог получился не самым удачным. Надеюсь, со временем voice mode станет более отзывчивым и вовлечённым в разговор.

Тем не менее, на выходе у меня остался часовой разговор о моём опыте. Я отправил его в сервис транскрибации, получил текстовую расшифровку, а затем загрузил этот транскрипт в ChatGPT вместе с промптом (ниже). В результате получил файл для импорта, который можно загрузить на странице настроек.

Промпт для генерации опыта
Extract my professional experience from the attached materials and generate a structured JSON file for import into my CV manager.

I may attach:
- A transcript of a voice conversation about my career
- My existing CV/resume (PDF or text)
- Both — in that case, merge the information, preferring more detailed descriptions

Your goal: extract every distinct achievement, project, responsibility, education item, and course — and structure them as atomic "highlights" linked to jobs.

Guidelines for extraction:
- Split large responsibilities into separate highlights — one per distinct topic
- Write "content" in first person, professionally, with context and impact
- Infer metrics from the text where possible (e.g., "managed a team of 5" → metric)
- If dates are vague (e.g., "around 2019"), use your best estimate with "01" for unknown day/month
- Don't skip anything — it's better to have more highlights that can be filtered later

Output this exact JSON format:

```json
{
  "jobs": [
    {
      "company": "Company Name",
      "role": "Job Title",
      "startDate": "YYYY-MM-DD",
      "endDate": "YYYY-MM-DD"
    }
  ],
  "highlights": [
    {
      "title": "Short title of achievement",
      "content": "Detailed description with context and impact",
      "type": "achievement",
      "job": "Company Name",
      "startDate": "YYYY-MM-DD",
      "skills": ["Skill1", "Skill2"],
      "domains": ["Domain1"],
      "metrics": [
        { "label": "Revenue increase", "value": 25, "unit": "%" }
      ]
    }
  ]
}
```

Rules:
- Dates must be "YYYY-MM-DD" format. Use "01" for day if unknown.
- "job" field must exactly match a company name from the jobs array
- "type" can be: achievement, project, responsibility, education, course, teaching
- "metrics" are optional but encouraged — use them for quantifiable results
- "domains" = business areas (e.g., "Fintech", "E-commerce")
- "skills" = technologies/tools (e.g., "React", "Python", "Kubernetes")
- Omit endDate for current positions
- Output only the JSON, no commentary

Как попробовать?

Как запустить это для себя:

  1. Заходите в веб-интерфейс cv-cms.ru и импортируете свои данные (про это дальше).

  2. Регистрируете бесплатный аккаунт в n8n и OpenRouter.

  3. Копируете мой темплейт в свой n8n, вставляете свой API ключ и выбираете нужную модель. (часто бывает что топовые лабы выпускают бесплатные модели можно вообще обойтись без пополнения баланса)

  4. В настройках Build CV добавляете ссылку на ваш личный webhook из n8n.

  5. Готово. Вы вставляете текст вакансии, нажимаете кнопку оптимизации, докручиваете результат во встроенном редакторе и выгружаете идеальный PDF.

Результат

Переход на генерацию точечных резюме изменил для меня две ключевые метрики:

  • Во-первых, время на один качественный таргетированный отклик сократилось с часов ручной возни с резюме до 5 минут в интерфейсе CMS.

  • Во-вторых, на первичном скрининге мне стали регулярно отвечать живые люди, а не присылать автоматические отказы.

Без читерства, просто упаковка опыта под конкретную вакансию.

OpenSource

CV-CMS полностью OpenSource проект - репозиторий на GitHub.