# Квантик-ассистент — дизайн-документ

> Статус: **дизайн** (код не пишем). Движок подсказок: **правиловый/эвристический** (без LLM).
> Цель: превратить существующего питомца «Квантик» в сквозного ассистента, который
> помогает работать в системе, подсказывает и проактивно напоминает.

---

## 1. Цель и принципы

Маленький плавающий компаньон (тот же Квантик) присутствует на всех страницах и:
1. **Подсказывает по контексту страницы** — что тут можно, неочевидные фичи.
2. **Проактивно напоминает** — из реальных данных (домашка, карточки, урок, серия, квесты).
3. **Радуется успехам** — левелап, ачивка, серия, тест на 100%.
4. **Ведёт новичка** — короткий тур по разделам при первом входе.
5. **Отвечает «как сделать X»** — поиск по справке/FAQ (LLM — за рамками, точка расширения).

Принципы:
- **Единая личность** — имя/цвет/настроение из `/api/pet`, лицо — `pet-sprite.js`. Никакого второго персонажа.
- **Не назойливый** — один пузырь за раз, дневной лимит, кулдауны, «понял / не показывать», тихий режим, выключаемость.
- **Детерминированный** — правила и шаблоны на реальных данных, предсказуемо и офлайн.
- **Без эмоджи в коде** — только inline SVG `.ic` (правило проекта). Тексты подсказок — тоже без эмоджи.
- **Лёгкий** — не грузит страницы, ленивая инициализация, минимум сетевых запросов.

Не-цели (сейчас): свободный диалог/LLM; голос; геймификация поверх (ачивки за общение — позже, Ф4).

---

## 2. Что уже есть (фундамент)

- **Питомец «Квантик»**: 8 уровней по XP, настроение (`_mood` от серии/дней без входа), аксессуары
  (`_accessories`: hat/glasses/crown/star), монеты, поглаживание/кормёжка, **дневные квесты** (`_quests`),
  недельный XP, лента активности, прогноз настроения (`_moodForecast`), цвета, магазин фонов.
- **`GET /api/pet`** (`petController.getPet`) уже отдаёт: `petName, petLevel, petColor, mood,
  daysSinceLogin, accessories, xp, level, streakCurrent, streakBest, coins, quests[], moodForecast,
  recentActivity[], weeklyXP[], xpForNextLevel`. → почти весь контекст для подсказок берётся отсюда.
- **`pet-sprite.js`** — `window.PetSprite.render(level, mood, accessories, colorKey, streak)` → SVG.
  Переиспользуем как «лицо» ассистента (мини-версия в пузыре).
- Показ: страница `/pet` + виджет на `/dashboard`.
- **Онбординга/туров/подсказок в системе нет** — строим с нуля, конфликтов не будет.
- **Точка инъекции:** глобальные скрипты подключаются на каждой app-странице
  (`api.js`, `sidebar.js`, `search.js`, `notifications.js`, `mobile.js`). `sidebar.js` есть везде →
  он догружает `assistant.js` одной строкой, HTML страниц не трогаем.
- Питомец — фича за `requireFeature('pet')` (см. `server.js`).

---

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

```
sidebar.js (на каждой странице)
   └─ догружает /js/assistant.js (если фича включена и не отключено юзером)
        ├─ Assistant.boot()
        │    ├─ собирает ctx (page + данные)
        │    ├─ прогоняет реестр правил → выбирает 1 подсказку по приоритету/кулдауну
        │    └─ рисует компаньона + пузырь (лицо = PetSprite.render)
        ├─ assistant-rules.js — реестр правил (данные, не логика)
        └─ состояние/капы — localStorage (+ опц. сервер в Ф1+)
```

### 3.1. Компоненты (файлы — создаём в фазах, не сейчас)
- `frontend/js/assistant.js` — движок + UI (стили инжектит сам, как `board-clip.js`).
- `frontend/js/assistant-rules.js` — каталог правил (отдельно, чтобы правила правились без движка).
- `js/sidebar.js` — +строка ленивой загрузки ассистента.
- `frontend/profile.html` — настройки (вкл/выкл, частота, сброс подсказок).
- (Ф1) `backend/src/routes/assistant.js` + `controllers/assistantController.js` — `GET /api/assistant/context`.
- (Ф1, опц.) миграция: серверная отметка «видел подсказку» для кросс-девайс (иначе только localStorage).

### 3.2. Движок: контекст и правила

**Контекст `ctx`** (собирается при загрузке страницы):
```js
{
  path, page,            // page — нормализованный id ('textbook','classroom','exam-prep',...)
  role,                  // student | teacher | admin
  isFirstVisit,          // нет ни одной отметки о показе
  pet,                   // кэш /api/pet (мин. TTL, чтобы не дёргать на каждой странице)
  data: {                // лениво/из /api/assistant/context (Ф1)
    homeworkDue: [{title, deadline, status}],
    dueCards: <int>,     // карточек к повторению
    activeLesson: {courseId, title, pct} | null,
    weakTopics: [...],
    quests: [...]        // из /api/pet
  },
  events: [...],         // свежие левелап/ачивка (детект по дельте)
  now
}
```

