Как маркетолог собрал внутренний дашборд за 3 вечера без навыков программирования: реальный опыт с вайбкодингом

Что такое вайбкодинг и почему это не про программирование

Вайбкодинг выглядит так: открываешь Cursor или Lovable, пишешь "сделай мне лендинг с формой захвата и таймером обратного отсчёта", и через несколько секунд у тебя есть рабочий HTML с JavaScript. Ты не написал ни строчки кода. И не должен был.

Термин придумал Андрей Карпати в феврале 2025-го. Он описал процесс, когда полностью отдаёшь написание кода модели, а сам остаёшься в роли человека, который формулирует задачу, смотрит на результат и говорит "нет, кнопка должна быть красной и форма должна отправлять данные в Google Sheets". Это не программирование. Это постановка задачи.

Многие путают с no-code. Разница принципиальная. Bubble или Webflow дают тебе конструктор: перетаскиваешь блоки, настраиваешь логику кликами. Ты работаешь внутри чужой системы с чужими ограничениями. Вайбкодинг генерирует реальный исходный код под твою конкретную задачу. Хочешь нестандартную логику A/B-теста? Хочешь парсить данные из нескольких источников и складывать в свою таблицу? Просто описываешь. Код появляется именно под это.

В 2026 году порог входа стал смешным. Replit Agent разворачивает рабочее приложение за один промпт. Lovable в большинстве случаев понимает задачу со второй итерации. Люди без технического бэкграунда осваивают эти инструменты за вечер, я видел это на практике, не метафорически.

И вот почему маркетолог здесь оказывается в неожиданно выгодной позиции. Узкое место вайбкодинга никогда не было в коде. Оно в постановке задачи. Нужно точно знать, что ты хочешь получить, уметь описать это словами, понимать, какую метрику проверять, чтобы убедиться: оно работает. Маркетолог делает это каждый день. Пишет бриф агентству, ставит задачу дизайнеру, формулирует гипотезу для теста. Навык уже есть. Инструмент просто поменялся.

Человек описывает задачу словами, ИИ генерирует готовый код для дашборда

Весь процесс начинается с обычного текстового описания: что нужно показать, откуда брать данные и как это должно выглядеть.

Задача: какой дашборд нужен и зачем его строить самому

Конкретная ситуация: маркетолог каждую пятницу открывает три вкладки браузера, выгружает отчёты из Google Ads, заходит в Mailchimp за показателями email-рассылок, тащит цифры из Google Sheets с CRM-данными, и всё это сводит руками в Excel. Час работы, которая не создаёт никакой ценности. Просто перекладывание цифр из одного места в другое.

Казалось бы, есть готовые решения. Looker Studio бесплатный, Power BI популярен. Но дьявол в коннекторах: нужный источник либо требует платного плана, либо официальный коннектор тянет не те поля, либо нужно возиться с OAuth и правами доступа дольше, чем пишется свой скрипт. Power BI вообще заточен под экосистему Microsoft, и если данные живут в Google-инструментах, настройка превращается в отдельный проект.

Самописный вариант решает конкретно эту задачу: берёт данные из Google Sheets (куда уже стекается всё нужное), считает нужные метрики и показывает их на одном экране. Кнопка "Обновить" запускает подтягивание актуальных данных. Ничего лишнего.

Я говорю про дашборд с 4-6 виджетами: динамика по неделям, ключевые показатели в виде чисел сверху, пара графиков. Не BI-система, не аналитическая платформа. Рабочий инструмент под одну задачу.

Три вечера по 2-3 часа, это реалистичный срок, если не пытаться сразу сделать "как в Tableau". Первый вечер: настройка получения данных и базовая структура. Второй: визуализация. Третий: полировка и деплой. Переусложнение убивает такие проекты быстрее всего, я видел это много раз.

Схема объединения трёх источников данных в один дашборд через Python

Три разрозненных источника, например CSV, API и база данных, сводятся в одну таблицу ещё до того, как Plotly рисует первый график.

