Files
notes-qpid-pro/TODO.md
T

66 KiB
Raw Blame History

📋 Задачи проекта: study.qpid.pro (Backlog & Execution Queue)

Список задач для последовательной реализации в рамках принципов Ponytail (максимальная надёжность, нативные средства платформы, zero-dependency, высокая скорость).


🚀 Очередь реализации (Пошаговый план)

1. 📑 Полноценный рендеринг Markdown (.md) в читалке

  • Блоки кода (Fenced Code Blocks ```language):
    • Выделение блоков кода в контейнер <pre><code class="language-...">.
    • Моноширинный шрифт (JetBrains Mono, Consolas), сохранение отступов и табуляции (white-space: pre).
    • Тёмная подложка, горизонтальный скролл при переполнении, отключение красной строки (text-indent: 0).
    • Кнопка «Копировать код» в шапке блока.
    • Отключение создания интерактивных словарных спанов <span class="reader-word"> для кода, чтобы синтаксис не ломал форматирование.
  • Инлайн-код (`variable`):
    • Оборачивание в нативный тег <code class="reader-inline-code"> с бейджик-стилем.
  • Списки и цитаты:
    • Преобразование маркированных (- , * ) и нумерованных (1. ) списков в <ul><li> / <ol><li>.
    • Преобразование цитат (> ) в <blockquote> с акцентной левой границей.
    • Слова внутри списков и цитат остаются кликабельными (интерактивный клик-перевод работает!).
  • Заголовки Markdown (##, ###):
    • Конвертация в <h3>, <h4> с удалением сырых решёток #.
  • Таблицы Markdown (| col | col |):
    • Адаптивные таблицы с рамками, стилизацией заголовков <thead>, зебра-подсветкой строк и горизонтальным скроллом на мобильных.
    • Каждая ячейка поддерживает интерактивные слова для изучения и инлайн-код.
  • HTML-блоки и теги в Markdown (<p align="center">, <h1>, <em>, <strong>, <sub>, <br>):
    • Нативный парсинг через встроенный DOMParser без внешних библиотек.
    • Устранена утечка сырых тегов (<picture>, <source>, <p align=...>) в словарные слова.
  • Ссылки и изображения ([text](url), ![alt](url), <img>):
    • Поддержка бейджей shields.io, тренд-графиков и внешних картинок.
    • Автоматическое скрытие битых/отсутствующих локальных путей (assets/...) через обработчик onerror.
  • Точное позиционирование окна перевода у курсора/слова (Popup Positioning):
    • Исправлен баг двойного смещения координат: убран window.scrollY при position: fixed.
    • Окно перенесено в корень <body> для исключения искажений контекста позиционирования.
    • Плавное отслеживание скролла через requestAnimationFrame с автозакрытием при уходе слова за границы экрана или под липкую шапку.
  • Стилизация в CSS (app/static/css/style.css):
    • Добавлены стили для .reader-content-body pre, code, blockquote, ul, ol, .reader-table, .reader-heading, .reader-link, .reader-img.

2. 🗜️ Сжатие статического трафика (GZipMiddleware)

  • Подключить GZipMiddleware(minimum_size=1000) в app/main.py.
  • Сократить объём передаваемых файлов app.js (111.8 КБ -> 21.5 КБ), index.html (55.2 КБ -> 10.3 КБ) и style.css (58.2 КБ -> 9.4 КБ) на 81.7% (суммарно с 225.2 КБ до 41.2 КБ).
  • Проверить заголовки Content-Encoding: gzip в ответах и добавить регрессионный тест в tests/test_api.py.

3. 🛡️ Дедупликация слов и защита от повторного добавления (Reader + API)

  • Проверка дубликатов на бэкенде (POST /api/cards):
    • Проверка слова без учёта регистра lower(trim(term)).
    • При повторном добавлении не создаётся дубликат, а дополняется контекстное предложение и объединяются теги, возвращается already_exists: True.
  • Индикация в читалке и карточке поиска:
    • В читалке при клике на слово и в карточке поиска выводится бейдж ⭐ В библиотеке.
    • Кнопка «+ В словарь» заменяется на бейдж ⭐ Слово уже в библиотеке с опциональной кнопкой + Добавить эту цитату к карточке.
  • Индекс целостности в SQLite:
    • Создан UNIQUE INDEX idx_vocab_user_term_nocase ON vocabulary_cards(user_id, term COLLATE NOCASE); гарантирующий отсутствие дубликатов на уровне движка БД за O(\log N).
  • Слияние существующих дубликатов в базе:
    • Объединены дубликаты admired (ID 5 и ID 7) и suddenly/Suddenly (ID 2 и ID 9) с объединением контекстных предложений, слиянием тегов и сохранением прогресса SRS.

4. 📱 Мобильная оптимизация и адаптивная верстка (iPhone 12 / iOS Safari)

  • Системный фундамент 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).
  • Мобильная навигация: переход к нативному паттерну (App Header + Bottom Tab Bar):
    • Компактная верхняя шапка для смартфонов: логотип 📖 Notes, переключатель темы 🌓, кнопка вызова профиля ⚙️.
    • Фиксированная нижняя панель вкладок (Bottom Tab Bar) с нативным iOS UX:
      1. 🔍 Словарь (Поиск и словарь)
      2. 🎓 Тренажёр (SRS с бейджем количества повторений)
      3. 📚 Читалка (Библиотека книг)
      4. 📊 Прогресс (Статистика и стрик)
      5. ⚙️ Меню (Смена пароля, экспорт, выход)
    • Полное сохранение десктопного navbar без изменений на больших экранах (> 768px).
  • Адаптация экрана словаря и карточек (Dictionary & Cards View):
    • Поле поиска/перевода на полную ширину экрана с кнопкой «Перевести».
    • Скрытие неактуальных десктопных подсказок горячих клавиш (<kbd>Ctrl+Enter</kbd>) на мобильных устройствах.
    • Вертикальная раскладка полей метаданных при редактировании карточки.
    • Горизонтальный скролл чипсов коллекций и тегов (overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch).
    • Увеличенные зоны нажатия (Touch Targets ≥ 44px) для кнопок действий над карточкой.
  • Интерактивная читалка и переход к Mobile Bottom Sheet:
    • Трансформация всплывающего попапа перевода (reader-word-popup) в нативную выдвижную нижнюю шторку (Bottom Sheet) на смартфонах с ручкой перетаскивания sheet-drag-handle.
    • Двухстрочный адаптивный тулбар читалки (навигация по главам + размер шрифта A-/A+ и подсветка).
    • Сетка библиотеки bookshelf-grid в одну колонку на экранах ≤ 640px.
  • Тренажёр интервальных повторений (SRS Trainer):
    • Ограничение высоты карточки SRS (max-height: 48dvh), чтобы карточка и кнопки оценки гарантированно помещались без вертикального скролла на 390px.
    • Кнопки оценки (Снова / Трудно / Хорошо / Легко) в сетку 2×2 с высотой от 48px и четкими цветовыми акцентами.
    • Вертикальный список вариантов в режиме квиза (4 варианта) на всю ширину экрана.
  • Модальные окна (Статистика, Пароль, Экспорт):
    • Метрики статистики в сетку 2×2 вместо сжатых 4 колонок.
    • Плавный горизонтальный скролл календаря активности (Heatmap).
    • Разворачивание модальных окон в адаптивный мобильный слой с удобной кнопкой закрытия.


5. 🔤 Кастомизация оформления читалки (Типографика, темы, отступы, LocalStorage)

  • Панель настроек оформления текста (Aa):
    • Кнопка вызова настроек в тулбаре читалки: поповер на ПК и выдвижная шторка (Bottom Sheet) на смартфонах.
  • Настройка размера шрифта и степпер:
    • Степпер A- / A+ с индикатором точного размера (от 14px до 34px).
  • Семейство шрифтов (Font Family):
    • Переключение в 1 клик между Sans (системный), Serif (книжный с засечками), Mono (моноширинный).
  • Межстрочный интервал (Line Height):
    • Компактный (1.35), Оптимальный (1.65), Широкий (1.95).
  • Поля и ширина колонки (Margins & Max Width):
    • Узкие поля (940px), Стандарт (760px), Книжная колонка (600px).
  • Цветовые темы читалки (Themes):
    • 🌙 Тёмная (Dark Slate), 📜 Сепия (Тёплый пергамент), ☀️ Светлая (Чистый лист), 🖤 OLED (Абсолютный чёрный).
  • Выравнивание текста (Text Alignment):
    • По левому краю / По ширине (Justified).
  • Автосохранение и персистентность:
    • Мгновенное реактивное применение стилей через CSS-переменные без перезагрузки и сохранение настроек в localStorage.

6. 🔄 Комплексная переработка навигации, роутинга и честного прогресса чтения (Completed)

  • 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.
  • 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%.
    • Отображение честного суммарного прогресса на карточках книг в библиотеке и в тулбаре читалки.
  • 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%), ○ Не начато.
  • 6.4. Устойчивая фиксация позиции чтения (Paragraph Anchor + Scroll):
    • Сохранение не только пикселей scrollTop, но и индекса первого видимого абзаца (anchor_paragraph_idx).
    • Устойчивость к изменению шрифта Aa и ориентации экрана: восстановление скролла к конкретному предложению/абзацу, а не слепым пикселям.
    • Фиксация скролл-контейнера #reader-scroll-area с аппаратным ускорением на мобильных.
  • 6.5. Сквозное чтение и бесшовная автоподгрузка (Continuous Book View & Seamless Infinite Append):
    • Режим «Вся книга целиком» (flowMode: 'continuous'): объединение всех глав книги в один непрерывный свиток со стильными разделителями глав без необходимости перелистывания.
    • Режим «По главам» с автоподгрузкой (autoLoadNext: true): бесшовное присоединение следующей главы снизу при приближении к концу текущей главы.
    • Навигационный блок завершения главы: эргономичные кнопки «◀ Назад» и «Следующая: [Название] ▶» прямо под текстом (без необходимости тянуться наверх).
    • Настройка режима чтения («По главам» / «Вся книга») и переключатель автоподгрузки добавлены в панель настроек Aa с автосохранением в localStorage.
    • Карточка завершения книги (🎉 Книга прочитана!) с быстрыми ссылками на тренировку слов и возврат в библиотеку.

7. 📑 Поддержка чтения PDF (Cisco CCNA, O'Reilly & Tech Books с оглавлением и текстовым слоем) (Completed)

  • Легковесный Pure-Python парсер (pypdf, Zero C-Dependency):
    • Подключение pypdf (< 400 КБ, чистый Python, без раздувания Docker-образа и без системных библиотек poppler-utils / mupdf).
  • Извлечение оглавления и закладок PDF (reader.outline):
    • Извлечение авторского оглавления (ToC / Bookmarks), стандартного для книг Cisco Press (CCNA Official Cert Guide), O'Reilly и Wiley.
    • Разбивка книги на логические главы и разделы (Part I, Chapter 1, Chapter 2) точно по оглавлению автора.
  • Fallback-разбивка при отсутствии оглавления:
    • При отсутствии PDF-закладок — автоопределение заголовков через regex (Chapter \d+, Глава \d+) или группировка страниц порциями по ~12–15 страниц.
  • Очистка шума и колонтитулов:
    • Фильтрация повторяющихся верхних/нижних колонтитулов («CCNA 200-301 Official Cert Guide», «Page 45 of 900»).
  • Сохранение CLI/Console блоков:
    • Распознавание консольного вывода и команд сетевого оборудования (Router# show ip interface brief, Switch(config)#) и оборачивание в блоки кода Markdown для читалки с кнопкой «Копировать».
  • Защита от сканов без OCR (Scanned PDF Guard):
    • Валидация наличия текстового слоя: если суммарный объём извлечённого текста < 100 слов, возврат информативной ошибки с предложением использовать текстовый PDF или OCR.
  • Интеграция в интерфейс читалки:
    • Разрешение загрузки .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)

  • В app/dictionary.py создать синглтон-клиент get_http_client() с пулом соединений:
    limits = httpx.Limits(max_keepalive_connections=10, max_connections=20, keepalive_expiry=60.0)
    
  • Заменить вызовы async with httpx.AsyncClient() в парсерах на переиспользуемый клиент.
  • Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив задержку внешних запросов на 300–600 мс.
  • Добавить вызов close_http_client() в lifespan FastAPI при остановке приложения для чистого закрытия открытых сокетов.
  • Добавить юнит-тесты test_http_connection_pooling в tests/test_api.py (22/22 passed).

9. 🗄️ Тюнинг SQLite PRAGMA и составных индексов

  • В app/database.py:
    • Вынесен PRAGMA journal_mode=WAL; в однократную инициализацию init_db() и миграции (устранены повторные блокировки и запись заголовка файла на каждый HTTP-запрос).
    • Включены высокопроизводительные параметры памяти Linux для каждого соединения:
      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;")
      
  • Zero-copy чтение страниц: включён mmap_size = 256MB, позволяющий ядру Linux отдавать страницы SQLite напрямую из системного дискового кэша без лишних системных вызовов read() и копирования в буферы пользовательского пространства.
  • Составные индексы (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) — ускорение валидации сессий и каскадной очистки.
  • Добавлен регрессионный тест test_sqlite_pragma_tuning_and_composite_indexes в tests/test_api.py (23/23 тестов успешно).

10. ✂️ Де-блоатинг внешних парсеров (YAGNI)

  • Удалён сетевой опрос Datamuse (fetch_datamuse):
    • Устранена зависимость от api.datamuse.com, которая дублировала определения и перегружала выдачу зашифрованными метками тегов и рифмами.
    • Сокращено число исходящих HTTP-запросов на каждый поиск слова на 20% (с 5 до 4 параллельных вызовов).
  • Переход на современный 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 с сохранением регистра (для слов с заглавной буквы в начале предложений).
  • Нормализация определений и примеров:
    • fetch_wiktionary_definitions дополнен декодированием HTML-сущностей (html.unescape) и нормализацией пробельных символов.
  • Добавлен регрессионный тест test_debloat_dictionary_and_wiktionary_rest_parser в tests/test_api.py (24/24 тестов успешно).

11. 📚 Локальный оффлайн-словарь (99%+ покрытия со словоформами, SQLite 10–20 МБ) (Completed)

  • Создана в SQLite таблица:
    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);
    
  • Высококачественная база на 141 772 словарных статьи (data/offline_dict.tsv.gz, сжатый размер всего 2.48 МБ):
    • Построена генератором 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).
  • Архитектура 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 секунды.
  • Иерархическая логика словарного поиска в app/dictionary.py:
    1. dictionary_cache \rightarrow мгновенный возврат при повторном запросе.
    2. offline_dictionary \rightarrow мгновенный ответ за 0.02 мс с источником source: "offline".
    3. Только при отсутствии слова в базе (или для длинных предложений > 4 слов) \rightarrow fallback-запрос во внешнюю сеть (Wiktionary REST / MyMemory).
  • Исключено исчерпание квот MyMemory (100 запросов/день) — 99%+ запросов обслуживаются локально.
  • Добавлен регрессионный юнит-тест test_offline_dictionary_lookup_and_coverage в tests/test_api.py (25/25 тестов успешно, 100% green).

12. 🧩 Модульность фронтенда на нативных ES-модулях (без Webpack/Vite) (Completed)

  • Перевести app/static/js/app.js на нативный браузерный синтаксис <script type="module">.
  • Выделить модули с нативным 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, префлайт вида без мерцания, мобильный таббар.
  • Сохранить полное отсутствие внешних сборщиков (0 npm-пакетов, чистая платформа, нативные ES6 модули браузера).
  • Обновлен Service Worker (sw.js) с прекэшированием всех модулей и версией кэша notes-v5.0.

13. 🌐 Контекстный перевод предложений в читалке (In-Context Sentence Translator) (Completed)

  • Кнопка 🌐 Перевести предложение в попапе слова читалки (рядом с контекстной цитатой).
  • Интеллектуальный перевод всей фразы целиком с сохранением смысла книги через локальный ИИ (устраняет ловушку оторванных значений слов вроде draft, address, run).
  • Разбор и точное значение целевого слова именно в данном контексте (word_meaning).
  • Мгновенный кэш переводов предложений в SQLite (sentence_translations) с SHA-256 хешированием за 0.01 мс.
  • Возможность сохранить правильный контекстный перевод прямо в карточку словаря («Вставить в карточку»).
  • Развёрнут локальный контейнер Ollama с моделями Qwen 2.5 (qwen2.5:1.5b и qwen2.5:3b) с автоматической выгрузкой из памяти при простое (OLLAMA_KEEP_ALIVE=5m) и 100% автономностью без внешних API.

14. 🔗 Детектор фразовых глаголов и идиом в читалке (Multi-Word / Phrasal Verb Detector) (Completed)

  • База частых английских фразовых глаголов и коллокаций (A2–B2: take off, run out of, look forward to, figure out, set up, carry out, turn off, put up with и др.).
  • При клике на слово в читалке — автоматический анализ контекстного окна (1–3 слова до и после + разделяемые фразовые глаголы turn it off).
  • При обнаружении устойчивой связки — карточка связки прямо в окне перевода слова (took off \rightarrow «взлетать, снимать», а не «взял»).
  • Поддержка переключения между одиночным словом и фразовым глаголом в 1 клик.
  • Сохранение готовой устойчивой связки в личный словарь в один клик (в отдельную коллекцию «Фразовые глаголы & Идиомы» с тегом #phrasal-verbs).

15. 🎯 Уровневые тесты CEFR (A1, A2, B1, B2) с авто-добавлением ошибок в активный словарь (Completed)

  • Эталонная база вопросов Oxford 3000/5000 (160 отобранных тестовых единиц: по 40 на каждый уровень A1, A2, B1, B2) в модуле app/cefr.py.
  • Быстрый и удобный мобильный формат: 1-тап выбор ключевого узла (Cloze Tap):
    • Естественные контекстные предложения с пропуском ___.
    • Подсказка значения слова на русском языке и часть речи.
    • 4 сбалансированных варианта ответа одинаковой части речи и уровня сложности (исключены грамматические подсказки).
    • Мгновенная тактильная реакция: зеленая/красная подсветка, автоподстановка правильного слова в пропуск, раскрытие транскрипции IPA и пояснения.
  • Автоматический двухсторонний захват пробелов (Dual Gap Ingestion):
    • При ошибке \rightarrow автоматически в словарь SRS со статусом «В процессе» (learning) добавляются ОБА слова:
      1. Истинное целевое слово (правильный ответ).
      2. Выбранный дистрактор (слово, на которое кликнул пользователь, с его переводом и транскрипцией).
    • Срочный срок повторения (srs_next_review = now), коллекция Уровни CEFR ({level}) и теги #level-{level}, #cefr-test, #test-mistake.
  • Интерактивный разбор всех вариантов (Options Breakdown & 1-Tap Add):
    • Карточки всех 4 вариантов ответа с переводом из оффлайн-словаря и частью речи.
    • Автоматическая маркировка добавленных слов (✓ В словаре (SRS) / ✓ В библиотеке).
    • Быстрая кнопка + В словарь для любых оставшихся незнакомых вариантов вопроса в 1 тап.
  • Расширенная база вопросов (Oxford 3000/5000):
    • Банк расширен со 160 до 260 эталонных вопросов (по 65 вопросов на каждый уровень A1, A2, B1, B2).
  • Наглядный прогресс-трекер:
    • Экран обзора со шкалами освоения каждого уровня (A1 Beginner, A2 Elementary, B1 Intermediate, B2 Upper-Intermediate).
    • Счётчики: процент закрытия уровня, освоено, ошибок, слов в тренировке SRS.
    • Режим «Работа над ошибками» (быстрый прогон только ошибочных вопросов).
    • Возможность сброса прогресса уровня.
  • Добавлен регрессионный тест test_cefr_testing_and_gap_ingestion в tests/test_api.py (29/29 тестов успешно, 100% green).

16. 📖 Оффлайн-модуль грамматики Мерфи и бумажная тетрадь (Murphy Engine & Handwritten Journaling)

  • Индексация юнитов Essential Grammar in Use (A1–A2) и English Grammar in Use (B1–B2) в SQLite (grammar_units).
  • Поддержка «Вечернего вайба глубокого погружения» (Deep Work Mode): 5–7 минутные микро-уроки.
  • Компактная выжимка правил на контрастах жизненных ситуаций (I do vs I am doing, I did vs I have done и т.д.).
  • 5 интерактивных упражнений с удобным 1-тап выбором на телефоне и мгновенным разбором логики ошибок.
  • Интервальное повторение грамматики в SRS: ошибки из упражнений Мерфи автоматически улетают в карточки утреннего повторения SRS (srs_state = 'learning', теги grammar, murphy-unit-{N})!
  • Блок работы с бумажной тетрадью (мышечная и зрительная память):
    • Золотая формула правила для записи цветной ручкой/маркером.
    • Обязательное составление 2–3 личных примеров от руки из своей реальной жизни.
    • Интерактивный чекбокс: [✓] Записал от руки в тетрадь с мгновенной синхронизацией в SQLite.

16.2. ⚡ Фоновые задачи и генерация тестов CEFR из загруженных книг (Background Tasks & Book Mining)

  • Zero-Daemon менеджер фоновых задач (app/tasks.py):
    • Таблица SQLite background_tasks (id, user_id, task_type, status, progress_current, progress_total, message, params_json, result_json, error_message).
    • Асинхронное исполнение через чистый asyncio.create_task без Celery, Redis и внешних брокеров (100% Ponytail).
    • Кооперативная отмена задач (cancel_task, is_task_cancelled).
    • Эндпоинты API: POST /api/tasks/mine-books, GET /api/tasks/active, GET /api/tasks/{task_id}, POST /api/tasks/{task_id}/cancel.
  • Движок анализа и майнинга предложений из книг (app/miner.py):
    • Разбиение текста глав на чистые предложения с защитой английских инициалов и сокращений (Mr., Mrs., Dr., Prof., St., Jr.).
    • Сопоставление с лексической шкалой Oxford 3000/5000 (A1..B2) и базой частей речи.
    • Подбор грамматически и лексически корректных дистракторов того же уровня CEFR и части речи.
    • Формирование 4-вариантных заданий Cloze Tap со скрытием ключевого слова ___.
    • Защита от дубликатов предложений через UNIQUE(level, sentence) в SQLite.
    • Автоматическая очистка русскоязычного глоссария (clean_translation) от паразитных латинских транслитов Викисловаря.
  • Интерфейс в веб-приложении (PWA):
    • Кнопка ⚡ Собрать тесты из книг в шапке тестов CEFR.
    • Модальное окно с выбором книги (или всей библиотеки), целевого уровня (A1..B2 / ALL) и количества вопросов.
    • Интерактивный фоновый баннер со спиннером, живым счетчиком прогресса X / Y (%) и кнопкой отмены задачи.
    • Бейджик источника 📖 «Название книги» (Глава) в карточке вопроса и в разборе ответа.
  • Автоматический тест test_background_tasks_and_book_mining в tests/test_api.py (30/30 тестов успешно пройдены).

🐛 Устранённые дефекты и хотфиксы (Bug Tracker & Hotfixes)

  • Баг читалки: Преждевременный обрыв контекстного предложения на точках сокращений (Mr., Mrs., Dr., Prof., St., etc., e.g., i.e., 1.5):
    • Симптом: При клике на слово в предложении с обращением или сокращением (например, «Mr. and Mrs. Dursley were proud...») кнопка перевода предложения («🌐 Перевести предложение») отправляла на перевод лишь обрезок до или после точки («Mr.», «and Mrs.» или «Dursley were proud...»). Если перед словом была точка в обращении, текст дальше не переводился.
    • Причина: В функции extractContextSentence(fullText, word) в app/static/js/modules/reader.js использовалось наивное регулярное выражение [^.!?\n]*, считавшее абсолютно любую точку концом предложения.
    • Решение: Реализована безопасная защита списка английских титулов и сокращений (READER_HONORIFICS) и дробных чисел перед сегментацией. Предложения корректно делятся по терминальным знакам препинания с закрывающими кавычками/скобками ([.!?]['"”’»)]*), гарантируя передачу полного, связного контекста в переводчик и словарь.

17. 🍔 Разгрузка хеддера и единая навигация через боковое меню / Drawer (Unified Navigation & Header Redesign) (Completed)

  • Проблема перегруженного хеддера полностью решена:
    • Ликвидировано нагромождение из 8+ кнопок в шапке, устранён визуальный шум и горизонтальный сдвиг на планшетах и компактных экранах.
    • Устранена разрозненность UX: на десктопе, планшете и смартфоне теперь действует единая система навигации.
  • Единый лаконичный Header (Desktop, Tablet, Mobile):
    • Слева: Кнопка вызова бокового меню (Бургер ☰ / ph-list), кликабельный логотип 📖 Notes (возврат в словарь).
    • Центр: Фокусная кнопка быстрого доступа к главному ежедневному действию (🎓 Тренажёр SRS с живым счётчиком повторений srs-badge) и компактные счетчики базы (Всего: X, Сегодня: +Y). На смартфонах счетчики автоматически скрываются, а кнопка сжимается до компактного бейджа 🎓 (N).
    • Справа: Переключатель темы 🌓, компактная плашка пользователя/аватар 👤 user (на смартфонах отображается только иконка аватара).
  • Единый выдвижной Drawer (Боковое меню навигации):
    • Плавная аппаратная анимация (transform: translateX, backdrop-filter: blur(4px)).
    • Карточка профиля с аватаром, именем пользователя и описанием.
    • Интерактивный мини-дашборд статистики (Всего в базе, Сегодня, На повторение).
    • Логическая группировка пунктов с красивыми иконками:
      • Обучение & Чтение: Словарь & Поиск, Тренажёр SRS (с живым бейджем), Читалка & Книги, Тесты CEFR (A1–B2), Грамматика Мерфи & Тетрадь.
      • Аналитика: Календарь активности & Статистика (Heatmap).
      • Настройки & Профиль: Экспорт словаря, Сменить пароль, Переключение темы, Выход из аккаунта.
    • Закрытие по клику вне области (оверлей), кнопке ✕, клавише Esc и свайпу влево на тач-устройствах (Swipe to dismiss).
    • Блокировка скролла фона (overflow: hidden на body) при открытом Drawer.
    • Подсветка активного раздела (.active), синхронизированная с URL-хэшем и переходами между экранами.
  • Оптимизация мобильного режима:
    • На нижней панели (Bottom Tab Bar) оставлены 4 ключевых быстрых действия: 📖 Словарь, 🎓 Тренажёр, 📚 Читалка, ☰ Меню.
    • Тап по ☰ Меню на мобильном открывает единый Drawer, полностью заменив устаревший отдельный модальный слой mobile-menu-modal без дублирования верстки и стилей.

18. 🎧 Автономная нейро-озвучка Piper TTS и аудирование

  • Локальный движок Piper TTS:
    • Автономный VITS-инференс, 100% оффлайн, ~120 МБ RAM, сверхбыстрый отклик на AMD Ryzen 9 5950X (RTF ~0.11).
  • Качественные модели дикторов:
    • Английский: en_US-lessac (чёткий нативный американский диктор).
    • Русский: ru_RU-dmitri (естественный русский голос).
  • Проактивное фоновое пред-кэширование (Zero Latency):
    • При сохранении карточки в словарь (POST /api/cards) бэкенд в фоне синтезирует слово и всё предложение-контекст.
    • В читалке при переводе предложения (POST /api/translate-sentence) аудио фразы пред-кэшируется в фоне.
  • Интеграция в интерфейс:
    • Карточки SRS (лицевая сторона 🔊, обратная сторона 🔊, и отдельная кнопка озвучки контекста 🔊).
    • Викторина SRS (кнопка 🔊 озвучки слова).
    • Читалка (кнопка 🔊 у слова в попапе, 🔊 у всего предложения, и 🔊 RU для русского перевода).
    • Словарь (кнопка 🔊 в результатах поиска).
  • Второй этап: интерактивный тренажёр аудирования (Listening & Q&A) с ситуационными сценариями, вопросами диктора, проверкой понимания на слух и билингвальными транскриптами.
  • Мульти-голосовой переключатель: 6 моделей Piper TTS (3 EN: Paula, Ryan, Alan; 3 RU: Irina, Denis, Dmitri) с калибровкой темпа и глубоких пауз на тире/знаках препинания.

19. 🚀 Конструктор комплексного урока & Сессионный раннер (Beta) (Completed)

  • Гибкий конфигуратор структуры урока:
    • Настройка порядка блоков (стрелки ▲/▼), включение/выключение этапов (Toggle-свитчеры), регулировка объёма (5/10/15/20 слов, 3/5/10 упражнений, 1/2/3 аудио-ситуации).
    • Готовые встроенные шаблоны в 1 клик:
      • ⚡ «Утренний экспресс (10 мин)» (слова + ретро-тест + 1 ситуация на слух).
      • 🎯 «Сбалансированный урок (20 мин)» (слова + закрепление + новая теория Мерфи + 2 ситуации).
      • 📖 «Глубокое погружение (30 мин)» (полный стек: слова, грамматика, аудирование и чтение статьи).
      • 🎧 «Аудио + Чтение (15 мин)» (понимание на слух и работа с текстом).
    • Возможность сохранить любой собственный план в базу SQLite под своим именем.
  • Бесшовный сессионный раннер урока:
    • Единый режим урока с пошаговым хлебным прогресс-баром ([1] Слова ➔ [2] Закрепление ➔ [3] Новая тема ➔ [4] Аудио ➔ [5] Чтение ➔ [6] ИИ-Итог).
    • Таймер сессии, мгновенный автопереход между блоками без кликов по меню.
    • Оффлайн-база познавательных микро-статей (Наука, IT, Природа, Космос, История) с кликабельным переводом слов и кнопкой «+ В словарь».
    • Умный адаптивный выбор темы грамматики для повторения: «Самая слабая тема (по ошибкам)», «Предыдущая тема» или выбор любого юнита вручную.
  • Сквозная телеметрия ошибок & ИИ-дебрифинг (Qwen 2.5 3B):
    • Фиксация ошибок на каждом этапе: забытые слова, нарушенные правила Мерфи, пропущенные детали аудирования.
    • Обогащение историческим контекстом: сопоставление с прошлыми ошибками в srs_logs и grammar_progress.
    • Итоговый педагогический разбор от Qwen 2.5 3B: итоговая оценка сессии (A+, A, B, C), разбор паттернов ошибок с формулами Мерфи, сильные стороны и персональный фокус на завтра.
    • Мгновенный детерминированный fallback: если Ollama занята или выключена, урок завершается моментальным структурированным математическим отчётом без зависаний.
  • Интеграция в интерфейс & тесты:
    • Отдельный пункт в боковом меню 🚀 Комплексный урок (Beta) и хэш-маршрут #lesson.
    • Модальное окно истории комплексных уроков с сохранением результатов сессий в lesson_sessions.
    • 44/44 проходящих автоматизированных теста в tests/test_api.py.

20. 🏗️ Комплексный технический рефакторинг и оптимизация архитектуры (Completed)

  • Этап 1: Очистка мертвого кода и оптимизация SQL:
    • Удалена старая незавершенная функция parse_text в app/reader.py (строки 290–326).
    • Функция update_task_progress в app/tasks.py переписана с цикла на единый параметризованный SQL-запрос UPDATE tasks SET progress = ?, current_item = ?, ....
  • Этап 2: Вынос датасетов в JSON (data/seeds/*.json):
    • Из исходников извлечено более 3 100 строк статических данных: cefr_questions.json (260 вопросов), grammar_units.json (15 юнитов), phrasal_verbs.json (157 глаголов), reading_articles.json (8 статей).
    • Модули app/cefr.py, app/grammar.py, app/phrasal.py, app/lessons.py переведены на динамическую ленивую загрузку с сохранением полной обратной совместимости.
  • Этап 3: Оптимизация сети и локального ИИ:
    • Внедрен постоянный пул соединений httpx.AsyncClient с Keep-Alive (120s) для локальной Ollama в app/ai.py, управляемый в жизненном цикле приложения (lifespan).
    • Интегрирована встроенная офлайн-лемматизация (lemmatize_word) в lookup_term (app/dictionary.py), предотвращающая лишние сетевые запросы при поиске словоформ (starts -> start, studying -> study).
  • Этап 4: Модуляризация бэкенда FastAPI:
    • Монолитный app/main.py сокращен с 2 240 до 142 строк.
    • Создан пакет app/routers/ с 11 тематическими APIRouter: auth.py, cards.py, dictionary.py, srs.py, export.py, reader.py, cefr.py, grammar.py, tasks.py, lessons.py, listening.py.
  • Этап 5: Модуляризация CSS и Service Worker:
    • Монолитный style.css (8 746 строк) разделен на 7 предметных таблиц в app/static/css/: base.css, components.css, dictionary.css, srs.css, reader.css, grammar_cefr.css, lesson.css.
    • Мастер-файл style.css загружает стили через @import и содержит полную архитектурную карту.
    • Обновлен Service Worker (notes-v6.7) с добавлением всех CSS в PRECACHE_URLS для полной офлайн-работы PWA.
  • Инфраструктура быстрого переключения и отката:
    • Добавлены скрипты scripts/deploy_beta.sh и scripts/rollback_to_main.sh для мгновенного отката или развертывания в 1 клик.
    • Создан резервный бэкап базы данных data/notes.db.backup-main-pre-beta.
  • 100% успешное тестирование:
    • Все 44 интеграционных теста pytest tests/test_api.py успешно проходят в Docker-контейнере.

🐛 Зафиксированные баги (Ждут команды на исправление)

  • BUG-01: Не открывается окно редактирования слова в словаре на главной:
    • Симптом: при клике на иконку ✏️ у карточки слова в списке словаря ничего не происходит.
    • Диагностика: в app/static/js/modules/dictionary.js функция openEditModal ищет элемент по id 'edit-card-modal' (document.getElementById('edit-card-modal')), в то время как в app/static/index.html модальное окно объявлено с id 'edit-modal' (<div id="edit-modal" class="modal-backdrop hidden">). Из-за несовпадения ID селектор возвращает null, и вызов openModal(null) тихо игнорируется.
    • Статус: зафиксировано, ожидает команды на исправление.
  • BUG-02: Отсутствует возможность прослушать слово и предложение из словаря:
    • Симптом: в списке карточек словаря на главной странице нет кнопок 🔊 для воспроизведения аудио слова и контекстного предложения.
    • Диагностика: в шаблоне рендеринга renderCardsList (app/static/js/modules/dictionary.js) внутри .card-top и .card-context не отрисовываются кнопки аудиовызова с вызовом playAudio() / playTextSpeech(), хотя модуль ui.js полностью поддерживает их воспроизведение.
    • Статус: зафиксировано, ожидает команды на исправление.
  • BUG-03: Спойлер корня слова в переводе грамматических форм в тестах (например, (прош. вр. от explain)):
    • Симптом: при добавлении словоформ в словарь (например, explained) в переводе сохраняются пометки словообразования: объяснять, объяснить (прош. вр. от explain). Во время теста (SRS / Урок) отображение этого перевода напрямую спойлерит английское слово explain.
    • Диагностика: в app/dictionary.py функция clean_russian_translation (строки 235–277) намеренно защищает грамматические пометки вида (прош. вр. от ...), и они попадают в поле card.translation. Во время тестирования в srs.js и lesson.js эта строка выводится в вопросе теста целиком без фильтрации.
    • Варианты решения: по умолчанию скрывать пометку под интерактивный кликабельный спойлер [+ грамматика] или вырезать английский корень из вопроса теста через regex /\s*\([^)]*от\s+[a-zA-Z\x27-]+\)/gi.
    • Статус: зафиксировано, ожидает команды на исправление.
  • BUG-04: В квизе «4 варианта» правильный ответ всегда находится на 1-м месте:
    • Симптом: в комплексном уроке и SRS при выборе режима «4 варианта» правильный ответ всегда гарантированно оказывается первым вариантом.
    • Диагностика: в app/static/js/modules/ui.js (строка 28) функция shuffleArray(array) возвращает новый скопированный массив (return arr;), не мутируя оригинал на месте. В app/static/js/modules/lesson.js (строка 778) и app/static/js/modules/srs.js (строка 461) написано shuffleArray(options);, но результат возврата игнорируется (options не перезаписывается), из-за чего правильный ответ, добавленный первым в [correctText, ...], всегда остаётся на позиции 0.
    • Варианты решения: переписать вызовы на options = shuffleArray(options); (или сделать shuffleArray мутирующим).
    • Статус: зафиксировано, ожидает команды на исправление.

⏳ Coming Soon

  • 🌐 Быстрый захват из браузера (Bookmarklet):
    • Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь study.qpid.pro (низший приоритет).
  • Нативная автономная озвучка (HTML5 Web Speech API / speechSynthesis):
    • Использовать встроенный в браузер синтезатор речи window.speechSynthesis (en-US, en-GB) как дополнительный резервный фолбэк при работе на мобильных без связи.
  • Расширение библиотеки Murphy:
    • Добавление следующих 15 юнитов грамматики (юниты 16–30: пассивный залог, косвенная речь, модальные глаголы).

🛠️ Правила и соглашения проекта (Ponytail Rules)

  1. Stdlib & Native First: стандартная библиотека языка и возможности платформы (браузера, SQLite, Linux) всегда приоритетнее внешних библиотек и микросервисов.
  2. Меньше кода — меньше багов: удаление кода и упрощение структуры всегда лучше усложнения.
  3. Безопасность: все мутации данных изолированы по user_id, пароли защищены PBKDF2 с уникальной солью.
  4. Тестирование: после каждого изменения запуск pytest tests/test_api.py -v (100% тестов должны быть зелеными).