Skip to main content

Feedback System

1. Summary

Goal: Система обратной связи и поддержки пользователей. Обеспечивает двустороннюю коммуникацию: пользователь создаёт тикет, поддержка отвечает, пользователь видит ответ и может продолжить диалог.

User Value: Возможность сообщить о проблеме, предложить улучшение, запросить ручную верификацию Steam или подать апелляцию бана — и получить ответ от команды поддержки.


2. Business Logic

Ticket Types

Назначение: Сообщение о технической проблеме

Auth: telegramAuth (только авторизованные пользователи)

Цель: Bug reporting, technical issues

Ticket Lifecycle

Core Mechanics

1. Создание тикета

  • Пользователь отправляет сообщение (10-300 символов)
  • Сообщение sanitized через DOMPurify
  • Создаётся UserFeedback со статусом NEW

2. Messaging

  • Пользователь и админ могут добавлять сообщения
  • При ответе админа статус → IN_PROGRESS
  • Rate limit: 10 сообщений в день на пользователя

3. Notifications

  • Ответ админа → Telegram уведомление пользователю
  • Ответ пользователя → Telegram уведомление в топик REPLIES
  • Закрытие → Telegram уведомление пользователю
Admin Telegram Topics

Уведомления для админов отправляются в специальную Telegram-группу с ~10 топиками для разных типов событий (заявки, ответы, критичные действия).

4. Auto-close

  • Cron job: ежедневно в 03:00 UTC
  • Закрывает тикеты без активности > 10 дней
  • Добавляет системное сообщение + уведомление

Ban Appeal Mechanics

Особая логика для апелляций

Ban Appeal использует telegramAuthLight — облегчённую авторизацию без проверки бана. Это позволяет забаненным пользователям подавать апелляции.

Алгоритм:

  1. Проверка: пользователь забанен? (иначе 400 NOT_BANNED)
  2. Проверка: нет isAppealsBanned? (иначе 403 APPEALS_BANNED)
  3. Проверка: нет открытой апелляции? (иначе 400 ALREADY_EXISTS)
  4. Rate limit: 1 апелляция/день (иначе 429)
  5. Создание апелляции + уведомление админам

Результаты:

  • APPROVED → Пользователь разбанен, BannedSteamId удаляется
  • REJECTED → Апелляция отклонена, счётчик++

Auto-ban апелляций: После 3 отклонённых апелляций isAppealsBanned = true — пользователь больше не может подавать апелляции.

Protection

ДействиеRate LimitAuthValidation
Submit feedbackfeedback (1/min)TelegramFeedbackSchema
Send message10/day (app-level)TelegramcreateMessageSchema
Submit ban appeal1/day (app-level)TelegramLightBAN_APPEAL_LIMITS
Close ticket-TelegramticketIdParamSchema
Admin actionsmutationsAdmin JWTvaries
Детали реализации

См. 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_FOUND404Тикет не найден
TICKET_CLOSED400Тикет закрыт
TICKET_ALREADY_CLOSED400Тикет уже закрыт
RATE_LIMITED429Лимит сообщений/апелляций
NOT_BANNED400Вы не заблокированы
APPEAL_ALREADY_EXISTS400Открытая апелляция уже есть
APPEALS_BANNED403Апелляции заблокированы

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

КомпонентПутьОписание
TicketServicebackend/src/domains/feedback/services/ticket.service.tsБизнес-логика тикетов
TicketNotificationServicebackend/src/domains/feedback/services/ticket-notification.service.tsTelegram уведомления
TicketAutoCloseServicebackend/src/domains/feedback/services/ticket-auto-close.service.tsAuto-close логика
TicketRepositorybackend/src/domains/feedback/repositories/ticket.repository.tsData access layer
BanAppealControllerbackend/src/domains/feedback/controllers/ban-appeal.controller.tsBan appeal логика
Ticket Routesbackend/src/domains/feedback/routes/ticket.routes.tsUser API
Ban Appeal Routesbackend/src/domains/feedback/routes/ban-appeal.routes.tsBan appeal API
Admin Routesbackend/src/domains/admin/routes/admin-feedback.routes.tsAdmin API

5. Database Schema

Models

МодельОписаниеКлючевые поля
UserFeedbackТикет/обращениеtype, status, message, appealResult, tradeUrl
FeedbackMessageСообщение в тикетеfeedbackId, authorType, message
UserПользовательisBanned, isAppealsBanned, appealsBannedAt

Enums

EnumЗначенияОписание
UserFeedbackTypeSUGGESTION, PROBLEM, VERIFICATION_REQUEST, BAN_APPEAL, WITHDRAWAL_ISSUEТип обращения
UserFeedbackStatusNEW, IN_PROGRESS, RESOLVEDСтатус тикета
MessageAuthorUSER, ADMIN, SYSTEMАвтор сообщения
AppealResultAPPROVED, REJECTEDРезультат апелляции

Relationships


6. API Endpoints

МетодЭндпоинтОписаниеDocs
GET/api/ticketsСписок тикетов пользователя
GET/api/tickets/unread-countКоличество непрочитанных
GET/api/tickets/:idДетали тикета
POST/api/tickets/:id/messagesОтправить сообщение
POST/api/tickets/:id/closeЗакрыть тикет

  • Profile — данные пользователя, бан-статус
  • Referrals — другой social домен
  • Security Matrix — обзор защит