Инструменты: Cursor, Lovable или Replit, что выбрать новичку

Три инструмента, которые сейчас реально используют для вайбкодинга. Все три разные по философии, и выбор зависит от одного вопроса: тебя пугает терминал или нет?

Cursor, это VS Code с встроенным ИИ. Если ты хоть раз открывал VS Code или хотя бы видел его на скриншотах, интерфейс будет знакомым. Cursor работает локально: скачиваешь, устанавливаешь, пишешь код прямо на своей машине. Бесплатный план есть, Pro стоит $20 в месяц. По моему опыту, в паре с Claude 3.7 он давал чистый, рабочий код с первой-второй попытки на задаче с дашбордом на Google Sheets, тогда как другие инструменты требовали больше итераций.

Но есть порог входа. Нужно установить Python или Node, разобраться с виртуальными окружениями, понять, как запустить сервер локально. Для кого-то это 20 минут. Для кого-то это стена.

Lovable работает в браузере. Заходишь, описываешь что хочешь, получаешь React-приложение. Ничего не надо устанавливать, ни терминала, ни пакетных менеджеров. Если ты впервые видишь редактор кода вообще, Lovable снижает тревогу почти до нуля. Генерирует фронтенд быстро, деплой встроен. Минус: меньше контроля над тем, что происходит под капотом, и сложнее делать что-то нестандартное.

Replit занимает среднюю позицию. Облачная среда, где и код, и выполнение, и деплой происходят в браузере, но при этом ты видишь файлы, видишь терминал, можешь что-то руками поправить. ИИ-агент Replit сам ставит зависимости и запускает проект. Хороший выбор, если хочешь чуть больше понимать, что происходит, но ещё не готов к полноценной локальной разработке.

Мой совет такой. Если задача конкретная и техническая, скажем, подключиться к Google Sheets, обработать данные, вывести графики, бери Cursor и Claude 3.7. Да, придётся один раз разобраться с установкой, но результат будет точнее. Если задача больше про UI, лендинг, простое веб-приложение, и терминал вызывает дискомфорт, Lovable закроет потребность без лишнего стресса.

Вечер первый: настройка среды и первый рабочий запрос

Cursor скачивается с cursor.com. Установка, вход через GitHub или Google, создание пустого проекта. Всё занимает минут десять, не больше.

Открываешь папку проекта, нажимаешь Cmd+K (или Ctrl+K на Windows) и видишь чат с ИИ прямо в редакторе. Теперь важная часть: что туда написать.

Первый промпт должен быть максимально скучным и конкретным. Не "помоги мне сделать дашборд", а что-то вроде:

"Создай HTML-страницу с одной таблицей, которая читает данные из Google Sheets по этому URL и показывает колонки: дата, канал, клики, расходы."

Чем конкретнее, тем меньше мусорного кода получишь в ответ.

Подготовить Google Sheets нужно заранее. Заходишь в таблицу, жмёшь "Поделиться", выбираешь "Все, у кого есть ссылка, могут просматривать". Это открывает доступ к CSV-экспорту без OAuth и API-ключей. URL для запроса выглядит так:

https://docs.google.com/spreadsheets/d/[ID]/export?format=csv

Cursor напишет примерно такой код:

// Промпт был: "Напиши fetch-запрос к Google Sheets CSV URL,
// распарси данные и выведи их в HTML-таблицу."

fetch('https://docs.google.com/spreadsheets/d/[ID]/export?format=csv')
  .then(res => res.text())
  .then(csv => {
    const rows = csv.split('\n').map(r => r.split(','));
    const table = document.querySelector('#data-table');
    rows.forEach(row => {
      const tr = document.createElement('tr');
      row.forEach(cell => {
        const td = document.createElement('td');
        td.textContent = cell;
        tr.appendChild(td);
      });
      table.appendChild(tr);
    });
  });

