# Техническое задание

# Telegram-бот + MiniApp «AI-подбор техники для кухни ЗОВ»

**Версия:** 1.0
**Дата:** 2026-05-08
**Заказчик:** Василий (vasrusgen@gmail.com), куратор партнёрской сети ЗОВ
**Канал:** [@wasrusgen1](https://t.me/wasrusgen1)
**Целевая аудитория продукта:** 112 менеджеров салонов ЗОВ + конечные клиенты, ведомые через канал

---

## 1. Контекст и цели

### 1.1 Что это за продукт

Telegram-бот выступает шлюзом авторизации, после чего открывается единый MiniApp с двумя ролями:

- **Кабинет менеджера** — рабочий инструмент: подбор техники для клиента, замеры, заявки, сделки, статус доступа.
- **Кабинет клиента** — воронка покупки кухни: замер, подбор, калькулятор, идеи, связь с менеджером.

Внутри MiniApp клиент или менеджер заполняют структурированный чек-лист. Данные уходят в backend, который вызывает LLM (OpenAI / Claude). LLM возвращает готовое предложение по технике с учётом брендов, ниш, бюджета и сценария использования. Результат доставляется обратно в Telegram.

### 1.2 Какую проблему решает

- Сокращает срок согласования кухни с клиентом (главная боль ЗОВ).
- Привязывает менеджера к куратору: «работаешь со мной — инструмент бесплатно, ушёл — платно».
- Превращает 112 менеджеров в управляемую партнёрскую сеть с метриками.
- Даёт клиентам бесплатную ценность до контакта с менеджером (калькулятор, идеи, самозамер).

### 1.3 Бизнес-модель в продукте

| Сегмент | Доступ | Условие |
|---|---|---|
| Менеджеры ЗОВ (свои салоны) | бесплатно навсегда | по умолчанию |
| Менеджеры партнёрских салонов, активные | бесплатно | сделка через куратора за последние 90 дней |
| Менеджеры партнёрских салонов, неактивные | платно | подписка / pay-per-use |
| Конечные клиенты | базовый доступ бесплатно | подбор + замер открыты, премиум-функции потом |

Точное определение «активного менеджера» — поле `last_order_date` в реестре + 90 дней.

### 1.4 Что в скоупе MVP

- Бот с одним диалогом (выбор роли + кнопка «Открыть кабинет»).
- MiniApp с двумя меню (менеджер / клиент), но **рабочих пунктов всего три**:
  - 🔧 «Подбор техники» (для менеджера, на базе существующего HTML-чек-листа `02_Чек-лист_клиенту.html`).
  - 📐 «Самозамер» (для клиента, новая 5-шаговая форма).
  - 💰 «Мой статус» (для менеджера, простая страница).
- Backend на Google Apps Script + Google Sheet как БД.
- AI-подбор через OpenAI API (`gpt-4o-mini`) с готовым промптом.
- Доставка результата менеджеру через бота.

### 1.5 Что НЕ в скоупе MVP (на будущее)

- Платёжная интеграция (ЮKassa / Telegram Stars).
- Раздел «Сделки», «База знаний», «Обучение», «FAQ», «Записаться в салон».
- Личный кабинет клиента с историей.
- Push-уведомления об активности.
- Партнёрская комиссия с производителей техники.
- Мобильное нативное приложение (всегда останется MiniApp).

---

## 2. Архитектура

### 2.1 Компоненты

```
Telegram канал @wasrusgen1
        │ кнопка/ссылка "Открыть подбор"
        ▼
Telegram бот @zov_tech_bot
        │ /start → выбор роли → кнопка WebApp
        ▼
MiniApp (SPA, HTML+JS)
   на хостинге GitHub Pages / Netlify (HTTPS обязателен)
        │ POST /api/*
        ▼
Backend Google Apps Script (Web App URL)
        │ R/W
        ▼
Google Sheet "ЗОВ — База"
        │
        │ при подборе:
        ▼
OpenAI API (gpt-4o-mini)
        │ результат
        ▼
Backend → Telegram Bot API → менеджер/клиент
```

### 2.2 Технологический стек

| Слой | Технология | Обоснование |
|---|---|---|
| Бот | Python + aiogram **либо** n8n + Telegram Trigger | aiogram — гибче, n8n — без кода |
| MiniApp | HTML + Vanilla JS + минимальный CSS | существующий чек-лист уже в этом стеке |
| Хостинг MiniApp | GitHub Pages | бесплатно, HTTPS, Git-history |
| Backend | Google Apps Script (Web App) | бесплатно, нативная связка с Sheet |
| БД | Google Sheet | прозрачность для заказчика, ручное редактирование |
| AI | OpenAI API, модель `gpt-4o-mini` | дёшево (~$0.001 на запрос), хватает для подбора |
| Платежи (вне MVP) | ЮKassa или Telegram Stars | российские реалии |

### 2.3 Окружения

- **Dev:** локальный HTML, бот в режиме polling, тестовая Google Sheet.
- **Prod:** GitHub Pages, бот в режиме webhook, прод-Sheet с реестром.

---

## 3. Бот @zov_tech_bot

### 3.1 Общие принципы

- Бот **не содержит продуктовой логики**. Он только аутентифицирует и открывает MiniApp.
- Все длинные диалоги, формы, чек-листы — внутри MiniApp.
- Бот шлёт результаты подбора и системные уведомления.

### 3.2 Команды

| Команда | Доступ | Действие |
|---|---|---|
| `/start` | все | приветствие, выбор роли (если новый пользователь) или кнопка «Открыть кабинет» (если уже зарегистрирован) |
| `/start <invite_code>` | все | спец-сценарий: переход по ссылке-приглашению от менеджера |
| `/menu` | все | повторная кнопка «Открыть кабинет» |
| `/help` | все | краткая справка + контакт куратора |
| `/admin` | только админ (tg_id куратора) | админ-меню (см. 3.5) |

### 3.3 Дерево диалогов

```
[НОВЫЙ ПОЛЬЗОВАТЕЛЬ]
/start
  │
  ▼
"👋 Здравствуйте! Я помогу подобрать технику для кухни.
Кто вы?"
[👤 Менеджер]   [🏠 Клиент]
  │                  │
  ▼                  ▼
сохранить           сохранить
role=manager        role=client
в БД                в БД
  │                  │
  ▼                  ▼
"Отлично, открываю    "Спасибо! Открываю
ваш кабинет 👇"      кабинет 👇"
[🚀 Открыть кабинет] [🚀 Открыть кабинет]
       (WebApp button с URL MiniApp)


[ВЕРНУВШИЙСЯ ПОЛЬЗОВАТЕЛЬ]
/start
  │
  ▼
"С возвращением, {имя}!"
[🚀 Открыть кабинет]


[ССЫЛКА-ПРИГЛАШЕНИЕ ОТ МЕНЕДЖЕРА]
/start client_inv_AB12CD
  │
  ▼
проверить invite_code в БД
  │ найден → manager_id = X
  ▼
сохранить role=client + manager_id=X
  ▼
"Здравствуйте! Вас сопровождает {ФИО менеджера}, ЗОВ {салон}.
Открываю кабинет 👇"
[🚀 Открыть кабинет]
```

### 3.4 Кнопка «Открыть кабинет»

Это **WebApp-кнопка** Telegram (не URL-button), которая открывает MiniApp с подписанным `initData`.

Параметр `web_app.url`:
```
https://wasrusgen.github.io/zov-tech/?v=1
```
`initData` содержит `tg_id`, имя пользователя, hash для проверки. Backend проверяет hash и определяет роль по БД.

### 3.5 Админ-функции (для куратора)

Команда `/admin` доступна только при `tg_id == ADMIN_TG_ID` (env-переменная).

Меню:
- `📊 Статистика` — сколько активных менеджеров, заявок за неделю, конверсия
- `👤 Управление менеджерами`
  - `+ Добавить менеджера` (диалог: ФИО, tg_username, salon)
  - `✏️ Изменить статус` (выбор → active / lapsed + дата)
  - `🔍 Найти менеджера` (по ФИО / tg_username)
- `📨 Рассылка` — отправить сообщение всем менеджерам / всем клиентам / выбранным сегментам

### 3.6 Системные уведомления (исходящие от бота)

| Триггер | Получатель | Текст |
|---|---|---|
| Клиент завершил подбор | менеджер этого клиента | «Новая заявка от {ФИО клиента}: {short_summary}. [Открыть в кабинете]» |
| Менеджер запросил подбор | менеджер | «Готово! Подбор для {ФИО клиента}: [PDF / текст]» |
| Клиент сделал самозамер | менеджер этого клиента | «{ФИО клиента} прислал замер кухни. [Посмотреть]» |
| Статус менеджера изменён куратором | менеджер | «Ваш доступ продлён до {дата}» / «Доступ переведён в платный режим» |

Все уведомления сопровождаются inline-кнопкой, открывающей соответствующий экран MiniApp.

### 3.7 Технические требования к боту

- Режим **webhook** в проде, polling в деве.
- Хранилище состояний — память (FSM aiogram) или Redis для масштаба. На MVP — память.
- Логирование всех `update` в файл / Sheet «Логи бота».
- Обработка ошибок: при exception — сообщение «Произошла ошибка, мы уже разбираемся» + alert куратору.

### 3.8 Регистрация бота в @BotFather

1. `/newbot` → `zov_tech_bot` (или альтернативное имя, если занято).
2. `/setdomain` → домен MiniApp (`wasrusgen.github.io`).
3. `/newapp` → создать MiniApp:
   - Title: «Подбор техники ЗОВ»
   - Short name: `podbor`
   - Web App URL: `https://wasrusgen.github.io/zov-tech/`
4. `/setmenubutton` → опционально, кнопка-меню в боте, ведущая в MiniApp.

---

## 4. MiniApp

### 4.1 Карта страниц (hash-роутинг внутри одного SPA)

```
#/                        — авто-редирект по роли
#/m                       — главное меню менеджера
#/m/podbor                — чек-лист подбора (существующий HTML)
#/m/measurements          — список замеров
#/m/measurements/new      — форма замера (менеджер за клиента)
#/m/measurements/:id      — карточка одного замера
#/m/leads                 — список заявок (просмотр, MVP — read-only)
#/m/status                — мой статус и доступ
#/m/help                  — связь с куратором

#/c                       — главное меню клиента
#/c/measure               — выбор: вызвать замерщика / замерить самому
#/c/measure/self          — 5-шаговая форма самозамера
#/c/measure/visit         — заявка на выезд замерщика
#/c/podbor                — упрощённый чек-лист (вне MVP, заглушка)
#/c/contact               — связь с менеджером
```

### 4.2 Авторизация и определение роли

```js
// Псевдокод старта MiniApp
const tg = window.Telegram.WebApp;
tg.ready();
tg.expand();

const initData = tg.initData;       // подписанная строка
const startParam = tg.initDataUnsafe.start_param || null;

const me = await fetch('/api/me', {
  method: 'POST',
  body: JSON.stringify({ initData, startParam })
}).then(r => r.json());

// me = { role: "manager"|"client", user: {...}, manager: {...}, status: "active"|"lapsed" }

if (me.role === 'manager') router.go('#/m');
else router.go('#/c');
```

Backend `/api/me`:
1. Проверяет HMAC `initData` по `BOT_TOKEN` (стандартная процедура Telegram).
2. Ищет `tg_id` в листе «Пользователи».
3. Если нет — создаёт запись (роль уже сохранена ботом, должна быть в БД).
4. Возвращает профиль + статус.

### 4.3 Кабинет менеджера

**Главный экран `#/m`:**

```
┌─────────────────────────────────────┐
│  Привет, {ФИО}                      │
│  Салон: {salon}                     │
│  Статус: 🟢 active до 12.08.2026    │
│                                     │
│  ───────────────────────────────    │
│                                     │
│  🔧  Подбор техники для клиента  →  │
│  📐  Замеры                      →  │
│  📋  Заявки клиентов             →  │
│  💼  Сделки  (скоро)             ·  │
│  📚  База знаний  (скоро)        ·  │
│  💰  Мой статус                  →  │
│  🆘  Связь с куратором           →  │
└─────────────────────────────────────┘
```

Пункты «Сделки», «База знаний» в MVP — disabled-кнопки с текстом «Скоро».

**Страница `#/m/podbor`:**

Это существующий файл `02_Чек-лист_клиенту.html` с минимальными доработками:
1. Удалить захардкоженный блок менеджера (Любовь Алпеева) — подставлять из `me.user`.
2. Добавить поле «Размеры ниш» (см. п. 4.5 — пробелы из анализа).
3. Добавить поле «Бюджет по категориям».
4. Добавить блок «Сценарий использования» (семья, готовка).
5. Кнопку «Отправить» завести на `POST /api/podbor` вместо `mailto:`.
6. После отправки — `tg.showAlert('Заявка отправлена, результат придёт в чат')` + `tg.close()`.

**Страница `#/m/measurements`:**

Список замеров клиентов этого менеджера. Колонки: дата, ФИО клиента, статус (🟡 запрошен / 🟢 готов / 🔵 загружен вручную), кнопка «Открыть».

**Страница `#/m/measurements/new`:**

Та же форма, что и у клиента в `#/c/measure/self`, но с дополнительным полем «Клиент» (выбор из списка или ввод).

**Страница `#/m/status`:**

```
┌─────────────────────────────────────┐
│  Ваш статус                         │
│                                     │
│  🟢 Active                          │
│  Доступ продлён до 12.08.2026       │
│  Осталось 96 дней                   │
│                                     │
│  Последняя сделка через куратора:   │
│  «Кухня Петров, 14.05.2026»         │
│                                     │
│  Заявок за всё время: 23            │
│  Сделок через подбор: 7 (30%)       │
│                                     │
│  Чтобы продлить доступ —            │
│  проведите следующую сделку         │
│  через @wasrusgen.                  │
└─────────────────────────────────────┘
```

Если `status == lapsed`:

```
┌─────────────────────────────────────┐
│  ⚠️  Доступ ограничен               │
│                                     │
│  Последняя сделка через куратора    │
│  была 12.02.2026.                   │
│  Бесплатный доступ закончился.      │
│                                     │
│  Варианты:                          │
│  • Возобновить сопровождение через  │
│    @wasrusgen — доступ снова free.  │
│  • Подписка 3 000 ₽/мес.            │
│  • Pay-per-use 500 ₽/подбор.        │
│                                     │
│  [Связаться с куратором]            │
│  [Оформить подписку] (вне MVP)      │
└─────────────────────────────────────┘
```

### 4.4 Кабинет клиента

**Главный экран `#/c`:**

```
┌─────────────────────────────────────┐
│  Привет, {имя}                      │
│  {если есть}                        │
│  Менеджер: {ФИО}, ЗОВ {салон}       │
│                                     │
│  ───────────────────────────────    │
│                                     │
│  📐  Замер кухни                 →  │
│  🔧  Подобрать технику   (скоро) ·  │
│  📐  Калькулятор бюджета (скоро) ·  │
│  💡  Идеи и кейсы        (скоро) ·  │
│  📞  Связаться с менеджером      →  │
│  📍  Записаться в салон  (скоро) ·  │
└─────────────────────────────────────┘
```

В MVP активны: «Замер кухни», «Связаться с менеджером».

**Страница `#/c/measure`:**

Развилка:
```
Выберите способ замера:

[📞 Вызвать замерщика]
   Бесплатно при заказе кухни
   2 000 ₽ — отдельная услуга

[📏 Замерить самому]
   5 шагов с инструкцией
   Займёт ~15 минут
```

**Страница `#/c/measure/self`:**

5 экранов, каждый — отдельный шаг. Прогресс-бар сверху.

**Шаг 1: План кухни**
- Выбор формы (radio-картинки): прямая / Г-образная / П-образная / с островом / свой вариант
- Поле «Площадь, м²» (number)
- Поле «Высота потолка, мм» (number, default 2700)

**Шаг 2: Стены и габариты**
- Длина стены 1, мм
- Длина стены 2, мм (если Г-/П-образная)
- Длина стены 3, мм (если П-образная)
- Загрузка фото общего вида (опционально)

**Шаг 3: Окна и двери**
- Чекбоксы: «Есть окно» / «Есть дверь» / «Есть выход на балкон»
- Для каждого активного — поля: положение (выбор стены), ширина, высота, расстояние от пола

**Шаг 4: Коммуникации (важно для AI-подбора)**
- Тип подключения варочной: газ / электрика 220 / электрика 380
- Наличие вентиляционной шахты на кухне: да / нет / не знаю
- Расположение мойки: стена 1 / 2 / 3 / остров
- Свободное поле «Особенности коммуникаций»

**Шаг 5: Ниши под технику (если планируется встройка)**
Чекбокс «Планирую встроенную технику» → раскрывает блок:
- Холодильник: Ш × В × Г, мм
- Варочная: Ш × В × Г, мм
- Духовой шкаф: Ш × В × Г, мм
- Посудомойка: Ш × В × Г, мм
- Стиральная (если на кухне): Ш × В × Г, мм
- Микроволновка: Ш × В × Г, мм
- Кофемашина: Ш × В × Г, мм

Поля опциональные. Если не планируется встройка — блок свёрнут, шаг можно пропустить.

**Финал:**
- Кнопка «Сохранить замер».
- POST `/api/measurement` → сохранение + уведомление менеджеру (если manager_id привязан).
- `tg.showAlert('Замер сохранён')` + `tg.close()`.

### 4.5 Доработки существующего чек-листа подбора

Согласно анализу `02_Чек-лист_клиенту.html` нужно добавить:

1. **Блок «Параметры кухни»** в онбординг (или подгружать из последнего замера).
2. **Бюджет по категориям** — простая таблица в финальном экране.
3. **Блок «Семья и готовка»** — 4–5 быстрых вопросов с радиокнопками:
   - Состав семьи: 1 взрослый / пара / семья с детьми / 2+ поколения
   - Частота готовки: ежедневно / 3–4 раза в неделю / реже
   - Любимые техники: выпечка / на пару / гриль / wok / низкотемпературное (multi-select)
   - Приём гостей: часто / иногда / редко
4. **Чекбокс «уже есть, не меняю»** в каждой категории — клиент исключает позиции.
5. **Webhook вместо `mailto:`** — POST на backend.
6. **Обязательные поля**: имя, контакт, общий бюджет, адрес.

### 4.6 Дизайн-токены (брендинг ЗОВ)

Использовать существующие в HTML переменные:
```css
:root {
  --bronze: #76BD22;   /* фирменный зелёный */
  --accent: #003E7E;   /* фирменный синий */
  --cream:  #FAFAFA;
  --sand:   #F0F9E8;
}
```

Шрифт — системный sans-serif (как в текущем HTML). Скруглённые углы 8px, тени минимальные.

---

## 5. База данных (Google Sheets)

Файл: **«ЗОВ — База»** (один документ, несколько листов).

### 5.1 Лист «Users»

Все пользователи бота (менеджеры + клиенты).

| Колонка | Тип | Описание |
|---|---|---|
| tg_id | number | Telegram user ID, **первичный ключ** |
| tg_username | text | @username, может отсутствовать |
| first_name | text | Имя из Telegram |
| last_name | text | Фамилия из Telegram |
| role | text | `manager` / `client` / `admin` |
| created_at | datetime | Дата первого `/start` |
| last_seen_at | datetime | Последний контакт с ботом |
| invite_code_used | text | Код приглашения, если был |

### 5.2 Лист «Managers»

Расширенный профиль менеджеров.

| Колонка | Тип | Описание |
|---|---|---|
| tg_id | number | FK → Users.tg_id |
| full_name | text | ФИО полное |
| email | text | Рабочая почта |
| phone | text | Телефон |
| salon | text | Название салона |
| city | text | Город |
| is_zov_employee | bool | true = свой, false = партнёр |
| status | formula | `=IF(active_until>=TODAY();"active";"lapsed")` |
| last_order_date | date | Дата последней сделки через куратора |
| active_until | formula | `=last_order_date+90` |
| total_leads | formula | `=COUNTIF(Leads.manager_tg_id; tg_id)` |
| total_deals | number | Заполняется куратором вручную |
| conversion_rate | formula | `=total_deals / total_leads` |
| invite_code | text | Уникальный код для генерации client-ссылок (например `MGR_AB12`) |

### 5.3 Лист «Clients»

| Колонка | Тип | Описание |
|---|---|---|
| tg_id | number | FK → Users.tg_id |
| full_name | text | |
| phone | text | |
| email | text | |
| address | text | |
| city | text | |
| budget_total | number | Общий бюджет на кухню + технику |
| manager_tg_id | number | FK → Managers.tg_id, **связка клиент—менеджер** |
| source | text | `channel` / `manager_invite` / `direct` |
| last_measurement_id | text | FK → Measurements.id |

### 5.4 Лист «Measurements»

| Колонка | Тип | Описание |
|---|---|---|
| id | text | UUID |
| created_at | datetime | |
| client_tg_id | number | FK → Clients.tg_id |
| manager_tg_id | number | FK → Managers.tg_id |
| filled_by | text | `client_self` / `manager_for_client` |
| layout | text | прямая / Г / П / остров / другое |
| area_m2 | number | |
| ceiling_mm | number | |
| walls_json | json-text | `{"w1":3200,"w2":2400,"w3":null}` |
| openings_json | json-text | окна, двери |
| infra_json | json-text | газ/электрика, шахта, мойка |
| niches_json | json-text | размеры ниш под встройку |
| photos_urls | text | через запятую |
| notes | text | |
| status | text | `draft` / `submitted` / `verified` |

### 5.5 Лист «Leads» (заявки на подбор)

| Колонка | Тип | Описание |
|---|---|---|
| id | text | UUID |
| created_at | datetime | |
| manager_tg_id | number | кто отправил |
| client_tg_id | number | для кого |
| client_name | text | |
| measurement_id | text | FK → Measurements.id, может быть пусто |
| checklist_json | json-text | весь ответ чек-листа |
| ai_response | long-text | результат от LLM |
| ai_model | text | `gpt-4o-mini` |
| ai_tokens_used | number | для контроля расходов |
| sent_to_tg | bool | результат доставлен в Telegram |
| deal_status | text | `new` / `in_progress` / `won` / `lost` (заполняет менеджер вручную или куратор) |
| deal_amount | number | сумма закрытой кухни |

### 5.6 Лист «Logs»

Лог всех action-событий (для дебага и аналитики).

| Колонка | Тип |
|---|---|
| timestamp | datetime |
| event | text (`bot_start`, `role_selected`, `miniapp_opened`, `measurement_submitted`, `lead_created`, `ai_response_received`, `ai_error`, ...) |
| tg_id | number |
| payload | json-text |

### 5.7 Лист «Settings»

Параметры, которые могут меняться без правки кода.

| key | value | description |
|---|---|---|
| ACTIVE_PERIOD_DAYS | 90 | срок active-статуса после сделки |
| GRACE_PERIOD_DAYS | 14 | grace-период перед переводом в lapsed |
| AI_MODEL | gpt-4o-mini | какая модель используется |
| AI_TEMPERATURE | 0.3 | температура для подбора |
| ADMIN_TG_ID | <ваш tg_id> | кто получает алерты |
| PAID_PRICE_PER_LEAD | 500 | цена pay-per-use |
| PAID_SUBSCRIPTION | 3000 | цена подписки |

### 5.8 Лист «Dashboard» (для куратора)

Сводка с формулами:

```
Активных менеджеров:        =COUNTIF(Managers.status; "active")
Lapsed-менеджеров:           =COUNTIF(Managers.status; "lapsed")
Заявок за 30 дней:           =COUNTIFS(Leads.created_at; ">="&TODAY()-30)
Конверсия в сделку:          =COUNTIF(Leads.deal_status; "won") / COUNTA(Leads.id)
Средний чек закрытых сделок: =AVERAGEIF(Leads.deal_status; "won"; Leads.deal_amount)
Топ-5 менеджеров по сделкам: pivot
Расход на AI за 30 дней:     =SUMPRODUCT(Leads.ai_tokens_used) * 0.0000015 * <курс>
```

---

## 6. Backend (Google Apps Script)

### 6.1 Структура проекта

```
ZOV_Backend.gs
├─ doPost(e)                  — единая точка входа, роутер
├─ /api/me                    — определить пользователя по initData
├─ /api/measurement           — сохранить замер
├─ /api/podbor                — создать заявку, вызвать AI, отправить в Telegram
├─ /api/lead/:id              — получить заявку (для менеджера)
├─ /api/manager/status        — статус менеджера
├─ helpers/
│   ├─ verifyInitData(initData, botToken)
│   ├─ readSheet(sheetName, query)
│   ├─ writeSheet(sheetName, row)
│   ├─ callOpenAI(prompt, params)
│   ├─ sendTelegram(chatId, text, options)
│   └─ generateUuid()
```

### 6.2 Деплой

1. Привязать скрипт к Google Sheet «ЗОВ — База».
2. Deploy → New deployment → Type «Web app».
3. Execute as: «Me».
4. Who has access: «Anyone» (для приёма запросов с MiniApp).
5. Получить URL `https://script.google.com/macros/s/.../exec` — это backend endpoint, прописать в MiniApp как `BACKEND_URL`.

### 6.3 Переменные окружения (Script Properties)

| Ключ | Описание |
|---|---|
| `BOT_TOKEN` | Токен бота от BotFather |
| `OPENAI_API_KEY` | ключ OpenAI |
| `ADMIN_TG_ID` | ваш Telegram ID |
| `SHEET_ID` | ID Google Sheet |

### 6.4 Безопасность

- Все запросы из MiniApp **обязаны** содержать `initData` от Telegram.
- Backend проверяет HMAC `initData` по `BOT_TOKEN` (стандартная процедура).
- Без валидного `initData` любой запрос → 401.
- Документация процедуры: <https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app>

### 6.5 Бизнес-логика статусов менеджера

```pseudo
function getManagerStatus(tg_id):
  m = Managers.find(tg_id)
  if not m: return "unknown"
  if m.is_zov_employee: return "active"            // свои всегда active
  active_until = m.last_order_date + ACTIVE_PERIOD_DAYS
  grace_until  = active_until + GRACE_PERIOD_DAYS
  today = TODAY()
  if today <= active_until: return "active"
  if today <= grace_until:  return "grace"          // мягкое предупреждение
  return "lapsed"
```

---

## 7. AI-подбор

### 7.1 Входные данные (контракт LLM-вызова)

JSON, который backend собирает перед отправкой в OpenAI:

```json
{
  "client": {
    "name": "Пётр Сидоров",
    "city": "Москва",
    "family": "пара_с_ребёнком",
    "cooking_frequency": "ежедневно",
    "favorite_techniques": ["выпечка", "пар"],
    "guests": "иногда"
  },
  "kitchen": {
    "layout": "Г-образная",
    "area_m2": 12,
    "ceiling_mm": 2700,
    "walls": { "w1": 3200, "w2": 2400 },
    "infra": {
      "stove_power": "электрика_220",
      "vent_shaft": true
    },
    "niches": {
      "fridge": { "w": 600, "h": 1850, "d": 600 },
      "hob":    { "w": 600, "h": 60,   "d": 520 },
      "oven":   { "w": 600, "h": 600,  "d": 560 },
      "dw":     { "w": 450, "h": 820,  "d": 555 }
    }
  },
  "budget": {
    "total": 350000,
    "by_category": {
      "fridge": 80000,
      "hob": 50000,
      "oven": 60000,
      "hood": 25000,
      "dw": 50000,
      "microwave": 15000,
      "coffee": 40000,
      "washer": 30000
    }
  },
  "preferences": {
    "fridge": {
      "tier": "middle",
      "brands_preferred": ["Bosch", "Liebherr"],
      "brands_alternative": ["Samsung"],
      "type": "двухкамерный",
      "color": "inox",
      "features": ["NoFrost", "инвертор", "≤40 дБ"]
    },
    "hob": { "...": "..." }
    /* и т.д. для всех 8 категорий, как в чек-листе */
  },
  "exclusions": ["microwave"]   // уже есть, не подбирать
}
```

### 7.2 Промпт (system + user)

**System prompt:**

```
Ты — эксперт-консультант по подбору кухонной техники для фабрики мебели «ЗОВ».
Ты работаешь с менеджерами салонов и помогаешь им быстро согласовать с клиентом
комплект техники под их кухню.

Принципы подбора:
1. Физические ограничения важнее эстетики. Если ниша 600×1850×600 — не предлагай
   холодильник 700×2000×650, даже если он лучше.
2. Уважай бюджет. Если в категории задан лимит — не превышай его более чем на 10%.
3. Уважай предпочтения по брендам. Сначала пробуй preferred (★), потом alternative (✓),
   потом нейтральные альтернативы. Если ни один preferred бренд не подходит по цене —
   скажи прямо.
4. Связывай выбор со сценарием использования. Семья с детьми = простота интерфейса,
   защита от детей, легко мыть. Любитель выпечки = пар + 4D HotAir + термощуп.
5. Учитывай инфраструктуру. Газ исключает индукцию (если пользователь не готов
   менять подключение). Нет шахты = только рециркуляция в вытяжке.
6. По каждой позиции: модель, цена, 2-3 ключевых преимущества под этого клиента,
   1 предупреждение/нюанс если он есть.

Формат ответа — JSON по схеме:
{
  "summary": "1-2 предложения",
  "items": [
    {
      "category": "fridge",
      "brand": "Bosch",
      "model": "KGN39LB35R",
      "price_rub": 79990,
      "size_mm": { "w": 600, "h": 2030, "d": 660 },
      "fits_niche": true,
      "highlights": ["NoFrost", "инвертор", "тихий 39 дБ"],
      "caveats": "Глубина 660мм — на 60мм глубже стандартной ниши, проверьте",
      "match_score": 0.92,
      "rationale": "Соответствует предпочтениям по бренду и тиру..."
    }
  ],
  "total_price_rub": 350000,
  "budget_status": "в рамках" | "превышение" | "значительно ниже",
  "warnings": ["..."],
  "next_steps": ["..."]
}

Не выдумывай несуществующие модели. Если не уверен в модели — указывай линейку
("Bosch Serie 4, 60см, NoFrost") а не конкретный артикул.

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

Отвечай только валидным JSON без оборачивания в markdown-блоки.
```

**User prompt:**

```
Подбери технику для следующего клиента:

{JSON_INPUT}

Дай развёрнутое предложение в формате, описанном в инструкции.
```

### 7.3 Параметры вызова OpenAI

```python
{
  "model": "gpt-4o-mini",
  "temperature": 0.3,
  "max_tokens": 4000,
  "response_format": { "type": "json_object" }
}
```

### 7.4 Постобработка ответа

Backend получает JSON от OpenAI и:
1. Валидирует схему. При расхождении — алёрт куратору, ответ всё равно пытается доставить.
2. Сохраняет в `Leads.ai_response` (raw JSON).
3. Рендерит в человекочитаемый вид (текст + кнопки).
4. Отправляет менеджеру через бота:

```
✅ Подбор готов

Клиент: Пётр Сидоров
Бюджет: 350 000 ₽

🧊 Холодильник
Bosch Serie 4 KGN39LB35R — 79 990 ₽
✓ NoFrost, инвертор, тихий 39 дБ
⚠️ Глубина 660мм — на 60мм больше ниши, проверьте

🔥 Варочная панель
Electrolux EHF6342XOK — 49 990 ₽
✓ Hi-Light, защита от детей, простой интерфейс
...

ИТОГО: 348 970 ₽ (в рамках бюджета)

[📄 Скачать предложение для клиента]
[💬 Открыть в кабинете]
```

---

## 8. Безопасность и приватность

### 8.1 Аутентификация

- Все вызовы backend от MiniApp подписаны `initData` Telegram.
- Backend верифицирует HMAC `initData` ≤ 24 часов давности.
- Без подписи → 401.

### 8.2 Контроль доступа

- Менеджер видит **только свои** заявки и замеры (фильтр `WHERE manager_tg_id = me.tg_id`).
- Клиент видит **только свои** замеры.
- Куратор (admin) видит всё.

### 8.3 Хранение PII

- Имена, телефоны, адреса клиентов лежат в Google Sheet куратора.
- Доступ к Sheet — только у куратора.
- В логи не пишутся телефоны/email открытым текстом — только маскированно (`+7***1234`).

### 8.4 Согласие на обработку данных

- При первом `/start` клиент получает короткое сообщение:

> Заполняя форму подбора, вы соглашаетесь с обработкой данных в рамках консультации по подбору кухни. Подробнее — [политика](https://wasrusgen.github.io/zov-tech/privacy.html).

- Простая HTML-страница `privacy.html` рядом с MiniApp.

---

## 9. Метрики успеха MVP

Через 60 дней после запуска проверяем:

| Метрика | Целевое значение |
|---|---|
| Зарегистрированных менеджеров | ≥ 60 из 112 |
| Менеджеров, сделавших ≥1 подбор | ≥ 30 |
| Сделанных замеров клиентами | ≥ 50 |
| Заявок на подбор | ≥ 80 |
| AI-подборов с положительной обратной связью | ≥ 70% |
| Время от заявки до результата | ≤ 60 секунд |
| Конверсия подбор → закрытая сделка | ≥ 20% |
| Стоимость одного подбора (AI) | ≤ 0.5 ₽ |

---

## 10. Дорожная карта после MVP

**Спринт 4 (через 1 месяц после MVP):**
- Раздел «Сделки» с возможностью менеджеру отмечать выигранные сделки.
- Авто-продление статуса по факту отметки сделки (с подтверждением куратора).
- Раздел «База знаний» с гайдами и сравнениями.

**Спринт 5 (через 2 месяца):**
- Платный режим для lapsed-менеджеров через ЮKassa или Telegram Stars.
- Подписка / pay-per-use, биллинг.

**Спринт 6 (3+ месяца):**
- Записаться в салон (выбор салона + дата + слот).
- Личный кабинет клиента с историей замеров и заявок.
- Раздел «Идеи и кейсы» с галереей.
- Партнёрки с производителями техники.

---

## 11. Чек-лист запуска

```
[ ] Бот создан в @BotFather, токен сохранён в Apps Script Properties
[ ] Домен MiniApp привязан к боту (/setdomain)
[ ] MiniApp зарегистрирован в @BotFather (/newapp)
[ ] HTML захостен на GitHub Pages, HTTPS работает
[ ] Google Sheet «ЗОВ — База» создан, листы 5.1—5.7 готовы
[ ] Apps Script деплой как Web App, URL получен
[ ] OpenAI ключ получен, лимиты выставлены ($20/мес)
[ ] Реестр 112 менеджеров загружен в Sheet «Managers»
[ ] Свои менеджеры ЗОВ помечены is_zov_employee=true
[ ] Существующий чек-лист `02_Чек-лист_клиенту.html` доработан (4.5)
[ ] Форма самозамера реализована (4.4 шаги 1-5)
[ ] AI-промпт протестирован на 5 синтетических заявках
[ ] Уведомления бота работают (3.6)
[ ] Privacy-страница опубликована
[ ] /admin меню работает только для ADMIN_TG_ID
[ ] Бот переведён в режим webhook
[ ] Закрепили пост в канале с кнопкой WebApp
[ ] Сделали внутренний прогон с 3 «своими» менеджерами
```

---

## 12. Контакты и ответственные

| Роль | Кто | Контакт |
|---|---|---|
| Заказчик / куратор | Василий | vasrusgen@gmail.com, @wasrusgen |
| Канал | @wasrusgen1 | |
| Telegram-бот | @zov_tech_bot (после регистрации) | |
| MiniApp URL | https://wasrusgen.github.io/zov-tech/ (плановый) | |

---

## 13. Приложение: что отдаём разработчику

При выдаче ТЗ разработчику передаём:
1. Этот документ (`ТЗ_ЗОВ_Бот_MiniApp_v1.md`).
2. Текущий HTML-чек-лист `02_Чек-лист_клиенту.html`.
3. Доступ к Telegram-каналу @wasrusgen1 (для размещения кнопки).
4. Креды от Google-аккаунта для создания Sheet и Apps Script.
5. (После регистрации бота) — токен и admin_tg_id в зашифрованном виде.

**Ожидаемое время выполнения MVP:** 5–7 рабочих дней.
**Ожидаемая стоимость инфраструктуры в месяц:** $5–15 (только OpenAI, всё остальное бесплатно).
