/
indievid
/
GigaStudio-e019bd12
Обзор
Документация
Войти
/
indievid
/
GigaStudio-e019bd12
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
src/lib/interview-data.ts
702 строки
44 KB
studio-agent
Squash 'studio-workflow-75590c30-d1f0-4ca2-80c3-dc0ba87c97fc' into dev
25 июл 2026, 13:34
25 июл 2026, 13:34
2a2178c
Код
Авторство
О чём код?
export type Role = | "AI Product Owner" | "AI Product Designer" | "AI Lead Developer" | "AI QA Engineer" | "AI DevOps"; export type TopicState = | "idle" | "awaiting_answer" | "awaiting_clarification" | "locked"; export type TopicId = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; export type ClarificationStepKind = "primary" | "clarification"; export type ClarificationStep = { /** индекс шага внутри темы: 0 = основной вопрос, 1..N = уточняющие */ index: number; kind: ClarificationStepKind; question: string; example: string; /** короткая подсказка «как лучше ответить» — обычно только на основном вопросе */ hint?: string; /** подпись-пояснение, что должен содержать хороший ответ */ answerGuide?: string; }; export type Topic = { id: TopicId; title: string; shortTitle: string; role: Role; roleShort: string; roleAccent: string; /** Все шаги интервью по теме: первый — основной, остальные — уточняющие. */ steps: ClarificationStep[]; state: TopicState; /** Ответ пользователя на основной вопрос (шаг 0). */ rawAnswer: string; /** Ответы на уточняющие шаги (1..N). Длина = текущий достигнутый шаг - 1 (если ещё не зафиксирована). */ clarifications: string[]; /** Готовый зафиксированный текст для ТЗ. */ lockedAnswer: string | null; }; export type MessageKind = | "ai_primary" | "ai_clarification" | "ai_sealed" | "user" | "system"; export type ChatMessage = { id: string; kind: MessageKind; role: Role | "Заказчик" | "Система"; roleShort: string; topicId: TopicId | null; /** Для ai_clarification — индекс шага внутри темы (0 = основной, 1..N = уточнения). */ stepIndex?: number; /** Всего шагов в теме (для отображения прогресса «Шаг 2/5»). */ stepTotal?: number; text: string; example?: string; hint?: string; /** Короткая подпись «что должно быть в ответе» (видна рядом с примером). */ answerGuide?: string; ts: number; }; export const ROLE_ACCENT: Record<Role, string> = { "AI Product Owner": "from-indigo-500 to-violet-500", "AI Product Designer": "from-fuchsia-500 to-pink-500", "AI Lead Developer": "from-cyan-500 to-indigo-500", "AI QA Engineer": "from-amber-500 to-rose-500", "AI DevOps": "from-emerald-500 to-teal-500", }; export const ROLE_AVATAR_INITIAL: Record<Role, string> = { "AI Product Owner": "PO", "AI Product Designer": "PD", "AI Lead Developer": "LD", "AI QA Engineer": "QA", "AI DevOps": "OP", }; function step( index: number, question: string, example: string, options?: { hint?: string; answerGuide?: string; kind?: ClarificationStepKind } ): ClarificationStep { return { index, kind: options?.kind ?? (index === 0 ? "primary" : "clarification"), question, example, hint: options?.hint, answerGuide: options?.answerGuide, }; } export function makeInitialTopics(): Topic[] { return [ { id: 1, title: "Название продукта", shortTitle: "Название", role: "AI Product Owner", roleShort: "Product Owner", roleAccent: ROLE_ACCENT["AI Product Owner"], steps: [ step( 0, "Как называется ваш продукт? Как бы вы представили его другу в одном предложении?", "Пример: FitPass — приложение, в котором клиенты за пару кликов находят и бронируют тренировки в фитнес-клубах рядом с домом или работой.", { hint: "Если у вас пока нет точного названия — придумайте рабочее, мы зафиксируем его как черновик. Главное, чтобы по названию уже было понятно, что это за продукт.", answerGuide: "Назовите продукт и коротко — для кого он и какую задачу решает.", } ), step( 1, "Это название для клиентов, торговая марка с логотипом или внутреннее рабочее имя?", "Пример: «FitPass» — это публичный бренд для клиентов и для соцсетей. Логотип и домен fitpass.ru уже есть. Внутреннее имя в команде — просто «продукт» или «наш сервис».", { answerGuide: "Уточните: бренд / логотип / домен — что уже есть, что нужно придумать.", } ), step( 2, "Есть ли у продукта слоган или короткое описание (1 предложение), которое мы запишем в ТЗ как официальное позиционирование?", "Пример: «Запишись на тренировку за 30 секунд — рядом с домом, в удобное время, без звонков администратору».", { answerGuide: "Если готового слогана нет — мы возьмём в ТЗ ваше объяснение «для друга».", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 2, title: "Пользователи и роли", shortTitle: "Роли", role: "AI Product Owner", roleShort: "Product Owner", roleAccent: ROLE_ACCENT["AI Product Owner"], steps: [ step( 0, "Кто ваши пользователи? Назовите 2–4 типа людей, которые будут пользоваться приложением.", "Пример: Клиент (занимается в клубе), Тренер (проводит тренировки), Администратор клуба (управляет расписанием и ценами), Суперадминистратор (владелец сети клубов — управляет всеми площадками).", { hint: "Старайтесь думать не про «должности», а про роли в приложении: что человек видит и что он может делать.", answerGuide: "Перечислите типы пользователей — у каждого будут свои кнопки и свои экраны.", } ), step( 1, "Чем конкретно отличаются эти роли — что каждая из них будет видеть и что сможет делать в приложении?", "Пример: Клиент — выбирает и оплачивает занятия, видит свои записи. Тренер — видит свой календарь и список записанных клиентов, может отметить посещение. Администратор клуба — управляет слотами, тренерами, ценами своего клуба. Суперадминистратор — управляет всеми клубами и видит общую статистику.", { answerGuide: "Для каждой роли: «Видит … / Может … / Не может …».", } ), step( 2, "Нужна ли авторизация (вход по логину/паролю, по SMS или через соцсети) для каждой роли?", "Пример: Клиент входит по номеру телефона + SMS-код. Тренер и администратор — по логину и паролю, которые выдаёт владелец клуба.", { answerGuide: "Для каждой роли укажите способ входа (SMS / пароль / Telegram / Google).", } ), step( 3, "Будут ли в одной учётной записи несколько ролей сразу (например, человек и клиент, и тренер)?", "Пример: Нет, у каждого человека одна роль. Если тренер сам хочет заниматься — он регистрируется как клиент в другом аккаунте.", { answerGuide: "Ответьте «да» или «нет» и коротко поясните — это повлияет на структуру профиля.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 3, title: "Главное действие", shortTitle: "Действие", role: "AI Product Owner", roleShort: "Product Owner", roleAccent: ROLE_ACCENT["AI Product Owner"], steps: [ step( 0, "Что именно пользователь должен сделать в приложении в первую очередь — самое важное «главное действие»?", "Пример: Забронировать место на тренировке: выбрать клуб, дату, время и подтвердить запись.", { hint: "Сфокусируйтесь на ОДНОМ главном действии — то, ради чего пользователь вообще открывает приложение.", answerGuide: "Опишите сценарий от «открыл приложение» до «получил результат».", } ), step( 1, "За какое максимальное количество шагов клиент должен дойти от открытия приложения до результата?", "Пример: Не больше трёх шагов — «Открыл» → «Выбрал время и тренера» → «Подтвердил и оплатил».", { answerGuide: "Чёткое число шагов — это требование к дизайну и разработке, без него они начнут «улучшать» и добавлять экраны.", } ), step( 2, "Что приложение должно показать пользователю сразу после успешного действия?", "Пример: Экран «Вы записаны» с датой, временем, адресом клуба и кнопкой «Добавить в календарь телефона». Параллельно — push-уведомление и письмо на e-mail.", { answerGuide: "Опишите экран подтверждения + какие уведомления получит клиент.", } ), step( 3, "Как клиент отменяет или переносит запись? Есть ли штраф за отмену?", "Пример: В разделе «Мои записи» — кнопка «Отменить». Отмена бесплатно — не позднее чем за 12 часов до занятия. Позже — штраф 50% от стоимости.", { answerGuide: "Опишите правила отмены: где кнопка, за сколько часов бесплатно, что с деньгами.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 4, title: "Оплата и стоимость", shortTitle: "Оплата", role: "AI Product Owner", roleShort: "Product Owner", roleAccent: ROLE_ACCENT["AI Product Owner"], steps: [ step( 0, "Планируете ли вы брать деньги с пользователей в приложении и как именно?", "Пример: Подписка 3 900 ₽/мес за безлимит + разовая оплата разовых занятий (от 800 ₽) + комиссия 3% с каждой онлайн-бронирования в пользу клуба.", { hint: "Перечислите ВСЕ денежные потоки: подписки, разовые платежи, комиссии, возвраты.", answerGuide: "Назовите типы платежей и ориентировочные суммы — точные цены уточним позже.", } ), step( 1, "Когда именно клиент платит — сразу при бронировании, при посещении или в конце месяца?", "Пример: Подписка — сразу при регистрации, разовое занятие — в момент бронирования. Возврат возможен не позднее, чем за 12 часов до занятия.", { answerGuide: "Для каждого типа платежа укажите: «когда списывается» и «можно ли вернуть».", } ), step( 2, "Какими способами клиент сможет платить (карта, СБП, кошельки, подписочные сервисы)?", "Пример: Банковские карты «Мир» / Visa / MasterCard через ЮKassa и оплата по СБП через QR-код. Apple Pay / Google Pay — по желанию клиента.", { answerGuide: "Перечислите способы оплаты — это влияет на выбор платёжного шлюза.", } ), step( 3, "Нужны ли чеки и онлайн-касса? Нужно ли формировать документы для бухгалтерии (акты, отчёты)?", "Пример: Да, нужны онлайн-чеки (54-ФЗ) и ежемесячный отчёт по платежам для бухгалтерии в формате CSV.", { answerGuide: "Если вы ИП/ООО и принимаете оплату от физлиц — чеки обязательны по закону. Зафиксируйте это явно.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 5, title: "Главный экран и кнопки", shortTitle: "Главный экран", role: "AI Product Designer", roleShort: "Product Designer", roleAccent: ROLE_ACCENT["AI Product Designer"], steps: [ step( 0, "Что именно пользователь должен увидеть на самом первом экране сразу после входа?", "Пример: Календарь свободных слотов на сегодня и большая центральная кнопка «Записаться на занятие».", { hint: "Думайте не про «все возможности», а про один главный сценарий: «зашёл → сделал главное действие».", answerGuide: "Опишите верх / центр / низ главного экрана — что расположено в каждой части.", } ), step( 1, "Сколько важных кнопок должно быть на главном экране и какие ещё блоки информации там нужны?", "Пример: Главная кнопка — «Записаться». Сверху — приветствие по имени и текущий баланс абонемента. Снизу — три небольших ярлыка: «Мои записи», «Абонемент», «Профиль».", { answerGuide: "Перечислите кнопки и блоки — это станет картой главного экрана.", } ), step( 2, "Какой стиль и настроение у приложения: строгое/деловые, дружелюбное/игровое, минимализм или насыщенный?", "Пример: Дружелюбный спортивный стиль: яркие акценты (индиго / фуксия), крупные кнопки, много «воздуха», без мелкого текста и таблиц.", { answerGuide: "Опишите 3–5 слов-ассоциаций: «спортивный, яркий, дружелюбный, простой, без таблиц».", } ), step( 3, "Где должно быть главное меню — внизу экрана (как в Instagram), слева (как в Telegram) или в «бургере»?", "Пример: Главное меню — внизу экрана, всегда видно, 4 раздела: «Главная», «Записи», «Абонемент», «Профиль».", { answerGuide: "Укажите, где меню и какие 3–5 разделов в него входят.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 6, title: "Где будет работать", shortTitle: "Платформа", role: "AI Lead Developer", roleShort: "Lead Developer", roleAccent: ROLE_ACCENT["AI Lead Developer"], steps: [ step( 0, "На каких устройствах клиенты будут открывать ваше приложение?", "Пример: Мобильное веб-приложение (PWA) для смартфонов на Android и iPhone. Десктопная версия пока не нужна.", { hint: "Если вы не знаете, что выбрать — самый быстрый и дешёвый путь сейчас это PWA (веб-приложение с установкой на домашний экран).", answerGuide: "Перечислите платформы: iOS / Android / Web / Десктоп. Можно несколько.", } ), step( 1, "Нужно ли устанавливать приложение на домашний экран телефона или достаточно открывать через браузер?", "Пример: Да, важна установка на домашний экран — клиенты должны запускать как обычное приложение, без адресной строки браузера (режим standalone).", { answerGuide: "«Да, устанавливать» или «Нет, только в браузере» — это критично для PWA и офлайн-режима.", } ), step( 2, "Должны ли базовые функции (расписание, мои записи) работать без интернета?", "Пример: Да, последнее загруженное расписание и мои записи должны быть видны офлайн. Сама запись нового занятия — только онлайн.", { answerGuide: "Перечислите, что ДОЛЖНО работать офлайн, а что только при наличии сети.", } ), step( 3, "Нужны ли push-уведомления (всплывающие сообщения на телефоне)?", "Пример: Да — напоминание за 2 часа до тренировки, подтверждение записи и важные новости от клуба.", { answerGuide: "Укажите, какие события должны присылать push-уведомления.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 7, title: "Списки и База данных", shortTitle: "База данных", role: "AI Lead Developer", roleShort: "Lead Developer", roleAccent: ROLE_ACCENT["AI Lead Developer"], steps: [ step( 0, "Какую главную информацию программа должна сохранять и помнить? Перечислите «списки» (сущности) вашего продукта.", "Пример: Пользователи (клиенты, тренеры, администраторы), Клубы, Занятия (типы тренировок), Слоты расписания (конкретные даты и время), Записи клиентов, Платежи, Абонементы.", { hint: "Представьте, что вам нужно нарисовать «таблички» на бумаге — какие это будут таблички и что в каждой из них.", answerGuide: "Назовите 5–10 «списков» (сущностей). У каждого списка будут свои поля.", } ), step( 1, "Какие основные поля нужно хранить внутри каждого такого списка?", "Пример: Пользователь — ФИО, телефон, e-mail, тип абонемента, дата рождения, пол. Запись — клиент, тренер, дата и время, статус (оплачено/ожидает/отменено). Платёж — клиент, сумма, способ, дата, статус.", { answerGuide: "Для каждого списка — 5–10 самых важных полей. Имена полей — по-русски, понятным языком.", } ), step( 2, "Какие связи между списками? (например, «у клиента много записей», «у клуба много тренеров»)", "Пример: У Клиента много Записей и много Платежей. У Клуба много Тренеров и много Слотов. У Слота один Тренер. Каждая Запись привязана к одному Слоту и к одному Клиенту.", { answerGuide: "Перечислите 5–8 ключевых связей «один-ко-многим» — этого хватит, чтобы разработчик построил базу.", } ), step( 3, "Нужно ли хранить историю изменений (например, «кто и когда менял расписание»)?", "Пример: Да, для администратора важно видеть, кто изменил слот (отменил, перенёс, поменял цену) и когда. По клиентам историю можно не хранить.", { answerGuide: "«Да, по всему» / «Только по админ-действиям» / «Нет, не нужно».", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 8, title: "Внешние сервисы", shortTitle: "Интеграции", role: "AI Lead Developer", roleShort: "Lead Developer", roleAccent: ROLE_ACCENT["AI Lead Developer"], steps: [ step( 0, "Какие сторонние программы и сервисы нужно подключить к вашему приложению для работы?", "Пример: Банковский эквайринг ЮKassa для приёма оплаты, СМС-уведомления через SMS.ru, аналитика Яндекс.Метрика, отправка писем через Unisender.", { hint: "Перечислите всё, что должно «общаться» с вашим приложением: оплата, SMS, e-mail, аналитика, карты, мессенджеры.", answerGuide: "Назовите 3–7 внешних сервисов и для чего каждый нужен.", } ), step( 1, "Нужны ли push-уведомления в браузере/телефоне, чтобы клиент получал напоминания о записи?", "Пример: Да, нужны push-уведомления — за 2 часа до тренировки, сразу после успешной записи и при отмене тренером.", { answerGuide: "Перечислите события, на которые должно приходить push-уведомление.", } ), step( 2, "Нужна ли интеграция с картами и геолокацией (например, чтобы показать клубы рядом)?", "Пример: Да, на главном экране — карта с клубами поблизости. Используем Яндекс.Карты. По клику на клуб — маршрут через приложение Яндекс.Карт или 2ГИС.", { answerGuide: "«Да, нужна карта» / «Нет, только список адресов». Если да — укажите, чьи карты.", } ), step( 3, "Нужны ли уведомления в Telegram-боте или WhatsApp-рассылки?", "Пример: Нужны уведомления в Telegram-боте — клиент получает подтверждение записи и напоминание прямо в мессенджер. WhatsApp — нет.", { answerGuide: "Какие мессенджеры задействуем и для каких сообщений.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 9, title: "Форс-мажоры и ошибки", shortTitle: "Форс-мажоры", role: "AI QA Engineer", roleShort: "QA Engineer", roleAccent: ROLE_ACCENT["AI QA Engineer"], steps: [ step( 0, "Что должно происходить в программе, если пропал интернет или произошла ошибка?", "Пример: Сохранять данные локально на телефоне и показывать предупреждение «Нет связи. Мы отправим запись, когда интернет появится».", { hint: "Думайте о худшем сценарии: человек в подвале клуба, на половине оплаты интернет моргнул — что должно произойти?", answerGuide: "Опишите поведение приложения при потере связи: что сохраняется, что показывается на экране.", } ), step( 1, "Какие сценарии считаем критичными — потеря оплаты, двойная запись, долгая загрузка?", "Пример: Критично: (1) защита от двойной записи при моргании интернета во время оплаты, (2) понятное сообщение об ошибке вместо «белого экрана», (3) автоповтор отправки данных при восстановлении связи.", { answerGuide: "Перечислите 3–5 сценариев, которые НЕЛЬЗЯ допустить ни при каких обстоятельствах.", } ), step( 2, "Как пользователь должен узнать, что что-то пошло не так? Нужны ли уведомления администратору?", "Пример: Пользователь видит конкретное сообщение «Оплата не прошла, деньги не списаны, попробуйте ещё раз». Администратору (в Telegram-бот) — уведомление о любой ошибке оплаты и о падении сервера.", { answerGuide: "Что видит клиент и что получает администратор — это два разных канала уведомлений.", } ), step( 3, "Какие сообщения об ошибках точно НЕЛЬЗЯ показывать пользователю?", "Пример: Нельзя показывать технические тексты («500 Internal Server Error», «TypeError: undefined»), зелёные «всё ок» при ошибке и пустые белые экраны. Вместо этого — дружелюбный текст на русском с понятным следующим шагом.", { answerGuide: "Перечислите «анти-примеры» ошибок, которые точно недопустимы.", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, { id: 10, title: "Размещение и адрес", shortTitle: "Хостинг", role: "AI DevOps", roleShort: "DevOps", roleAccent: ROLE_ACCENT["AI DevOps"], steps: [ step( 0, "Где именно будет физически работать готовое приложение в интернете?", "Пример: Российский VPS-сервер (Selectel или Timeweb) с защищённым адресом HTTPS и доменом fitpass.ru.", { hint: "Если вы не знаете — отметьте «хостинг в России, обычный VPS», конкретного провайдера подберём вместе с разработчиком.", answerGuide: "Страна размещения + тип сервера (облако/VPS/свой сервер) + есть ли домен.", } ), step( 1, "Какие требования по скорости работы и доступности — обычные или повышенные?", "Пример: Обычные — приложение личное, до 1 000 клиентов в день. Главное — ежедневная резервная копия базы данных и защищённый адрес HTTPS.", { answerGuide: "Сколько клиентов в день / месяц? Допускается ли простой 1–2 часа ночью?", } ), step( 2, "Нужны ли резервные копии (бэкапы) и как часто?", "Пример: Да, ежедневный бэкап базы данных, хранить 30 дней. Дополнительно — еженедельный полный бэкап всего сервера.", { answerGuide: "Как часто делать копии и сколько хранить — это конкретные цифры для админа.", } ), step( 3, "Нужна ли защита персональных данных по 152-ФЗ (Россия)?", "Пример: Да, так как храним ФИО, телефон, e-mail клиентов. Нужен договор с хостинг-провайдером о согласии на обработку ПДн и публичная «Политика конфиденциальности» в приложении.", { answerGuide: "Если есть ФИО / телефон / e-mail клиентов — практически всегда нужен 152-ФЗ. Ответьте «да» или «уточните у юриста».", } ), ], state: "idle", rawAnswer: "", clarifications: [], lockedAnswer: null, }, ]; } export const WELCOME_MESSAGE = "Приветствую! Я — ваш ИИ Бизнес-технолог студии «Индивид СтуИИя». Давайте начнём работу над детальным Техническим заданием на разработку (ТЗ).\n\nРабота по написанию ТЗ будет проходить в формате интервью, где я буду уточнять у Вас пожелания, и на основе Ваших ответов формировать ТЗ.\n\nДля Вашего удобства я буду задавать вопросы поочерёдно в режиме:\nМой вопрос → Ваш ответ → Мой уточняющий вопрос → Ваш дополнительный ответ → Я фиксирую ответ → Я задаю следующий вопрос.\n\nКоличество уточняющих вопросов по каждой теме будет разным — столько, сколько нужно, чтобы получить понятное для разработчика требование. Если тема простая — хватит пары вопросов, если сложная — я задам столько, сколько нужно.\n\nДавайте начнём? Напишите в чате — **«Да»**, чтобы я задал первый вопрос."; export const FINAL_MESSAGE = "🎉 Все 10 тем зафиксированы. Документ ТЗ готов.\n\nОткройте вкладку «📄 Готовое ТЗ» или нажмите «💾 Скачать готовое ТЗ (.md)» слева — файл сохранится к вам на устройство."; export type Preset = { id: "pwa" | "tma"; label: string; description: string; buildExampleAnswer: (topic: Topic) => { answer: string; clarifications?: string[]; } | null; }; export const PRESETS: Preset[] = [ { id: "pwa", label: "📱 PWA · Мобильное приложение", description: "Готовый блок ответов для прогрессивного веб-приложения (установка на домашний экран, push-уведомления, офлайн).", buildExampleAnswer: (topic) => { if (topic.id === 6) { return { answer: "Прогрессивное веб-приложение (PWA) — открывается в браузере смартфона (Chrome на Android, Safari на iPhone) и устанавливается на домашний экран как обычное приложение.", clarifications: [ "Да, нужна полноценная установка: перехват события установки в Chrome, пошаговая графическая подсказка «Поделиться → На экран Домой» для iOS, отдельный ярлык-иконка и запуск без адресной строки браузера (режим standalone).", "Базовые функции — последнее загруженное расписание и мои записи — должны быть доступны офлайн. Сама запись нового занятия и оплата — только при наличии интернета, с понятным сообщением «Нет связи» и авто-повтором при восстановлении.", "Push-уведомления в телефон нужны: напоминание за 2 часа до тренировки, сразу после успешной записи и при отмене тренером.", ], }; } if (topic.id === 9) { return { answer: "Если пропал интернет — приложение должно сохранять введённые данные локально на телефоне и показывать тёплое предупреждение «Нет соединения. Как только связь появится — мы автоматически отправим запись».", clarifications: [ "Критичные сценарии: (1) защита от двойной записи при моргании интернета во время оплаты, (2) понятное сообщение об ошибке вместо «белого экрана», (3) автоповтор отправки данных при восстановлении связи, (4) офлайн-просмотр уже загруженного расписания.", "Пользователь видит конкретное дружелюбное сообщение с понятным следующим шагом. Администратору — уведомление в Telegram-бот о любой ошибке оплаты и о падении сервера (health-check каждые 5 минут).", "Нельзя показывать технические тексты («500 Internal Server Error», «TypeError: undefined»), зелёные «всё ок» при ошибке и пустые белые экраны. Только дружелюбный текст на русском с понятным следующим шагом.", ], }; } return null; }, }, { id: "tma", label: "💬 Telegram Mini App", description: "Готовый блок ответов для Telegram Mini App (запуск внутри мессенджера, авторизация через Telegram, WebApp API).", buildExampleAnswer: (topic) => { if (topic.id === 6) { return { answer: "Telegram Mini App — приложение открывается внутри мессенджера Telegram через кнопку бота или ссылку t.me/... и работает как мобильный сайт без отдельной установки.", clarifications: [ "Авторизация клиента — через встроенный Telegram Login (по номеру телефона и ID пользователя, без отдельного пароля). Используем Telegram WebApp API для нативной кнопки «Закрыть», темы оформления и данных профиля.", "Базовые функции — последнее загруженное расписание и мои записи — должны быть доступны офлайн внутри Telegram. Сама запись нового занятия — только при наличии интернета.", "Push не нужны — все уведомления идут через бота в Telegram (см. тему «Внешние сервисы»).", ], }; } if (topic.id === 8) { return { answer: "Telegram Bot API — для отправки уведомлений клиенту прямо в мессенджер (вместо SMS и e-mail). Для приёма оплаты — ЮKassa или Prodamus (российский эквайринг, который работает с Telegram-ботами).", clarifications: [ "Push-уведомления через бота в Telegram: подтверждение записи, напоминание за 2 часа до занятия и итоговое сообщение после посещения. СМС не нужны.", "Карты и геолокация не нужны — список клубов с адресами и кнопкой «Открыть в Яндекс.Картах».", "Telegram-бот используется ТОЛЬКО для уведомлений. Все остальные каналы (e-mail, SMS, WhatsApp) — не нужны.", ], }; } if (topic.id === 9) { return { answer: "Если пропал интернет в Telegram Mini App — показываем встроенное предупреждение Telegram (через WebApp.showAlert) и сохраняем черновик действия локально в браузере. При восстановлении связи — отправляем автоматически.", clarifications: [ "Критично: (1) защита от двойной записи при потере связи во время оплаты, (2) понятное сообщение об ошибке через нативный попап Telegram, (3) сохранение состояния формы при сворачивании мини-приложения.", "Пользователь видит нативный попап Telegram с конкретным следующим шагом. Администратору — уведомление в этот же Telegram-бот об ошибках оплаты и health-check сервера.", "Нельзя показывать технические тексты, зелёные «всё ок» при ошибке и пустые экраны. Только дружелюбный текст на русском с понятным следующим шагом.", ], }; } return null; }, }, ];