Открываешь HTML-файл в браузере, смотришь в консоль. С вероятностью процентов восемьдесят там будет ошибка CORS: браузер заблокировал запрос, потому что страница открыта как локальный файл. Не надо разбираться почему. Просто копируешь текст ошибки целиком и вставляешь в чат Cursor. Он предложит запустить через локальный сервер или добавить проксирование. Делаешь то, что написал.

После второй-третьей итерации таблица появится. Данные из Google Sheets, в браузере, без бэкенда и без единой строки, написанной вручную.

Это и есть итог первого вечера: работающая страница с реальными данными. Ничего впечатляющего визуально, но механика понятна. Дальше будет быстрее.

Интерфейс редактора Cursor с открытым чатом и первым промптом для дашборда

Cursor позволяет писать промпт прямо рядом с кодом, так что ИИ видит весь контекст файла, а не только текст вопроса.

Вечер второй: графики, фильтры и нормальный вид

Второй вечер я начал с того, что открыл вчерашний HTML и понял: таблица работает, данные грузятся, но смотреть на это невозможно. Голый Bootstrap, серый фон, ноль контекста. Надо добавить график и хоть какую-то жизнь.

Первый промпт был простым:

"Подключи Chart.js из CDN и нарисуй линейный график расходов по датам на основе уже загруженных данных"

Клод знает Chart.js хорошо. Через минуту у меня был рабочий canvas с осью X по датам и осью Y по расходам. Единственное, что пришлось поправить руками: порядок сортировки дат. Данные в CSV шли не хронологически, и график выглядел как кардиограмма паникующего человека. Добавил один промпт про sort() и стало нормально.

Дальше попробовал схитрить и запросить сразу три вещи: фильтр по каналу, второй график с разбивкой по каналам, и экспорт в PNG. Получил полурабочий код с конфликтующими обработчиками событий. Урок очевидный: один промпт, одна функция. Это не лень, это просто работает лучше.

Откатился и сделал фильтр отдельно:

"Добавь выпадающий список с уникальными значениями из колонки Channel. При выборе значения перестраивается и таблица, и график одновременно"

Здесь Клод справился хорошо. Список заполнялся динамически из данных, при смене значения вызывались обе функции рендеринга. Связка таблица+график обновлялась синхронно.

Потом добавил условное форматирование. Промпт:

"Если значение в колонке Расходы больше 5000, покрась строку красным"

Три строки кода в функции рендеринга таблицы. Работает. Я добавил ещё порог на 3000 (жёлтый) своим руками, потому что это проще написать самому, чем объяснять.

Последним шёл косметический промпт:

"Сделай страницу чище: белый фон, шрифт Inter, карточки с тенями, без таблицы по умолчанию Bootstrap"

Результат был 80% готов сразу. Клод подключил Inter через Google Fonts, обернул блоки в карточки с box-shadow, убрал стандартные Bootstrap-стили с таблицы. Пришлось подправить отступы и цвета вручную, но это заняло минут десять в DevTools.

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

Итого два вечера, около четырёх часов суммарно, и что-то, что реально можно открыть на рабочем совещании без стыда.

Готовый дашборд с графиком продаж, фильтром по периоду и подсветкой строк

Условное форматирование строк здесь работает через callback: цвет меняется в зависимости от значения в колонке, без перезагрузки страницы.

Вечер третий: подключение второго источника и деплой

К этому моменту у меня уже был дашборд с рекламными данными из одного листа. Задача вечера: добавить открываемость писем из Mailchimp и выложить всё по нормальной ссылке.

Mailchimp → Google Sheets. Прямой интеграции через бесплатный план нет, поэтому я пошёл простым путём: экспорт отчёта из Mailchimp в CSV, затем импорт в отдельный лист той же таблицы. Если хочешь автоматизировать, Nodul умеет забирать данные из Mailchimp по расписанию и писать их в Sheets без кода. Но для первого раза ручной экспорт раз в неделю вполне рабочий вариант.

