Files
slm-design/DRAFT/domains/auth-example.md

6.5 KiB
Raw Blame History

Auth как проверочный пример

Рабочая заметка на основе реального модуля /home/gromov/projects/biocad/newbiocadru/apps/web/src/business/auth. Код проекта не изменялся.

Цель примера: проверить гипотезы Domain на существующем SLM business-модуле, а не предложить немедленную миграцию.

Текущее устройство

business/auth/
├── auth.factory.ts
├── errors/
├── hooks/
├── mappers/
├── services/
├── tests/
├── types/
└── index.ts

Runtime-сборка находится отдельно:

compositions/business/knv/auth/
├── adapters/
├── create-knv-auth-business.ts
└── index.ts

Новая сущность Domain может колоцировать обе ответственности без смешивания ролей:

domains/auth/
├── business/
├── presets/
│   └── {preset-name}/
│       └── adapters/
└── {framework-binding}/

Factory и client boundary

AUTH-N001: Текущий AuthApi содержит client-oriented hook

auth.factory.ts импортирует createAuthHook, а hooks/use-auth.hook.ts содержит 'use client'. Кроме того, AuthDeps.session описывает useToken.

Текущий transitive graph:

authFactory
  → createAuthHook
  → 'use client'

Это практический пример того, почему neutral factory должна проверяться по всему transitive import graph, а framework hooks должны находиться в отдельном framework module Domain. Точный путь этого module пока не выбран.

Возможное направление:

business AuthApi
  → framework-neutral state observation

React binding
  → useAuth над готовым AuthApi

Финальный state contract пока не выбран.

Pure phone logic

AUTH-N002: Нормализация телефона уже дублируется

Business содержит private normalizePhoneOtpPhone, а auth-widget содержит отдельный getPhoneDigits и собственный PHONE_DIGITS_LENGTH.

Это кандидат на public pure business function:

import {
  normalizeAuthPhone,
  validateAuthPhone,
} from '@/domains/auth/business'

Business service и UI могут использовать одну семантику. Business service всё равно повторно валидирует вход независимо от UI-проверки.

Существующий business/user показывает другой workaround: pure validators возвращаются через собранный userFactory API. Прямой pure export позволит не требовать assembly для детерминированной функции.

Error contract

AUTH-N003: Error contract фактически публичен, но описан не полностью

Business создаёт AuthBusinessError с code и retryAfterSeconds, но public index.ts экспортирует только type AuthErrorCode.

Consumer auth-widget поэтому:

  • повторяет строковые error codes в message map;
  • создаёт локальный AuthErrorData;
  • вручную проверяет code и retryAfterSeconds в unknown;
  • самостоятельно нормализует форму caught error.

Предварительное исправление границы:

// Public business API.
export { AUTH_ERROR_CODES, isAuthError }
export type { AuthError, AuthErrorCode }

// Business-private implementation.
class AuthBusinessError extends Error {}
const createAuthBusinessError = (...) => {}

Consumer получает безопасный observation contract, но не получает constructor и source mapping.

Presets

AUTH-N004: Текущий createKnvAuthBusiness является preset

createKnvAuthBusiness() выбирает knvAuthPhoneAdapter и appAuthSessionAdapter, затем вызывает authFactory.

В новой терминологии это application preset, внутри которого могут оставаться KNV-specific adapters:

domains/auth/presets/application/create-application-auth.ts

Он не является единственно допустимым assembly site. Tests, SSR request composition и другой product preset могут напрямую вызвать ту же authFactory.

SSR-вариант

Одна factory позволяет получить request-scoped API без второй реализации business:

import 'server-only'

export const createAuthForRequest = (input: AuthRequestInput) => {
  return authFactory({
    authPhone: createKnvServerAuthPhoneAdapter(input),
    session: createRequestAuthSessionAdapter(input),
  })
}

Browser preset использует другую реализацию тех же ports. Factory, business types, pure functions и error contract остаются общими.

Предварительная целевая структура

domains/auth/
├── business/
│   ├── auth.factory.ts
│   ├── errors/
│   ├── lib/
│   ├── mappers/
│   ├── services/
│   ├── tests/
│   ├── types/
│   └── index.ts
├── presets/
│   └── application/
│       ├── adapters/
│       ├── create-application-auth.ts
│       ├── create-application-auth.test.ts
│       └── index.ts
└── {framework-binding}/
    └── index.ts

Это только проверочная структура. Она не фиксирует обязательность всех папок и не должна использоваться как scaffold checklist.

Server-only/request preset может быть добавлен отдельным module при реальной потребности. Он не образует обязательную server-ветку Domain.

Tests не используют общий testing preset. Business tests выполняют per-test assembly напрямую через authFactory, а production presets тестируются рядом с собственной реализацией только на wiring, scope и lifecycle.