Веб-приложение для обмена текстовыми сообщениями между пользователями GitHub, у которых есть хотя бы один общий приватный репозиторий. Поддерживаются личные и групповые чаты, формируемые автоматически на основе состава приватных репозиториев.
- Вход только через OAuth GitHub.
- При входе запрашиваются права на чтение приватных репозиториев.
- В базе сохраняются:
— имя пользователя (GitHub username)
— email
— аватар
— общее количество приватных репозиториев
— общее количество звёзд
— количество звёзд на приватных репозиториях
- Все пользователи видят всех остальных пользователей приложения.
- Страница профиля доступна для любого пользователя.
- Личные чаты (1-1) и групповые чаты (до 50 участников).
- Групповые чаты создаются автоматически для всех владельцев каждого приватного репозитория.
- Пользователь может выйти из группового чата (без автоматического возврата).
- В чате отображаются:
— список участников (ник, аватар)
— сообщения (аватар, ник, текст, время отправки) - Сообщения:
— только текстовые, до 400 символов
— история сообщений хранится всегда
— бесконечная прокрутка истории
— стандартное выделение для копирования
— нельзя редактировать или удалять сообщения
— отображается время отправки
— аватарка рядом с каждым сообщением
— индикатор количества непрочитанных сообщений
— только внутренние уведомления (индикатор новых сообщений) - Статус онлайн/офлайн участников отображается.
- Сообщения доставляются всем, независимо от статуса онлайн.
- Страница профиля содержит:
— имя, email, аватар
— общее количество приватных репозиториев
— общее количество звёзд
— количество звёзд на приватных репозиториях - Переход на профиль по клику на аватар/имя в чате.
- Mobile first, адаптивная вёрстка.
- Тёмная тема.
- Поддержка русского и английского языков.
- Подтверждение выхода из группового чата (модальное окно).
- Безопасность: OAuth, HTTPS, защита от XSS/CSRF, стандартные Rails best practices.
- Нет интеграций с внешними сервисами, кроме GitHub.
- Нет модерации, фильтрации, поиска, закрепления сообщений, приглашений, поиска пользователей.
- Нет отображения количества общих репозиториев между участниками.
- Backend: Ruby on Rails (API + Web)
- Frontend: Hotwire (Turbo, Stimulus), Tailwind CSS
- База данных: PostgreSQL
- Аутентификация: OmniAuth GitHub OAuth
- Хранение сообщений: таблица messages (связь с chat и user)
- Хранение чатов: таблица chats (тип: личный/групповой, связь с users)
- Хранение пользователей: таблица users (GitHub ID, username, email, avatar, counts)
- Хранение связей user-repo: таблица user_repositories (для вычисления общих репозиториев)
- Синхронизация с GitHub — только при входе пользователя
- При входе пользователя: — Получение и сохранение данных пользователя и его приватных репозиториев через GitHub API. — Определение общих приватных репозиториев с другими пользователями. — Автоматическое создание/обновление чатов для каждого приватного репозитория.
- Сообщения сохраняются в базе, не удаляются.
- При выходе пользователя из группового чата — связь user-chat удаляется, но чат и сообщения сохраняются.
- Ошибки аутентификации — отображать понятные сообщения (например, "Не удалось войти через GitHub").
- Ошибки при работе с GitHub API — повторять попытку, показывать уведомление о проблеме.
- Ошибки при отправке сообщений — показывать уведомление, не терять введённый текст.
- Ограничения (длина сообщения, лимит участников) — валидировать на сервере и клиенте, показывать ошибки пользователю.
- Ошибки доступа (например, попытка написать в чат, где пользователь не состоит) — возвращать 403 Forbidden.
- Покрытие моделей, контроллеров и сервисов тестами (RSpec или Minitest).
- Тесты на: — Аутентификацию и интеграцию с GitHub — Создание и отображение чатов — Отправку и отображение сообщений — Ограничения (длина, количество участников) — Интерфейс (Turbo, Stimulus, Tailwind) — Мобильную адаптивность и тёмную тему — Локализацию (RU/EN) — Безопасность (XSS, CSRF, доступ к чатам)
- Интеграционные тесты пользовательских сценариев (вход, чат, выход из чата, просмотр профиля и т.д.)
- Нет необходимости в реальном времени синхронизировать данные с GitHub.
- Нет необходимости в модерации, фильтрации, поиске, закреплении сообщений, приглашениях.
- Все чаты и участники формируются автоматически на основе данных GitHub.
- Все сообщения и чаты хранятся бессрочно.
- id: bigint (PK)
- github_id: bigint, уникальный, не null
- username: string, не null
- email: string
- avatar_url: string
- private_repos_count: integer, default: 0
- stars_count: integer, default: 0
- private_stars_count: integer, default: 0
- online: boolean, default: false
- created_at, updated_at
- id: bigint (PK)
- github_repo_id: bigint, уникальный, не null
- name: string, не null
- private: boolean, не null
- created_at, updated_at
- id: bigint (PK)
- user_id: bigint (FK users)
- repository_id: bigint (FK repositories)
- created_at, updated_at
- id: bigint (PK)
- chat_type: string, enum: ['private', 'group'], не null
- repository_id: bigint (FK repositories, nullable для личных чатов)
- created_at, updated_at
- id: bigint (PK)
- chat_id: bigint (FK chats)
- user_id: bigint (FK users)
- joined_at: datetime
- left_at: datetime (nullable)
- created_at, updated_at
- id: bigint (PK)
- chat_id: bigint (FK chats)
- user_id: bigint (FK users)
- content: string (max 400)
- created_at
- id: bigint (PK)
- user_id: bigint (FK users)
- chat_id: bigint (FK chats)
- last_read_message_id: bigint (FK messages, nullable)
- updated_at
GET /auth/github— редирект на GitHub OAuthGET /auth/github/callback— callback, создание/обновление пользователя
GET /api/users— список всех пользователей
Ответ: [{id, username, avatar_url, online}, ...]GET /api/users/:id— профиль пользователя
Ответ: {id, username, email, avatar_url, private_repos_count, stars_count, private_stars_count}GET /api/me— текущий пользователь
GET /api/chats— список чатов пользователя
Ответ: [{id, chat_type, repository_id, participants: [{id, username, avatar_url, online}], unread_count, last_message}, ...]GET /api/chats/:id— детали чата
Ответ: {id, chat_type, participants, messages: [ ... ], repository_id}POST /api/chats/:id/leave— выйти из группового чата
GET /api/chats/:chat_id/messages?before=<message_id>&limit=30— история сообщений (бесконечная прокрутка)POST /api/chats/:chat_id/messages
Тело: {content: string}
Ответ: {id, user_id, content, created_at}POST /api/chats/:chat_id/read— отметить сообщения как прочитанные
POST /api/me/online— установить онлайнPOST /api/me/offline— установить оффлайн
- Слева: список чатов (аватар, название, индикатор непрочитанных, онлайн-статус участников)
- По центру: выбранный чат (история сообщений, бесконечная прокрутка, поле ввода, кнопка отправки)
- Вверху: кнопка профиля, переключатель темы (светлая/тёмная)
- Вверху: название чата, список участников (аватары, онлайн-статус)
- Сообщения:
— слева аватар, справа bubble с текстом, ник, время
— новые сообщения подсвечиваются
— стандартное выделение текста - Внизу: поле ввода (макс. 400 символов), кнопка отправки
- Кнопка "Выйти из чата" (для групповых чатов, с подтверждением)
- Аватар, ник, email
- Количество приватных репозиториев, общее количество звёзд, количество звёзд на приватных
- Кнопка "Назад" или переход к чату
- Меню чатов — выпадающее/выезжающее
- Чат — на весь экран, адаптивные элементы
- Кнопка профиля и переключатель темы — в меню