Feedback System
1. Summary
Goal: Система обратной связи и поддержки пользователей. Обеспечивает двустороннюю коммуникацию: пользователь создаёт тикет, поддержка отвечает, пользователь видит ответ и может продолжить диалог.
User Value: Возможность сообщить о проблеме, предложить улучшение, запросить ручную верификацию Steam или подать апелляцию бана — и получить ответ от команды поддержки.
2. Business Logic
Ticket Types
- Problem
- Suggestion
- Verification Request
- Ban Appeal
- Withdrawal Issue
Назначение: Сообщение о технической проблеме
Auth: telegramAuth (только авторизованные пользователи)
Цель: Bug reporting, technical issues
Назначение: Предложение улучшения
Auth: telegramAuth
Цель: Feature requests, UX feedback
Назначение: Заявка на ручную верификацию Steam
Auth: telegramAuth
Данные: Сохраняет tradeUrl пользователя
Процесс:
- Пользователь создаёт заявку с Trade URL
- Админ переходит по ссылке и проверяет аккаунт (игры, активность, возраст)
- Approve → steamId извлекается из Trade URL, пользователь верифицирован
- Reject → заявка закрыта с причиной отклонения
Цель: Альтернатива автоматической верификации Steam
Назначение: Апелляция бана
Auth: telegramAuthLight (работает для забаненных)
Ограничения:
- Максимум 1 открытая апелляция
- Максимум 1 апелляция в день
- Автоблокировка после 3 отклонений
Цель: Возможность обжаловать бан
Назначение: Проблема с выводом скина
Auth: telegramAuth
User Flow:
- Пользователь пытается вывести скин
- Предмета нет на боте → модалка с предложением написать в поддержку
- Пользователь описывает проблему → создаётся тикет
- Дальше обычная переписка с поддержкой
Цель: Решение проблем когда withdrawal не удался (предмет недоступен на боте)
Ticket Lifecycle
Core Mechanics
1. Создание тикета
- Пользователь отправляет сообщение (10-300 символов)
- Сообщение sanitized через DOMPurify
- Создаётся
UserFeedbackсо статусомNEW
2. Messaging
- Пользователь и админ могут добавлять сообщения
- При ответе админа статус →
IN_PROGRESS - Rate limit: 10 сообщений в день на пользователя
3. Notifications
- Ответ админа → Telegram уведомление пользователю
- Ответ пользователя → Telegram уведомление в топик
REPLIES - Закрытие → Telegram уведомление пользователю
Уведомления для админов отправляются в специальную Telegram-группу с ~10 топиками для разных типов событий (заявки, ответы, критичные действия).
4. Auto-close
- Cron job: ежедневно в 03:00 UTC
- Закрывает тикеты без активности > 10 дней
- Добавляет системное сообщение + уведомление
Ban Appeal Mechanics
Ban Appeal использует telegramAuthLight — облегчённую авторизацию без проверки бана. Это позволяет забаненным пользователям подавать апелляции.
Алгоритм:
- Проверка: пользователь забанен? (иначе 400 NOT_BANNED)
- Проверка: нет
isAppealsBanned? (иначе 403 APPEALS_BANNED) - Проверка: нет открытой апелляции? (иначе 400 ALREADY_EXISTS)
- Rate limit: 1 апелляция/день (иначе 429)
- Создание апелляции + уведомление админам
Результаты:
APPROVED→ Пользователь разбанен, BannedSteamId удаляетсяREJECTED→ Апелляция отклонена, счётчик++
Auto-ban апелляций:
После 3 отклонённых апелляций isAppealsBanned = true — пользователь больше не может подавать апелляции.
Protection
| Действие | Rate Limit | Auth | Validation |
|---|---|---|---|
| Submit feedback | feedback (1/min) | Telegram | FeedbackSchema |
| Send message | 10/day (app-level) | Telegram | createMessageSchema |
| Submit ban appeal | 1/day (app-level) | TelegramLight | BAN_APPEAL_LIMITS |
| Close ticket | - | Telegram | ticketIdParamSchema |
| Admin actions | mutations | Admin JWT | varies |
См. Security Matrix для полного обзора защит.
Edge Cases
| Ситуация | UI поведение |
|---|---|
| Тикет закрыт | Кнопка "Отправить" disabled |
| 10 сообщений за день | 429 RATE_LIMITED |
| Не забанен (ban-appeal) | 400 NOT_BANNED |
| Открытая апелляция есть | 400 APPEAL_ALREADY_EXISTS |
| Апелляции заблокированы | 403 APPEALS_BANNED |
| 10 дней без активности | Тикет auto-closed |
Backend Error Codes
| Код | HTTP | Сообщение |
|---|---|---|
TICKET_NOT_FOUND | 404 | Тикет не найден |
TICKET_CLOSED | 400 | Тикет закрыт |
TICKET_ALREADY_CLOSED | 400 | Тикет уже закрыт |
RATE_LIMITED | 429 | Лимит сообщений/апелляций |
NOT_BANNED | 400 | Вы не заблокированы |
APPEAL_ALREADY_EXISTS | 400 | Открытая апелляция уже есть |
APPEALS_BANNED | 403 | Апелляции заблокированы |
3. ADR (Architectural Decisions)
Почему telegramAuthLight для Ban Appeal?
Проблема: Забаненные пользователи не проходят telegramAuth (middleware проверяет isBanned), но им нужна возможность подать апелляцию.
Решение: Создан telegramAuthLight — упрощённый middleware, который:
- Верифицирует Telegram initData
- НЕ проверяет бан-статус
- Возвращает
userIdиtelegramId
Альтернативы (отклонены):
- Публичный эндпоинт без auth — риск спама
- Отдельный бот для апелляций — сложность инфраструктуры
Последствия: Простая интеграция, но требует отдельных эндпоинтов с telegramAuthLight.
Почему автоблокировка после 3 отклонений?
Проблема: Пользователи могут злоупотреблять апелляциями, создавая нагрузку на поддержку.
Решение: isAppealsBanned = true после 3 отклонённых апелляций.
Альтернативы (отклонены):
- Увеличивающийся cooldown — сложнее в реализации, всё равно не решает проблему
- Без ограничений — нагрузка на поддержку
Последствия: Защита от злоупотреблений, но требует ручного снятия блокировки если ошибка.
Почему 10 сообщений в день?
Проблема: Нужен баланс между доступностью и защитой от спама.
Решение: MESSAGE_LIMIT_PER_DAY = 10 на уровне приложения (не rate limit middleware).
Почему не rate limit middleware?
- Rate limit считает по IP/telegramId за минуту
- Нам нужен суточный лимит на сообщения (не запросы)
Последствия: Подсчёт через countUserMessagesToday() в БД.
4. Architecture
Services Overview
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| TicketService | backend/src/domains/feedback/services/ticket.service.ts | Бизнес-логика тикетов |
| TicketNotificationService | backend/src/domains/feedback/services/ticket-notification.service.ts | Telegram уведомления |
| TicketAutoCloseService | backend/src/domains/feedback/services/ticket-auto-close.service.ts | Auto-close логика |
| TicketRepository | backend/src/domains/feedback/repositories/ticket.repository.ts | Data access layer |
| BanAppealController | backend/src/domains/feedback/controllers/ban-appeal.controller.ts | Ban appeal логика |
| Ticket Routes | backend/src/domains/feedback/routes/ticket.routes.ts | User API |
| Ban Appeal Routes | backend/src/domains/feedback/routes/ban-appeal.routes.ts | Ban appeal API |
| Admin Routes | backend/src/domains/admin/routes/admin-feedback.routes.ts | Admin API |
5. Database Schema
Models
| Модель | Описание | Ключевые поля |
|---|---|---|
| UserFeedback | Тикет/обращение | type, status, message, appealResult, tradeUrl |
| FeedbackMessage | Сообщение в тикете | feedbackId, authorType, message |
| User | Пользователь | isBanned, isAppealsBanned, appealsBannedAt |
Enums
| Enum | Значения | Описание |
|---|---|---|
| UserFeedbackType | SUGGESTION, PROBLEM, VERIFICATION_REQUEST, BAN_APPEAL, WITHDRAWAL_ISSUE | Тип обращения |
| UserFeedbackStatus | NEW, IN_PROGRESS, RESOLVED | Статус тикета |
| MessageAuthor | USER, ADMIN, SYSTEM | Автор сообщения |
| AppealResult | APPROVED, REJECTED | Результат апелляции |
Relationships
6. API Endpoints
- User: Tickets
- User: Ban Appeal
- Admin: Feedback
- Admin: Verification
- Admin: Ban Appeal
| Метод | Эндпоинт | Описание | Docs |
|---|---|---|---|
| GET | /api/tickets | Список тикетов пользователя | → |
| GET | /api/tickets/unread-count | Количество непрочитанных | → |
| GET | /api/tickets/:id | Детали тикета | → |
| POST | /api/tickets/:id/messages | Отправить сообщение | → |
| POST | /api/tickets/:id/close | Закрыть тикет | → |
| Метод | Эндпоинт | Описание | Docs |
|---|---|---|---|
| POST | /api/feedback/ban-appeal | Подать апелляцию | → |
| GET | /api/feedback/ban-appeal/status | Статус апелляции | → |
| Метод | Эндпоинт | Описание | Docs |
|---|---|---|---|
| GET | /admin/feedback | Все тикеты | → |
| PUT | /admin/feedback/:id | Обновить статус | → |
| DELETE | /admin/feedback/:id | Удалить | → |
| GET | /admin/feedback/stats | Статистика | → |
| GET | /admin/feedback/:id/messages | Сообщения тикета | → |
| POST | /admin/feedback/:id/messages | Ответить | → |
| POST | /admin/feedback/:id/close | Закрыть | → |
7. Related
- Profile — данные пользователя, бан-статус
- Referrals — другой social домен
- Security Matrix — обзор защит