Files
Learn_System/plans/pet-assistant/PLAN.md
T
Maxim Dolgolyov 26c0ac0e58 docs(assistant): дизайн-документ «Квантик-ассистент» (правиловый, без кода)
План сквозного ассистента поверх существующего питомца: контекстные подсказки,
проактивные напоминания из реальных данных, поздравления, онбординг-тур.
Архитектура (assistant.js через sidebar.js, правиловый движок, анти-назойливость),
каталог правил, фазы Ф0–Ф4, открытые вопросы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:59:56 +03:00

247 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Квантик-ассистент — дизайн-документ
> Статус: **дизайн** (код не пишем). Движок подсказок: **правиловый/эвристический** (без 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`, 56 правил §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`).