Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Введение

Что такое nice-pea-chat - Полноценный мессенджер - приложение, сервер и обвязка

Цель документа - Составить общую картину, наращивать функционал требуемый функционал и не сбиться🦥

Область применения - Нет

Глоссарий

ключевые термины и сокращения

Предметная область - Часть реального мира, рассматриваемая в пределах данного контекста

Сущность - Описание объекта предметной области

Модель - Сущность описанная в коде

Обзор системы

Архитектурный стиль - service-oriented architecture(SOA).

Высокоуровневая диаграмма компонентов системы

todo

Детальный дизайн

Компоненты системы

Описание каждого значимого компонента:
Назначение
Ответственность
Интерфейсы (API, события)
Зависимости

API Design

Принципы проектирования (REST, GraphQL, gRPC)
Важные эндпоинты с примерами
Схемы данных (DTO, модели)
Аутентификация/авторизация

Модель данных

ER-диаграмма или схема данных
Стратегия миграций (если применимо)

Описание сущностей и их отношений

Чат

Структура:

  • Идентификатор
  • Название чата - может меняться, неуникальное
  • идентификатор главного администратора - может меняться

Интеграции

Внешние системы и протоколы взаимодействия
Форматы сообщений/событий
Схемы интеграции (синхронная/асинхронная)

Нефункциональные требования

Масштабируемость

Горизонтальное/вертикальное масштабирование

Надежность

Стратегии обработки ошибок
Механизмы retry
Резервирование

Операционные аспекты

Логирование (формат, уровни, ротация)
Мониторинг (метрики, алерты)
Развертывание (CI/CD, стратегии)
Резервное копирование

Приложения

Диаграммы (последовательностей, состояний и т.д.)

Ссылки на дополнительные материалы

Makefile

В этом проект для упрощения и автоматизации рутинных задач разработки используется Makefile. Ниже приведён список доступных целей (targets) и их описание.

Доступные цели

https://github.com/nice-pea/npchat

ЦельОписание
testЗапустить тесты Go во всём проекте.
vetЗапустить утилиту go vet, для статического анализа.
lintЗапустить линтер (golangci-lint), на всего - 1 количестве ядер.
checkЗапуск vet и lint. Рекомендуется для проверки перед коммитом или PR.
runЗапустить приложение (cmd/npc/main.go).
mdbookСобирать mdbook в режиме watch и открыть в браузере по умолчанию.
mdbook-buildСобирать mdbook.

https://github.com/nice-pea/npchat-docs

ЦельОписание
openСобирать mdbook в режиме watch и открыть в браузере по умолчанию.
buildСобирать mdbook.

Как использовать

Чтобы выполнить какую-либо цель, просто введите в терминале:

make <цель>

Например:

make test

или

make check

Соглашение по git

Формат коммитов в master

Название коммита:

