Когда появилась идея создать стартап используя vibe-codding
Когда появилась идея создать стартап используя vibe-codding

Наступил 2026 год, и у меня были новогодние праздники для создания международного стартапа - единорога ?.

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

А чтобы успеть за две недели, я решил использовать vibe-кодинг, а то потом ещё к ЕГЭ по математике готовится.

VIBE-кодинг

Для написания кода я использую cursor.com версию pro - стоимость 20 $(есть российские бесплатные аналоги - sourcecraft и gigacode). Сразу скажу что в cursor есть лимит токенов, и за пару неполных недель я сжёг 3 учётки на проект.

Советую настроить User Rules Oper Settings(Ctrl+Shift+J)->Rules and Commands и задать User Roles.

Пример User Roles: Save all temporary files in the temp folder (including .py scripts) Do not use them in the main project, as they will be deleted. If you need a permanent utility file, place it in the utils folder.
Пример User Roles: Save all temporary files in the temp folder (including .py scripts)
Do not use them in the main project, as they will be deleted.
If you need a permanent utility file, place it in the utils folder.

Идея стартапа:

Контент

Картинки легко скачать из телеграмм, пример скрипта

#!/usr/bin/env python3
"""Скачивание стикеров из Telegram: python script.py pack_name bot_token"""
import sys, requests
from pathlib import Path

pack_name, bot_token = sys.argv[1], sys.argv[2]
Path(pack_name).mkdir(exist_ok=True)

api = f"https://api.telegram.org/bot{bot_token}/getStickerSet"
stickers = requests.get(api, params={"name": pack_name}).json()['result']['stickers']

for i, s in enumerate(stickers, 1):
    file_path = requests.get(f"https://api.telegram.org/bot{bot_token}/getFile", params={"file_id": s['file_id']}).json()['result']['file_path']
    file_url = f"https://api.telegram.org/file/bot{bot_token}/{file_path}"
    Path(pack_name, f"{i:03d}{Path(file_path).suffix}").write_bytes(requests.get(file_url).content)
    print(f"✅ {i}/{len(stickers)}")

Мультиязычность

Выбрал 50 языков для максимального охвата. Для удобства сделал API https://ai-stickers.ru/api/languages, который возвращает список видимых языков для фронтенда.

Перевод статики организован через JSON-файлы в папке locality: для каждого языка свой файл (например, ru.jsonen.jsonzh-CN.json). Базовый файл — ru.json с иерархической структурой (страницы, мета-теги, сообщения, кнопки). Скрипт на Python автоматически переводит ru.json на все языки через Google Translate API, сохраняя структуру и создавая файлы для всех языков.

#Пример кода перевода
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import os
import time
import requests
from googletrans import Translator

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

def translate_json(obj, dest_lang, src_lang='ru'):
    if isinstance(obj, dict):
        return {k: translate_json(v, dest_lang, src_lang) for k, v in obj.items()}
    elif isinstance(obj, list):
        return [translate_json(item, dest_lang, src_lang) for item in obj]
    elif isinstance(obj, str) and obj.strip():
        try:
            result = Translator().translate(obj, dest=dest_lang, src=src_lang)
            time.sleep(0.1)
            return result.text
        except:
            return obj
    return obj

# Загружаем ru.json
with open(os.path.join(SCRIPT_DIR, 'ru.json'), 'r', encoding='utf-8') as f:
    ru_data = json.load(f)

# Получаем языки из API
languages = [lang['code'] for lang in requests.get('https://ai-stickers.ru/api/languages').json()['languages'] if lang['code'] != 'ru']

# Переводим и сохраняем
for lang_code in languages:
    translated = translate_json(ru_data, lang_code)
    with open(os.path.join(SCRIPT_DIR, f'{lang_code}.json'), 'w', encoding='utf-8') as f:
        json.dump(translated, f, ensure_ascii=False, indent=2)
    print(f"✓ {lang_code}.json")

Автоматическое определение языка реализовано в middleware i18n.py. При каждом запросе система проверяет наличие языка в URL (например, /ru/search или /en/pack/123). Если язык отсутствует, используется приоритет: язык из сессии → язык по домену → язык из заголовка Accept-Language → дефолтный язык из переменной окружения. После определения выполняется редирект на URL с языковым префиксом, язык сохраняется в сессии и доступен через g.current_language во всех обработчиках.

Для SEO используются hreflang-теги. На каждой странице генерируются альтернативные ссылки для всех языков, указывающие на соответствующие версии. В sitemap каждая запись содержит полный набор hreflang-тегов для всех языков, что помогает поисковикам индексировать все языковые версии.

