Собрал локальный MVP сервиса для поиска тиммейтов

Я регулярно встречаю объявления вроде «ищу дуо», «нужен саппорт», «собираю стак» в TikTok, Telegram, Discord и игровых пабликах.

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

На хакатоне Kodik я решил проверить идею отдельного сервиса для такой задачи. Рабочее название — AbyssHub.

Я делал проект один. Сейчас у меня есть локальная версия, интерфейсы и кодовая база. Публично сервис ещё не запущен: я хочу сначала понять, есть ли у этой идеи спрос, какие сценарии важнее всего и где пользователи увидят проблемы раньше, чем я вложу в разработку ещё несколько месяцев.

Собрал локальный MVP сервиса для поиска тиммейтов

Что хочу сделать

В первой версии пользователь заполняет анкету: выбирает игры, ранг, роль, регион, часовой пояс, язык, формат общения и цель поиска. Затем смотрит ленту анкет, ставит лайк или пропускает карточку. Взаимный лайк должен открывать чат. Отдельно предусмотрен поиск команды под конкретную задачу: турнир, стрим, регулярная игра или разовый сбор.

На бумаге это похоже на механику дейтинг-приложений. В игровом контексте важнее другое: перед первым сообщением быстро понять, совпадаете ли вы по условиям игры.

Например, я бы скорее написал человеку с такой анкетой:

CS2, Premier, будни после 20:00 по Москве. Ищу постоянный стак. Играю на результат, нужен войс, без оскорблений и ливов после первой неудачной карты.

Чем отвечал бы на короткое «ищу тиммейтов в CS2».

Собрал локальный MVP сервиса для поиска тиммейтов

Что есть в коде

Репозиторий я собрал как монорепо: в нём лежат backend, frontend и инфраструктура. Бэкенд написан на Go, интерфейс — на TypeScript с Next.js, а SQL-миграции вынесены отдельно.

Внутри бэкенда я сразу разложил домены по сервисам:

  • auth-service — регистрация, вход и токены;
  • profile-service — анкета, игровые данные и аватары;
  • matching-service — выдача карточек, лайки и мэтчи;
  • chat-service — переписка после мэтча;
  • team-search-service — поиск команды под конкретную задачу;
  • moderation-service — жалобы и блокировки;
  • notification-service — уведомления;
  • payment-service — будущие платные возможности.

Это спорное решение для соло-разработки и ранней стадии. Несколько автономных сервисов добавляют точки отказа, усложняют локальную отладку и требуют больше дисциплины в API-контрактах. Я выбрал такую структуру, потому что у доменов довольно разные границы: авторизация, подбор, чат и модерация будут развиваться по-разному, а чат потенциально создаёт самую заметную нагрузку и самые неприятные риски.

Если по итогам обсуждения окажется, что такая структура слишком тяжёлая для текущей стадии, я без сожалений сведу часть логики в модульный монолит. Мне важнее скорость проверки продуктовой гипотезы, чем архитектурная красота.

Как устроен локальный стенд

Локальное окружение поднимается через Docker Compose. В нём есть PostgreSQL 16, Redis 7, Centrifugo для real-time-соединений, Asynqmon для наблюдения за фоновыми задачами, Nginx и контейнеры сервисов.

PostgreSQL хранит основные сущности продукта. В репозитории уже есть миграции для исходной схемы, ролей пользователей, soft delete, расширения pgcrypto, тестовых данных, дневных лимитов свайпов, аналитических данных, поиска команды и аватаров чатов.

Redis нужен для вещей, которые не хочется каждый раз считать или хранить в основной базе: сессий, лимитов, rate limiting и фоновых задач. Для реального времени я заложил Centrifugo: он снимает с прикладного кода часть работы с постоянными WebSocket-подключениями и pub/sub.

Собрал локальный MVP сервиса для поиска тиммейтов

Почему подбор пока простой

Сейчас подбор устроен намеренно грубо: пользователи могут попасть в выдачу, если у них есть хотя бы одна общая игра. Вокруг этого уже можно строить фильтры по рангу, региону и роли.

Я сознательно не стал делать «умную» алгоритмическую ленту во время хакатона. Для неё нужны данные, которых у меня пока нет: какие карточки люди реально открывают, кому пишут, после каких мэтчей доходят до игры, какие фильтры используют и почему возвращаются или не возвращаются.

Есть слишком много предположений, которые хочется проверить:

  • Для Доты и CS2 ранг \ ммр может быть важнее прайм-тайма.
  • Для кооп-игр вроде Genshin Impact важнее цель и стиль общения.
  • Для постоянной команды критичны часовой пояс и регулярность.

Сложный скоринг появится позже, если подтвердится, что люди вообще готовы заполнять профиль и искать через карточки. Сначала нужна простая, объяснимая логика выдачи.

Самая трудная часть — безопасность

Карточки, фильтры и лайки — понятная продуктовая механика. Больше всего времени у меня ушло на вопросы, связанные с безопасностью.

Сервис собирает чувствительный для игрока контекст: когда он бывает онлайн, где играет, как предпочитает общаться, что ищет и с кем готов вступать в контакт. После мэтча появляется переписка между незнакомыми людьми. В такой системе быстро возникают спам, оскорбления, преследование, мошеннические ссылки и попытки вытащить личные данные.

Поэтому в проект заложены отдельный сервис модерации, репорты, блокировки, soft delete и ограничения на действия пользователей. В конфигурации локального окружения секреты вынесены в переменные окружения, Redis запускается с паролем, а сервисы зависят от healthcheck’ов PostgreSQL и Redis.

Для входа планируется обычная схема email/логин и пароль с хэшированием через bcrypt, а для чата — TLS на уровне канала. Подтверждение email и привязку Steam/Riot-аккаунтов я отложил на следующий этап: эти механики нужны для доверия к профилям, но не должны тормозить проверку базового сценария.

Что хочу проверить до запуска

Сейчас для меня важнее всего ответы на несколько вопросов:

  1. Захотят ли игроки заполнить анкету из 10–15 полей ради более точного поиска.
  2. Какие параметры действительно нужны в карточке до первого сообщения.
  3. Достаточно ли совпадения по игре для первой выдачи.
  4. Где пользователи проведут границу между полезным профилем и лишним сбором данных.

В репозитории уже заложены продуктовые воронки: заполнение анкеты, первый свайп, первый мэтч, первое сообщение, а также retention D1, D7 и D30. Именно эти показатели я хочу смотреть в закрытом тесте, а не общее число регистраций.

Нужна критика

Буду рад фидбеку от игроков, разработчиков и администраторов игровых сообществ.

Если ты ищешь тиммейтов, расскажи:

  • В какие игры ты играешь и где сейчас ищешь людей.
  • Какие три поля чужого профиля для тебя самые важные.
  • Готов ли ты пользоваться внутренним чатом или предпочёл бы сразу перейти в Discord/Telegram.
  • Что вызовет недоверие к такому сервису.
  • В каком сценарии ты бы попробовал AbyssHub первым: одна катка, дуо в рейтинг, постоянный стак, кооп или турнир.

Если ты работаешь с Go, real-time-системами или продуктами с пользовательским контентом, особенно интересны замечания к текущему делению на сервисы, модели безопасности и очередности разработки.

1