13 KiB
13 KiB
📋 Задачи проекта: 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),,<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)). - При попытке повторного добавления: не создавать дубликат-клон, а дополнять контекстное предложение (если в новой цитате другой контекст) и объединять теги книги (
tags), возвращая существующую карточку со статусомalready_exists.
- Проверять наличие слова для пользователя без учёта регистра:
- Индикация в читалке (Reader Popup):
- При клике на слово проверять, есть ли уже
cleanTermв словаре пользователя. - Если слово уже сохранено: показывать зелёный бейдж
✓ В словаревместо активной кнопки+ В словарь(предотвращая случайные повторные клики). - Предоставить кнопку «Добавить контекст» для привязки новой цитаты к существующей карточке.
- При клике на слово проверять, есть ли уже
- Индекс целостности в SQLite:
- Добавить
CREATE INDEX IF NOT EXISTS idx_vocab_user_term_nocase ON vocabulary_cards(user_id, term COLLATE NOCASE);для мгновенного поиска заO(\log N).
- Добавить
- Слияние существующих дубликатов в базе:
- Написать безопасную миграцию/скрипт, объединяющий накопившиеся дубликаты (например,
admired,suddenly/Suddenlyу пользователяkopri), объединяя контексты предложений и сохраняя историю повторений SRS.
- Написать безопасную миграцию/скрипт, объединяющий накопившиеся дубликаты (например,
4. 🔌 Пул соединений 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 мс.
5. 🗄️ Тюнинг 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.
6. ✂️ Де-блоатинг внешних парсеров (YAGNI)
- Удалить лишний сетевой опрос Datamuse (
fetch_datamuse) — он дублирует определения и перегружает ответ нерелевантными рифмами. - Упростить хрупкий regex-парсинг разметки Wikitext, опираясь на стабильные REST JSON эндпоинты.
7. 📚 Локальный оффлайн-словарь (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 мс прямо из оперативной памяти процесса). - Реализовать логику словарного поиска:
- Сначала запрос в
offline_dictionary\rightarrowмгновенный ответ за 0.1 мс. - Только при отсутствии слова в базе
\rightarrowfallback-запрос во внешнюю сеть.
- Сначала запрос в
- Полностью исключить исчерпание лимитов внешних API (MyMemory 100 req/day).
8. 🧩 Модульность фронтенда на нативных 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-пакетов, чистая платформа).
9. 🌐 Быстрый захват из браузера (Bookmarklet)
- Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь
study.qpid.pro.
⏳ Coming Soon
- Нативная автономная озвучка (HTML5 Web Speech API /
speechSynthesis):- Использовать встроенный в браузер синтезатор речи
window.speechSynthesis(en-US, en-GB). - 0 сетевых запросов к серверу, 100% оффлайн-работа.
- Поддержка озвучивания отдельных слов, фраз, идиом и предложений-контекстов читалки.
- Использовать встроенный в браузер синтезатор речи
- Возврат режима «Диктант» в SRS:
- Возобновление работы аудиотренажёра на базе нативного браузерного синтезатора речи без зависимости от внешних аудиофайлов.
🛠️ Правила и соглашения проекта (Ponytail Rules)
- Stdlib & Native First: стандартная библиотека языка и возможности платформы (браузера, SQLite, Linux) всегда приоритетнее внешних библиотек и микросервисов.
- Меньше кода — меньше багов: удаление кода и упрощение структуры всегда лучше усложнения.
- Безопасность: все мутации данных изолированы по
user_id, пароли защищены PBKDF2 с уникальной солью. - Тестирование: после каждого изменения запуск
pytest tests/test_api.py -v(100% тестов должны быть зелеными).