Cover

Предыстория, или "Ну сколько можно терпеть?"

Знаете это чувство, когда сидишь на очередном спринт-планировании, команда пытается оценить таски, а планинг покер тормозит так, что успеваешь кофе сварить, пока карточка загрузится?

Вот у меня в AGG TEAM такая же история была. Мы пробовали:

  • Planning Poker Online - лагает, реклама, UI из 2010-го

  • Scrum Poker for Jira - платный, тяжелый, нужен Jira (сюрприз!)

  • PlanITpoker - работает, но без фич, которые нужны именно нам

И тут я подумал: "А че, сам накодить не судьба?"
Спойлер: судьба, но получилось годно! 🚀


Проблема: когда у тебя 6 команд и один покер 😅

У нас в компании не одна команда, а шесть подразделений. Представьте: все хотят планировать одновременно, но в одной комнате покера. Это как пытаться играть в карты в переполненном баре - хаос и непонятки.

Нужно было:

  • ✅ Несколько столов одновременно (до 6)

  • ✅ Каждый стол со своей оценкой

  • ✅ Общая оценка по всем столам

  • ✅ Real-time синхронизация (не в режиме "обнови страницу")

  • ✅ Кидаться эмодзи друг в друга (это важно!)

  • ✅ Темная тема (это ж 2026-й на дворе!)

  • ✅ Мультиязычность (RU/EN)


Что получилось: Scrum Poker AGG TEAM

Demo Screenshot
Demo Screenshot

Фичи, которыми я горжусь 💪

1. Multi-table режим 🎰

Создаёшь сессию → выбираешь до 6 столов → каждый выбирает свой стол → все видят всех. Красота!

// Каждый стол имеет свой ID, название и статус
interface Table {
  id: string;
  name: string;
  revealed: boolean;
}

Хост может управлять столами на лету: добавлять, удалять, переименовывать. Остальные просто переключаются между ними.

2. Real-time всего и вся ⚡

Использовал Supabase как бэкенд. Polling каждые 2 секунды -тне элегантно, но работает стабильно:

useEffect(() => {
  if (view === 'room' && roomId) {
    fetchRoomState();
    const interval = setInterval(fetchRoomState, 2000);
    return () => clearInterval(interval);
  }
}, [view, roomId]);

Да, WebSocket'ы были бы круче, но для прототипа и 50 человек polling - самое то. Если масштаб вырастет, переделаю (наверное 😄).

3. Emoji-атаки! 🎉👍🔥

Можно кидаться эмодзи прямо в других участников! Анимация летит от твоего аватара к цели. Это добавило геймификации и веселья на скучные планирования.

12 эмодзи на выбор: 👍 👏 🎉 ❤️ 🚀 🔥 😂 🤔 💯 ✨ 👌 🙌

const throwAtPlayer = async (targetPlayerId: string, emoji: string) => {
  await fetch(`${API_URL}/rooms/${roomId}/throw`, {
    method: 'POST',
    body: JSON.stringify({
      fromPlayerId: playerId,
      toPlayerId: targetPlayerId,
      emoji,
    }),
  });
};

4. Карты Фибоначчи + дополнительные 🃏

Классика: 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, плюс "?" (не знаю) и "☕" (нужен кофе-брейк).

Можно менять голос даже после раскрытия - удобно, когда обсудили и хочешь скорректировать оценку.

5. Автоматический расчёт среднего 🧮

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

const calculateAverage = (tablePlayers: Player[], revealed: boolean) => {
  if (!revealed) return null;
  
  const numericVotes = tablePlayers
    .map(p => p.vote)
    .filter(v => v && !isNaN(Number(v)))
    .map(v => Number(v));
  
  if (numericVotes.length === 0) return null;
  
  const sum = numericVotes.reduce((a, b) => a + b, 0);
  return (sum / numericVotes.length).toFixed(1);
};

6. Темная тема + мультиязычность 🌙🌍

