Files
slm-design/DRAFT/level-2/domains/framework-bindings.md
2026-07-30 20:48:05 +03:00

5.9 KiB
Raw Blame History

Framework Groups и модули

Пояснение domain-specific framework-кода на примере React.

Связанные правила

Framework Group

Папка для domain-specific React binding modules называется react:

domains/auth/react/            # Framework Group
├── session/                   # SLM-модуль
│   ├── hooks/
│   ├── providers/
│   └── index.ts
└── login-form/                # SLM-модуль
    ├── components/
    └── index.ts

react является Group, а не модулем. У неё нет index.ts, состояния, реализации, lifecycle или агрегирующего API. Если пакет поддерживает Vue, рядом появляется отдельная Group vue.

Каждый прямой дочерний каталог является обычным SLM-модулем со своей ответственностью, публичным API и узлом графа. Он не является вложенным модулем, потому что родительская граница react является Group.

Framework binding module

Модуль принадлежит Framework Group, если его самостоятельная ответственность состоит в связывании готового DomainApi одного домена с конкретным framework. Сам факт зависимости от framework недостаточен: framework-specific preset остаётся в presets, а page-specific модуль остаётся в compositions.

Framework binding module может:

  • передавать готовый DomainApi через Provider и context;
  • предоставлять domain-specific hooks;
  • отображать состояние и безопасные ошибки домена;
  • реализовывать переиспользуемую domain-specific форму или guard;
  • связывать framework lifecycle с публичным API домена.

Он не вызывает business-фабрику или preset, не выбирает adapters и не создаёт новые предметные сценарии.

Framework binding module импортирует типы и runtime error contract через разные фасеты:

import type {
  AuthApi,
  AuthError,
} from '@/domains/auth/business'

import {
  AUTH_ERROR_CODES,
  isAuthError,
} from '@/domains/auth/business/error'

Импорт business/factory из Framework Group запрещён: готовый DomainApi передаётся модулю извне.

Модуль session

auth/react/session может владеть Provider и hooks доступа к уже созданному AuthApi:

'use client'

type AuthSessionProviderProps = PropsWithChildren<{
  api: AuthApi
}>

export const AuthSessionProvider = ({
  api,
  children,
}: AuthSessionProviderProps) => {
  return (
    <AuthSessionContext.Provider value={api}>
      {children}
    </AuthSessionContext.Provider>
  )
}

Публичный путь модуля:

import {
  AuthSessionProvider,
  useAuthSession,
} from '@/domains/auth/react/session'

Импорт @/domains/auth/react запрещён, потому что Group не имеет API.

Модуль login-form

auth/react/login-form может владеть переиспользуемой формой, если она работает только с AuthApi, AuthState и AuthError. Она может использовать публичный API соседнего auth/react/session, если зависимость остаётся ацикличной.

Конкретная страница, продуктовый текст, layout, redirect и выбор маршрута принадлежат compositions. Поэтому domain-owned AuthGuard может решить, разрешён ли доступ, но политика перехода на /login остаётся у route composition.

Запрет cross-domain framework imports

Framework binding module не импортирует hooks, contexts, Providers, components или framework state другого доменного пакета:

// Недопустимо: domains/user/react/profile
import { useAuthSession } from '@/domains/auth/react/session'

Cross-domain UI собирается в compositions:

const session = useAuthSession()

return (
  <UserProfile
    userId={session.userId}
    canEdit={session.isAuthenticated}
  />
)

Передача через props является границей композиции, но не требует prop drilling внутри домена: каждый пакет может использовать собственный Provider и context. Если User business постоянно нуждается в Auth, готовый AuthApi передаётся User factory при сборке графа, а User framework module работает уже со своим UserApi.

Публичные API

import { AuthSessionProvider } from '@/domains/auth/react/session'
import { LoginForm } from '@/domains/auth/react/login-form'

Framework Group не реэкспортирует дочерние модули. Это сохраняет независимые ответственности и не превращает react в скрытый корневой модуль домена.