sequenceDiagram
autonumber
actor User as Пользователь (Экран Регистрации)
participant APP as Мобильное приложение (Flutter)
participant AS as Сервис Авторизации (FastAPI)
participant DB as Реляционная СУБД (PostgreSQL)
participant KAFKA as Брокер событий (Kafka)
User->>APP: Заполняет email, пароль, выбирает режим OFFICE, жмет "Создать"
APP->>AS: HTTP POST /api/v1/auth/register (JSON с метаданными)
activate AS
note over AS: Шаг 3: Проверка сложности пароля и формата email (Pydantic)
Note over AS, DB: Старт атомарной SQL-транзакции
AS->>DB: SELECT 1 FROM users WHERE email = input.email
activate DB
DB-->>AS: Пустой ответ (Email уникален и свободен)
deactivate DB
alt Режим == JOIN_EXISTING
AS->>DB: SELECT home_group_id, account_type FROM invites WHERE token = invite_token
DB-->>AS: Возвращает ID и тип существующей группы
else Режим == CREATE_NEW_OFFICE или CREATE_NEW_HOME
note over AS: Шаг 7: Генерация нового UUID для home_group_id
end
note over AS: Шаг 8: Асинхронное хэширование пароля (Argon2 / Bcrypt)
AS->>DB: INSERT INTO users (email, password_hash, home_group_id, account_type)
activate DB
DB-->>AS: Успешная запись (Генерация user_id)
deactivate DB
Note over API, DB: Коммит атомарной транзакции (COMMIT)
AS->>KAFKA: send_to_kafka_async("bupar.auth.events.registered")
AS-->>APP: HTTP 201 Created (status: "success", user_id: "usr-...")
deactivate AS
note over APP: Flutter показывает сообщение об успехе и перенаправляет на экран логина
Метод POST /api/v1/auth/register
Документация API: Регистрация пользователей с инициализацией Multi-Tenancy контуров HOME и OFFICE
- INVENTORY-2XX Backlog — Краткое Описание задачи 1.
- INVENTORY-1XX Refinement (Уточнение) — Краткое Описание задачи 2.
1 Функциональное назначение
Метод предназначен для первичной регистрации пользователя в экосистеме.
Помимо стандартного создания учетной записи (хэширования паролей), данный метод решает фундаментальную задачу инициализации инфраструктуры хранения ресурсов:
- Динамическое ветвление пространств: На основе параметра
space_creation_modeметод либо генерирует абсолютно новый изолированный холодильник со своим уникальнымhome_group_id(для семьи или офиса), либо привязывает нового пользователя к уже существующей группе на основе переданного инвайт-кода (invite_token). - Первичная разметка бизнес-логики: Фиксирует для создаваемой группы флаг
account_type(HOMEилиOFFICE), который в дальнейшем определяет, разрешены ли скрытые виртуальные минусы при готовке и утилизации, или система должна работать в режиме строгого складского контроля.
2 Протокол взаимодействия (HTTP Контракт)
- Метод:
POST - Маршрут:
/api/v1/auth/register - Формат данных:
application/json
2.1 Спецификация заголовков (HTTP Headers)
| Заголовок | Обязательный | Описание | Пример значения |
|---|---|---|---|
Content-Type |
Да | Указывает на передачу строго типизированного JSON-пакета | application/json |
X-Request-ID |
Да | Сквозной ID запроса для трассировки создания новой учетной записи | req-auth-reg-001a |
2.2 Спецификация тела запроса (Request Body)
| Поле | Тип | Обязательный | Описание | Пример значения |
|---|---|---|---|---|
email |
String | Да | Уникальный адрес электронной почты (валидируется регулярным выражением) | user@somedomain.kz |
password |
String | Да | Пароль пользователя (строго не менее 8 символов) | SecretSecurePassword123 |
space_creation_mode |
String (Enum) | Да | Режим инициализации складского пространства | "CREATE_NEW_OFFICE" |
invite_token |
String | Нет | UUID инвайт-кода для вступления в уже созданную семью/офис | null (или UUID) |
2.2.1 Допустимые константы space_creation_mode (Enum):
CREATE_NEW_HOME— создать новую семью (разрешены виртуальные минусы).CREATE_NEW_OFFICE— создать новый офис (строгий контроль остатков, блокировка дефицита).JOIN_EXISTING— вступить в готовую группу по инвайт-коду из поляinvite_token.
2.2.2 Пример сырого JSON-запроса (Payload — Сценарий: регистрация компании с созданием нового офисного пространства):
{
"email": "user@somedomain.kz",
"password": "SecretSecurePassword123",
"space_creation_mode": "CREATE_NEW_OFFICE",
"invite_token": null
}3 Схема обработки запроса пользователя (Mermaid)
На диаграмме представлена логика регистрации. Сервис Auth открывает атомарную транзакцию, создаёт запись в таблице пользователей, генерирует уникальный home_group_id для нового пространства (или связывает пользователя с существующим по инвайт-коду) и надёжно хэширует пароль.
4 Расшифровка шагов
- Шаг 1 (
User -> APP): Пользователь заполняет форму регистрации: вводит email, придумывает безопасный пароль, выбирает режим создания пространства (например,"CREATE_NEW_OFFICE") и нажимает кнопку «Зарегистрироваться». - Шаг 2 (
APP -> AS): Мобильное приложение Flutter отправляет запросHTTP POST /api/v1/auth/registerс JSON-телом на бэкенд. В заголовке прокидывается сквознойX-Request-ID. - Шаг 3 (
AS -> AS): Микросервис Авторизации на базеFastAPIперехватывает запрос и проводит первичную валидацию схемы данных. Проверяется синтаксис email-адреса и длина пароля (строго не менее 8 символов), защищая базу данных от некорректных записей. - Шаг 4 (
AS -> DB): Сервис открывает атомарную SQL-транзакцию вPostgreSQLи проверяет email на уникальность:SELECT 1 FROM users WHERE email = $1. - Шаг 5 (
DB -> AS): База данных возвращает пустой ответ, подтверждая, что данный логин свободен и регистрация может быть продолжена. Если email занят, транзакция прерывается с ошибкойHTTP 409 Conflict. - Шаг 6 (
AS -> DB): Ветвление логики пространств: Если в параметреspace_creation_modeпередан флагJOIN_EXISTING, сервис делает запрос к таблице инвайтов для извлечения параметровhome_group_idиaccount_typeгруппы, в которую хочет вступить пользователь. - Шаг 7 (
AS -> AS): Если пользователь регистрирует новое пространство (CREATE_NEW_HOMEилиCREATE_NEW_OFFICE), бэкенд на уровне бизнес-логики генерирует криптографически стойкийUUIDv4, который становится уникальным сквозным идентификаторомhome_group_idдля нового холодильника. - Шаг 8 (
AS -> AS): Бэкенд выполняет одностороннее хэширование пароля с использованием стойких алгоритмов (Argon2id или Bcrypt с солью), исключая хранение паролей в открытом виде. - Шаг 9 (
AS -> DB): Очищенные метаданные записываются в таблицу пользователей СУБД:INSERT INTO users (email, password_hash, home_group_id, account_type) VALUES ($1, $2, $3, $4) RETURNING id. - Шаг 10 (
DB -> AS): База данных успешно коммитит транзакцию (COMMIT) и возвращает сгенерированный идентификаторuser_id. - Шаг 11 (
AS -> KAFKA): Сервис Авторизации отправляет асинхронное системное событие в топик Kafkabupar.auth.events.registered. Смежные сервисы аналитики и уведомлений подхватывают этот сигнал для подготовки стартовых конфигураций под новую группу. - Шаг 12 (
AS -> APP): Сервер возвращает мобильному приложению статус успешной генерации сущностиHTTP 201 Created. Flutter-клиент скрывает лоадеры и перенаправляет пользователя на экран ввода логина и пароля для прохождения первичного эндшпиля авторизации (Метод 1).
5 Спецификация ответов сервера (Response Body) и ошибок
5.1 Успешный ответ (Success Response)
5.1.1 HTTP 201 Created (Ответ на Шаге 12)
Возвращается мобильному приложению после успешного коммита транзакции. В теле ответа фиксируется сгенерированный идентификатор пользователя и параметры Multi-Tenancy контура.
- Заголовки ответа (Response Headers):
Content-Type: application/json
- Тело ответа (Response Body):
{
"status": "success",
"data": {
"user_id": "usr-8822-fa41",
"home_group_id": "8a71d11e-9500-4b11-9a2c-d2b0d7b3dcba",
"account_type": "OFFICE",
"timestamp": "2026-07-02T02:15:00Z"
}
}5.2 Вилки исключений и обработка ошибок
5.2.1 Ошибка коллизии: Email уже зарегистрирован (HTTP 409 Conflict — Шаг 5)
Выбрасывается на Шаге 5, если проверка в базе данных выявила, что указанный адрес электронной почты уже занят другой учетной записью. Это предотвращает дублирование профилей в СУБД.
- Заголовки ответа (Response Headers):
Content-Type: application/json
- Тело ответа (Response Body):
{
"error_code": "ERR-EMAIL-ALREADY-EXISTS",
"message": "Пользователь с таким email-адресом уже зарегистрирован в системе.",
"details": {
"rejected_email": "manager@bupar-office.kz",
"action": "Redirect user to login screen or trigger password recovery flow."
}
}5.2.2 Ошибка: Невалидный или просроченный инвайт-код (HTTP 410 Gone / 404 Not Found — Шаг 6)
Выбрасывается на Шаге 6 в режиме JOIN_EXISTING, если переданный invite_token отсутствует в таблице инвайтов, аннулирован создателем пространства или истек по времени жизни.
{
"error_code": "ERR-INVITE-TOKEN-INVALID",
"message": "Указанный пригласительный код недействителен, просрочен или аннулирован.",
"details": {
"provided_token": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"action": "Prompt user to request a fresh invite token from the space administrator."
}
}