**Форма правила:**
```js
{
  id: 'textbook-clip',
  scope: 'page' | 'proactive' | 'celebration',
  when: (ctx) => boolean,        // условие показа
  priority: 50,                  // больше = важнее (celebration > proactive > page)
  cooldownDays: 7,               // не чаще раза в N дней
  maxShows: 3,                   // пожизненный лимит показов
  suppressOn: ['exam-run','board-draw'], // не мешать в фокусных режимах
  text: (ctx) => 'Можно вырезать кусок страницы в «Мои материалы».',
  action: (ctx) => ({ label: 'Показать', url: null, run: fn }) | null,
  petMood: 'happy'               // настроение лица (опц.)
}
```

**Алгоритм выбора:** отфильтровать `when && !suppressed && подходит по кулдауну/лимиту`,
отсортировать по `scope`-весу + `priority`, взять **одно**. Показ — по триггеру (см. 3.3).

### 3.3. Анти-назойливость (критично)
- **1 пузырь** на экране за раз.
- Триггеры показа: page-подсказка — через 6–8 с на странице **или** по наведению на компаньона;
  proactive — раз в сессию на категорию; celebration — сразу по событию.
- **Дневной лимит** проактивных подсказок (по умолчанию 3).
- **Кулдаун** на правило + **пожизненный maxShows**.
- Кнопки в пузыре: «Понятно» (скрыть), «Не показывать» (навсегда для этого правила).
- **Тихий режим** и глобальный выключатель в профиле.
- **Не мешать в фокусе:** скрывать на странице запущенного теста, во время рисования на доске,
  на онлайн-уроке (`suppressOn`).
- `prefers-reduced-motion` — без анимаций/конфетти.

### 3.4. Хранение состояния
- localStorage: `asst_off` (вкл/выкл), `asst_freq`, `asst_seen:{ruleId}={count,lastTs}`,
  `asst_mute_until`, `asst_pet_level`/`asst_ach_seen` (для детекта событий).
- (Опц., Ф1) сервер: таблица `assistant_seen(user_id, rule_id, count, last_at)` для кросс-девайс —
  иначе подсказки повторятся на другом устройстве. Решить в Открытых вопросах.

---

## 4. Каталог правил (черновик)

### 4.1. Контекстные (scope: page) — «что тут можно»
| id | страница | текст (суть) | действие |
|----|----------|--------------|----------|
| textbook-clip | /textbook | Вырежи кусок страницы картинкой в «Мои материалы» | подсветить кнопку «Вырезать область» |
| textbook-deeplink | /textbook | Можно делиться ссылкой прямо на параграф | — |
| board-tools | /classroom, /board | Лассо, фигуры, формулы KaTeX, линейка — попробуй панель | — |
| exam-modes | /exam-prep | Режимы: экзамен / тренировка / случайный | — |
| lab-sims | /lab | Симуляции запускаются прямо тут, без установки | — |
| flashcards-katex | /flashcards | Формулы вводятся через KaTeX-палитру | — |
| materials-folders | /my-materials | Раскладывай материалы по папкам и аннотируй фото | — |
| dashboard-widgets | /dashboard | Виджеты дашборда можно настроить под себя | — |

### 4.2. Проактивные (scope: proactive) — из реальных данных
| id | условие | текст | действие |
|----|---------|-------|----------|
| hw-due-soon | есть домашка с дедлайном < 24ч и не сдана | Домашка «X» — дедлайн скоро | → /homework |
| hw-overdue | есть просроченная несданная | Просрочена домашка «X» | → /homework |
| cards-due | dueCards > 0 | К повторению N карточек | → /flashcards |
| lesson-continue | есть незаконченный урок | Продолжи «X» (N%) | → /course?id=... |
| streak-risk | streakCurrent ≥ 1 и сегодня нет активности (вечер) | Серия N дней под угрозой — закрепи | → /exam-prep |
| quest-nudge | есть незакрытый дневной квест | Добей квест: «X» | → соответствующий раздел |
| weak-topic | низкий средний по теме | Подтяни тему «X» | → тест/учебник по теме |

### 4.3. Поздравления (scope: celebration) — по событию
| id | триггер | реакция |
|----|---------|---------|
| levelup | pet.level вырос с прошлой проверки | Квантик ecstatic + «Уровень N!» |
| achievement | новая ачивка | поздравление + название |
| streak-milestone | серия достигла 3/7/14/30 | поздравление + аксессуар-намёк |
| test-perfect | тест на 100% (из recentActivity) | поздравление |

> Эмоджи в существующих квестах (`⭐📝🔥` в `petController._quests`) заменить на inline SVG `.ic`
> при интеграции — для соответствия правилу проекта.

---

## 5. Источники данных (всё уже в системе)

