~/wiki / osnovy-vibe-design / slug-kak-zapustit-servis-samomu-vibecoding

Как запустить сервис самому: всё что дают на курсах по вайбкодингу — в одной статье

Основной чат

Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.

$ cd раздел/ $ join vibe dev
Как запустить сервис самому: всё что дают на курсах по вайбкодингу — в одной статье - обложка

Что нужно

Инструмент Зачем Стоимость
Claude Code Агент, пишет и запускает код Pro $20/мес (токены отдельно) или Max $100/мес
Codex CLI Альтернативный агент от OpenAI ChatGPT Plus/Pro/Team включён
VS Code Редактор, где хранится проект бесплатно
Supabase База данных и авторизация бесплатно до лимита
VPS Сервер для деплоя от $6/мес
OpenRouter API для AI-функций в сервисе от $10 пополнение
GitHub Хранение кода и деплой бесплатно

Claude Code и Codex — взаимозаменяемы. Логика работы та же, различаются только команды установки и название файла с инструкциями (CLAUDE.md или AGENTS.md). Далее в тексте будет указано где они расходятся.


Блок 1. Инструменты

Установить агента

Claude Code:

bash
npm install -g @anthropic-ai/claude-code
claude  # запустится браузерная авторизация

Codex CLI:

bash
npm install -g @openai/codex   # именно @openai/codex, не просто codex
codex auth                      # браузерная авторизация через ChatGPT

Важно: пакет без @openai/ — это несвязанный проект 2012 года. Он установится без ошибок но ничего полезного не сделает.

После установки запустите агента в любой папке:

bash
claude   # для Claude Code
codex    # для Codex

Агент видит все файлы в текущей папке, может их создавать, редактировать и запускать команды в терминале.


Как работает связка VS Code + агент

VS Code — редактор. Там хранится код и видно что происходит. Агент запускается в встроенном терминале (Ctrl+ на Windows/Linux, Cmd+ на Mac).

Рабочий цикл выглядит так:

  1. Открыли папку проекта в VS Code
  2. Открыли терминал, запустили claude или codex
  3. Написали задачу текстом
  4. Агент предложил изменения — вы проверили и подтвердили
  5. Открыли браузер на localhost:3000 — проверили результат
  6. Написали следующую задачу

По умолчанию Claude Code спрашивает разрешение перед каждым изменением файла. Codex работает аналогично. Если хочется чтобы агент работал без постоянных подтверждений — в Claude Code это флаг --dangerously-skip-permissions, в Codex — режим --full-auto. Для обучения лучше оставить подтверждения включёнными — так лучше понимаешь что происходит.


Блок 2. Спека и флоу

Спека — это текстовый файл с описанием сервиса. Главный урок вайбкодинга: чем точнее описана задача, тем меньше итераций нужно. Не «сделай форму заявок», а полное описание кто пользуется, что делает и что происходит в каждом состоянии.

Попросите агента помочь написать спеку в диалоге:

plaintext
Я хочу сделать форму для сбора заявок с простой админкой.
Задавай мне вопросы по одному, я буду отвечать.
По ходу записывай всё в файл SPEC.md.
Когда соберёшь достаточно информации — покажи итоговый файл.

Агент будет уточнять детали. Отвечайте конкретно. В конце у вас будет файл — основа для всей дальнейшей работы.


Что должно быть в спеке

Вот шаблон который работает. Это не формальный документ — просто ответы на конкретные вопросы:

markdown
# SPEC.md

## Что это
Форма для приёма заявок на консультацию. 
Гость заполняет форму → заявка сохраняется → 
владелец видит все заявки в закрытой админке.

## Пользователи
- Гость — заполняет форму, не регистрируется
- Админ — логинится, видит все заявки, меняет статус

## Флоу гостя
1. Открывает страницу → видит форму
2. Вводит имя, email, текст запроса → нажимает «Отправить»
3. Видит экран благодарности: «Свяжемся в течение дня»

## Флоу админа
1. Открывает /admin → редиректит на /admin/login если не залогинен
2. Вводит email и пароль → попадает в список заявок
3. Видит заявки: имя, email, текст, дата, статус (новая / в работе / закрыта)
4. Нажимает на заявку → может изменить статус

## Экраны и состояния

### Форма (/):
- Состояние: обычное — форма заполнена частично или пуста
- Состояние: отправка — кнопка неактивна, показывает «Отправляю...»
- Состояние: ошибка валидации — подсветить незаполненные поля, текст ошибки
- Состояние: ошибка сервера — «Что-то пошло не так, попробуйте позже»
- Состояние: успех — скрыть форму, показать сообщение

### Список заявок (/admin):
- Состояние: загрузка — скелетон строк
- Состояние: пусто — «Заявок пока нет»
- Состояние: список — таблица с сортировкой по дате (новые сверху)

