Управління каналами зв’язку користувача
1. Загальний опис
Наразі користувач має можливість налаштовувати канали зв’язку для отримання повідомлень від системи:
-
email - Відправка поштових повідомлень
-
diia - Відправка push-нотифікацій у мобільний додаток Дія
Особливістю inbox каналу зв’язку є те, що він буде активований за замовчуванням, користувач не зможе редагувати, деактивувати або якимось іншим чином налаштовувати цей канал. Іншими словами, робота з inbox каналом не є предметом даної статті |
2. Функціональні сценарії
-
Пошук налаштувать користувача за ідентифікатором користувача
-
Пошук налаштувань користувача за ідентифікатором користувача, отриманим з токена доступу
-
Активація каналу зв’язку шляхом введення / оновлення даних атрибутів каналу (наприклад: поштова адреса)
-
Деактивація каналу зв’язку
-
Валідація введених налаштувань користувача (за патерном email, відсутністю в blacklist тощо)
3. Базові принципи
-
Користувач має право змінювати лише власні налаштування
-
Користувач може мати лише один канал кожного типу (email, diia)
-
Отримувати налаштування користувача може користувач, якому належать ці налаштування, або система (для змоги надсилати повідомлення користувачам на обрані ними канали зв’язку)
4. Технічний дизайн рішення
При імплементації роботи з каналами зв’язку було змінено дизайн Сервісу налаштувань. Основна зміна полягає в тому, що сервіси user-settings-service-api та user-settings-service-persistence об’єднані в один сервіс user-settings-service. |
4.1. Компоненти системи та їх призначення в рамках дизайну рішення
У даному розділі наведено перелік компонент системи, які задіяні або потребують змін/створення в рамках реалізації функціональних вимог згідно технічного дизайну рішення.
Компонент | Службова назва | Призначення |
---|---|---|
Кабінет громадянина |
citizen-portal |
Управління налаштуваннями користувача через сторінку "Профіль" кабінету |
Сервіс управління налаштуваннями користувачів |
user-settings-service |
Отримання та зміна налаштувань каналів зв’язку, обраних користувачем |
Розподілена реляційна база даних Citus |
citus-master |
Довготривале збереження налаштувань каналів зв’язку користувачів на цільовому оточенні реєстру |
Розподілений брокер повідомлень Kafka |
kafka |
Асинхронне відправлення аудит-повідомлень про зміни в каналах зв’язку |
Сервіс управління Avro-схемами опису структур даних |
kafka-schema-registry |
Збереження Avro-схеми опису структури даних значущих подій аудиту |
4.2. Налаштування політик міжсервісної взаємодії
Для коректної роботи сервісу налаштувань, мають бути налаштовані відповідні мережеві політики NetworkPolicy, які дозволяють взаємодію для наступних компонентів:
-
kong → user-settings-service
-
user-settings-service → citus-master
-
user-settings-service → kafka
-
user-settings-service → kafka-schema-registry
4.3. API управління налаштуваннями та каналами зв’язку
Отримання доступу до API можливе лише в рамках виконання запиту автентифікованого користувача в системі |
4.3.1. Отримання користувачем налаштувань, що йому належать
Даний API-роут є публічним та має бути опублікованим для зовнішнього доступу через окремий Kong Route для Кабінету Громадянина. |
GET /api/settings/me
Параметр | Тип | Частина запиту | Опис |
---|---|---|---|
X-Access-Token |
JWT |
HTTP заголовок |
Токен доступу користувача |
{
"settingsId": "uuid",
"channels": [
{
"channel": "email",
"activated": "true",
"address": "user@domain.com",
"deactivationReason": "some reason"
}
]
}
Код | Опис |
---|---|
200 |
OK |
400 |
Некоректно сформований запит |
401 |
Помилка автентифікації (відсутній токен доступу) |
404 |
Дані не знайдено |
500 |
Серверна помилка обробки запиту |
4.3.2. Отримання налаштувань для користувача за ідентифікатором
GET /api/settings/{userId}
Даний API-роут не є службовим та не має бути опублікованим для зовнішнього доступу через Kong Route. |
Параметр | Тип | Частина запиту | Опис |
---|---|---|---|
X-Access-Token |
JWT |
HTTP заголовок |
Токен доступу користувача |
userId |
Текстовий |
Параметр запиту |
Унікальний ідентифікатор користувача в системі |
{
"settingsId": "uuid",
"channels": [
{
"channel": "email",
"activated": "true",
"address": "user@domain.com",
"deactivationReason": "some reason"
}
]
}
Код | Опис |
---|---|
200 |
OK |
400 |
Некоректно сформований запит |
401 |
Помилка автентифікації (відсутній токен доступу) |
404 |
Дані не знайдено |
500 |
Серверна помилка обробки запиту |
4.3.3. Валідація адреси для каналу зв’язку
Серверна валідація даних, внесених у якості адреси для каналу зв’язку. Набір правил залежить від типу каналу, для channel = email:
-
Валідація поштової адреси за regexp
-
Валідація поштової адреси на унікальність
-
Валідація поштової адреси проти сконфігурованого blacklist-набору
Валідація для channel = diia не застосовується. |
Данний API-роут є публічним та має бути опублікованим для зовнішнього доступу через окремий Kong Route для Кабінету Громадянина. |
POST /api/settings/me/channels/{channel}/validate
Параметр | Тип | Частина запиту | Опис |
---|---|---|---|
X-Access-Token |
JWT |
HTTP заголовок |
Токен доступу користувача |
channel |
Текстовий |
Параметр запиту |
Назва каналу [email, diia] |
{
"address": "<email>"
}
{
"traceId": "string",
"code": "string",
"message": "string",
"localizedMessage": "string"
}
Код |
Опис |
200 |
OK |
400 |
Некоректно сформований запит |
401 |
Помилка автентифікації (відсутній токен доступу) |
422 |
Помилка валідації |
500 |
Серверна помилка обробки запиту |
4.3.4. Активація каналу зв’язку користувача
Активація каналу зв’язку для користувача, створення налаштувань для каналу, якщо вони ще не існують.
Данний API-роут є публічним та має бути опублікованим для зовнішнього доступу через окремий Kong Route для Кабінету Громадянина. |
POST /api/settings/me/channels/{channel}/activate
Параметр | Тип | Частина запиту | Опис |
---|---|---|---|
X-Access-Token |
JWT |
HTTP заголовок |
Токен доступу користувача |
channel |
Текстовий |
Параметр запиту |
Назва каналу [email, diia] |
{
"address": "user@domain.com"
}
Код | Опис |
---|---|
200 |
OK |
400 |
Некоректно сформований запит |
401 |
Помилка автентифікації (відсутній токен доступу) |
409 |
Порушення обмежень бази даних |
500 |
Серверна помилка обробки запиту |
4.3.5. Деактивація каналу зв’язку
POST /api/settings/me/channels/{channel}/deactivate
Данний API-роут є публічним та має бути опублікованим для зовнішнього доступу через окремий Kong Route для Кабінету Громадянина. |
Параметр | Тип | Частина запиту | Опис |
---|---|---|---|
X-Access-Token |
JWT |
HTTP заголовок |
Токен доступу користувача |
channel |
Текстовий |
Параметр запиту |
Назва каналу [email, diia] |
{
"deactivationReason": "<deactivation reason enum: [USER_DEACTIVATED|SYSTEM_DEACTIVATED|BLACKLIST_DEACTIVATED]> + some message"
}
Код |
Опис |
200 |
OK |
400 |
Некоректно сформований запит |
401 |
Помилка автентифікації (відсутній токен доступу) |
500 |
Серверна помилка обробки запиту |
4.5. Фізична модель зберігання даних
В рамках реалізації функціональних вимог, необхідно створити окрему схему SETTINGS та розширити фізичну модель додатковими таблицями:
-
SETTINGS - зберігання налаштувань користувача
-
NOTIFICATION_CHANNEL - зберігання налаштувань каналів зв’язку користувача
У випадку необхідності введення статусу/ролі користувача таблиця "subject_settings" може бути розширена відповідними полями. |
4.5.1. Структура даних SETTINGS
Поле | Тип | Обмеження | Значення за замовчуванням | Опис |
---|---|---|---|---|
ID |
UUID |
Primary Key |
uuid_generate_v4() |
Унікальний автоматично згенерований ідентифікатор запису |
KEYCLOAK_ID |
UUID |
Not Null |
- |
Зовнішній ідентифікатор користувача в keycloak |
4.5.2. Структура даних NOTIFICATION_CHANNEL
Поле | Тип | Обмеження | Значення за замовчуванням | Опис |
---|---|---|---|---|
ID |
UUID |
Primary Key |
uuid_generate_v4() |
Унікальний автоматично згенерований ідентифікатор запису |
SETTINGS_ID |
UUID |
Foreign Key, Not Null, Unique Constraint with CHANNEL |
- |
Ідентифікатор запису в settings |
CHANNEL |
ENUM |
Not Null, Unique Constraint with SETTINGS_ID [email,diia] |
- |
Назва каналу зв’язку для використання шаблону повідомлення |
ADDRESS |
TEXT |
Unique |
- |
Адреса для відправлення повідомлень (опційна, в залежності від типу каналу зв’язку) |
DEACTIVATION_REASON |
TEXT |
- |
- |
Причина попередньої деактивації каналу |
IS_ACTIVATED |
BOOLEAN |
Not Null |
false |
Чи активований даний канал |
CREATED_AT |
TIMESTAMP |
Not Null |
now() |
Дата/Час створення запису |
UPDATED_AT |
TIMESTAMP |
Not Null |
now() |
Дата/Час оновлення запису |
Роботи з забезпечення унікальності поштових адрес заплановані на 2023 рік. До тих пір Unique обмеження для поля ADDRESS не є необхідним |
4.6. Ролі/системні користувачі БД
Для обслуговування операцій взаємодії з БД, необхідно створити ролі/користувачів з визначеними правами доступу для використання відповідними компонентами системи:
Компонент системи | Роль/Користувач | Привілегії |
---|---|---|
user-settings-service |
settings_role |
GRANT SELECT, INSERT, UPDATE, DELETE ON SETTINGS GRANT SELECT, INSERT, UPDATE, DELETE ON CHANNELS |
4.7. Аудит та журналювання подій
Події активації/деактивації каналів зв’язку фіксуються у журналі аудиту з повним контекстом. Для реалізації вимоги необхідно розширити підсистему аудиту наступними службовими операціями:
-
USER_NOTIFICATION_CHANNEL_ACTIVATION
-
USER_NOTIFICATION_CHANNEL_DEACTIVATION
Детальніше з дизайном підсистеми "Журнал аудиту" можна ознайомитися за посиланням |
4.7.1. Структура події аудиту
Нижче наведено структуру події аудиту та її відповідність структурі та значенням отриманого через Kafka-топік повідомлення про необхідність відправки нотифікації користувачу.
4.7.1.1. Структура контексту події аудиту
{
"channel": "email",
"address": "email@email.com"
}
{
"channel": "email",
"address": "email@email.com",
"deactivationReason": "deactivationReason"
}
4.8. Налаштування публікації подій аудиту
audit:
kafka:
topic: audit-events
schemaRegistryUrl: http://kafka-schema-registry:8081
5. Редизайн системи
В рамках редизайну системи, необхідно виконати наступні кроки:
-
Змінити ім’я сервіса налаштувань на user-settings-service
-
В усіх місцях, де використовується стара адреса сервіса налаштувань, змінити її на нову (виклики з Кабінету користувача, bpms, Сервісу відправки повідомлень)
-
Виправити назву сервіса налаштувань всюди, де вона використовується (для усіх мережевих політик, деплойментів, конфігурацій, секретів тощо)
-
Декомісувати сервіс user-settings-service-persistence, усі пов’язані з ним деплойменти, секрети, конфігмапи тощо
-
Видалити наступні kafka-топіки:
-
read-settings-inbound
-
read-settings-outbound
-
update-settings-inbound
-
update-settings-outbound
-
read-settings-by-keycloak-id-inbound
-
read-settings-by-keycloak-id-outbound
-
.DLT топіки для усіх перерахованих *-inbound
-
6. Міграція даних
Для збереження вже наявних поштових адрес користувачів, при оновленні фізичної моделі даних, необхідно виконати процедуру міграції
В рамках процедури міграції необхідно виконати наступні кроки:
-
Створити таблицю NOTIFICATION_CHANNEL
-
В рамках liquibase міграції БД для кожного наявного запису в таблиці SETTINGS створити у таблиці NOTIFICATION_CHANNEL відповідний запис з заповненими значеннями
Поле | Значення |
---|---|
SETTINGS_ID |
Ідентифікатор запису з таблиці SETTINGS |
CHANNEL |
|
ADDRESS |
Значення з колонки email |
IS_ACTIVATED |
true |
-
Оновити структуру таблиці SETTINGS
7. Міграція бізнес-процесів
В рамках переходу до реалізації концепції каналів зв’язку, необхідно забезпечити можливість їх управління виключно через профіль користувача. Задля цього необхідно мігрувати бізнес-процеси он-бордингу користувачів існуючих реєстрів на нову версію, в якій відсутні кроки внесення поштової адреси. |
Існують 2 делегати, що використовувались для роботи з налаштуваннями користувача:
-
userSettingsConnectorReadDelegate
-
userSettingsConnectorUpdateDelegate
Після змін у сервісі роботи з налаштуваннями користувача, для коректного продовження роботи userSettingsConnectorReadDelegate необхідно:
-
Перейти до використання нового ендпоінту отримання налаштувань
-
Перетворити дані, отримані з сервіса, до старої структури, та не змінювати формат відповіді делегата
Делегат userSettingsConnectorUpdateDelegate стає deprecated і підлягає подальшому видаленню у наступних оновленнях платформи