Files
notes-qpid-pro/TODO.md
T

315 lines
35 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.
# 📋 Задачи проекта: study.qpid.pro (Backlog & Execution Queue)
Список задач для последовательной реализации в рамках принципов **Ponytail** (максимальная надёжность, нативные средства платформы, zero-dependency, высокая скорость).
---
## 🚀 Очередь реализации (Пошаговый план)
### 1. 📑 Полноценный рендеринг Markdown (.md) в читалке
- [x] **Блоки кода (Fenced Code Blocks ```` ```language ````)**:
- Выделение блоков кода в контейнер `<pre><code class="language-...">`.
- Моноширинный шрифт (`JetBrains Mono`, `Consolas`), сохранение отступов и табуляции (`white-space: pre`).
- Тёмная подложка, горизонтальный скролл при переполнении, отключение красной строки (`text-indent: 0`).
- Кнопка «Копировать код» в шапке блока.
- Отключение создания интерактивных словарных спанов `<span class="reader-word">` для кода, чтобы синтаксис не ломал форматирование.
- [x] **Инлайн-код (`` `variable` ``)**:
- Оборачивание в нативный тег `<code class="reader-inline-code">` с бейджик-стилем.
- [x] **Списки и цитаты**:
- Преобразование маркированных (`- `, `* `) и нумерованных (`1. `) списков в `<ul><li>` / `<ol><li>`.
- Преобразование цитат (`> `) в `<blockquote>` с акцентной левой границей.
- **Слова внутри списков и цитат остаются кликабельными** (интерактивный клик-перевод работает!).
- [x] **Заголовки Markdown (`##`, `###`)**:
- Конвертация в `<h3>`, `<h4>` с удалением сырых решёток `#`.
- [x] **Таблицы Markdown (`| col | col |`)**:
- Адаптивные таблицы с рамками, стилизацией заголовков `<thead>`, зебра-подсветкой строк и горизонтальным скроллом на мобильных.
- Каждая ячейка поддерживает интерактивные слова для изучения и инлайн-код.
- [x] **HTML-блоки и теги в Markdown (`<p align="center">`, `<h1>`, `<em>`, `<strong>`, `<sub>`, `<br>`)**:
- Нативный парсинг через встроенный `DOMParser` без внешних библиотек.
- Устранена утечка сырых тегов (`<picture>`, `<source>`, `<p align=...>`) в словарные слова.
- [x] **Ссылки и изображения (`[text](url)`, `![alt](url)`, `<img>`)**:
- Поддержка бейджей shields.io, тренд-графиков и внешних картинок.
- Автоматическое скрытие битых/отсутствующих локальных путей (`assets/...`) через обработчик `onerror`.
- [x] **Точное позиционирование окна перевода у курсора/слова (Popup Positioning)**:
- Исправлен баг двойного смещения координат: убран `window.scrollY` при `position: fixed`.
- Окно перенесено в корень `<body>` для исключения искажений контекста позиционирования.
- Плавное отслеживание скролла через `requestAnimationFrame` с автозакрытием при уходе слова за границы экрана или под липкую шапку.
- [x] **Стилизация в CSS ([`app/static/css/style.css`](file:///home/ai-projects/services/study.qpid.pro/app/static/css/style.css))**:
- Добавлены стили для `.reader-content-body pre`, `code`, `blockquote`, `ul`, `ol`, `.reader-table`, `.reader-heading`, `.reader-link`, `.reader-img`.
---
### 2. 🗜️ Сжатие статического трафика (`GZipMiddleware`)
- [x] Подключить `GZipMiddleware(minimum_size=1000)` в [`app/main.py`](file:///home/ai-projects/services/study.qpid.pro/app/main.py).
- [x] Сократить объём передаваемых файлов `app.js` (111.8 КБ -> 21.5 КБ), `index.html` (55.2 КБ -> 10.3 КБ) и `style.css` (58.2 КБ -> 9.4 КБ) на 81.7% (суммарно с 225.2 КБ до 41.2 КБ).
- [x] Проверить заголовки `Content-Encoding: gzip` в ответах и добавить регрессионный тест в `tests/test_api.py`.
---
### 3. 🛡️ Дедупликация слов и защита от повторного добавления (Reader + API)
- [x] **Проверка дубликатов на бэкенде (`POST /api/cards`)**:
- Проверка слова без учёта регистра `lower(trim(term))`.
- При повторном добавлении не создаётся дубликат, а дополняется контекстное предложение и объединяются теги, возвращается `already_exists: True`.
- [x] **Индикация в читалке и карточке поиска**:
- В читалке при клике на слово и в карточке поиска выводится бейдж `⭐ В библиотеке`.
- Кнопка «+ В словарь» заменяется на бейдж `⭐ Слово уже в библиотеке` с опциональной кнопкой `+ Добавить эту цитату к карточке`.
- [x] **Индекс целостности в SQLite**:
- Создан `UNIQUE INDEX idx_vocab_user_term_nocase ON vocabulary_cards(user_id, term COLLATE NOCASE);` гарантирующий отсутствие дубликатов на уровне движка БД за $O(\log N)$.
- [x] **Слияние существующих дубликатов в базе**:
- Объединены дубликаты `admired` (ID 5 и ID 7) и `suddenly`/`Suddenly` (ID 2 и ID 9) с объединением контекстных предложений, слиянием тегов и сохранением прогресса SRS.
---
### 4. 📱 Мобильная оптимизация и адаптивная верстка (iPhone 12 / iOS Safari)
- [x] **Системный фундамент iOS и сброс ограничений (Core Foundation)**:
- Метатег `viewport`: добавлен `viewport-fit=cover` для поддержки выреза (notch) и нижней панели iPhone.
- Устранение бага принудительного авто-зума: установлен `font-size: 16px` для `<input>`, `<textarea>`, `<select>` на экранах `≤ 768px`.
- Внедрены динамические единицы `100dvh` (Dynamic Viewport Height) и безопасные отступы `env(safe-area-inset-top)` / `env(safe-area-inset-bottom)`.
- Защита от горизонтального сдвига (`overflow-x: hidden` на `html`, `body` и `#app-shell`).
- [x] **Мобильная навигация: переход к нативному паттерну (App Header + Bottom Tab Bar)**:
- Компактная верхняя шапка для смартфонов: логотип `📖 Notes`, переключатель темы `🌓`, кнопка вызова профиля `⚙️`.
- Фиксированная нижняя панель вкладок (Bottom Tab Bar) с нативным iOS UX:
1. 🔍 **Словарь** (Поиск и словарь)
2. 🎓 **Тренажёр** (SRS с бейджем количества повторений)
3. 📚 **Читалка** (Библиотека книг)
4. 📊 **Прогресс** (Статистика и стрик)
5. ⚙️ **Меню** (Смена пароля, экспорт, выход)
- Полное сохранение десктопного `navbar` без изменений на больших экранах (`> 768px`).
- [x] **Адаптация экрана словаря и карточек (Dictionary & Cards View)**:
- Поле поиска/перевода на полную ширину экрана с кнопкой «Перевести».
- Скрытие неактуальных десктопных подсказок горячих клавиш (`<kbd>Ctrl+Enter</kbd>`) на мобильных устройствах.
- Вертикальная раскладка полей метаданных при редактировании карточки.
- Горизонтальный скролл чипсов коллекций и тегов (`overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch`).
- Увеличенные зоны нажатия (Touch Targets ≥ 44px) для кнопок действий над карточкой.
- [x] **Интерактивная читалка и переход к Mobile Bottom Sheet**:
- Трансформация всплывающего попапа перевода (`reader-word-popup`) в нативную выдвижную нижнюю шторку (Bottom Sheet) на смартфонах с ручкой перетаскивания `sheet-drag-handle`.
- Двухстрочный адаптивный тулбар читалки (навигация по главам + размер шрифта `A-/A+` и подсветка).
- Сетка библиотеки `bookshelf-grid` в одну колонку на экранах `≤ 640px`.
- [x] **Тренажёр интервальных повторений (SRS Trainer)**:
- Ограничение высоты карточки SRS (`max-height: 48dvh`), чтобы карточка и кнопки оценки гарантированно помещались без вертикального скролла на 390px.
- Кнопки оценки (Снова / Трудно / Хорошо / Легко) в сетку 2×2 с высотой от 48px и четкими цветовыми акцентами.
- Вертикальный список вариантов в режиме квиза (4 варианта) на всю ширину экрана.
- [x] **Модальные окна (Статистика, Пароль, Экспорт)**:
- Метрики статистики в сетку 2×2 вместо сжатых 4 колонок.
- Плавный горизонтальный скролл календаря активности (Heatmap).
- Разворачивание модальных окон в адаптивный мобильный слой с удобной кнопкой закрытия.
---
---
### 5. 🔤 Кастомизация оформления читалки (Типографика, темы, отступы, LocalStorage)
- [x] **Панель настроек оформления текста (`Aa`)**:
- Кнопка вызова настроек в тулбаре читалки: поповер на ПК и выдвижная шторка (Bottom Sheet) на смартфонах.
- [x] **Настройка размера шрифта и степпер**:
- Степпер `A-` / `A+` с индикатором точного размера (от 14px до 34px).
- [x] **Семейство шрифтов (Font Family)**:
- Переключение в 1 клик между `Sans` (системный), `Serif` (книжный с засечками), `Mono` (моноширинный).
- [x] **Межстрочный интервал (Line Height)**:
- Компактный (1.35), Оптимальный (1.65), Широкий (1.95).
- [x] **Поля и ширина колонки (Margins & Max Width)**:
- Узкие поля (940px), Стандарт (760px), Книжная колонка (600px).
- [x] **Цветовые темы читалки (Themes)**:
- 🌙 Тёмная (Dark Slate), 📜 Сепия (Тёплый пергамент), ☀️ Светлая (Чистый лист), 🖤 OLED (Абсолютный чёрный).
- [x] **Выравнивание текста (Text Alignment)**:
- По левому краю / По ширине (Justified).
- [x] **Автосохранение и персистентность**:
- Мгновенное реактивное применение стилей через CSS-переменные без перезагрузки и сохранение настроек в `localStorage`.
---
### 6. 🔄 Комплексная переработка навигации, роутинга и честного прогресса чтения (Completed)
- [x] **6.1. Нативная маршрутизация окон (URL Hash Router & Zero-Flicker F5)**:
- Внедрение хэш-роутинга: `#dictionary`, `#srs`, `#bookshelf`, `#reader/:book_id`, `#reader/:book_id/ch/:chapter_idx`.
- Синхронное переключение `view` при старте скрипта (до любых сетевых запросов авторизации): если в URL `#reader/...`, сразу скрывать `#dictionary-view` и показывать скелетон читалки, устраняя мигание словарем.
- Развязка асинхронных вызовов: `loadBookshelf()` больше не должен принудительно гасить `readerInterface`, если уже инициировано открытие книги через `openBook()`.
- Поддержка нативной истории браузера (кнопки «Назад» / «Вперёд» на мыши, клавиатуре и мобильных свайпах).
- Автоматическая синхронизация активного экрана в URL и `localStorage`.
- [x] **6.2. Честный непрерывный расчет прогресса книги и главы (Weighted Reading Progress)**:
- Устранение бага ложных «100%»: полная ликвидация формулы `(current_ch + 1) / total_ch`, выдававшей 100% на первой странице одноглавных документов.
- Прогресс текущей главы в реальном времени: непрерывный расчет от вертикального скролла (`scrollTop / (scrollHeight - clientHeight) * 100`) от 0% до 100%.
- Взвешенный общий прогресс книги: расчет по объему слов прочитанных глав + точная доля текущей главы:
$$\text{TotalProgress} = \frac{\sum_{i=0}^{\text{cur}-1} \text{words}(ch_i) + \text{words}(ch_{\text{cur}}) \times \frac{\text{ChapterPct}}{100}}{\text{TotalWords}} \times 100\%$$
- Для документа на 1000 слов прогресс будет плавно расти: 0% $\rightarrow$ 15% $\rightarrow$ 50% $\rightarrow$ 100%.
- Отображение честного суммарного прогресса на карточках книг в библиотеке и в тулбаре читалки.
- [x] **6.3. Интеллектуальный парсинг глав и оглавление (Smart Chapter & ToC Detection)**:
- Расширение детектора глав в `app/reader.py`:
- Markdown-заголовки всех уровней (`# `, `## `, `### `, `#### `).
- Нумерованные разделы и модули (`1. `, `1.1 `, `2.0 `, `Section 1`, `Part 1`, `Раздел 1`).
- Выделенные строки в верхнем регистре (ALL CAPS) от 3 до 60 символов, обрамленные пустыми строками (`INTRODUCTION`, `ETHERNET BASICS`).
- Жирные заголовки в начале абзацев (`**Chapter 1**`, `**Глава 1**`).
- Адаптивный порог авто-разбивки: снижение порога чанкования текста без явных глав с 3000 до 800–1000 слов, чтобы даже небольшие статьи имели логическое деление на части.
- Интерактивное оглавление со статусами прочтения: `✔ Прочитано`, `▶ В процессе (45%)`, `○ Не начато`.
- [x] **6.4. Устойчивая фиксация позиции чтения (Paragraph Anchor + Scroll)**:
- Сохранение не только пикселей `scrollTop`, но и индекса первого видимого абзаца (`anchor_paragraph_idx`).
- Устойчивость к изменению шрифта `Aa` и ориентации экрана: восстановление скролла к конкретному предложению/абзацу, а не слепым пикселям.
- Фиксация скролл-контейнера `#reader-scroll-area` с аппаратным ускорением на мобильных.
- [x] **6.5. Сквозное чтение и бесшовная автоподгрузка (Continuous Book View & Seamless Infinite Append)**:
- Режим «Вся книга целиком» (`flowMode: 'continuous'`): объединение всех глав книги в один непрерывный свиток со стильными разделителями глав без необходимости перелистывания.
- Режим «По главам» с автоподгрузкой (`autoLoadNext: true`): бесшовное присоединение следующей главы снизу при приближении к концу текущей главы.
- Навигационный блок завершения главы: эргономичные кнопки «◀ Назад» и «Следующая: [Название] ▶» прямо под текстом (без необходимости тянуться наверх).
- Настройка режима чтения («По главам» / «Вся книга») и переключатель автоподгрузки добавлены в панель настроек `Aa` с автосохранением в `localStorage`.
- Карточка завершения книги (`🎉 Книга прочитана!`) с быстрыми ссылками на тренировку слов и возврат в библиотеку.
---
### 7. 📑 Поддержка чтения PDF (Cisco CCNA, O'Reilly & Tech Books с оглавлением и текстовым слоем) (Completed)
- [x] **Легковесный Pure-Python парсер (`pypdf`, Zero C-Dependency)**:
- Подключение `pypdf` (< 400 КБ, чистый Python, без раздувания Docker-образа и без системных библиотек `poppler-utils` / `mupdf`).
- [x] **Извлечение оглавления и закладок PDF (`reader.outline`)**:
- Извлечение авторского оглавления (ToC / Bookmarks), стандартного для книг Cisco Press (CCNA Official Cert Guide), O'Reilly и Wiley.
- Разбивка книги на логические главы и разделы (`Part I`, `Chapter 1`, `Chapter 2`) точно по оглавлению автора.
- [x] **Fallback-разбивка при отсутствии оглавления**:
- При отсутствии PDF-закладок — автоопределение заголовков через regex (`Chapter \d+`, `Глава \d+`) или группировка страниц порциями по ~12–15 страниц.
- [x] **Очистка шума и колонтитулов**:
- Фильтрация повторяющихся верхних/нижних колонтитулов («CCNA 200-301 Official Cert Guide», «Page 45 of 900»).
- [x] **Сохранение CLI/Console блоков**:
- Распознавание консольного вывода и команд сетевого оборудования (`Router# show ip interface brief`, `Switch(config)#`) и оборачивание в блоки кода Markdown для читалки с кнопкой «Копировать».
- [x] **Защита от сканов без OCR (Scanned PDF Guard)**:
- Валидация наличия текстового слоя: если суммарный объём извлечённого текста < 100 слов, возврат информативной ошибки с предложением использовать текстовый PDF или OCR.
- [x] **Интеграция в интерфейс читалки**:
- Разрешение загрузки `.pdf` в `<input type="file" accept=".epub,.pdf,.txt,.md">`.
- Обновление кнопки в библиотеке: `📁 Загрузить EPUB / PDF / TXT`.
---
### 7.1. 🖼️ Извлечение и отображение схем, топологий и диаграмм из PDF / EPUB (Planned)
- [ ] **Извлечение бинарных изображений на диск**:
- При парсинге PDF/EPUB извлекать графические объекты (`page.images` / архивы изображений) на файловую систему в изолированную директорию книги: `data/books/{book_id}/images/{img_name}`.
- Избегать раздувания базы данных SQLite: база хранит только текст и метаданные, бинарная графика хранится на диске.
- [ ] **Кэширующий медиа-эндпоинт**:
- Создать эндпоинт `GET /api/books/{book_id}/images/{image_name}` с заголовками кэширования (`Cache-Control: public, max-age=31536000, immutable`).
- [ ] **Встраивание в текст читалки**:
- Привязывать иллюстрации к соответствующей странице/главе через Markdown-теги: `![Схема топологии](/api/books/{book_id}/images/{img_name})`.
- Интерактивный просмотр и зум схем по клику в читалке.
---
### 8. 🔌 Пул соединений HTTP (`httpx.AsyncClient` с Keep-Alive) (Completed)
- [x] В [`app/dictionary.py`](file:///home/ai-projects/services/study.qpid.pro/app/dictionary.py) создать синглтон-клиент `get_http_client()` с пулом соединений:
```python
limits = httpx.Limits(max_keepalive_connections=10, max_connections=20, keepalive_expiry=60.0)
```
- [x] Заменить вызовы `async with httpx.AsyncClient()` в парсерах на переиспользуемый клиент.
- [x] Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив задержку внешних запросов на 300–600 мс.
- [x] Добавить вызов `close_http_client()` в `lifespan` FastAPI при остановке приложения для чистого закрытия открытых сокетов.
- [x] Добавить юнит-тесты `test_http_connection_pooling` в `tests/test_api.py` (22/22 passed).
---
### 9. 🗄️ Тюнинг SQLite PRAGMA и составных индексов
- [x] В [`app/database.py`](file:///home/ai-projects/services/study.qpid.pro/app/database.py):
- Вынесен `PRAGMA journal_mode=WAL;` в однократную инициализацию `init_db()` и миграции (устранены повторные блокировки и запись заголовка файла на каждый HTTP-запрос).
- Включены высокопроизводительные параметры памяти Linux для каждого соединения:
```python
conn.execute("PRAGMA synchronous = NORMAL;")
conn.execute("PRAGMA mmap_size = 268435456;") # 256MB memory-mapped I/O
conn.execute("PRAGMA cache_size = -32000;") # 32MB RAM page cache
conn.execute("PRAGMA temp_store = MEMORY;") # временные таблицы и сортировки в ОЗУ
conn.execute("PRAGMA foreign_keys = ON;")
```
- [x] **Zero-copy чтение страниц**: включён `mmap_size = 256MB`, позволяющий ядру Linux отдавать страницы SQLite напрямую из системного дискового кэша без лишних системных вызовов `read()` и копирования в буферы пользовательского пространства.
- [x] **Составные индексы (Composite Indexes)** для ускорения частых выборок:
- `vocabulary_cards`:
- `idx_vocab_user_created ON (user_id, created_at DESC)` — мгновенная пагинация списка слов без сортировки в памяти.
- `idx_vocab_user_srs_state ON (user_id, srs_state, srs_next_review)` — выборка очереди интервальных повторений SRS (`/api/srs/queue`).
- `idx_vocab_user_srs_created ON (user_id, srs_state, created_at DESC)` — выборка новых слов для интервального повторения.
- `idx_vocab_collection ON (user_id, collection)` — мгновенная фильтрация по коллекциям.
- `idx_vocab_user_term_nocase ON (user_id, term COLLATE NOCASE)` — предотвращение дубликатов за $O(\log N)$.
- `srs_logs`:
- `idx_srs_card ON (card_id)` — устранение full table scan при каскадном удалении карточек (`ON DELETE CASCADE`).
- `idx_srs_reviewed ON (user_id, reviewed_at)` — выборка журнала повторений и расчёт тепловой карты активности.
- `books`:
- `idx_books_user_updated ON (user_id, updated_at DESC)` — сортировка списка книг библиотеки по дате чтения.
- `sessions`:
- `idx_sessions_user ON (user_id)` — ускорение валидации сессий и каскадной очистки.
- [x] Добавлен регрессионный тест `test_sqlite_pragma_tuning_and_composite_indexes` в `tests/test_api.py` (23/23 тестов успешно).
---
### 10. ✂️ Де-блоатинг внешних парсеров (YAGNI)
- [x] **Удалён сетевой опрос Datamuse (`fetch_datamuse`)**:
- Устранена зависимость от `api.datamuse.com`, которая дублировала определения и перегружала выдачу зашифрованными метками тегов и рифмами.
- Сокращено число исходящих HTTP-запросов на каждый поиск слова на 20% (с 5 до 4 параллельных вызовов).
- [x] **Переход на современный REST API Wiktionary**:
- `fetch_wiktionary_wikitext` переведён на легковесный эндпоинт `https://en.wiktionary.org/w/rest.php/v1/page/{word}` (скорость ответа 0.3с вместо 0.5с у legacy `action=parse`).
- Добавлена строгая изоляция англоязычной секции `==English==`, исключившая утечку переводов и IPA из других языков (например, французское слово *chat* больше не заносит «кот» в английский словарь).
- Реализован автоматический fallback с сохранением регистра (для слов с заглавной буквы в начале предложений).
- [x] **Нормализация определений и примеров**:
- `fetch_wiktionary_definitions` дополнен декодированием HTML-сущностей (`html.unescape`) и нормализацией пробельных символов.
- [x] Добавлен регрессионный тест `test_debloat_dictionary_and_wiktionary_rest_parser` в `tests/test_api.py` (24/24 тестов успешно).
---
### 11. 📚 Локальный оффлайн-словарь (99%+ покрытия со словоформами, SQLite 10–20 МБ) (Completed)
- [x] Создана в SQLite таблица:
```sql
CREATE TABLE IF NOT EXISTS offline_dictionary (
term TEXT PRIMARY KEY COLLATE NOCASE,
translation TEXT NOT NULL,
phonetic TEXT DEFAULT '',
pos TEXT DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_offline_dict_term ON offline_dictionary(term COLLATE NOCASE);
```
- [x] **Высококачественная база на 141 772 словарных статьи** ([`data/offline_dict.tsv.gz`](file:///home/ai-projects/services/study.qpid.pro/data/offline_dict.tsv.gz), сжатый размер всего **2.48 МБ**):
- Построена генератором [`scripts/build_offline_dict.py`](file:///home/ai-projects/services/study.qpid.pro/scripts/build_offline_dict.py).
- Интегрированы FreeDict TEI XML (54k+ базовых лемм с IPA и частями речи) и очищенный русско-английский Wiktionary DSL (55k+ лемм).
- Включены все формы неправильных глаголов (16k+ форм: 3rd person singular, past, past participle, present participle).
- Включены множественные числа существительных (18k+ форм: regular & irregular plurals, например *men, women, hypotheses, criteria*).
- Включены регулярные инфлексии глаголов (50k+ форм: *-ed, -ing, -s*).
- Добавлен словарь IT и сетевой терминологии Cisco/O'Reilly (*packet, switch, router, throughput, bandwidth, latency, subnet, vlan*).
- [x] **Архитектура Zero Daemon**:
- Нативный SQLite с `PRAGMA mmap_size = 256MB` и `PRAGMA cache_size = -32000` (32MB RAM page cache).
- Никаких внешних сервисов (Redis/Postgres) — чтение за **0.015–0.030 мс** прямо из оперативной памяти ядра Linux.
- Автоматический сидинг базы при инициализации (`_seed_offline_dictionary()` в `app/database.py`) пачками по 10 000 строк занимает < 0.7 секунды.
- [x] **Иерархическая логика словарного поиска** в [`app/dictionary.py`](file:///home/ai-projects/services/study.qpid.pro/app/dictionary.py):
1. `dictionary_cache` $\rightarrow$ мгновенный возврат при повторном запросе.
2. `offline_dictionary` $\rightarrow$ мгновенный ответ за 0.02 мс с источником `source: "offline"`.
3. Только при отсутствии слова в базе (или для длинных предложений > 4 слов) $\rightarrow$ fallback-запрос во внешнюю сеть (Wiktionary REST / MyMemory).
- [x] Исключено исчерпание квот MyMemory (100 запросов/день) — 99%+ запросов обслуживаются локально.
- [x] Добавлен регрессионный юнит-тест `test_offline_dictionary_lookup_and_coverage` в [`tests/test_api.py`](file:///home/ai-projects/services/study.qpid.pro/tests/test_api.py) (25/25 тестов успешно, 100% green).
---
### 12. 🧩 Модульность фронтенда на нативных ES-модулях (без Webpack/Vite)
- [ ] Перевести [`app/static/js/app.js`](file:///home/ai-projects/services/study.qpid.pro/app/static/js/app.js) на нативный браузерный синтаксис `<script type="module">`.
- [ ] Выделить модули с нативным `import/export`:
- `modules/reader.js` — читалку, блок-парсер и навигацию по главам.
- `modules/srs.js` — алгоритм SM-2, флэшкарты и квиз.
- `modules/api.js` — клиентские сетевые вызовы.
- `modules/ui.js` — тосты, модальные окна, темы оформления.
- [ ] Сохранить полное отсутствие внешних сборщиков (0 npm-пакетов, чистая платформа).
---
### 13. 🧠 Локальный ИИ-учитель и аудирование (Dual-Model: Llama 3.2 3B + Qwen 2.5 7B)
> Полный роадмап и архитектурный манифест вынесен в отдельный документ: [`AI_TODO.md`](file:///home/ai-projects/services/study.qpid.pro/AI_TODO.md).
- [ ] Инфраструктура Zero Daemon (`llama-cli` on-demand, `nice -n 19`, RAM < 4 ГБ).
- [ ] Fast Tier (Llama 3.2 3B): генерация контрольных вопросов по главам, True/False, аудирование.
- [ ] Deep Tier (Qwen 2.5 7B): грамматический аудит эссе, тренажёр «Обратный перевод», объяснения правил.
- [ ] Личный радар грамматических слабостей в SQLite (`user_grammar_weaknesses`).
---
## ⏳ Coming Soon
- [ ] **🌐 Быстрый захват из браузера (Bookmarklet)**:
- Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь [`study.qpid.pro`](https://study.qpid.pro) (низший приоритет).
- [ ] **Нативная автономная озвучка (HTML5 Web Speech API / `speechSynthesis`)**:
- Использовать встроенный в браузер синтезатор речи `window.speechSynthesis` (en-US, en-GB).
- 0 сетевых запросов к серверу, 100% оффлайн-работа.
- Поддержка озвучивания отдельных слов, фраз, идиом и предложений-контекстов читалки.
- [ ] **Возврат режима «Диктант» в SRS**:
- Возобновление работы аудиотренажёра на базе нативного браузерного синтезатора речи без зависимости от внешних аудиофайлов.
---
## 🛠️ Правила и соглашения проекта (Ponytail Rules)
1. **Stdlib & Native First**: стандартная библиотека языка и возможности платформы (браузера, SQLite, Linux) всегда приоритетнее внешних библиотек и микросервисов.
2. **Меньше кода — меньше багов**: удаление кода и упрощение структуры всегда лучше усложнения.
3. **Безопасность**: все мутации данных изолированы по `user_id`, пароли защищены PBKDF2 с уникальной солью.
4. **Тестирование**: после каждого изменения запуск `pytest tests/test_api.py -v` (100% тестов должны быть зелеными).