Files
slm-design/DRAFT/level-3/domains/business.md

92 lines
4.3 KiB
Markdown
Raw Normal View History

# Business module внутри Domain
2026-07-30 13:22:45 +03:00
> Пояснение semantic core Domain.
2026-07-30 13:22:45 +03:00
## Связанные правила
2026-07-30 13:22:45 +03:00
- [`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)
2026-07-30 13:22:45 +03:00
## Роль
2026-07-30 13:22:45 +03:00
`business` -- единственный обязательный module Domain. Он владеет:
2026-07-30 13:22:45 +03:00
- public business scenarios и `DomainApi`;
- factory, `Deps` и ports;
- business-owned types и contracts;
- детерминированными rules, validation и normalization;
- domain error contract;
- семантикой domain state, commands и selectors.
2026-07-30 13:22:45 +03:00
Business не владеет SDK, storage implementation, browser/Node API, framework integration, environment wiring или concrete state manager.
2026-07-30 13:22:45 +03:00
## Public API
2026-07-30 13:22:45 +03:00
Business entrypoint открывает только contract, нужный consumers, presets и adapters:
```ts
export { authFactory } from './auth.factory'
2026-07-30 13:22:45 +03:00
export { AUTH_ERROR_CODES, isAuthError } from './errors/auth-error'
export { normalizeAuthPhone, validateAuthPhone } from './lib/auth-phone'
export type {
AuthApi,
AuthDeps,
AuthError,
AuthErrorCode,
AuthFactory,
2026-07-30 13:22:45 +03:00
AuthPhonePort,
AuthSessionPort,
AuthState,
2026-07-30 13:22:45 +03:00
} from './types'
```
2026-07-30 13:22:45 +03:00
Port types экспортируются, потому что preset и promoted adapter реализуют именно эти contracts. `services`, private mappers, error constructor, source mapper, persistence key и concrete state runtime остаются закрытыми.
2026-07-30 13:22:45 +03:00
## Types и pure functions
2026-07-30 13:22:45 +03:00
`types`, `errors`, `lib`, `ports`, `services` и `tests` -- segments business module, а не отдельные Domain APIs. Type размещается у владельца:
2026-07-30 13:22:45 +03:00
| Contract | Владелец |
|---|---|
2026-07-30 13:22:45 +03:00
| `AuthApi`, `AuthDeps`, `AuthState`, ports | `business` |
| SDK DTO и transport error | Adapter или `infra` |
| React provider props | `react` |
| View model screen | Consumer composition |
2026-07-30 13:22:45 +03:00
Pure domain function может быть public, только если она выражает business rule и имеет реального external consumer. Она получает все данные аргументами, детерминирована, не использует `Deps`, state, clock, random, environment или framework runtime.
2026-07-30 13:22:45 +03:00
Consumer может применять `validateAuthPhone` для раннего UX feedback, но public business scenario повторяет validation на своей границе.
## Domain errors
2026-07-30 13:22:45 +03:00
Каждый public runtime scenario выдаёт только domain failure contract. Source error, SDK class, HTTP status, response body и transport code не становятся consumer API.
```ts
export const AUTH_ERROR_CODES = {
PHONE_OTP_PHONE_INVALID: 'AUTH_PHONE_OTP_PHONE_INVALID',
2026-07-30 13:22:45 +03:00
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 => {
2026-07-30 13:22:45 +03:00
// Runtime validation of the public observation shape.
}
```
2026-07-30 13:22:45 +03:00
Если public API использует exceptions, entrypoint экспортирует domain-specific guard, codes и read-only observation shape, но не constructor или source error mapper. Если проект выбирает discriminated `Result`, тот же contract должен быть выражен в result branch. Один business API не смешивает оба способа для одинаковых scenario.
2026-07-30 13:22:45 +03:00
## Domain state
2026-07-30 13:22:45 +03:00
Business определяет форму `AuthState`, начальное состояние, допустимые transitions и public observation contract. Concrete store, persistence, subscription source и framework hook реализуются снаружи business через ports/adapters.
2026-07-30 13:22:45 +03:00
Framework-neutral observation может иметь форму `getSnapshot` и `subscribe`. Это protocol business API, а не React hook или `StoreApi` конкретной библиотеки.