Files
notes-qpid-pro/TODO.md
T

26 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 с аппаратным ускорением на мобильных.

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

  • Легковесный 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,.txt,.md,.pdf">.
    • Обновление кнопки в библиотеке: 📁 Загрузить EPUB / PDF / TXT.

8. 🔌 Пул соединений HTTP (httpx.AsyncClient с Keep-Alive)

  • В app/dictionary.py создать синглтон-клиент get_http_client() с пулом соединений:
    limits = httpx.Limits(max_keepalive_connections=10, max_connections=20)
    
  • Заменить вызовы async with httpx.AsyncClient() в парсерах на переиспользуемый клиент.
  • Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив пинг внешних запросов на 300–600 мс.

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

  • В app/database.py:
    • Вынести PRAGMA journal_mode=WAL; в init_db() (убрать избыточный вызов при каждом запросе).
    • Включить параметры производительности памяти Linux:
      conn.execute("PRAGMA synchronous = NORMAL;")
      conn.execute("PRAGMA mmap_size = 268435456;") # 256MB mmap
      conn.execute("PRAGMA cache_size = -32000;")   # 32MB cache
      
  • Обеспечить Zero-copy чтение страниц БД ядром Linux.

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

  • Удалить лишний сетевой опрос Datamuse (fetch_datamuse) — он дублирует определения и перегружает ответ нерелевантными рифмами.
  • Упростить хрупкий regex-парсинг разметки Wikitext, опираясь на стабильные REST JSON эндпоинты.

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

  • Создать в 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);
    
  • Сформировать и интегрировать базу на 120 000–180 000 статей (~10–20 МБ в SQLite, сжатый архив ~3.5–5 МБ):
    • Включить все словоформы (past tense, irregular verbs, plurals, participles).
    • Включить фразовые глаголы, современный сленг и IT/Tech терминологию.
  • Использовать архитектуру Zero Daemon: нативный SQLite с PRAGMA mmap_size (без отдельного контейнера Redis, чтение < 0.1 мс прямо из оперативной памяти процесса).
  • Реализовать логику словарного поиска:
    1. Сначала запрос в offline_dictionary \rightarrow мгновенный ответ за 0.1 мс.
    2. Только при отсутствии слова в базе \rightarrow fallback-запрос во внешнюю сеть.
  • Полностью исключить исчерпание лимитов внешних API (MyMemory 100 req/day).

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

  • Перевести 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-пакетов, чистая платформа).

⏳ Coming Soon

  • 🌐 Быстрый захват из браузера (Bookmarklet):
    • Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь 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% тестов должны быть зелеными).