19 KiB
19 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)). - При повторном добавлении не создаётся дубликат, а дополняется контекстное предложение и объединяются теги, возвращается
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:
- 🔍 Словарь (Поиск и словарь)
- 🎓 Тренажёр (SRS с бейджем количества повторений)
- 📚 Читалка (Библиотека книг)
- 📊 Прогресс (Статистика и стрик)
- ⚙️ Меню (Смена пароля, экспорт, выход)
- Полное сохранение десктопного
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 варианта) на всю ширину экрана.
- Ограничение высоты карточки SRS (
- Модальные окна (Статистика, Пароль, Экспорт):
- Метрики статистики в сетку 2×2 вместо сжатых 4 колонок.
- Плавный горизонтальный скролл календаря активности (Heatmap).
- Разворачивание модальных окон в адаптивный мобильный слой с удобной кнопкой закрытия.
5. 🔤 Кастомизация оформления читалки (Типографика, темы, отступы, LocalStorage)
- Панель настроек оформления текста (
Aa):- Кнопка вызова настроек в тулбаре читалки: поповер на ПК и выдвижная шторка (Bottom Sheet) на смартфонах.
- Настройка размера шрифта и степпер:
- Степпер
A-/A+с индикатором точного размера (от 14px до 34px).
- Степпер
- Семейство шрифтов (Font Family):
- Переключение в 1 клик между
Sans(системный),Serif(книжный с засечками),Mono(моноширинный).
- Переключение в 1 клик между
- Межстрочный интервал (Line Height):
- Компактный (1.35), Оптимальный (1.65), Широкий (1.95).
- Поля и ширина колонки (Margins & Max Width):
- Узкие поля (940px), Стандарт (760px), Книжная колонка (600px).
- Цветовые темы читалки (Themes):
- 🌙 Тёмная (Dark Slate), 📜 Сепия (Тёплый пергамент), ☀️ Светлая (Чистый лист), 🖤 OLED (Абсолютный чёрный).
- Выравнивание текста (Text Alignment):
- По левому краю / По ширине (Justified).
- Автосохранение и персистентность:
- Мгновенное реактивное применение стилей через CSS-переменные без перезагрузки и сохранение настроек в
localStorage.
- Мгновенное реактивное применение стилей через CSS-переменные без перезагрузки и сохранение настроек в
6. 🔌 Пул соединений 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 мс.
7. 🗄️ Тюнинг 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.
8. ✂️ Де-блоатинг внешних парсеров (YAGNI)
- Удалить лишний сетевой опрос Datamuse (
fetch_datamuse) — он дублирует определения и перегружает ответ нерелевантными рифмами. - Упростить хрупкий regex-парсинг разметки Wikitext, опираясь на стабильные REST JSON эндпоинты.
9. 📚 Локальный оффлайн-словарь (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).
10. 🧩 Модульность фронтенда на нативных 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(низший приоритет).
- Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь
- Нативная автономная озвучка (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% тестов должны быть зелеными).