10 KiB
10 KiB
Улучшения системы обработки банковских транзакций
1. Упрощение логики бесконечного редактирования
1.1 Текущая проблема
- Используется таблица
user_sessionsдля хранения состояния редактирования - Множественные SELECT/UPDATE запросы при каждом действии пользователя
- Сложная логика ветвления в n8n для управления сессиями
1.2 Решение: Stateful callback_data с editMessage
Принцип работы: Храним все состояние редактирования прямо в callback_data кнопок Telegram
Формат callback_data
edit_card_{transactionId}_{counterparty}_{category}
set_category_{transactionId}_{counterparty}_{newCategory}
edit_field_{transactionId}_{counterparty}_{category}_{field}
confirm_{transactionId}_{counterparty}_{category}
Примеры
edit_card_123_Пятёрочка_Продукты
set_category_123_Пятёрочка_Авто
edit_field_123_Пятёрочка_Продукты_category
confirm_123_Пятёрочка_Продукты
Узлы n8n для удаления
- ❌
user_sessionsтаблица - ❌
get_session(SELECT) - ❌
add_session_category(INSERT) - ❌
add_session_counterparty(INSERT) - ❌
merge_user_and_session - ❌
parse_text_input(частично) - ❌
merge_changes
Новые узлы
- ✅
create_edit_card— генерирует карточку редактирования с inline-клавиатурой - ✅
update_card_on_action— обрабатывает callback и обновляет сообщение через editMessage
1.3 Преимущества
- Уменьшение нагрузки на БД на 80% — убираем 5-7 запросов на одно действие
- Упрощение workflow — вместо ветвления по сессиям — линейная обработка
- Мгновенная обратная связь — editMessage вместо новых сообщений
- Stateless архитектура — нет зависимостей между запросами
2. Улучшение UX для выбора категорий
2.1 Текущая проблема
- Текстовый ввод категорий требует запоминания всех 20 вариантов
- Ошибки при ручном вводе (опечатки, синонимы)
- Медленный процесс категоризации
2.2 Решение: Многоуровневая inline-клавиатура
Первый уровень — "умные" популярные категории
// Алгоритм выбора популярных категорий:
// 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 = () => ["Продукты", "Авто", "Дом"];
Второй уровень — все категории компактно
// Без эмодзи для экономии места
const ALL_CATEGORIES = [
["Продукты", "Авто", "Здоровье", "Арчи"],
["ЖКХ", "Дом", "Проезд", "Одежда"],
["Химия", "Косметика", "Инвестиции", "Развлечения"],
["Общепит", "Штрафы", "Налоги", "Подписки"],
["Перевод", "Наличные", "Подарки", "Спорт"],
["Другое"]
];
// Каждая кнопка: callback_data = "set_category_{id}_{counterparty}_{category}"
Узлы n8n для изменения
- 🔄
category_edit→send_category_keyboard(отправляет 4 кнопки) - ✅
show_all_categories→ новый узел для отправки полного списка - ❌ Текстовый ввод категорий удаляется полностью
Кэширование популярных категорий
// В Redis или памяти n8n (Global Variables)
// Ключ: user_top_cats_{chatId}
// TTL: 1 час
// Данные: ["Продукты", "Общепит", "Авто"]
// При запросе:
// 1. Проверяем кэш
// 2. Если нет → запрос к БД → сохранение в кэш
// 3. Возвращаем данные
2.3 Преимущества
- В 3-5 раз быстрее выбор категории
- Нет ошибок ввода — только валидные категории
- Персонализация — показываем часто используемые категории
- Экономия места — без эмодзи больше категорий на экране
3. Техническая реализация
Изменения в БД
-- Удаляем таблицу 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
Ветка редактирования (новая)
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)
Ветка выбора категории
set_category (callback) →
update_category_stats (DB) → -- инкрементируем счетчик
update_card (editMessage) → -- обновляем карточку
(возврат в режим редактирования)
Ветка "все категории"
show_all_cats (callback) →
send_all_categories (Telegram Message) → -- компактная клавиатура 5x4
(пользователь выбирает) →
set_category (существующая ветка)
Лимиты и ограничения
-
Callback_data length ≤ 64 байт
// Решение: кодирование/декодирование длинных строк const encodeData = (str) => encodeURIComponent(str.substring(0, 20)); const decodeData = (str) => decodeURIComponent(str); -
Inline keyboard rows ≤ 8-10 для удобства
-
Кэш TTL = 1 час для актуальности
4. Ожидаемые результаты
Метрики улучшений
| Показатель | Было | Стало | Улучшение |
|---|---|---|---|
| Запросов к БД на действие | 5-7 | 1-2 | ~70% ↓ |
| Время категоризации | 10-30 сек | 2-5 сек | 5x ↑ |
| Ошибок категоризации | 15-20% | <2% | 10x ↓ |
| Пользовательских кликов | 3-5 | 1-2 | 2x ↓ |
Безопасность
- Все данные в callback_data URL-encoded
- Валидация transactionId при каждом запросе
- Проверка прав доступа к чату
Резервное решение
Если callback_data превышает лимит Telegram:
// 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 дня)
- Создать новую таблицу
user_category_stats - Написать миграцию данных из истории транзакций
- Обновить узлы обработки callback_data
Фаза 2: Внедрение (1 день)
- Добавить новые узлы n8n параллельно существующим
- Протестировать на отдельном Telegram-боте
- Проверить лимиты callback_data
Фаза 3: Переключение (1 день)
- Направить 10% трафика на новую систему
- Сравнить метрики
- Полное переключение при успехе
Фаза 4: Оптимизация (непрерывно)
- Мониторинг нагрузки БД
- Настройка кэширования
- A/B тестирование разных наборов популярных категорий
Заключение
Предложенные изменения устраняют основные боли пользователей:
- Упрощают редактирование через мгновенное обновление карточек
- Ускоряют категоризацию через умные inline-клавиатуры
- Уменьшают нагрузку на инфраструктуру через stateless дизайн
Общее количество узлов n8n сократится с 36 до ~25 при улучшении UX и производительности.