# internal/m2mcore — ядро бизнес-логики M2M

Конечный автомат сделки, репозиторий, идемпотентность по GUID,
сборка `M2MTransferRequest` из заявки ЛК + данных Fansy, метрики SLA.

## Состав

- `fsm.go` — состояния FSM и матрица разрешённых переходов
  (`Draft → Validated → SubmittedToNSD → AwaitingDecision → Confirmed →
  AwaitingSUB16 → Done`, ветки `Rejected`, `TimedOut`,
  `ManualApproval`).
- `deal.go` — доменная модель `Deal` с явными методами переходов
  (`Validate`, `Submit`, `ReceiveDecision`, `Timeout`,
  `SendToManualApproval`, `ApproveManually`, `RejectManually`,
  `CompleteSUB16`). Каждый переход проверяет текущее состояние,
  пишет историю в `Stages` и фиксирует событие в журнале.
- `uuid.go` — генератор UUID v4 без внешних зависимостей.
- `repo.go` — порт `Repository` + in-memory реализация
  `MemoryRepository` с идемпотентным `Create` (по GUID возвращает
  существующую сделку). PostgreSQL-реализация — задача M2 (миграция
  лежит в `migrations/m2m-core/001__deals.sql`).
- `ports.go` — порты к внешним системам (`NSDSender`,
  `LKCallbackClient`, `CryptoVerifier`, `FansyStore`) с no-op
  заглушками для M1.
- `enrich.go` — функция `EnrichRequest`: из `ClaimInput` (заявка ЛК)
  + данных Fansy собирает валидный `M2MTransferRequest`, генерирует
  `GUID` и `ReferenceID` по каждой ЦБ.
- `metrics.go` — порт `Recorder` + `MemoryRecorder`, отдающий
  Prometheus text-format. В M2 заменим на `prometheus/client_golang`,
  когда прокси откроет Go-модули.

## Зависимости

Только stdlib и собственные пакеты `internal/m2m`, `internal/nsdxml`.
Никаких внешних модулей.

## Тесты

- `fsm_test.go` — переходы и терминальные состояния.
- `repo_test.go` — идемпотентность по GUID, фильтры в `List`.
- `uuid_test.go` — формат UUID v4 и `ReferenceID`.
- `metrics_test.go` — Prometheus-текст.

## Сервис cmd/m2m-core

`cmd/m2m-core/main.go` — HTTP-сервер с `/healthz` и `/metrics`,
in-memory репозиторий, no-op порты. Адрес из `BJ_HTTP_ADDR`
(по умолчанию `:8081`). В M2 будет заменено на реальные клиенты НРД
и crypto-service.
