docs(todo): add task 3 for word deduplication and duplicate prevention

This commit is contained in:
2026-10-05 15:06:30 +03:00
parent 2ba78191df
commit f52820fff6
+23 -12
View File
@@ -47,7 +47,22 @@
---
### 3. 🔌 Пул соединений HTTP (`httpx.AsyncClient` с Keep-Alive)
### 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`](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)
@@ -57,7 +72,7 @@
---
### 4. 🗄️ Тюнинг SQLite PRAGMA и составных индексов
### 5. 🗄️ Тюнинг SQLite PRAGMA и составных индексов
- [ ] В [`app/database.py`](file:///home/ai-projects/services/study.qpid.pro/app/database.py):
- Вынести `PRAGMA journal_mode=WAL;` в `init_db()` (убрать избыточный вызов при каждом запросе).
- Включить параметры производительности памяти Linux:
@@ -66,22 +81,17 @@
conn.execute("PRAGMA mmap_size = 268435456;") # 256MB mmap
conn.execute("PRAGMA cache_size = -32000;") # 32MB cache
```
- Добавить составной индекс:
```sql
CREATE INDEX IF NOT EXISTS idx_vocab_user_term_nocase
ON vocabulary_cards(user_id, term COLLATE NOCASE);
```
- [ ] Обеспечить Zero-copy чтение страниц БД ядром Linux и мгновенный поиск дубликатов по пользователю за $O(\log N)$.
- [ ] Обеспечить Zero-copy чтение страниц БД ядром Linux.
---
### 5. ✂️ Де-блоатинг внешних парсеров (YAGNI)
### 6. ✂️ Де-блоатинг внешних парсеров (YAGNI)
- [ ] Удалить лишний сетевой опрос Datamuse (`fetch_datamuse`) — он дублирует определения и перегружает ответ нерелевантными рифмами.
- [ ] Упростить хрупкий regex-парсинг разметки Wikitext, опираясь на стабильные REST JSON эндпоинты.
---
### 6. 📚 Локальный оффлайн-словарь (99%+ покрытия со словоформами, SQLite 10–20 МБ)
### 7. 📚 Локальный оффлайн-словарь (99%+ покрытия со словоформами, SQLite 10–20 МБ)
- [ ] Создать в SQLite таблицу:
```sql
CREATE TABLE IF NOT EXISTS offline_dictionary (
@@ -103,7 +113,7 @@
---
### 7. 🧩 Модульность фронтенда на нативных ES-модулях (без Webpack/Vite)
### 8. 🧩 Модульность фронтенда на нативных 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` — читалку, блок-парсер и навигацию по главам.
@@ -114,9 +124,10 @@
---
### 8. 🌐 Быстрый захват из браузера (Bookmarklet)
### 9. 🌐 Быстрый захват из браузера (Bookmarklet)
- [ ] Создать JavaScript-букмарклет для добавления слова/фразы из любого окна браузера в личный словарь [`study.qpid.pro`](https://study.qpid.pro).
---
## ⏳ Coming Soon