[номер задачи из таск-трэкера] [Название задачи] (#[номер PR с правкой по задаче])

Пример:

50078921 Добавить регистрацию пользователей (#42)

Если коммит большой, к нему стоит добавить описание, значительные изменения разделять новой строкой, начинающейся с *:

* Обновлен способ обработки ошибок в роутере

* Стандартный роутер заменен на "libname"

Формат веток

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

[автор]/[номер задачи из таск-трэкера]-[Название-задачи]

Пример:

saime/50078921-Добавить-регистрацию-пользователей

Формат коммитов в ветки авторов

Формат коммитов в ветки автором не установлен

1. Дизайн системы


1.1 Функционал


1.1.1 Клиент - мобильное приложение (android)

a.k.a mobile app

Приложение -

  • Если запрос прошел с ошибкой (не 500), то текст из ответа надо вывести на экрана
  • Для проверки поддержки апи, приложение отправляет на сервер запрос, в случае неудачи которого, открывается экран с ошибкой версии api
  • Если сервер вернет ошибку авторизации, приложение должно очистить кэш (кроме логина и адреса) и перейти на экран логина

1.1.2 Чат

a.k.a conversationchat/беседа

Структура чата:

  • Идентификатор
  • идентификатор создателя
  • Название чата
  • Список участников

Профиль чата (редактируемые поля):

  • Название чата

Приглашение в чат (invite/создать участника):

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

Чат -

  • В чат можно попасть по приглашению, либо создав новый чат, т.е все чаты являются приватными
  • Создатель чата не может покинуть свой чат
  • Количество чатов у пользователя не ограничено
  • Количество созданных чатов ограничено, лимит равен 100
  • Управление чатом и его сообщениями опирается на permissions
  • У пользователя должна быть возможность закреплять свои чаты вверху списка чатов в которых он состоит

1.1.3 Разрешения

a.k.a разрешения

Разрешения (permissions) -

  • Разрешения дают доступ на какое-либо действие
  • Некоторые (не все) требуют передачи параметра target, в этом случае помимо наличия права, будет выполнена проверка определенная проверка, которая где-то описана
  • Набор разешений "по умолчанию" настраивается в system configuration, это те права которыми будут обладать пользователи пришедшие в чат

Пример разрешений:

  1. Administrator // разрешают все, а снять это разрешение нельзя - некая защита от дурака
  2. ManageMemberPermissions
  3. AddMembers
  4. DeleteMembers
  5. DeleteMemberMessages
  6. EditChatInfo
  7. DeleteOwnMessage
  8. EditOwnMessage
  9. SendMessages

1.1.4 Системные настройки

a.k.a System configuration

1.1.5 Участник чата

a.k.a member

Структура участника:

  • Идентификатор
  • Идентификатор пользователя
  • Идентификатор чата
  • permission set

Участник -

  • Факт отношения пользователя к определенному чату

1.1.6 Сообщение

a.k.a message

Типы событий, в результате которых приходит анонимное сообщение в чат:

  • Изменение профиля чата
  • Создание нового участника
  • Удаление участника
  • Самостоятельный выход участника
  • Создание чата

Структура сообщения:

  • идентификатор
  • идентификатор чата
  • идентификатор пользователя, т.е автора сообщения (необязательно)
  • идентификатор сообщения, на которое это сообщение отвечает
  • текст (отсутствует если оно было удалено)
  • дата создания
  • дата редактирования (необязательно)
  • дата удаления (необязательно)
  • список пользователей, прочитавших сообщение (исключая создателя)

Сообщение (message) -

  • Может быть создано пользователем, являющимися участником чата, либо в результате события в чате
  • Текст может быть множество раз отредактирован автором, если не сообщение является удаленным
  • Может быть единожды удалено автором
  • На текст сообщения есть ограничение в 4096 символов
  • На существующее (даже если удалено) сообщение можно отвечать другим сообщением
  • Полная история сообщений в чате доступна каждому участнику

1.1.7 Push-уведомление

a.k.a notification/push-notification

Структура пуша:

  • Название чата
  • Текст сообщения (необязательно)
  • Текст события (необязательно)

В каких случаях пользователь получает пуш:

  • В любой чат в котором он состоит пришло новое сообщение
  • Приглашение пользователя (только тому кого пригласили)
  • Удаление пользователя (только тому кого удалили)

Когда пользователь не получает уведомления о новых сообщениях:

  • Если его только пригласили в чат (является новым участником), и он ни одного сообщения не прочел
  • Если пользователь уже находится в этом чате, т.е он открыт на клиенте
  • Если этот чат находится в муте у пользователя открывает

Уведомления -

  • Уведомления создают push-уведомления на клиенте, даже если сейчас он закрыт

1.1.8 Пользователь

a.k.a user

Структура пользователя:

  • Идентификатор
  • Юзернейм
  • Логин

Профиль пользователя (редактируемые поля):

  • Юзернейм

Пользователь -

  • Пользователя можно создать пройдя регистрацию
  • "Вход в профиль" осуществляется по логину
  • Профиль можно редактировать

1.2 Интерфейс ui/ux


1.2.1 Мобильное приложение

Вход в приложение

{width=603px}

Макет

https://www.figma.com/design/dQBEQWBNuffsOYNU54XZsX/CuteChatMobileApp?node-id=0%3A1&t=E96rjGdjCDQxyFKX-1

Экран выбора сервера и ввода логина -

  • Открывается при первом входе в приложение
  • Выбранный сервер сохраняется в кэш
  • Компоненты:
    • Инпут для адреса
    • Кнопка "пинг сервера"
      • По нажатию производится проверка доступности сервера и совместимости версии апи
    • Инпут логина
    • Кнопка "вход"
      • По нажатию происходит получение токена
      • После открывается экран чатов

Главный экран со списком чатов -

  • Компоненты:
    • Кнопка "посмотреть профиль"
      • Открывает диалог профиля пользователя
    • Кнопка "Создать чат*
      • Открывает диалог создания чата
    • Список чатов
      • По нажатию на чат, откроется его экран сообщений
      • Отсортирован по времени сообщений, последний сверх, а также по закрепленным, закрепленные сверху
      • Каждый элемент состоит из:
        • Названия
        • Индикатора количества новых сообщений
        • Автора (если есть) и текста сообщения
        • По длительному нажатию открывается диалог действий с чатом

Диалог действий с чатом -

  • Компоненты:
    • Кнопка "открепить\закрепить"
      • при закрепить - чат перемещается на первое место в списке закрепленных
      • при открепить - из закрепленных перемещается на первое место в списке чатов
    • Кнопка "покинуть"
      • по нажатию запрашивается подтверждение
      • после подтверждения выхода, чат удаляется из списка чатов пользователя

Диалог создания чата -

  • Компоненты:
    • инпут с названием чата
    • кнопка подтверждения
      • по нажатию кнопка переходит в состояние загрузки
  • после создания чата, он добавляется в список и открывается экран с этим чатом

Диалог профиля пользователя -

  • Компоненты:
    • Идентификатор
    • подсказка о том что ИД нужно передать модератору чата чтобы он мог пригласить
    • Юзернейм
    • Логин
    • подсказка о том что Логин используется для входа в профиль
    • кнопка Редактировать
      • открывает диалог Редактирования профиля пользователя
    • Кнопка выхода
      • по нажатию открывается диалог подтверждения
      • после подтверждения - Выбрасывает на экран логина

Диалог Редактирования профиля пользователя -

  • Компоненты:
    • инпут с юзернеймом
    • кнопка подтверждения
      • по нажатию кнопка переходит в состояние загрузки
  • после успешного редактирования, данные пользователя обновляются и диалог закрывается

Диалог профиль чата -

  • Компоненты:
    • юзернейм создателя,
    • название чата
    • Кнопка Изменить профиль чата
      • открывает диалог редактирования данных профиля чата
    • Кнопка покинуть чат (необязательно)
    • Кнопка добавить участника
      • Открывает диалог
      • Компоненты
        • Инпут ид пользователя
        • кнопка пригласить

Диалог профиль чата -

  • Компоненты:
    • Список участников
      • Каждый элемент состоит из:
        • юзернейм
        • permission set
      • По нажатию на пользователя открывается диалог Участник чата (только если нажал не на себя)

Диалог участника чата -

  • Компоненты:
    • ид профиля
    • юзернейм
    • кнопка удалить (необязательно)
      • открывает диалог с подтверждением удаления
    • кнопка "назначит набор разрешений" (необязательно)
      • открывает диалог со списков наборов и их описания/списка возможностей
      • каждый элемент это radio button

Экран сообщений чата -

  • Компоненты:
    • Инпут бар сообщения
      • Компоненты:
        • Выбранное сообщение для ответа (необязательно)
        • Введенные текст (необязательно)
        • Кнопка снизу, варианты:
          • "Применить изменения" - если происходить изменение сообщения
            • По нажатию применяется изменение, текст сообщения изменяется
          • Кнопка "Отправить" - если введен текст нового сообщения
            • По нажатию отправляется новое сообщение, оно появляется позже в чате
          • Кнопка "Начать ввод" - если сообщение пустое и клавиатура скрыта
            • По нажатию открывается клава
    • Тайтл бар
      • Компоненты:
        • Кнопка "вернуться"
        • название чата
        • Кнопка "меню"
          • Открывает диалог профиль чата
    • Список сообщений:
      • Каждый элемент состоит из:
        • Имени отправителя (необязательно)
        • Части сообщения на которое был сделан ответ (необязательно)
        • Текста сообщения
        • Даты отправки
        • Пометки "отредактировано" (необязательно)
        • Пометки "удалено" (необязательно)
      • По нажатию открывается меню
        • Компоненты:
          • Кнопка скопировать сообщение
          • Кнопка ответить на сообщение
            • помещает часть сообщения в Инпут бар сообщения
          • Кнопки удалить и изменить сообщение (необязательно)
            • По нажатию, появится диалог с подтверждением

диалог ошибки версии api -

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

1.3 Техническая часть


1.3.1 API для приложения

Эндпоинты

// Запросить информацию о сервере и сверить  версию клиента
GET {host}/healthcheck
response data:
  api_support {
    min_code int
    min string
    max_code int
    max string
  }


// Запросить токен для дальнейшей работы
POST {host}/auth
request body:
  login string
response data:
  access string



// Запросить пользователя по токену
GET {host}/users
headers:
  x-token-header string
response data:
  user User
  credentials {
    login string
  }


// Запросить пользователя по ID
GET {host}/users/{id}
path param:
  id int
response data:
  user User

// Изменить данные пользователя
PATH {host}/users
request body:
  username string?


// Запросить полный список чатов в которых пользователь является участником
GET {host}/chats
response data:
  chats []Chat


// Изменить данные чата
PATH {host}/chats/{id}
path param:
  id int
request body:
  name string?


// Список закрепленных чатов
GET {host}/chats/pins
response data:
  chat_ids []int32


// Изменить список закрепленных чатов
POST {host}/chats/pins
request body:
  chat_ids []int32


// Запросить полный список участников чата
GET {host}/chats/{id}/members
path param:
  id int
response data:
  members []User


// Удалить пользователя из чата
DELETE {host}/chats/{chat_id}/members/{id}
path param:
  chat_id int32
  id int32


// Добавить пользователя в чат
POST {host}/chats/{id}/members
path param:
  id int
request body:
  user_id int


// Назначить permissions  участнику
PATH {host}/chats/{chat_id}/members/{id}
path param:
  chat_id int32
  id int
request body:
  permissions []Permission


// Запросить часть истории сообщений в чате
GET {host}/chats/{chat_id}/messages
path param:
  chat_id int32
query param:
  limit int
  oneOf( 
    around_id int32
    before_id int32
    after_id int32
  )
response data:
  messages []Message


// Удалить сообщение
DELETE {host}/messages/{id}
path param:
  id int


// Изменить сообщение
PATH {host}/chats/{chat_id}/messages/{id}
path param:
  chat_id int32
  id int
request body:
  text string?


// Cоздать сообщение
POST {host}/chats/{chat_id}/messages
path param:
  chat_id int32
request body:
  text string
  reply_id int32?
  
  
// Пометить сообщение как прочитанное
POST {host}/chats/{chat_id}/messages/{id}/read
path param:
  chat_id int32
  id int32

Модели

User:
  id int
  username string

Permission:
  name string
  desc string

PermissionId:
  | Administrator
  | ManageMemberPermissions
  | AddMembers
  | DeleteMembers
  | DeleteMemberMessages
  | EditChatInfo
  | SendMessages
  

ReplyedMessage:
  id int32
  date int64
  text string?
  user User?
  edit_date int64?
  delete_date int64?
 
Message:
  id int32
  chat_id int32
  date int64
  text string?
  user User?
  reply ReplyedMessage?
  edit_date int64?
  delete_date int64?

Chat:
  id int32
  name string
  last_msg Message?
  last_read_msg int32?
  unread_count int
  permissions []PermissionId
  

Ответ с данными

// код 2**
response:
{
  "data": <Данные>,
}

Ответ с ошибкой

// код 4** или 5**
response:
{
  "error": "<Текст ошибки>",
}

1.3.2 Авторизация

  1. Administrator
    • Можно выполнять любые действия
    • Запрещено выдавать/забирать разрешение Administrator
  2. ManageMemberPermissions
    • Устанавливать разрешения участникам
    • Список разрешений ограничен сверху максимальным разрешением пользователя (не включая его в список)
    • Применять в отношение пользователей чьи разрешения ниже уровня ManageMemberPermissions
  3. DeleteMembers
    • Удалять (кикать\исключать) участников
    • Применять в отношение пользователей чьи разрешения ниже уровня DeleteMembers
  4. AddMembers
    • Добавлять пользователей в чат
  5. DeleteMemberMessages
    • Удалять сообщения участников
    • Применять в отношение пользователей чьи разрешения ниже уровня DeleteMemberMessages
  6. EditChatInfo
    • Редактировать данные чата
  7. DeleteOwnMessage
    • Удалять свои сообщения
  8. EditOwnMessage
    • Редактировать свои сообщения
  9. SendMessages
    • Писать сообщения

1.3.3 Аутентификация

  • хранимые данных в jwt
    • ид пользователя
  • время жизни токена
    • 15 минут
  • способ получения токена
    • в обмен на креды (логин)
  • способ обновления токена
    • отсутствует

1.3.4 Пользовательская БД. Субд. Схема Бд

1.3.5 Логирование

1.3.7 Тестирование

1.3.8 Gateway/Балансировщик

1.3.8 Очередь

1.3.9 Деплой

1.3.10 Версионирование

2. Сбор требований


2.1 Технические вопросы

  • На чем основана аутентификация? jwt или другие варианты? Если jwt то какая нагрузка у токенов будет?
  • Один инстанс сервера будет использоваться для всех чатов, т.е. 1:n либо 1:1, если таковые будут.
  • Будет ли поддержка горизонтального масштабирования? Если да, то что будет шлюзом?
  • Какой api будет между сервером, http, grpc, gql?
  • Будет ли использоваться долгоживущее соединение - websocket, long polling, etc?
  • Сервер будет stateless или statefull?
  • Будет ли сервер писать логи, как их можно будет читать?
  • Что будет использоваться для хранения данных - сообщения, данные чатов, пользователей?

Сообщения

  • Как будет происходить пагинация при запросе сообщений?

2.2 Анализ требуемого функционала

  • Какой клиент будет у "Cute-chat", web, mobile, desktop?
  • "Cute-chat" это о одном чате, т.е. все сообщения будут сваливаться в одну кучу или будет возможность отправлять сообщение в разные чаты?

Несколько чатов

  • Если чатов несколько, то вероятно их кто то должен создавать, кто это будет делать, или у кого такая возможность будет?
  • Как пользователи будут попадать в чаты? По приглашению, присоединяться самостоятельно, присоединяться принудительно?
  • Ограничения на вход будут? Т.е. приватые/публичные чаты?
  • Если возможность создавать чаты будет у пользователя, то вероятно должны быть ограничения на количество созданных чатов?
  • Как выглядит профиль чата? В профиле будут название, картинка, описание, список участников?
  • Будут ли у создателя чата особые права? Например он может изменять профиль чата, удалять чат, добавлять\исключать участников, модерировать?
  • Может ли создатель чата выходить из чата? Что будет если создатель выйдет из чата?
  • Будет возможность передавать права создателя?
  • Возможность удалить чат будет? Что произойдет с участниками? Если в этот момент пользователь перейдет по приглашению в чат, что он увидит?
  • Есть ли возможность просматривать список участников чата? Кому эта возможность доступна?
  • В чате есть ограничения по количеству участников?
  • Можно ли пересылать сообщения между чатами?

Сообщения

  • Что в чат можно отправлять пользователям? Медиа/стикеры/ссылки/текст/файлы?
  • Сообщение может содержать несколько типов контента? Будет ли применяться разбиение на несколько сообщений при превышении лимита медиа или символов в тексте?
  • Есть ли ограничения на отправку сообщений?
  • Какие действия можно совершать с сообщениями? Удалять/изменять/пересылать/отвечать/копировать/отправлять повторно?
  • Как будет выглядеть пересланное сообщение если его оригинал будет изменен/удален?
  • Сохраняется ли история сообщений? Новые участники видят всю историю или только ее часть?
  • Какого типа сообщения в чате будут появляться? Пользовательские/системные?
  • Возможность отправлять анонимные сообщения в чат будет?
  • Возможность отправлять сообщения со спойлером будет?
  • Возможность отправлять сообщения с автоматическим удалением будет? Что произойдет если это сообщение будет переслано?
  • Сообщения будут обладать статусом "прочитано"?
  • Какой порядок сообщений в истории, последние помещаются снизу или сверху?
  • Как выглядит профиль сообщения? В профиле сообщения будут дата создания, флаг о том что его прочитали, дата изменения/удаления, автор сообщения, чат?
  • Поиск по сообщениям в конкретном чате будет? К поиску будет возможность добавлять фильтры, автор, даты, статус, тип (медиа\текст)?
  • В текстовых сообщениях можно будет упоминать пользователей?

Новое сообщение

  • Новое сообщение будет сопровождаться индикатором на чате, меткой "новое" в истории?
  • Новое сообщение будет рассылать push уведомления всем участникам? Возможность отключать push уведомления будет?

Пользователь

  • Откуда берется пользователь? Он создается исключительно для "cute-chat", т.е. проходит регистрацию или база пользователей уже существует?
  • Как выглядит профиль пользователя? Имя, почта, ид, фото, описание, список чатов? Какие данные пользователь может редактировать?
  • Будут ли существовать пользователи с дополнительными возможностями? Например с возможностью редактировать/просматривать/удалять то что обычные не могут

Клиент web/mobile/desktop

  • Как будет происходить связывание клиента и сервера, в клиенте будет статически прописан адрес или пользователям надо вручную указывать адрес сервера?
  • Будет ли ограничения при использовании клиента не последней версии либо отчающейс я от поддерживаемой сервером?

Дополнение

Проект получил другое название: cute chat -> nice pea chat

Сокращения:

nice pea chat - нпс / проект / npc

permission set - набор прав / пермишны / ps

chat - чат / беседа

Авторизация:

Что было придумано

Планировалось реализовать авторизацию с помощью PS, которые должно были работать примерно так:

Клиент отправляет запрос - хочет выполнить действия X, оно выполнится если один из его PS разрешает его.

Т.е. PS это роль, которая дает право пользователь на выполнение определенных действий.

Зачем нужна авторизация нам

В первую очередь - модерация чатов

Гибкость для создания своих "миров" как в дискорде

Посмотрим какие подходы существуют

RBAC - Управление доступом на основе ролей

Данный подход предполагает использование ролевой системы доступа, где права пользователей определены на сновании должности, уровня полномочий, ответственности, потребностей согласно обозначенным задачам

ABAC - управление доступом на основе атрибутов

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

Подробнее про abac и rbac

Новый вариант авторизации

Пользователи будут составлять правила, используя строительные блоки:

- action / действие - название - subject - role / роль - id - название (оно и определяет приоритет) - priority / приоритет будет определяться сортировкой

Роли как в дискорде!

Пусть этот функционал будет называться "пермишенами"!

В БД отразим авторизацию так:

role ( id int name string permissions []int )

enum Permission ( id int name string # <-- наверное будет локализация, так что без этого поля обойдемся )

А ограничения будут отражаться в коде.