186 lines
18 KiB
Markdown
186 lines
18 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)
|
||
- [ ] **Системный фундамент iOS и сброс ограничений (Core Foundation)**:
|
||
- Метатег `viewport`: добавить `viewport-fit=cover` для поддержки челки и нижней панели iPhone.
|
||
- Устранение бага принудительного авто-зума: установить `font-size: 16px` для `<input>`, `<textarea>`, `<select>` на экранах `≤ 768px` (сохраняя компактные внутренние отступы).
|
||
- Замена `100vh` на динамические единицы `100dvh` (Dynamic Viewport Height) для модальных окон, оверлеев и экрана авторизации.
|
||
- Добавление безопасных отступов `env(safe-area-inset-top)` и `env(safe-area-inset-bottom)`.
|
||
- Предотвращение горизонтального скролла (`overflow-x: hidden` на уровне контейнера приложения).
|
||
- [ ] **Мобильная навигация: переход к нативному паттерну (App Header + Bottom Tab Bar)**:
|
||
- Компактная верхняя шапка: логотип `📖 Notes`, переключатель темы `🌓`, кнопка вызова профиля/действий.
|
||
- Фиксированная нижняя панель вкладок (Bottom Tab Bar) с нативным iOS UX:
|
||
1. 🔍 **Словарь** (Поиск и словарь)
|
||
2. 🎓 **Тренажёр** (SRS с бейджем количества повторений)
|
||
3. 📚 **Читалка** (Библиотека книг)
|
||
4. 📊 **Прогресс** (Статистика и стрик)
|
||
5. ⚙️ **Меню** (Смена пароля, экспорт, выход)
|
||
- Сохранение текущей десктопной строки без изменений на больших экранах (`> 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) на смартфонах:
|
||
- Заголовок с термином, транскрипцией и бейджем `⭐ В библиотеке`.
|
||
- Блок перевода и контекстной цитаты книги.
|
||
- Большая кнопка «💾 Добавить в словарь» под большой палец.
|
||
- Исключение вылетов за границы экрана и перекрытия текста пальцем.
|
||
- Двухстрочный адаптивный тулбар читалки (навигация по главам + размер шрифта `A-/A+` и подсветка).
|
||
- Сетка библиотеки `bookshelf-grid` в одну колонку на экранах `≤ 640px`.
|
||
- [ ] **Тренажёр интервальных повторений (SRS Trainer)**:
|
||
- Ограничение высоты карточки SRS (`max-height: 48dvh`), чтобы карточка и кнопки оценки гарантированно помещались без вертикального скролла на 390px.
|
||
- Кнопки оценки (Снова / Трудно / Хорошо / Легко) в сетку 2×2 с высотой от 50px и четкими цветовыми акцентами.
|
||
- Вертикальный список вариантов в режиме квиза (4 варианта) на всю ширину экрана.
|
||
- [ ] **Модальные окна (Статистика, Пароль, Экспорт)**:
|
||
- Метрики статистики в сетку 2×2 вместо сжатых 4 колонок.
|
||
- Плавный горизонтальный скролл календаря активности (Heatmap).
|
||
- Разворачивание модальных окон в адаптивный мобильный слой с удобной кнопкой закрытия.
|
||
|
||
---
|
||
|
||
### 5. 🔌 Пул соединений HTTP (`httpx.AsyncClient` с Keep-Alive)
|
||
- [ ] В [`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)
|
||
```
|
||
- [ ] Заменить вызовы `async with httpx.AsyncClient()` в парсерах на переиспользуемый клиент.
|
||
- [ ] Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив пинг внешних запросов на 300–600 мс.
|
||
|
||
---
|
||
|
||
### 6. 🗄️ Тюнинг SQLite PRAGMA и составных индексов
|
||
- [ ] В [`app/database.py`](file:///home/ai-projects/services/study.qpid.pro/app/database.py):
|
||
- Вынести `PRAGMA journal_mode=WAL;` в `init_db()` (убрать избыточный вызов при каждом запросе).
|
||
- Включить параметры производительности памяти Linux:
|
||
```python
|
||
conn.execute("PRAGMA synchronous = NORMAL;")
|
||
conn.execute("PRAGMA mmap_size = 268435456;") # 256MB mmap
|
||
conn.execute("PRAGMA cache_size = -32000;") # 32MB cache
|
||
```
|
||
- [ ] Обеспечить Zero-copy чтение страниц БД ядром Linux.
|
||
|
||
---
|
||
|
||
### 7. ✂️ Де-блоатинг внешних парсеров (YAGNI)
|
||
- [ ] Удалить лишний сетевой опрос Datamuse (`fetch_datamuse`) — он дублирует определения и перегружает ответ нерелевантными рифмами.
|
||
- [ ] Упростить хрупкий regex-парсинг разметки Wikitext, опираясь на стабильные REST JSON эндпоинты.
|
||
|
||
---
|
||
|
||
### 8. 📚 Локальный оффлайн-словарь (99%+ покрытия со словоформами, SQLite 10–20 МБ)
|
||
- [ ] Создать в 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);
|
||
```
|
||
- [ ] Сформировать и интегрировать базу на 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).
|
||
|
||
---
|
||
|
||
### 9. 🧩 Модульность фронтенда на нативных ES-модулях (без Webpack/Vite)
|
||
- [ ] Перевести [`app/static/js/app.js`](file:///home/ai-projects/services/study.qpid.pro/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`](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% тестов должны быть зелеными).
|