VIBE-DEBUGGING как организовать тестирование без боли и слез

VIBE-дебаггинг
VIBE-дебаггинг

Автотесты

Без автотестов в VIBE-кодить нельзя, иначе это будет боль и слезы, всё будет ломаться постоянно. В этом проекте я выстроил систему автотестов, которая работает как страховка от регрессий и позволяет уверенно рефакторить код.

Все тесты наследуются от базового класса, который содержит общую логику настройки Flask-приложения и вспомогательные методы для проверки JSON-ответов API.

Автоматический запуск тестов при старте приложения в режиме разработки — ключевая фича. Тесты запускаются в фоновом потоке через 5 секунд после старта сервера, не блокируя основной процесс. Это позволяет сразу обнаруживать проблемы до деплоя.

Отдельный класс проверяет скорость работы критичных эндпоинтов, используемых в React-компонентах. Это критично для UX: если после рефакторинга API стал работать медленнее, тесты сразу это покажут. Множественные запросы (симуляция загрузки страницы) должны выполняться не более чем за 3 секунды.

Стек

Сперва я начал писать проект на ванильном js, но когда устал исправлять бесконечные ошибки JS верстки - перешёл на React+Typescript.
Для бэкенда я использую Flask+Flasgger
Для AI-агентов фреймворк CrewAI.

GIT-контроль версий

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

Микро-сервисы + Vibe-кодинг = ❤️

Быстро я понял, что на большом проекте llm теряется из-за обилия контекста.
Сперва �� делил на модули и на папке, но в конечном счете перешёл на микро-сервисы по отдельным частям разработки. Здесь как раз и пригодился swagger(Flasgger).
Cursor прекрасно умеет создавать файлы openapi(swagger.yaml), при запуске приложения читает файл swagger.yaml с описанием всех API-эндпоинтов (что принимают, что возвращают, примеры) и автоматически создает интерактивную документацию по адресу /api-docs, где можно посмотреть все методы и протестировать их прямо в браузере.
Ссылку на документацию /api-docs достаточно скормить новому микро-сервису, чтобы он мог написать логику на её основе.

AI-агенты

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

Агенты работают совместно по иерархической модели: аналитик распределяет задачи, специалисты обрабатывают запросы, редактор проверяет и улучшает финальный ответ. Система поддерживает streaming процесс рассуждения в реальном времени через Server-Sent Events. В качестве LLM используется DeepSeek API, что делает решение более доступным по сравнению с OpenAI. Каждый агент имеет свою роль, цель и backstory, что позволяет создавать специализированных виртуальных сотрудников для решения конкретных задач.

from crewai import Agent, Crew, Task, LLM
from crewai import Process

# Создаем LLM для агентов
llm = LLM(
    model="deepseek-chat",
    api_key="your-api-key",
    base_url="https://api.deepseek.com/v1"
)

# Создаем агента-консультанта
consultant = Agent(
    role='Консультант',
    goal='Отвечать на вопросы пользователей',
    backstory='Ты опытный консультант с широкими знаниями',
    llm=llm,
    verbose=True
)

# Создаем задачу для агента
task = Task(
    description='Пользователь спрашивает: "Что такое машинное обучение?"',
    expected_output='Краткий и понятный ответ на вопрос',
    agent=consultant
)

# Создаем команду и выполняем задачу
crew = Crew(
    agents=[consultant],
    tasks=[task],
    process=Process.sequential
)

result = crew.kickoff()
print(result)

SEO-продвижение

Карта сайта

Статическая sitemap с автоматическим обновлением через скрипт, для высокой производительности (без нагрузки на БД) и кэширование на CDN.

Структура: разбит на файлы, по типам контента, с учетом лимитов(максимум 50,000 URL и 50 МБ на файл, учитывая размер hreflang тегов).

Интеграция: добавлен в Яндекс Вебмастер и Google Search Console.

Оптимизация на основе ключевых слов

Собрана база ключевых фраз через Яндекс Вордстат (несколько тысяч запросов с частотностью). Распределение по разметке:

Title и Meta Description — уникальные для каждой страницы с релевантными ключевыми словами.

Hreflang — в HTML и sitemap XML для правильной индексации мультиязычных версий.

Canonical URL — на каждой странице для предотвращения дублей.

Robots.txt — динамический, блокирует /api/, /debug/, /admin/, указывает sitemap, специфичные правила для разных ботов.

Особенности CDN

Для международного домена перевел DNS на Cloudflare и настроил кэширование.

Комментарии (0)