mirror of
https://github.com/gromlab-ru/slm-design.git
synced 2026-08-22 07:30:16 +03:00
92 lines
6.0 KiB
Markdown
92 lines
6.0 KiB
Markdown
# Модуль бизнес-логики внутри домена
|
||
|
||
> Пояснение смыслового центра домена.
|
||
|
||
## Связанные правила
|
||
|
||
- [`SLM-L3-BUSINESS-R003`](../../rules/level-3.md#slm-l3-business-r003)
|
||
- [`SLM-L3-BUSINESS-A004`](../../rules/level-3.md#slm-l3-business-a004)
|
||
- [`SLM-L3-PORT-R007`](../../rules/level-3.md#slm-l3-port-r007)
|
||
- [`SLM-L1-MODULE-A004`](../../rules/level-1.md#slm-l1-module-a004)
|
||
|
||
## Роль
|
||
|
||
`business` — единственный обязательный модуль домена. Он владеет:
|
||
|
||
- публичными предметными сценариями и `DomainApi`;
|
||
- фабрикой, типом зависимостей `Deps` и портами;
|
||
- предметными типами и контрактами;
|
||
- детерминированными правилами, проверкой и нормализацией данных;
|
||
- публичным контрактом ошибок предметной области;
|
||
- моделью состояния, командами и средствами чтения этого состояния.
|
||
|
||
Модуль `business` не владеет SDK, реализацией хранилища, API браузера или Node.js, связью с фреймворком, конфигурацией среды и конкретной системой управления состоянием.
|
||
|
||
## Публичный API
|
||
|
||
Точка входа `business` открывает только контракт, необходимый потребителям, сборкам и адаптерам:
|
||
|
||
```ts
|
||
export { authFactory } from './auth.factory'
|
||
export { AUTH_ERROR_CODES, isAuthError } from './errors/auth-error'
|
||
export { normalizeAuthPhone, validateAuthPhone } from './lib/auth-phone'
|
||
|
||
export type {
|
||
AuthApi,
|
||
AuthDeps,
|
||
AuthError,
|
||
AuthErrorCode,
|
||
AuthFactory,
|
||
AuthPhonePort,
|
||
AuthSessionPort,
|
||
AuthState,
|
||
} from './types'
|
||
```
|
||
|
||
Типы портов экспортируются, потому что сборки и самостоятельные адаптеры реализуют эти контракты. Сервисы, внутренние преобразователи, конструктор ошибки, преобразование исходной ошибки, ключ хранения и конкретный механизм состояния остаются закрытыми.
|
||
|
||
## Типы и чистые функции
|
||
|
||
Каталоги `types`, `errors`, `lib`, `ports`, `services` и `tests` являются сегментами модуля `business`, а не отдельными API домена. Тип размещается у владельца:
|
||
|
||
| Контракт | Владелец |
|
||
|---|---|
|
||
| `AuthApi`, `AuthDeps`, `AuthState`, порты | `business` |
|
||
| DTO SDK и транспортная ошибка | Адаптер или `infra` |
|
||
| Свойства React-провайдера | `react` |
|
||
| Модель представления экрана | Модуль-потребитель в `compositions` |
|
||
|
||
Чистая предметная функция может быть публичной, только если выражает предметное правило и нужна реальному внешнему потребителю. Она получает все данные аргументами, детерминирована и не использует `Deps`, состояние, часы, генератор случайных значений, окружение или фреймворк.
|
||
|
||
Потребитель может применять `validateAuthPhone` для ранней подсказки в интерфейсе, но публичный сценарий повторно проверяет данные на собственной границе.
|
||
|
||
## Ошибки предметной области
|
||
|
||
При сбое публичный сценарий выдаёт только ошибку из контракта домена. Исходная ошибка, класс SDK, статус HTTP, тело ответа и транспортный код не становятся API потребителя.
|
||
|
||
```ts
|
||
export const AUTH_ERROR_CODES = {
|
||
PHONE_OTP_PHONE_INVALID: 'AUTH_PHONE_OTP_PHONE_INVALID',
|
||
PHONE_OTP_REQUEST_FAILED: 'AUTH_PHONE_OTP_REQUEST_FAILED',
|
||
PHONE_OTP_VERIFY_CODE_INVALID: 'AUTH_PHONE_OTP_VERIFY_CODE_INVALID',
|
||
PHONE_OTP_RESEND_TOO_SOON: 'AUTH_PHONE_OTP_RESEND_TOO_SOON',
|
||
} as const
|
||
|
||
export type AuthError = Readonly<{
|
||
code: AuthErrorCode
|
||
retryAfterSeconds: number | null
|
||
}>
|
||
|
||
export const isAuthError = (value: unknown): value is AuthError => {
|
||
// Проверка публичной формы ошибки во время выполнения.
|
||
}
|
||
```
|
||
|
||
Если публичный API использует исключения, точка входа экспортирует проверку типа, коды и доступную только для чтения форму ошибки, но не её конструктор или преобразователь исходной ошибки. Если проект выбирает размеченный тип `Result`, тот же контракт выражается в ветви результата. Один API не смешивает оба способа для одинаковых сценариев.
|
||
|
||
## Состояние домена
|
||
|
||
Модуль `business` определяет форму `AuthState`, начальное состояние, допустимые переходы и публичный способ наблюдения. Конкретное хранилище, сохранение данных, источник подписки и хук фреймворка реализуются снаружи через порты и адаптеры.
|
||
|
||
Независимый от фреймворка интерфейс наблюдения может состоять из `getSnapshot` и `subscribe`. Это часть API бизнес-логики, а не React-хук или `StoreApi` конкретной библиотеки.
|