Второй лист опубликовал так же, как первый: "Файл → Опубликовать в интернете → CSV". Получил второй URL.

Промпт для объединения двух источников:

Загрузи данные из двух CSV-URL, объедини по колонке Дата,
покажи рядом расходы на рекламу и открываемость писем.
URL 1: [ссылка на лист с рекламой]
URL 2: [ссылка на лист с Mailchimp]

Cursor написал функцию слияния примерно за минуту. Логика простая: два массива объектов, join по полю date, результат идёт в общий график. Где данные не совпали по датам, там пробелы. Это честно и не вводит в заблуждение.

Кнопка "Обновить данные". Перезагружать страницу каждый раз неудобно. Попросил добавить кнопку, которая делает повторный fetch без перехода:

// Промпт для Cursor:
// 'Добавь кнопку Обновить. При клике она заново
// загружает оба CSV и перерисовывает графики и таблицу.
// Пока данные грузятся, показывай спиннер.'

document.getElementById('refresh-btn').addEventListener('click', () => {
  showSpinner();
  Promise.all([fetchSheet1(), fetchSheet2()])
    .then(([data1, data2]) => {
      renderCharts(data1, data2);
      hideSpinner();
    });
});

Cursor написал этот код с первой попытки. Спиннер сделал через CSS-анимацию, которую тоже сгенерировал сам. Я только проверил, что кнопка видна на мобиле.

Деплой через Netlify Drop. Открываешь netlify.com/drop, перетаскиваешь папку с index.html, script.js и style.css в браузер. Через 30 секунд получаешь ссылку вида https://random-name-12345.netlify.app. Бесплатно, без регистрации, без настройки сервера.

Если на первом вечере создал репозиторий на GitHub, то альтернатива: включаешь GitHub Pages в настройках репо, и ссылка будет обновляться автоматически при каждом git push. Это удобнее в длинной перспективе, но требует лишних двух шагов при старте.

Я выбрал Netlify Drop, потому что хотел показать дашборд коллеге в тот же вечер. Скинул ссылку в Slack.

Что получилось за три вечера. Дашборд живёт по ссылке, открывается без логина, показывает рекламные расходы и открываемость рядом. Данные обновляются: заходишь в Google Sheets, правишь строки, нажимаешь "Обновить" на странице, видишь изменения. Команда может смотреть с телефона. Это не Tableau и не Looker Studio, но для еженедельного отчёта по двум метрикам хватает с запасом.

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

Как правильно писать промпты: три правила, которые реально работают

Плохой промпт съедает время быстрее, чем любая ошибка в коде. Я потратил несколько недель на то, чтобы понять простую вещь: проблема почти никогда не в модели. Проблема в том, как сформулирован запрос.

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

Давай контекст через @-упоминания. В Cursor это буквально встроено в интерфейс. Вместо "добавь колонку Конверсия в таблицу" пиши @index.html добавь в таблицу колонку Конверсия. Модель видит конкретный файл, конкретную структуру, и вероятность того, что она вставит код в правильное место, резко вырастает. Без @-упоминания она работает по памяти о том, что ты ей показывал раньше. Это ненадёжно.

Копируй stack trace целиком. Не пересказывай "там что-то сломалось с таблицей". Вставь весь текст ошибки: тип исключения, строку файла, полный trace. Разница в качестве ответа колоссальная. Пересказ ошибки заставляет модель строить гипотезы. Полный trace даёт ей точные координаты.

Есть ещё один приём, который я использую регулярно: после того как ИИ написал кусок кода, прошу его объяснить, что именно он сделал. Не ради педагогики. Это работает как проверка. Иногда в объяснении всплывает что-то вроде "я предположил, что у вас нет авторизации на этом роуте", и сразу понятно, что логика построена на ошибочном допущении.