## Что НЕ входит в первую версию
- Уведомления на email при новой заявке
- Поиск и фильтрация заявок
- Несколько админов
- Удаление заявок

## Стек
Next.js App Router, TypeScript, Tailwind CSS, Supabase

Раздел «Что НЕ входит» — один из важнейших. Без него агент начинает добавлять функции которые не просили, а вы теряете время на их проверку.


Описание состояний экранов — сила дизайнера

Обычный разработчик напишет в промпте «сделай форму» и не подумает про empty state, ошибку валидации и состояние загрузки. Дизайнер думает именно так — экранами и состояниями. Это ваше преимущество.

Чем подробнее описаны состояния в спеке — тем меньше будет правок после. Агент реализует ровно то что написано.


Блок 3. Интерфейс

Создать проект

Попросите агента:

plaintext
Создай новый Next.js-проект в папке request-form.
Стек: TypeScript strict mode, Tailwind CSS, App Router.
После создания запусти dev-сервер и убедись что localhost:3000 открывается.

Или сами:

bash
npx create-next-app@latest request-form --typescript --tailwind --app
cd request-form
npm run dev

Создать файл с инструкциями для агента

Это аналог брифа — агент читает его в начале каждой сессии. Для Claude Code это CLAUDE.md, для Codex — AGENTS.md. Структура одинаковая:

markdown
# AGENTS.md  (или CLAUDE.md)

## Контекст
Читай SPEC.md перед началом любой задачи.
Если что-то не описано в SPEC.md — спроси, не придумывай.

## Стек
- Next.js App Router, TypeScript strict mode
- Tailwind CSS — никаких произвольных hex-значений, только классы Tailwind
- Supabase — auth и база данных через @supabase/ssr

## Правила
- Каждый экран в отдельном компоненте
- Все состояния из SPEC.md обязательны: загрузка, ошибка, пусто
- После изменений запусти npm run build — убедись что TypeScript не ругается
- Не добавляй фичи которых нет в SPEC.md

## Структура
src/
  app/           — роуты
  components/    — компоненты
  lib/           — утилиты, supabase-клиент

Собирать интерфейс по одному экрану

Не давайте задачу «собери весь интерфейс сразу». Лучше по одному экрану — так проще проверить каждый результат.

Задача на форму:

plaintext
Прочитай SPEC.md.

Создай главную страницу src/app/page.tsx с формой заявки.
Поля: Имя (обязательное), Email (обязательное, валидация формата), 
Текст запроса (обязательное, минимум 10 символов).
Кнопка «Отправить».

Состояния кнопки: обычное / «Отправляю...» с disabled во время запроса.
Состояния формы: пустая → валидация → успех (скрыть форму, показать текст) 
→ ошибка сервера (toast или текст под кнопкой).

Пока используй console.log вместо реального запроса — реальный добавим позже.
Адаптивно: мобильный и десктоп.

После того как форма выглядит правильно — проверяйте конкретно. Не «что-то не так», а точное описание:

plaintext
Кнопка «Отправить» на мобильном слишком мелкая — менее 44px высотой.
Сообщение об ошибке валидации появляется только после нажатия кнопки,
а нужно при потере фокуса (onBlur) на каждом поле.

Задача на страницу успеха:

plaintext
После отправки формы скрой её и покажи блок с текстом:
«Спасибо! Свяжемся с вами в течение дня.»
И ссылку «Отправить ещё одну заявку» которая возвращает форму.

Задача на админку:

plaintext
Создай страницу src/app/admin/page.tsx.
Таблица заявок: колонки — Имя, Email, Дата, Статус, Действие.
Статус: три варианта — «Новая», «В работе», «Закрыта».
Сортировка: новые сверху.

Состояния: загрузка (скелетон на 5 строк), пусто («Заявок пока нет»), список.
Пока используй моковые данные — массив из 3 объектов.
Реальные данные подключим когда настроим Supabase.

Блок 4. Деплой — сразу, не в конце

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

Vercel — одна команда

bash
npm install -g vercel
vercel

Vercel спросит несколько вопросов и задеплоит. Бесплатно для личных проектов. Каждый push в GitHub — автоматически новая версия.


VPS — агент делает сам

Купите VPS: DigitalOcean от $6/мес, Timeweb от 200 руб/мес, Selectel. Нужен Ubuntu 22/24.

Задача для агента:

plaintext
Задеплой этот Next.js-проект на мой VPS.
IP: [адрес]
Пользователь: root
Пароль: [пароль]

