From 26c0ac0e58e2f9f13a110d72d4cefedd5b780481 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Thu, 4 Jun 2026 15:59:56 +0300 Subject: [PATCH] =?UTF-8?q?docs(assistant):=20=D0=B4=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D0=B9=D0=BD-=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=20=C2=AB=D0=9A=D0=B2=D0=B0=D0=BD=D1=82=D0=B8=D0=BA-=D0=B0?= =?UTF-8?q?=D1=81=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BD=D1=82=C2=BB=20(?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D0=BE=D0=B2=D1=8B=D0=B9,?= =?UTF-8?q?=20=D0=B1=D0=B5=D0=B7=20=D0=BA=D0=BE=D0=B4=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit План сквозного ассистента поверх существующего питомца: контекстные подсказки, проактивные напоминания из реальных данных, поздравления, онбординг-тур. Архитектура (assistant.js через sidebar.js, правиловый движок, анти-назойливость), каталог правил, фазы Ф0–Ф4, открытые вопросы. Co-Authored-By: Claude Opus 4.8 (1M context) --- plans/pet-assistant/PLAN.md | 246 ++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 plans/pet-assistant/PLAN.md diff --git a/plans/pet-assistant/PLAN.md b/plans/pet-assistant/PLAN.md new file mode 100644 index 0000000..3ddce08 --- /dev/null +++ b/plans/pet-assistant/PLAN.md @@ -0,0 +1,246 @@ +# Квантик-ассистент — дизайн-документ + +> Статус: **дизайн** (код не пишем). Движок подсказок: **правиловый/эвристический** (без 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: , // карточек к повторению + 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`).