Сценарий: регистрация и login B2B/B2C
NOTE
Статус: Target design. Документ описывает целевую доменную модель. Соответствующий код реализован частично (см.
backend/internal/core/) или пока не начат. Правила маркировки — в50-processes/documentation-standard.md.
Принцип: используем shared/auth, не дублируем
Аутентификация (identity, JWT, refresh, RBAC, signup, профиль, удаление) полностью делегирована общему сервису /Users/belkanov/projects/shared/auth/ (auth-service). Tracium не реализует свои password hash, JWT issuance, refresh rotation, OAuth grant types — это делает auth-service. Tracium подписывается на его доменные события и расширяет профиль User бизнес-полями (B2B/B2C, pricing group, contracts, supplier credentials).
Любая функциональность, которой нет в shared/auth (см. секцию «Что расширяем»), реализуется внутри shared/auth через PR — а не дублируется в Tracium.
Терминология (выравнивание)
| Tracium-понятие | shared/auth-понятие | Где живёт |
|---|---|---|
Customer (бизнес-агрегат) | User (model/user.go) + Tracium-extension | User.Id — общий ключ |
AuthIdentity | login_password / messenger / system / (TBD: oauth, sso, api_key) | shared/auth |
Session | JWT cookies: access_token (~1ч) + jwt-refresh (~7д) | shared/auth |
SessionContext (Tracium VO) | JwtCustomClaims (Id, Roles, RolesUpdatedAt) + Tracium customer profile lookup | composed на API gateway |
Role | Role{Id, Name, DisplayName, Permissions} | shared/auth |
Permission | Permission{Resource, Action} | shared/auth |
| Token invalidation на смене ролей | RolesUpdatedAt Unix timestamp в JWT claims | shared/auth |
| Anonymous visitor | JWT с level: anonymous | shared/auth |
| M2M-сервис | system role + GenerateM2MToken (pkg/jwt) | shared/auth |
Участники
| BC / сервис | Роль |
|---|---|
| shared/auth | Owner identity / sessions / JWT / RBAC / signup / профиль / удаление аккаунта. |
| Customer (Tracium) | Owner бизнес-профиля: customer_type, legal_info, customer_pricing_group, contracts, supplier_credentials[]. Подписан на auth_user_events. |
| Visibility | Использует roles из JWT + customer_pricing_group как Subject. |
| Pricing | Подписан на CustomerPricingGroupChanged (Tracium event) для invalidate cache. |
| Credentials | Подготовка per-customer DEK при первой связи User → Customer. |
| External | OAuth/SSO провайдеры (TBD-расширение в shared/auth), Telegram/Max боты (есть), SMS/email gateway (есть). |
Endpoints из shared/auth (используем как есть)
| Endpoint | Назначение |
|---|---|
POST /signup/phone/token → /signup/phone/confirm → PUT /signup/phone | 3-шаговая регистрация по телефону + SMS-код + пароль |
POST /signup/email/token → /signup/email/confirm → PUT /signup/email | 3-шаговая по email |
POST /signup/system (требует system role JWT) | Идемпотентная регистрация B2B без верификации (для интеграций) |
POST /login (grant_type=password) | Универсальный login. Логин = email если есть @, иначе телефон. |
POST /login (grant_type=authorization_code) | OAuth code exchange |
POST /login (grant_type=refresh_token) | Refresh |
GET/POST /auth/refresh | Явный refresh |
GET/POST /logout | Очистка JWT cookies, anonymous token |
GET /auth/nginx | Internal: nginx auth_request — валидация JWT, refresh, проброс заголовков |
POST /login/messenger/token → /login/messenger/verify | Login через Telegram/Max бот (кодом) |
POST/DELETE/GET /messenger/link* | Привязка / отвязка messenger-аккаунта |
GET /profile / PATCH /profile / DELETE /profile | Профиль (под Nginx auth) |
POST /admin/users/{id}/roles / DELETE /admin/users/{id}/roles | Управление ролями (триггерит RolesUpdatedAt) |
GET /admin/roles / POST /admin/roles / PUT /admin/roles/{name} | Справочник ролей |
Доменные события shared/auth (топик auth_user_events)
| Событие | Когда | Tracium consumer |
|---|---|---|
user.profile.updated | PATCH /profile | Customer BC: sync display_name / email / phone в Tracium-extension |
user.messenger.linked | Привязан messenger | Customer BC: для UX-уведомлений |
user.messenger.unlinked | Отвязан messenger | То же |
user.deleted | DELETE /profile (или admin) | Customer BC: запуск Tracium-grace PersonalDataDeletionRequested |
Доменные события Tracium (топик customer.events.v1)
Публикуются Customer BC поверх событий shared/auth — отражают бизнес-смысл, которого нет в auth.
| Событие | Когда |
|---|---|
КлиентРасширенЗарегистрирован (CustomerProfileCreated) | Tracium увидел нового User.Id (через auth_user_events или first-touch) и создал Tracium-extension |
ЮридическиеДанныеПодтверждены (LegalInfoVerified) | Verified ИНН (B2B) |
ГруппаТарификацииНазначена (CustomerPricingGroupChanged) | Operator / promo / contract |
ДоговорПодписан (ContractSigned) | B2B |
КастомнаяФичаПереключена (CustomerFeatureToggled) | Operator / self-service |
ПерсональныеДанныеУдалены (PersonalDataDeleted) | После 30 дней grace (152-ФЗ) |
Sequence — B2C регистрация по email через shared/auth
sequenceDiagram autonumber participant V as Visitor participant API as Tracium API gateway participant AUTH as shared/auth participant SMTP as Email gateway participant K as Kafka (auth_user_events) participant C as Customer (Tracium) V->>API: POST /signup/email/token {email} API->>AUTH: proxy AUTH->>SMTP: send confirmation code AUTH-->>V: 200 V->>API: POST /signup/email/confirm {email, code} API->>AUTH: proxy AUTH-->>V: 200 + signup_token V->>API: PUT /signup/email {signup_token, password, name} API->>AUTH: proxy AUTH-->>AUTH: User создан, JWT cookies set AUTH-->>K: user.profile.updated (initial) K-->>C: consume C->>C: создать Tracium-extension (customer_type=individual, pricing_group=b2c_retail) C-->>C: КлиентРасширенЗарегистрирован AUTH-->>V: 200 + cookies (access_token + jwt-refresh)
Sequence — B2B регистрация (system signup от интегратора)
sequenceDiagram autonumber participant SVC as B2B integrator (M2M) participant API as Tracium API gateway participant AUTH as shared/auth participant K as Kafka (auth_user_events) participant C as Customer (Tracium) participant INN as ИНН-verify SVC->>SVC: GenerateM2MToken (system role) SVC->>API: POST /signup/system {email, name, password?, ...} API->>AUTH: proxy + JWT system AUTH->>AUTH: SystemRoleMiddleware ok AUTH-->>AUTH: User создан, SystemRegistered=true AUTH-->>K: user.profile.updated K-->>C: consume C->>C: Tracium-extension {customer_type=legal_entity, pricing_group=b2b_standard} C->>INN: verify ИНН (async) INN-->>C: result alt verified C-->>C: ЮридическиеДанныеПодтверждены else Note over C: pending verification, alert operator end AUTH-->>SVC: 200 + user object
Sequence — login (password grant)
sequenceDiagram autonumber participant U as Customer participant API as Tracium API gateway participant AUTH as shared/auth participant NGX as Nginx auth_request participant C as Customer (Tracium) U->>API: POST /login (grant_type=password, username, password) API->>AUTH: proxy AUTH->>AUTH: validate password (auto-detect email vs phone) alt success AUTH-->>U: cookies access_token + jwt-refresh else fail AUTH-->>U: 401 end U->>API: GET /api/... (next request) API->>NGX: auth_request /auth/nginx NGX->>AUTH: GET /auth/nginx with cookies AUTH-->>NGX: 200 + headers (X-User-Id, X-User-Roles, X-Roles-Updated-At) NGX-->>API: ok + headers API->>C: lookup Tracium-extension by User.Id C-->>API: customer_type, pricing_group, features API->>API: build SessionContext = JwtCustomClaims + Tracium profile
Sequence — login через messenger (Telegram/Max)
sequenceDiagram autonumber participant U as Customer participant BOT as Telegram/Max bot participant AUTH as shared/auth U->>BOT: /login команда BOT->>AUTH: POST /login/messenger/token {messenger_user_id} AUTH-->>BOT: code (6 digits) BOT-->>U: «введи код в UI» U->>AUTH: POST /login/messenger/verify {code} AUTH-->>U: cookies access_token + jwt-refresh
Что Tracium расширяет в shared/auth (нужны PR в auth-service)
Перечисленное отсутствует в текущем shared/auth и должно быть добавлено именно туда (а не реализовано в Tracium):
| Расширение | Зачем | Куда добавлять |
|---|---|---|
| OAuth провайдеры (Yandex / Google / VK) | B2C ускоренный onboarding — массовый запрос | новый grant_type oauth_provider + /login/oauth/{provider}/callback |
| SAML / OIDC SSO | B2B enterprise клиенты | /auth/sso/{org} + IdP-mapping |
| MFA / TOTP / Recovery codes | B2B admin, suspicious IP | User.MfaSecret (encrypted) + /mfa/setup / /mfa/verify / recovery codes |
| Account lockout (5 fails / 10 мин) | Brute force защита | rate limiter middleware на /login per (username, ip) |
| Suspicious IP detection + require_mfa flag | Adaptive auth | новое поле в JwtCustomClaims + middleware |
| Session TTL policy per-customer | B2B 12ч, B2C 30 дней — разные | User.SessionTtlOverride или role-based config |
| Customer-managed API keys (B2B integrations) | Не путать с M2M-system-токеном | ApiKey entity + /admin/users/{id}/api-keys + новый grant api_key |
| Personal data deletion с grace (152-ФЗ) | Сейчас DELETE /profile сразу + user.deleted | promotion: user.deletion.requested (T0) → user.deletion.confirmed (T+30д) → user.deleted |
auth_audit events | Login attempts, failures, MFA challenges | новый kafka topic auth_audit_events |
| Block / unblock with reason | Compliance + операторские действия | расширить Disabled в {disabled, reason, until} |
Каждое — отдельный RFC + PR в shared/auth. После merge — Tracium реализует consumer-side (новые подписки в Customer BC).
Что Tracium не просит у shared/auth (живёт у нас)
Customer.customer_type,legal_info,customer_pricing_group,contract,payment_profiles,delivery_addresses,features.supplier_credentials[](целиком Credentials BC).Subjectдля Visibility (composed из roles + pricing_group).- Бизнес-роли «закупщик / руководитель / аналитик» — тоже в shared/auth
Roleсправочнике; Tracium только использует. - Sessions list для UX (revoke all) — может остаться в shared/auth, Tracium не дублирует.
Decision points
- 5 failed логинов за 10 мин → отвечает shared/auth (расширение TBD: lockout). Tracium не вмешивается.
- suspicious IP / новый device → MFA → расширение в shared/auth (TBD).
- B2B admin role → MFA always → расширение (см. таблицу выше).
- B2B SSO без mapping pricing_group → fallback на
b2b_standard+ alert оператору Tracium. User.Idуже существует, но Tracium-extension нет → first-touch creates Tracium-extension с дефолтами.- Email уже existed с другим identity → правило shared/auth: signup идемпотентен по
(phone, email)— возвращает existing User. Tracium не меняет это поведение.
Edge cases
| Случай | Поведение |
|---|---|
Customer удалён через DELETE /profile (shared/auth) | user.deleted → Tracium запускает PersonalDataDeletionRequested → 30 дней grace → PersonalDataDeleted (Tracium-extension физически удаляется, supplier_credentials → ротация DEK + revoke). |
RolesUpdatedAt обновился (admin изменил роли) | Старый JWT станет stale при следующем /auth/nginx → forced refresh. Tracium pricing/visibility caches invalidate по (User.Id). |
| Recovery codes не работают (TBD-расширение отсутствует) | Сейчас reset через email/phone signup workflow shared/auth (3 шага). После расширения — recovery codes. |
| Customer вводит OAuth provider, которого нет в shared/auth | UX «временно недоступно» + offer email/phone fallback. После добавления — full flow. |
/auth/nginx отдал refresh (cookies обновились в pre-response) | Tracium API gateway проксирует Set-Cookie клиенту. Никакого Tracium-state. |
system-token истёк у B2B integrator | Integrator перегенерирует GenerateM2MToken (shared lib pkg/jwt). |
Инварианты сценария
- Tracium никогда не выпускает свои JWT для customer’ов. Только shared/auth.
- Tracium никогда не хранит
User.Passwordили TOTP-секреты. Только shared/auth. User.Id(UUID) — единственный stable ключ между shared/auth и Tracium-extension.- Tracium Customer aggregate не существует без
User.Id. Регистрация всегда начинается с shared/auth. - Любое поле
User, которое Tracium хочет читать (Name, Email, Phone, Roles), читается из JWT claims или черезGET /profile//internal/user/...— не дублируется в Tracium PG. - Tracium-extension — append-only по lifecycle событиям; материализован в
customer_directoryPG для админки. - Изменения, нужные Tracium для auth-механики → PR в shared/auth (см. таблицу расширений). Не в Tracium.
Метрики и observability
Tracium-метрики (только Tracium-side):
customer_extension_created_total{type}— после consumeauth_user_events.customer_pricing_group_changes_total{from, to}.customer_personal_data_deletions_total{stage}—requested/confirmed/deleted.customer_legal_info_verifications_total{result}.auth_event_consume_lag_seconds— задержка от shared/auth event до Tracium-extension update.
Auth-метрики (/login, /signup/*, lockouts, MFA) — собираются shared/auth, дашборд там же.
Связанные файлы
- Контексты:
../contexts/customer.md,../contexts/credentials.md,../contexts/visibility.md,../contexts/pricing.md. - Сценарии:
credential-onboarding.md. - shared/auth:
AUTHENTICATION.md,M2M_INTEGRATION.md,SYSTEM_SIGNUP.md,ROLES_INVALIDATION.md,CHANGELOG_EMAIL_SUPPORT.md,openapi.yaml. ../../40-operations/data-protection.md(TBD) — 152-ФЗ детали.