Что нужно сделать:
— Установить Node.js 20, nginx, PM2
— Запушить проект в новый GitHub-репозиторий [ссылка]
— Склонировать на сервер, запустить npm install и npm run build
— Запустить через PM2 на порту 3000
— Настроить nginx как reverse proxy: все запросы → localhost:3000
— Выписать SSL-сертификат через Let's Encrypt для домена [домен]
— PM2 в автозапуске при перезагрузке сервера

После каждого шага сообщай результат.

Агент выполнит всё последовательно. Если на каком-то шаге упадёт ошибка — опишет её и предложит решение.


Блок 5. База данных и авторизация

Подключить Supabase

Зарегистрируйтесь на supabase.com, создайте новый проект. В настройках (Settings → API) скопируйте Project URL и anon key.

Задача агенту:

plaintext
Подключи Supabase к проекту.
Project URL: [вставить]
Anon key: [вставить]

Нужно:
1. Установить @supabase/ssr и @supabase/supabase-js
2. Создать src/lib/supabase/client.ts — браузерный клиент
3. Создать src/lib/supabase/server.ts — серверный клиент для App Router
4. Добавить переменные в .env.local:
   NEXT_PUBLIC_SUPABASE_URL=...
   NEXT_PUBLIC_SUPABASE_ANON_KEY=...
5. Убедиться что .env.local есть в .gitignore

Создать таблицы

plaintext
Создай SQL-миграцию для таблицы requests в Supabase.

Поля:
- id: uuid, primary key, default gen_random_uuid()
- name: text, not null
- email: text, not null
- message: text, not null
- status: text, not null, default 'new', 
  check (status in ('new', 'in_progress', 'closed'))
- created_at: timestamptz, default now()

Включи Row Level Security (RLS):
- Вставка (insert): разрешить всем (анонимным тоже)
- Чтение (select): только авторизованным пользователям
- Обновление (update): только авторизованным

Дай мне готовый SQL для выполнения в Supabase Dashboard → SQL Editor.

Скопируйте SQL, откройте Supabase Dashboard → SQL Editor → New query → вставьте и запустите.


Подключить авторизацию в админку

plaintext
Добавь авторизацию для раздела /admin через Supabase Auth.

Нужно:
1. Страница /admin/login:
   — Форма: email + пароль
   — Кнопки «Войти» и «Зарегистрироваться»
   — При ошибке: показать текст ошибки под формой
   — При успехе: редирект на /admin