| Нужно | Откуда |
|-------|--------|
| настроение/серия/квесты/прогноз/уровень | `GET /api/pet` |
| домашка + дедлайны | assignments (как на дашборде: `asgn-row urgent/over`) |
| карточки к повторению | flashcards SRS (`LS.fc*`) |
| незаконченный урок | `/api/courses` (`doneCount/lessonCount`) / `lesson_progress` |
| слабые темы | analytics по `test_sessions` |
| левелап/ачивки | дельта `/api/pet` (level, xp) + список ачивок |

**Рекомендация (Ф1):** один эндпоинт `GET /api/assistant/context` собирает компактный бандл
(`homeworkDue, dueCards, activeLesson, weakTopics`), чтобы не дёргать 4 API с клиента.

---

## 6. UI / UX

- **Компаньон:** мини-Квантик (≈48–56px) в правом-нижнем углу (на мобиле — выше `mob-bar`, не перекрывая).
  Лёгкое «дыхание»; при наличии подсказки — мягкий пульс/бейдж.
- **Пузырь:** speech-bubble над компаньоном: текст (1–2 строки) + опц. кнопка действия +
  «Понятно» + «Не показывать». Закрытие: кнопка, клик вне, Esc.
- **Состояния:** idle / has-hint / bubble-open / celebrating (конфетти + ecstatic) / hidden.
- **Стиль:** дизайн-система `ls.css` (переменные `--violet/--text/--text-3`), inline SVG `.ic`,
  тёмная тема, без эмоджи. Тон: дружелюбный, на «ты», кратко.
- **A11y:** `aria-live="polite"` на пузыре, фокус/Esc, уважение `prefers-reduced-motion`.
- **Перетаскивание/сворачивание** компаньона (запоминать позицию) — опц., Ф2.

---

## 7. Настройки и приватность
- Профиль: переключатель «Ассистент Квантик», частота (обычная/низкая), «Сбросить подсказки».
- Фича-флаг: reuse `pet` **или** новый `assistant` (решить — см. Открытые вопросы).
- Роли: ученики — основной сценарий; учителям — отдельный набор подсказок (Ф4); по умолчанию для
  admin, возможно, выключен.
- Никакой персональной телеметрии наружу; состояние — локально (+опц. своя таблица).

---

## 8. Фазы

- **Ф0 — каркас:** `assistant.js` + `assistant-rules.js`, плавающий Квантик (лицо из `pet-sprite`),
  пузырь, dismissal/кулдауны/лимиты, вкл/выкл, инъекция через `sidebar.js`, 5–6 правил §4.1.
- **Ф1 — проактив:** `GET /api/assistant/context` + правила §4.2 + поздравления §4.3 (детект событий).
- **Ф2 — онбординг-тур** новичка по разделам + все контекстные подсказки + «не показывать снова» +
  (опц.) перетаскивание/сворачивание.
- **Ф3 — «Спроси Квантика»:** окно с поиском по справке/FAQ (использует `search.js`).
  Точка расширения под LLM — **за рамками этого плана**.
- **Ф4 — персонализация:** частота/тон, режим для учителей, ачивки за взаимодействие, на страницах
  учебника (серверный inject) тоже.

---

## 9. Затрагиваемые файлы (при будущей реализации)
- + `frontend/js/assistant.js`, `frontend/js/assistant-rules.js`
- ~ `js/sidebar.js` (одна строка-загрузчик)
- ~ `frontend/profile.html` (настройки)
- (Ф1) + `backend/src/routes/assistant.js`, `backend/src/controllers/assistantController.js`,
  mount в `server.js` (+ возможный фича-флаг `assistant`)
- (Ф1, опц.) + миграция `assistant_seen`
- ~ `petController._quests` — заменить эмоджи на `.ic` при интеграции

---

## 10. Открытые вопросы (обсудить перед Ф0)
1. **Фича-флаг:** переиспользуем `pet` или заводим отдельный `assistant`? (ассистент шире питомца).
2. **Кому по умолчанию вкл:** всем ученикам? учителям? admin — выкл?
3. **Кросс-девайс «видел»:** localStorage достаточно, или нужна серверная таблица `assistant_seen`?
4. **Учебник (серверный рендер):** включать ассистента и там (через inject) сразу или в Ф4?
5. **Тон/частота по умолчанию:** насколько активно напоминать (консервативно vs заметно)?
6. **«Спроси Квантика» (Ф3):** только справка/FAQ, или сразу закладываем место под локальную модель?

---

## 11. Риски
- **Назойливость** — главный риск; смягчается лимитами/кулдаунами/тихим режимом (§3.3).
- **Перекрытие UI** (особенно мобайл, существующие FAB вроде «Вырезать область», `flashcard-fab.js`) —
  согласовать z-index и позиции, не накладываться.
- **Лишние запросы** — кэш `/api/pet`, один бандл-эндпоинт, ленивая инициализация.
- **Рассинхрон личности** — всегда брать имя/цвет/настроение из одного источника (`/api/pet`).
