feat(m2m-core): FSM сделки, репозиторий, идемпотентность по GUID, метрики SLA

- internal/m2mcore/fsm.go: конечный автомат с переходами Draft → Validated → SubmittedToNSD → AwaitingDecision → Confirmed → AwaitingSUB16 → Done, ветки Rejected/TimedOut/ManualApproval
- internal/m2mcore/deal.go: доменная модель Deal с методами Validate/Submit/ReceiveDecision/Timeout/SendToManualApproval/ApproveManually/RejectManually/CompleteSUB16, журнал событий
- internal/m2mcore/uuid.go: генератор UUID v4 без внешних зависимостей (crypto/rand)
- internal/m2mcore/repo.go: порт Repository + MemoryRepository с идемпотентным Create по GUID
- internal/m2mcore/ports.go: порты NSDSender/LKCallbackClient/CryptoVerifier/FansyStore с no-op заглушками для M1
- internal/m2mcore/enrich.go: EnrichRequest — сборка M2MTransferRequest из ClaimInput + Fansy, генерация ReferenceID по каждой ЦБ
- internal/m2mcore/metrics.go: порт Recorder + MemoryRecorder в Prometheus-text формате
- cmd/m2m-core/main.go: HTTP-сервер с /healthz и /metrics, graceful shutdown
- migrations/m2m-core/001__deals.sql: схема для PostgreSQL-Repository (для M2)

Покрытие: 63.1%. make ci зелёный. Без внешних Go-зависимостей (pgx и
prometheus подключим в M2, когда прокси zetit откроет Go-модули).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
fontvielle
2026-05-14 00:52:12 +03:00
parent a040f8b07d
commit 9e6e95f431
16 changed files with 1455 additions and 1 deletions
+49
View File
@@ -0,0 +1,49 @@
# 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.