Метод POST /api/v1/auth/register

Документация API: Регистрация пользователей с инициализацией Multi-Tenancy контуров HOME и OFFICE

Published

July 2, 2026

1 Функциональное назначение

Метод предназначен для первичной регистрации пользователя в экосистеме.

Помимо стандартного создания учетной записи (хэширования паролей), данный метод решает фундаментальную задачу инициализации инфраструктуры хранения ресурсов:

  1. Динамическое ветвление пространств: На основе параметра space_creation_mode метод либо генерирует абсолютно новый изолированный холодильник со своим уникальным home_group_id (для семьи или офиса), либо привязывает нового пользователя к уже существующей группе на основе переданного инвайт-кода (invite_token).
  2. Первичная разметка бизнес-логики: Фиксирует для создаваемой группы флаг 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 для нового пространства (или связывает пользователя с существующим по инвайт-коду) и надёжно хэширует пароль.

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 показывает сообщение об успехе и перенаправляет на экран логина

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): Сервис Авторизации отправляет асинхронное системное событие в топик Kafka bupar.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."
  }
}