Чего точно не делать: "сделай красиво" без примера. ИИ не знает твой вкус. Либо дай скриншот референса, либо назови конкретный источник: "сделай в стиле дашборда Linear" или "как таблицы в Notion". Конкретный референс даёт модели якорь. Абстрактное "красиво" даёт ей полную свободу, и результат будет... нейтральным.

Три карточки с правилами написания промптов для генерации кода дашборда

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

Ограничения и честные предупреждения

Перед тем как запускать это в продакшн, нужно понимать несколько вещей. Не чтобы напугать, а потому что столкнётесь с ними раньше, чем ожидаете.

Google Sheets как источник данных работает только если лист публичный. CSV-экспорт через gviz/tq?tqx=out:csv не спрашивает авторизацию. Как только лист переходит в "только для тех, у кого есть доступ", fetch возвращает HTML-страницу с формой входа вместо данных. Для закрытых таблиц нужен либо OAuth 2.0, либо сервисный аккаунт Google Cloud с JSON-ключом. Это уже не вайбкодинг за вечер.

Дашборд показывает данные на момент последнего обновления страницы. Если менеджер обновил таблицу три минуты назад, а кто-то смотрит дашборд без перезагрузки, он видит старые цифры. "Реальное время" здесь не при чём. Можно настроить автообновление через setInterval каждые 30-60 секунд, но тогда растёт нагрузка на API Google. Для большинства внутренних дашбордов это нормально. Для трейдинга или мониторинга серверов, нет.

Cursor иногда ломает то, что работало. Особенно когда просишь "немного поправить стили" и получаешь переписанный блок логики. Если после правки что-то перестало работать, первый шаг: Cmd+Z несколько раз. Если не помогает, пишите в чат: "верни код к состоянию до последнего изменения" или "что именно ты изменил в этом блоке". Cursor помнит контекст сессии и обычно восстанавливает. Но если закрыли вкладку, контекст потерян. Поэтому коммитьте в git хотя бы раз в час.

Дальше честная граница применимости.

По мере роста кодовой базы поддерживать её в режиме вайбкодинга становится сложнее. Когда проект разрастается, появляются симптомы отсутствия архитектуры: функции дублируются, переменные называются похоже, логика размазана по файлу. Когда придёт задача "добавь фильтр по региону и экспорт в PDF", Cursor начнёт предлагать решения, которые конфликтуют с тем, что уже написано. Вы будете фиксить баг, который сами не понимаете. Именно эти ситуации разбирает разбор реальных сломов при AI-разработке в продакшене.

Если дашборд вырастает до чего-то серьёзного, вайбкодинг его не вытянет. Авторизация по логину и паролю, несколько источников данных с разными схемами, история изменений, роли пользователей, отдельная база данных. Это нормальная разработка с нормальным разработчиком. Что здесь описано хорошо работает для одного источника, публичного доступа и команды до 10 человек, которым нужно смотреть на цифры, а не управлять ими.

Что делать дальше: куда расти после первого дашборда

Первый дашборд работает. Теперь понятно, что хочется большего.

Самое очевидное узкое место: данные обновляются вручную. Это убивает весь смысл, если заходишь в дашборд раз в неделю и видишь цифры двухнедельной давности. Лечится через Apps Script прямо в Google Sheets: пишешь скрипт, который дёргает нужный источник и перезаписывает диапазон по расписанию. Cursor напишет этот скрипт за один запрос, если дашь ему структуру листа и объяснишь, откуда брать данные. Настраиваешь триггер на каждые 6 часов, и дашборд живёт сам.

Google Ads подключается двумя путями. Официальный коннектор прямо в Sheets, через "Дополнения", бесплатный и без кода. Если нужна более гибкая синхронизация по нескольким кампаниям или аккаунтам, Nodul справляется лучше: там визуальные сценарии, которые можно настроить за полчаса без написания запросов к API вручную.

Следующий серьёзный шаг: переехать с Google Sheets на Supabase. Sheets хорошо держит текущий срез, но плохо хранит историю. Если хочешь видеть