266 lines
10 KiB
Markdown
266 lines
10 KiB
Markdown
# Улучшения системы обработки банковских транзакций
|
||
|
||
## 1. Упрощение логики бесконечного редактирования
|
||
|
||
### 1.1 Текущая проблема
|
||
|
||
- Используется таблица `user_sessions` для хранения состояния редактирования
|
||
- Множественные SELECT/UPDATE запросы при каждом действии пользователя
|
||
- Сложная логика ветвления в n8n для управления сессиями
|
||
|
||
### 1.2 Решение: Stateful callback_data с editMessage
|
||
|
||
**Принцип работы:** Храним все состояние редактирования прямо в callback_data кнопок Telegram
|
||
|
||
#### Формат callback_data
|
||
|
||
```text
|
||
edit_card_{transactionId}_{counterparty}_{category}
|
||
set_category_{transactionId}_{counterparty}_{newCategory}
|
||
edit_field_{transactionId}_{counterparty}_{category}_{field}
|
||
confirm_{transactionId}_{counterparty}_{category}
|
||
```
|
||
|
||
#### Примеры
|
||
|
||
```text
|
||
edit_card_123_Пятёрочка_Продукты
|
||
set_category_123_Пятёрочка_Авто
|
||
edit_field_123_Пятёрочка_Продукты_category
|
||
confirm_123_Пятёрочка_Продукты
|
||
```
|
||
|
||
#### Узлы n8n для удаления
|
||
|
||
1. ❌ `user_sessions` таблица
|
||
2. ❌ `get_session` (SELECT)
|
||
3. ❌ `add_session_category` (INSERT)
|
||
4. ❌ `add_session_counterparty` (INSERT)
|
||
5. ❌ `merge_user_and_session`
|
||
6. ❌ `parse_text_input` (частично)
|
||
7. ❌ `merge_changes`
|
||
|
||
#### Новые узлы
|
||
|
||
1. ✅ `create_edit_card` — генерирует карточку редактирования с inline-клавиатурой
|
||
2. ✅ `update_card_on_action` — обрабатывает callback и обновляет сообщение через editMessage
|
||
|
||
### 1.3 Преимущества
|
||
|
||
- **Уменьшение нагрузки на БД на 80%** — убираем 5-7 запросов на одно действие
|
||
- **Упрощение workflow** — вместо ветвления по сессиям — линейная обработка
|
||
- **Мгновенная обратная связь** — editMessage вместо новых сообщений
|
||
- **Stateless архитектура** — нет зависимостей между запросами
|
||
|
||
## 2. Улучшение UX для выбора категорий
|
||
|
||
### 2.1 Текущая проблема
|
||
|
||
- Текстовый ввод категорий требует запоминания всех 20 вариантов
|
||
- Ошибки при ручном вводе (опечатки, синонимы)
|
||
- Медленный процесс категоризации
|
||
|
||
### 2.2 Решение: Многоуровневая inline-клавиатура
|
||
|
||
#### Первый уровень — "умные" популярные категории
|
||
|
||
```javascript
|
||
// Алгоритм выбора популярных категорий:
|
||
// 1. Берем топ-3 категории пользователя из истории (если есть)
|
||
// 2. Добавляем глобально популярные категории
|
||
// 3. Всего 4 кнопки
|
||
|
||
const getUserTopCategories = async (chatId) => {
|
||
// Запрос к БД за последние 30 дней
|
||
const topCats = await db.query(`
|
||
SELECT category, COUNT(*) as count
|
||
FROM transactions
|
||
WHERE chat_id = $1
|
||
AND category IS NOT NULL
|
||
AND received_at > NOW() - INTERVAL '30 days'
|
||
GROUP BY category
|
||
ORDER BY count DESC
|
||
LIMIT 3
|
||
`, [chatId]);
|
||
|
||
return topCats.map(row => row.category);
|
||
};
|
||
|
||
const getDefaultCategories = () => ["Продукты", "Авто", "Дом"];
|
||
```
|
||
|
||
#### Второй уровень — все категории компактно
|
||
|
||
```javascript
|
||
// Без эмодзи для экономии места
|
||
const ALL_CATEGORIES = [
|
||
["Продукты", "Авто", "Здоровье", "Арчи"],
|
||
["ЖКХ", "Дом", "Проезд", "Одежда"],
|
||
["Химия", "Косметика", "Инвестиции", "Развлечения"],
|
||
["Общепит", "Штрафы", "Налоги", "Подписки"],
|
||
["Перевод", "Наличные", "Подарки", "Спорт"],
|
||
["Другое"]
|
||
];
|
||
|
||
// Каждая кнопка: callback_data = "set_category_{id}_{counterparty}_{category}"
|
||
```
|
||
|
||
#### Узлы n8n для изменения
|
||
|
||
1. 🔄 `category_edit` → `send_category_keyboard` (отправляет 4 кнопки)
|
||
2. ✅ `show_all_categories` → новый узел для отправки полного списка
|
||
3. ❌ Текстовый ввод категорий удаляется полностью
|
||
|
||
#### Кэширование популярных категорий
|
||
|
||
```javascript
|
||
// В Redis или памяти n8n (Global Variables)
|
||
// Ключ: user_top_cats_{chatId}
|
||
// TTL: 1 час
|
||
// Данные: ["Продукты", "Общепит", "Авто"]
|
||
|
||
// При запросе:
|
||
// 1. Проверяем кэш
|
||
// 2. Если нет → запрос к БД → сохранение в кэш
|
||
// 3. Возвращаем данные
|
||
```
|
||
|
||
### 2.3 Преимущества
|
||
|
||
- **В 3-5 раз быстрее** выбор категории
|
||
- **Нет ошибок ввода** — только валидные категории
|
||
- **Персонализация** — показываем часто используемые категории
|
||
- **Экономия места** — без эмодзи больше категорий на экране
|
||
|
||
## 3. Техническая реализация
|
||
|
||
### Изменения в БД
|
||
|
||
```sql
|
||
-- Удаляем таблицу user_sessions
|
||
DROP TABLE IF EXISTS user_sessions;
|
||
|
||
-- Добавляем кэш популярных категорий (опционально)
|
||
CREATE TABLE IF NOT EXISTS user_category_stats (
|
||
chat_id BIGINT,
|
||
category VARCHAR(100),
|
||
count INTEGER DEFAULT 1,
|
||
last_used TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (chat_id, category)
|
||
);
|
||
|
||
-- Индекс для быстрого получения топ категорий
|
||
CREATE INDEX idx_user_cats ON user_category_stats(chat_id, count DESC);
|
||
```
|
||
|
||
### Изменения в workflow n8n
|
||
|
||
#### Ветка редактирования (новая)
|
||
|
||
```text
|
||
edit_field (callback) →
|
||
IF field = 'category' →
|
||
get_top_categories (Code + возможно DB) →
|
||
send_category_keyboard (Telegram Message)
|
||
|
||
IF field = 'counterparty' →
|
||
request_counterparty_input (Telegram Message) →
|
||
(текстовый ответ) →
|
||
update_card_with_new_counterparty (editMessage)
|
||
```
|
||
|
||
#### Ветка выбора категории
|
||
|
||
```text
|
||
set_category (callback) →
|
||
update_category_stats (DB) → -- инкрементируем счетчик
|
||
update_card (editMessage) → -- обновляем карточку
|
||
(возврат в режим редактирования)
|
||
```
|
||
|
||
#### Ветка "все категории"
|
||
|
||
```text
|
||
show_all_cats (callback) →
|
||
send_all_categories (Telegram Message) → -- компактная клавиатура 5x4
|
||
(пользователь выбирает) →
|
||
set_category (существующая ветка)
|
||
```
|
||
|
||
### Лимиты и ограничения
|
||
|
||
1. **Callback_data length** ≤ 64 байт
|
||
|
||
```javascript
|
||
// Решение: кодирование/декодирование длинных строк
|
||
const encodeData = (str) => encodeURIComponent(str.substring(0, 20));
|
||
const decodeData = (str) => decodeURIComponent(str);
|
||
```
|
||
|
||
2. **Inline keyboard rows** ≤ 8-10 для удобства
|
||
3. **Кэш TTL** = 1 час для актуальности
|
||
|
||
## 4. Ожидаемые результаты
|
||
|
||
### Метрики улучшений
|
||
|
||
| Показатель | Было | Стало | Улучшение |
|
||
| ------------ | ------ | ------- | ----------- |
|
||
| Запросов к БД на действие | 5-7 | 1-2 | ~70% ↓ |
|
||
| Время категоризации | 10-30 сек | 2-5 сек | 5x ↑ |
|
||
| Ошибок категоризации | 15-20% | <2% | 10x ↓ |
|
||
| Пользовательских кликов | 3-5 | 1-2 | 2x ↓ |
|
||
|
||
### Безопасность
|
||
|
||
1. Все данные в callback_data URL-encoded
|
||
2. Валидация transactionId при каждом запросе
|
||
3. Проверка прав доступа к чату
|
||
|
||
### Резервное решение
|
||
|
||
Если callback_data превышает лимит Telegram:
|
||
|
||
```javascript
|
||
// Fallback: короткий хэш + временное хранилище
|
||
const hash = md5(transactionId + counterparty + category).substring(0, 8);
|
||
cache.set(`card_${hash}`, {transactionId, counterparty, category}, 300); // 5 мин
|
||
callback_data = `short_${hash}`;
|
||
```
|
||
|
||
## 5. План внедрения
|
||
|
||
### Фаза 1: Подготовка (1-2 дня)
|
||
|
||
1. Создать новую таблицу `user_category_stats`
|
||
2. Написать миграцию данных из истории транзакций
|
||
3. Обновить узлы обработки callback_data
|
||
|
||
### Фаза 2: Внедрение (1 день)
|
||
|
||
1. Добавить новые узлы n8n параллельно существующим
|
||
2. Протестировать на отдельном Telegram-боте
|
||
3. Проверить лимиты callback_data
|
||
|
||
### Фаза 3: Переключение (1 день)
|
||
|
||
1. Направить 10% трафика на новую систему
|
||
2. Сравнить метрики
|
||
3. Полное переключение при успехе
|
||
|
||
### Фаза 4: Оптимизация (непрерывно)
|
||
|
||
1. Мониторинг нагрузки БД
|
||
2. Настройка кэширования
|
||
3. A/B тестирование разных наборов популярных категорий
|
||
|
||
## Заключение
|
||
|
||
Предложенные изменения устраняют основные боли пользователей:
|
||
|
||
- **Упрощают редактирование** через мгновенное обновление карточек
|
||
- **Ускоряют категоризацию** через умные inline-клавиатуры
|
||
- **Уменьшают нагрузку** на инфраструктуру через stateless дизайн
|
||
|
||
Общее количество узлов n8n сократится с 36 до ~25 при улучшении UX и производительности.
|