392 lines
46 KiB
Markdown
392 lines
46 KiB
Markdown
# 📋 Задачи проекта: 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)`, ``, `<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-теги: ``.
|
||
- Интерактивный просмотр и зум схем по клику в читалке.
|
||
|
||
---
|
||
|
||
### 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) (Completed)
|
||
- [x] Перевести [`app/static/js/app.js`](file:///home/ai-projects/services/study.qpid.pro/app/static/js/app.js) на нативный браузерный синтаксис `<script type="module">`.
|
||
- [x] Выделить модули с нативным `import/export`:
|
||
- `modules/api.js` — централизованный клиент сетевых вызовов с авто-интерцептором токена.
|
||
- `modules/ui.js` — тосты, модальные окна, темы оформления, утилиты экранирования и шафла.
|
||
- `modules/dictionary.js` — поиск, карточки, коллекции, теги, пакетные операции, модалки редактирования и экспорта.
|
||
- `modules/srs.js` — алгоритм SM-2, 5 режимов тренировки (флэшкарты, квиз, тайпинг, клоуз, диктант), статистика KPI и гитхаб-хитмап.
|
||
- `modules/reader.js` — книжная полка, читалка, блок-парсер, виртуализация глав, интерактивный попап слова, настройки Aa.
|
||
- `app.js` — главный оркестратор, роутер хэшей `#dictionary`, `#srs`, `#reader/book/:id`, префлайт вида без мерцания, мобильный таббар.
|
||
- [x] Сохранить полное отсутствие внешних сборщиков (0 npm-пакетов, чистая платформа, нативные ES6 модули браузера).
|
||
- [x] Обновлен Service Worker (`sw.js`) с прекэшированием всех модулей и версией кэша `notes-v5.0`.
|
||
|
||
---
|
||
|
||
### 13. 🌐 Контекстный перевод предложений в читалке (In-Context Sentence Translator) (Completed)
|
||
- [x] Кнопка `🌐 Перевести предложение` в попапе слова читалки (рядом с контекстной цитатой).
|
||
- [x] Интеллектуальный перевод всей фразы целиком с сохранением смысла книги через локальный ИИ (устраняет ловушку оторванных значений слов вроде *draft*, *address*, *run*).
|
||
- [x] Разбор и точное значение целевого слова именно в данном контексте (`word_meaning`).
|
||
- [x] Мгновенный кэш переводов предложений в SQLite (`sentence_translations`) с SHA-256 хешированием за 0.01 мс.
|
||
- [x] Возможность сохранить правильный контекстный перевод прямо в карточку словаря («Вставить в карточку»).
|
||
- [x] Развёрнут локальный контейнер Ollama с моделями Qwen 2.5 (`qwen2.5:1.5b` и `qwen2.5:3b`) с автоматической выгрузкой из памяти при простое (`OLLAMA_KEEP_ALIVE=5m`) и 100% автономностью без внешних API.
|
||
|
||
---
|
||
|
||
### 14. 🔗 Детектор фразовых глаголов и идиом в читалке (Multi-Word / Phrasal Verb Detector) (Completed)
|
||
- [x] База частых английских фразовых глаголов и коллокаций (A2–B2: *take off, run out of, look forward to, figure out, set up, carry out, turn off, put up with* и др.).
|
||
- [x] При клике на слово в читалке — автоматический анализ контекстного окна (1–3 слова до и после + разделяемые фразовые глаголы *turn it off*).
|
||
- [x] При обнаружении устойчивой связки — карточка связки прямо в окне перевода слова (*took off* $\rightarrow$ «взлетать, снимать», а не «взял»).
|
||
- [x] Поддержка переключения между одиночным словом и фразовым глаголом в 1 клик.
|
||
- [x] Сохранение готовой устойчивой связки в личный словарь в один клик (в отдельную коллекцию «Фразовые глаголы & Идиомы» с тегом `#phrasal-verbs`).
|
||
|
||
---
|
||
|
||
### 15. 🎯 Уровневые тесты CEFR (A1, A2, B1, B2) с авто-добавлением ошибок в активный словарь (Completed)
|
||
- [x] **Эталонная база вопросов Oxford 3000/5000** (160 отобранных тестовых единиц: по 40 на каждый уровень A1, A2, B1, B2) в модуле [`app/cefr.py`](file:///home/ai-projects/services/study.qpid.pro/app/cefr.py).
|
||
- [x] **Быстрый и удобный мобильный формат: 1-тап выбор ключевого узла (Cloze Tap)**:
|
||
- Естественные контекстные предложения с пропуском `___`.
|
||
- Подсказка значения слова на русском языке и часть речи.
|
||
- 4 сбалансированных варианта ответа одинаковой части речи и уровня сложности (исключены грамматические подсказки).
|
||
- Мгновенная тактильная реакция: зеленая/красная подсветка, автоподстановка правильного слова в пропуск, раскрытие транскрипции IPA и пояснения.
|
||
- [x] **Автоматический захват пробелов (Automated Gap Ingestion)**:
|
||
- При правильном ответе $\rightarrow$ вопрос отмечается как освоенный в `cefr_progress`.
|
||
- При ошибке $\rightarrow$ слово/оборот **автоматически создаётся (или обновляется) как карточка в личном словаре со статусом `learning`** и немедленным сроком повторения (`srs_next_review = now`), коллекцией `Уровни CEFR ({level})` и тегами `#level-{level}`, `#cefr-test`, `#test-mistake`.
|
||
- [x] Проблемные слова сразу попадают в утренний пул интервальных повторений SRS тренажера.
|
||
- [x] **Наглядный прогресс-трекер**:
|
||
- Экран обзора со шкалами освоения каждого уровня (A1 Beginner, A2 Elementary, B1 Intermediate, B2 Upper-Intermediate).
|
||
- Счётчики: процент закрытия уровня, освоено, ошибок, слов в тренировке SRS.
|
||
- Режим «Работа над ошибками» (быстрый прогон только ошибочных вопросов).
|
||
- Возможность сброса прогресса уровня.
|
||
- [x] Добавлен регрессионный тест `test_cefr_testing_and_gap_ingestion` в [`tests/test_api.py`](file:///home/ai-projects/services/study.qpid.pro/tests/test_api.py) (28/28 тестов успешно, 100% green).
|
||
|
||
---
|
||
|
||
### 16. 📖 Оффлайн-модуль грамматики Мерфи и бумажная тетрадь (Murphy Engine & Handwritten Journaling)
|
||
- [x] Индексация юнитов *Essential Grammar in Use* (A1–A2) и *English Grammar in Use* (B1–B2) в SQLite (`grammar_units`).
|
||
- [x] Поддержка «Вечернего вайба глубокого погружения» (Deep Work Mode): 5–7 минутные микро-уроки.
|
||
- [x] Компактная выжимка правил на контрастах жизненных ситуаций (*I do* vs *I am doing*, *I did* vs *I have done* и т.д.).
|
||
- [x] 5 интерактивных упражнений с удобным 1-тап выбором на телефоне и мгновенным разбором логики ошибок.
|
||
- [x] **Интервальное повторение грамматики в SRS**: ошибки из упражнений Мерфи автоматически улетают в карточки утреннего повторения SRS (`srs_state = 'learning'`, теги `grammar`, `murphy-unit-{N}`)!
|
||
- [x] **Блок работы с бумажной тетрадью (мышечная и зрительная память)**:
|
||
- Золотая формула правила для записи цветной ручкой/маркером.
|
||
- Обязательное составление **2–3 личных примеров от руки из своей реальной жизни**.
|
||
- Интерактивный чекбокс: `[✓] Записал от руки в тетрадь` с мгновенной синхронизацией в SQLite.
|
||
|
||
---
|
||
|
||
### 17. 🍔 Разгрузка хеддера и единая навигация через боковое меню / Drawer (Unified Navigation & Header Redesign)
|
||
- [ ] **Проблема перегруженного хеддера**:
|
||
- В шапке скопилось 8+ кнопок (`📚 Читалка`, `🎯 Тесты CEFR`, `📖 Грамматика`, `🎓 Тренажёр`, `📊 Статистика`, `📤 Экспорт`, тема, шестеренка, профиль), на экранах планшетов и ноутбуков возникает переполнение и визуальный шум.
|
||
- Разрозненность UX: на десктопе все кнопки в шапке, на мобильных — нижний таб-бар + модальное меню.
|
||
- [ ] **Единый лаконичный Header (Desktop, Tablet, Mobile)**:
|
||
- Слева: Кнопка вызова бокового меню (Бургер `☰` / `ph-list`), кликабельный логотип `📖 Notes` (возврат в словарь).
|
||
- Центр: Фокусная кнопка быстрого доступа к активному действию (например, `🎓 Тренажёр SRS` с живым счётчиком повторений `srs-badge`).
|
||
- Справа: Переключатель темы `🌓`, компактная плашка пользователя/аватар.
|
||
- [ ] **Единый выдвижной Drawer (Боковое меню навигации)**:
|
||
- Плавная аппаратная анимация (`transform: translateX`, `backdrop-filter: blur`).
|
||
- Логическая группировка пунктов с красивыми иконками:
|
||
- **Обучение & Чтение**: Словарь, Читалка, Тесты CEFR, Грамматика Мерфи, Тренажёр SRS.
|
||
- **Аналитика**: Статистика обучения и календарь активности (Heatmap).
|
||
- **Настройки & Профиль**: Экспорт словаря, Смена пароля, Переключение темы, Выход.
|
||
- Закрытие по клику вне области (оверлей), кнопке `✕`, клавише <kbd>Esc</kbd> и свайпу влево на тач-устройствах (Swipe to dismiss).
|
||
- Блокировка скролла фона (`overflow: hidden` на `body`) при открытом Drawer.
|
||
- [ ] **Оптимизация мобильного режима**:
|
||
- Согласование с Bottom Tab Bar: оставить на нижней панели только 3-4 ключевых быстрых действия либо полностью перевести навигацию в чистый Drawer-паттерн без дублирования элементов.
|
||
|
||
---
|
||
|
||
### 18. 🎧 Автономная нейро-озвучка Piper TTS и аудирование (Низкий приоритет, в конце)
|
||
- [ ] Подключение локального C++ движка Piper TTS (VITS, 100% оффлайн, ~150 МБ RAM, CPU RTF 0.2).
|
||
- [ ] Компактные модели дикторов (EN `en_US-lessac` + RU `ru_RU-dmitri`).
|
||
- [ ] Регулировка скорости воспроизведения (0.75x для разбора сложных звуков, 1.0x, 1.25x для тренировки беглой речи).
|
||
- [ ] Оффлайн-кэширование аудио предложений в `data/audio_cache/` со сжатием в Opus и автоочисткой по TTL 7 дней (Zero Bloat).
|
||
- [ ] Фоновый экспорт главы в аудиокнигу для дороги и прогулок.
|
||
- [ ] Интерактивный Shadowing (прослушивание $\rightarrow$ повтор в микрофон $\rightarrow$ клиентская проверка).
|
||
|
||
---
|
||
|
||
## ⏳ 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% тестов должны быть зелеными).
|