P2-008 Группы для приватных событий¶
Метаданные¶
| Поле | Значение |
|---|---|
| Фаза | Phase 2: Core |
| Статус | done |
| Приоритет | high |
| Связь с roadmap | Roadmap - Организации |
Контекст¶
Бизнес-контекст¶
Группы позволяют создавать приватные события внутри организации (FR-3.4). Например: региональные команды, VIP-доступ, корпоративные мероприятия. Участники группы видят и могут регистрироваться на события, привязанные к их группе.
Технический контекст¶
- Группы принадлежат организации
- Пользователь приглашается по уникальному инвайт-коду
- Событие может быть привязано к одной или нескольким группам
- Владелец и модераторы организации видят все события (включая групповые)
Связанные документы: - User Service — API endpoints - Domain Model - Group - Domain Model - GroupMember - Role Model - Группы
Цель¶
Реализовать CRUD групп внутри организации и механизм приглашения участников по инвайт-коду.
Definition of Ready (DoR)¶
- [x] Контекст понятен и описан
- [x] Цель сформулирована
- [x] Acceptance Criteria определены
- [x] Технические детали проработаны
- [x] Зависимости определены и разрешены
- [x] Нет блокеров
Acceptance Criteria¶
CRUD Групп¶
- [x] OWNER и MODERATOR могут создавать группы (
POST /api/v1/organizations/{id}/groups) - [x] Только OWNER может удалять группы (
DELETE /api/v1/groups/{id}) - [x] При создании генерируется уникальный invite_code (8 символов)
- [x] Группа имеет: название, описание (опционально), invite_code
- [x] Список групп организации (
GET /api/v1/organizations/{id}/groups)
Участники групп¶
- [x] Пользователь присоединяется по инвайт-коду (
POST /api/v1/groups/join/{inviteCode}) - [x] Владелец/модератор видит список участников группы (
GET /api/v1/groups/{id}/members) - [x] Владелец/модератор может удалить участника из группы
- [x] Участник может покинуть группу самостоятельно
- [x] Пользователь может состоять в нескольких группах одной организации
Инвайт-коды¶
- [x] Инвайт-код уникален глобально
- [x] OWNER/MODERATOR могут регенерировать инвайт-код
- [x] Ссылка для приглашения:
/groups/join/{inviteCode}или Telegram deeplink
Видимость¶
- [x] Владелец и модераторы видят все группы организации
- [x] Участник видит только группы, в которых состоит
Definition of Done (DoD)¶
- [x] Все Acceptance Criteria выполнены
- [x] Код написан согласно code style проекта
- [x] Unit тесты написаны
- [x] Integration тесты написаны
- [x] Миграции созданы
- [x] Events опубликованы (
group.created,group.member.added) - [x] Code review пройден
- [x] CI/CD pipeline проходит
Технические детали¶
Затрагиваемые компоненты¶
- [x] Backend:
user-service-api,user-service-service,user-service-db - [ ] Frontend: управление группами, присоединение по коду
- [x] Database: таблицы
groups,group_members - [ ] Infrastructure: —
Модель данных¶
CREATE TABLE user_service.groups (
id UUID PRIMARY KEY,
organization_id UUID NOT NULL REFERENCES user_service.organizations(id),
name VARCHAR(100) NOT NULL,
description TEXT,
invite_code VARCHAR(8) NOT NULL UNIQUE,
created_by UUID NOT NULL REFERENCES user_service.users(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE user_service.group_members (
id UUID PRIMARY KEY,
group_id UUID NOT NULL REFERENCES user_service.groups(id),
user_id UUID NOT NULL REFERENCES user_service.users(id),
invited_by UUID REFERENCES user_service.users(id),
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(group_id, user_id)
);
CREATE INDEX idx_groups_organization ON user_service.groups(organization_id);
CREATE INDEX idx_groups_invite_code ON user_service.groups(invite_code);
CREATE INDEX idx_group_members_user ON user_service.group_members(user_id);
API Endpoints¶
# Groups
GET /api/v1/organizations/{id}/groups — список групп организации
POST /api/v1/organizations/{id}/groups — создание группы
GET /api/v1/groups/{id} — детали группы
PUT /api/v1/groups/{id} — обновление группы
DELETE /api/v1/groups/{id} — удаление группы
POST /api/v1/groups/{id}/regenerate-code — новый инвайт-код
# Members
GET /api/v1/groups/{id}/members — список участников
DELETE /api/v1/groups/{id}/members/{userId} — удаление участника
POST /api/v1/groups/{id}/leave — выход из группы
# Join
POST /api/v1/groups/join/{inviteCode} — присоединение по коду
Генерация invite_code¶
private String generateInviteCode() {
// 8 символов: uppercase буквы + цифры (без похожих: 0, O, I, L)
String chars = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
SecureRandom random = new SecureRandom();
return random.ints(8, 0, chars.length())
.mapToObj(chars::charAt)
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
.toString();
}
Зависимости¶
Блокирует¶
- P2-009 События (привязка к группе)
Зависит от¶
- P2-006 Организации
Out of Scope¶
- Вложенные группы (группы в группах)
- Роли внутри группы (все участники равны)
- Экспорт участников группы
- Групповые рассылки
Заметки¶
- Invite code должен быть читаемым (для ручного ввода)
- При удалении группы — события остаются, но становятся публичными внутри организации
- Пользователь может состоять в нескольких группах одной организации