Переключатели в правом верхнем углу. Язык и тема сохраняются в localStorage:

const { t, language, toggleLanguage } = useTranslation();

// Все тексты через переводы
<h1>{t.welcome.title}</h1>

Перевёл весь интерфейс: все кнопки, сообщения, toast-уведомления.


Технический стек 🛠

  • Frontend: React + TypeScript + Tailwind CSS v4

  • Backend: Supabase Edge Functions (Hono framework)

  • Database: Supabase KV Store (key-value таблица)

  • Hosting: Supabase (всё в одном месте)

  • State Management: React Hooks (useState, useEffect, useCallback)

  • Icons: Lucide React

  • Notifications: Sonner (toast messages)

Почему Supabase?

  1. Быстрый старт — не нужно поднимать свой сервер

  2. Edge Functions — бэкенд на TypeScript/Deno прямо рядом с фронтом

  3. KV Store — простая табличка для хранения состояния комнат

  4. Auth из коробки — если понадобится добавить авторизацию

  5. Бесплатный tier — для прототипа достаточно


Архитектурные решения 🏗

1. Трёхслойная архитектура

Frontend (React) 
    ↕️ fetch API
Server (Hono on Deno) 
    ↕️ SQL/KV
Database (Supabase Postgres + KV)

Фронт общается только с сервером, сервер - с базой. Классика.

2. KV Store вместо SQL

Комнаты хранятся как JSON в key-value таблице:

// Сохранение комнаты
await kv.set(`room:${roomId}`, {
  id: roomId,
  createdAt: Date.now(),
  hostId: hostPlayerId,
  tables: [...],
  emojis: [...],
});

// Получение комнаты
const room = await kv.get(`room:${roomId}`);

Для игроков - отдельные ключи:

await kv.set(`room:${roomId}:players`, players);

Просто, быстро, без миграций!

3. Polling вместо WebSockets

Да, не самое модное решение, но:

  • ✅ Проще в отладке

  • ✅ Не нужно управлять соединениями

  • ✅ Работает через любые прокси

  • ❌ Чуть больше нагрузки на сервер

Для команд до 100 человек - норм. Если вырастет - добавлю Supabase Realtime.


С чем пришлось повозиться 😤

1. "А где мои игроки?!"

Первая версия не кикала неактивных. Люди закрывали вкладку, а их аватары висели. Добавил heartbeat - стало гораздо лучше.

2. Переводы всего подряд

Когда добавлял мультиязычность, понял, что хардкод-текста было ВЕЗДЕ. Пришлось вынести в отдельный файл translations.ts и заменить 100+ строк на t.welcome.title, t.toast.error и т.д.

3. Tailwind CSS v4

Использовал новую версию - синтаксис немного и��менился. Пришлось читать документацию вместо копипаста со Stack Overflow 😅


Что дальше? 🚀

План на будущее:

  • WebSocket вместо polling (когда надоест)

  • История сессий (сколько оценили, кто как голосовал)

  • Таймер для голосования

  • Звуковые уведомления (можно отключить)

  • Кастомные колоды (не только Фибоначчи)

  • Интеграция с Jira/Linear (автоматическая оценка тасков)


Попробуйте сами! 🎮

https://scrumpoker.aggone.dev/


Выводы 🧠

  1. Не бойтесь писать свои решения - иногда проще сделать самому, чем искать идеальное

  2. Polling - не всегда зло - для малых команд вполне рабочее решение

  3. Supabase - огонь для быстрых прототипов

  4. Геймификация работает - эмодзи реально оживили планирования

  5. Темная тема - must have - уже 2026-й, ребят!


P.S.

Если вы тоже страдаете от корпоративных инструментов, которые тормозят и бесят - welcome в клуб "Сделаю сам". Иногда выходные, потраченные на свой велосипед, экономят месяцы нервов в будущем 😉
А можете пользоваться и моим решением. Оно бесплатное!
Всех благ!

Вопросы? Идеи? Баги? Пишите в комментариях!