2. Middleware (middleware.ts в корне):
   — Любой запрос на /admin/* — проверить сессию
   — Если нет сессии — редирект на /admin/login

3. Кнопка «Выйти» на странице /admin
   — При нажатии: signOut → редирект на /admin/login

После этого создайте тестового пользователя в Supabase Dashboard → Authentication → Users → Add user.


Заменить моковые данные на реальные

Форма → реальная отправка:

plaintext
Форма на главной странице сейчас делает console.log.
Замени на реальную отправку в Supabase.

Используй Server Action (файл src/app/actions.ts):
— Принимает: name, email, message
— Валидирует: все поля обязательные, email — валидный формат
— Вставляет в таблицу requests
— Возвращает: { success: true } или { error: 'текст ошибки' }

В форме: при ошибке — показать текст пользователю, 
при успехе — переключить в состояние успеха.

Админка → реальные данные:

plaintext
Страница /admin сейчас показывает моковые данные.
Замени на загрузку из Supabase.

Список заявок — серверный компонент, запрос через серверный клиент.
Сортировка: created_at DESC.

Изменение статуса — Client Component с Server Action:
— Выпадающий список: Новая / В работе / Закрыта
— При изменении: обновляет запись в базе, 
  перезагружает данные через revalidatePath('/admin')

Блок 6. AI-функции и интеграции

OpenRouter — один API для всех моделей

OpenRouter даёт доступ к Claude, GPT, Gemini и десяткам других моделей через единый API. Удобен для AI-функций в сервисе: не нужно заводить несколько подписок.

Зарегистрируйтесь на openrouter.ai, пополните баланс, скопируйте ключ.

plaintext
Добавь в .env.local:
OPENROUTER_API_KEY=sk-or-...

Создай src/lib/openrouter.ts:

async function generateReply(
  customerName: string,
  customerMessage: string
): Promise<string>

Функция отправляет запрос к OpenRouter.
Модель: anthropic/claude-sonnet-4
Системный промпт: «Ты помощник по работе с клиентами. 
Пиши вежливо, по-русски, кратко — 2-3 предложения.»
Пользовательский промпт: «Напиши черновик ответа клиенту [имя], 
который написал: [сообщение]»

При ошибке запроса — вернуть null, не бросать исключение.

Добавить в админку:

plaintext
В таблицу заявок добавь кнопку «Черновик ответа» рядом с каждой заявкой.

При нажатии:
— Кнопка показывает спиннер
— Вызывает generateReply с именем и текстом заявки
— Показывает результат в модальном окне с кнопками «Скопировать» и «Закрыть»
— Кнопка «Скопировать» копирует текст в буфер, меняет текст на «Скопировано ✓» на 2 секунды

Telegram-уведомления о новых заявках

Создайте бота через @BotFather в Telegram, получите токен. Узнайте свой chat ID через @userinfobot.

plaintext
При успешной вставке заявки в Supabase отправляй уведомление в Telegram.

В Server Action после INSERT добавь:
fetch('https://api.telegram.org/bot[токен]/sendMessage', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    chat_id: '[chat_id]',
    text: `Новая заявка от ${name}\nEmail: ${email}\n\n${message}`
  })
})

Запрос асинхронный — не await, не блокирует ответ пользователю.
Ошибка отправки не влияет на сохранение заявки.

Блок 7. Тесты

Тесты нужны чтобы знать — новое изменение не сломало то что уже работает. Особенно важно когда проект растёт.

Unit-тесты через Vitest

plaintext
Установи Vitest и напиши тесты для основных функций.

Что тестировать:

1. Валидация формы (src/lib/validate.ts — создай если нет):
   — Пустое имя → ошибка 'Введите имя'
   — Невалидный email → ошибка 'Введите корректный email'
   — Сообщение короче 10 символов → ошибка 'Слишком короткое сообщение'
   — Все поля заполнены корректно → возвращает null (нет ошибок)

2. generateReply из openrouter.ts:
   — Замокай fetch
   — Успешный ответ → возвращает строку
   — Ошибка сети → возвращает null, не бросает исключение

После написания запусти npx vitest run — все тесты должны пройти.

E2E-тест через Playwright

plaintext
Установи @playwright/test и напиши e2e тест:

1. Открыть главную страницу
2. Заполнить форму: имя «Тест», email «test@example.com», 
   сообщение «Тестовое сообщение для проверки»
3. Нажать «Отправить»
4. Проверить что появился текст «Спасибо»
5. Проверить что форма больше не видна

Тест должен использовать тестовую базу (задай через env SUPABASE_URL_TEST)
или мокать Server Action.

Pre-commit хук — тесты перед каждым коммитом

plaintext
Настрой pre-commit хук через husky и lint-staged:

Перед каждым коммитом:
1. npx vitest run — unit-тесты
2. npm run build — проверка TypeScript и сборки

Если что-то упало — коммит не проходит, показывает какой тест провалился.

Блок 8. Портфолио и кейс

Что показывать

Сервис в продакшене — это уже кейс. Но для портфолио важно показать мышление, а не только результат.

Структура кейса для вайбкодинга:

markdown
## Задача
Что хотел сделать и зачем — одним абзацем.

## Как описывал задачу
Покажите первую и финальную версию промпта на одну фичу.
Что уточнялось, от чего отказались и почему.

## Что было нетривиально
Один-два момента где агент не справился с первого раза.
Что именно не так и как переформулировали задачу.

## Результат
Ссылка на живой сервис.
Скриншот или короткое видео.

Разница между сильным кейсом и слабым — в разделе «как описывал задачу». Два похожих по результату сервиса, но один показывает процесс мышления — и это тот который запомнят.


Типичные проблемы

Агент ходит по кругу с одной ошибкой. Не давайте ему больше итераций с той же формулировкой. Откройте новую сессию, опишите только конкретную ошибку: текст из консоли, файл, строку. Без контекста всего проекта.

После изменений сломалось что работало. Запустите npx vitest run. Если тестов нет — попросите агента написать тест на сломавшееся место, потом починить его.

Агент добавляет фичи которые не просили. В AGENTS.md/CLAUDE.md добавьте явное правило: «Не добавляй ничего чего нет в SPEC.md. Если считаешь нужным — спроси прежде чем делать».

Суpabase выдаёт ошибку Row Level Security. Значит политика RLS не разрешает операцию для текущего пользователя. Опишите агенту: что за операция, авторизован ли пользователь, и текст ошибки. Агент поправит политику.

Контекст теряется между сессиями. SPEC.md и AGENTS.md/CLAUDE.md решают это. В начале новой сессии: «Прочитай SPEC.md и AGENTS.md. Кратко — что уже сделано, что осталось».


Итог

Артефакт Где лежит
Описание сервиса SPEC.md
Правила для агента AGENTS.md или CLAUDE.md
Интерфейс src/app/ и src/components/
База данных и авторизация Supabase
AI-функции src/lib/openrouter.ts
Тесты Vitest + Playwright
Сервис в продакшене VPS или Vercel

Главное изменение после первого запущенного сервиса: перестаёшь думать «нужен разработчик» и начинаешь думать «нужна спека».

$ cd ../ ← назад к Основы VibeDesign