Files
slm-design/DRAFT/level-3/domains/factory-ports-adapters.md

89 lines
4.4 KiB
Markdown
Raw Normal View History

# Factory, ports и adapters
2026-07-30 13:22:45 +03:00
> Пояснение runtime boundary business module.
2026-07-30 13:22:45 +03:00
## Связанные правила
2026-07-30 13:22:45 +03:00
- [`SLM-L3-FACTORY-R005`](../../rules/level-3.md#slm-l3-factory-r005)
- [`SLM-L3-FACTORY-R006`](../../rules/level-3.md#slm-l3-factory-r006)
- [`SLM-L3-PORT-R007`](../../rules/level-3.md#slm-l3-port-r007)
- [`SLM-L3-ADAPTER-R008`](../../rules/level-3.md#slm-l3-adapter-r008)
- [`SLM-L3-BUSINESS-A004`](../../rules/level-3.md#slm-l3-business-a004)
## Factory и API instance
```text
2026-07-30 13:22:45 +03:00
Factory + implementations ports -> business API instance
```
2026-07-30 13:22:45 +03:00
Factory принадлежит `business`, получает полный `AuthDeps` и возвращает `AuthApi`:
```ts
export type AuthFactory = (deps: AuthDeps) => AuthApi
```
2026-07-30 13:22:45 +03:00
Все presets одной factory предоставляют полный набор ports и получают одинаковый business API. Browser, request и server action не создают разные factory только из-за среды. Preset может открыть consumer суженный view API, но не меняет contract самой factory.
2026-07-30 13:22:45 +03:00
Factory construction создаёт только deterministic services и closures. Она не делает request, не читает cookies/storage/env, не запускает subscription/timer, не обращается к platform API, не выбирает adapter и не запускает framework lifecycle.
2026-07-30 13:22:45 +03:00
## Isomorphic import graph
2026-07-30 13:22:45 +03:00
Проверяется весь production graph, достижимый из `business` entrypoint, а не только файл factory. Он не должен достигать:
2026-07-30 13:22:45 +03:00
- React, Vue, Next.js и framework markers;
- browser-only, Node-only, `client-only` или `server-only` boundary;
- SDK, generated client, storage implementation или concrete state/query runtime;
- adapters, presets, framework modules и environment configuration.
2026-07-30 13:22:45 +03:00
Tree shaking не является доказательством изоляции. Type-only import concrete runtime создаёт ту же архитектурную зависимость и также запрещён.
## Ports
2026-07-30 13:22:45 +03:00
Port принадлежит business и описывает capability на business language:
```ts
export type AuthPhonePort = {
requestCode: (phone: string) => Promise<unknown>
verifyCode: (data: VerifyPhoneOtpData) => Promise<unknown>
}
export type AuthSessionPort = {
getSnapshot: () => AuthState
subscribe: (listener: () => void) => () => void
setToken: (token: string | null) => void
}
```
2026-07-30 13:22:45 +03:00
Port не принимает SDK client, generated operation, `Request`, `Window`, React hook, `StoreApi` или environment-specific type. Он абстрагирует implementation, а не доступность capability: optional port и method, который намеренно падает в одной среде, нарушают factory contract.
2026-07-30 13:22:45 +03:00
`unknown` допустим только на границе непроверенного external result. Business обязан валидировать его до превращения в domain result, state или error. Если adapter уже может представить устойчивый business-owned result, port описывает именно этот result, а не concrete DTO.
## Adapters
2026-07-30 13:22:45 +03:00
Adapter соединяет business port и concrete runtime:
```text
2026-07-30 13:22:45 +03:00
business port <- adapter -> SDK / storage / platform / request input
```
2026-07-30 13:22:45 +03:00
Adapter может преобразовать domain argument в transport argument, вызвать concrete source, нормализовать техническую форму к port contract и вернуть source failure. Он не определяет domain error code, business fallback, invariant или public method `AuthApi`.
2026-07-30 13:22:45 +03:00
Default location -- private segment минимального preset owner:
```text
2026-07-30 13:22:45 +03:00
domains/auth/presets/application/
├── adapters/
2026-07-30 13:22:45 +03:00
│ └── auth-phone.adapter.ts
└── index.ts
```
2026-07-30 13:22:45 +03:00
Если один adapter имеет несколько assembly consumers или самостоятельную integration responsibility, он становится promoted module:
```text
2026-07-30 13:22:45 +03:00
domains/auth/adapters/
└── identity-provider/
└── index.ts
```
2026-07-30 13:22:45 +03:00
Promoted adapter сохраняет минимальный public API. Его появление не делает concrete SDK частью public business contract.