Files
Bridge-and-Join-s/docs/architecture/plan.md
zuevav 3fdc526031 docs: план проекта + промпты задач PR-1..PR-6 для Claude Code на ВМ
- docs/architecture/plan.md — полный план проекта (архитектура,
  стек, SLA, регуляторика, Реестр ПО, roadmap M1–M5, открытые
  вопросы и решения).
- docs/tasks/README.md — индекс задач и инструкция запуска для
  Claude Code на dev-ВМ.
- docs/tasks/PR-1-go-models-m2m.md — Go-модели M2M, парсер
  windows-1251, NSDDateTime, round-trip тесты на эталонах.
- docs/tasks/PR-2-fansy-ddl.md — DDL принимающей БД для команды
  Fansy (контракт данных, ETL-требования, словарь полей,
  тестовые данные).
- docs/tasks/PR-3-lk-openapi.md — OpenAPI контракт lk-gateway по
  ESIA Finance API V1, для синхронизации с командой ЛК.
- docs/tasks/PR-4-m2m-core-skeleton.md — FSM сделки,
  репозиторий, идемпотентность по GUID, метрики SLA.
- docs/tasks/PR-5-nsd-adapter-skeleton.md — REST-клиент ИШ НРД,
  маршрутизация типов пакетов (M2MTR/M2MTD/M2MER/SUBBR/SUBER/SUB16).
- docs/tasks/PR-6-crypto-service-skeleton.md — gRPC-каркас
  Java-сервиса криптографии (КриптоПро JCP, UDS, Provider-абстракция).

С этого коммита дальнейшая разработка идёт на dev-ВМ через
запущенный там Claude Code. Промпты PR-1..PR-3 готовы к параллельному
запуску; PR-4 после PR-1; PR-5 и PR-6 ждут поставку артефактов
(ИШ НРД, сертификаты, КриптоПро JCP).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 22:48:21 +03:00

674 lines
95 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План: Сервис M2M (НРД) — связующий модуль брокера, Реестр российского ПО
## Краткий итог на одной странице
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ЧТО ДЕЛАЕМ: Внутренний модуль брокера для M2M-перевода ЦБ через НРД (MOST) │
│ КОМУ: сначала — нашему заказчику; потом — тиражируется другим брокерам │
│ СТЕК: Go (ядро) + Java (crypto-service на КриптоПро JCP) + React (admin-ui) │
│ ОС/СУБД: РЕД ОС 7.3 (целевая) + PostgreSQL Pro Certified │
│ ДЕПЛОЙ: одна ВМ внутри контура, docker-compose (без k8s) │
│ КАНАЛ К НРД: Интеграционный шлюз (REST) — основной; ONYX — резерв │
│ ВНЕШНИЕ: ЛК ESIA Finance (через эмулятор сейчас); Fansy → fansy-store │
│ КРИПТО: КриптоПро CSP/JCP, класс СКЗИ КС1; подпись операторов — серверная │
│ SLA: 5 мин/этап (старт) → 2 мин/этап (цель); таймаут MOST: 10→5 мин │
│ ДЕДЛАЙН ПРОДА: 01.09.2026 (124-ФЗ + Указание ЦБ) │
│ РЕЕСТР ПО: ПП-1236, заявка на M5; стек и архитектура — соответствуют │
└──────────────────────────────────────────────────────────────────────────────┘
```
## Архитектура одной картинкой
```
ВМ внутри контура брокера (Astra Linux SE)
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────┐ REST (ESIA Finance API V1) ┌────────────────────┐ │
│ │ lk-emulator │ ─────────────────────────────► │ lk-gateway │ │
│ │ (Go + HTMX) │ ◄─ callback статусов ────────── │ (Go) │ │
│ └──────────────┘ └─────────┬──────────┘ │
│ (заглушка ЛК клиента, пока ЛК ESIA Finance не готов) │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ admin-ui ◄─── WebSocket / REST ───────────────│ m2m-core │ │
│ (React) │ FSM + SLA-метрики │ │
│ • журнал │ идемпотентность │ │
│ • ручное согласование │ по GUID │ │
│ • сертификаты └────┬─────────┬──────┘ │
│ • уведомления │ │ │
│ • SLA-дашборд ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ fansy- │ │ notify │ │
│ │ store │ │ (Go) │ │
│ │ (PG Pro) │ │ plugins: │ │
│ │ ◄─ ETL │ │ smtp, │ │
│ │ команда │ │ ya360, │ │
│ │ Fansy │ │ webhook, │ │
│ └──────────┘ │ ws-push │ │
│ └──────────┘ │
│ ▲ │
│ gRPC по UDS │ │
│ ┌──────────────────────┐ ┌──────────┴──────────┐ │
│ │ crypto-service │ ◄────────────────│ nsd-adapter │ │
│ │ Java + КриптоПро JCP │ │ (Go) │ │
│ │ • XMLDSig подпись │ │ ┌──────────────────┐ │ │
│ │ • проверка входящих │ │ │ ИШ REST основ. │ │ │
│ │ • подпись операторов │ │ │ WS ONYX резерв │ │ │
│ │ (КС1) │ │ │ ФШ fallback│ │ │
│ └──────────────────────┘ │ └────────┬─────────┘ │ │
│ └──────────┼───────────┘ │
│ │ │
└───────────────────────────────────────────────────────┼────────────────────┘
│ HTTPS / mTLS
┌────────────────────────┐
│ ИШ НРД (на нашей ВМ) │
│ REST: /api/package/… │
└───────────┬────────────┘
│ ЭДО НРД (подпись делает ИШ)
┌────────────────────────┐
│ Сервис MOEX MOST / │
│ WS ONYX gost-*.nsd.ru │
└────────────────────────┘
```
Хранилища на ВМ: **PostgreSQL Pro Certified** (`m2m-core`, `fansy-store`, аудит, конфиги), **MinIO** (эталоны подписанных XML).
## Поток одной заявки end-to-end (донор)
```
ИНВЕСТОР ЛК (ESIA lk-gateway m2m-core fansy-store crypto-svc nsd-adapter ИШ НРД → MOST → Брокер 2
Finance/
эмулятор)
│ │ │ │ │ │ │ │ │ │
│ заявление │ │ │ │ │ │ │ │ │
├──подпись──►│ │ │ │ │ │ │ │ │
│ │ POST /claims │ │ │ │ │ │ │ │
│ ├─────────────►│ │ │ │ │ │ │ │
│ │ │ verify sig │ │ │ │ │ │ │
│ │ ├───────────────────────────────────────►│ │ │ │ │
│ │ │ enqueue │ │ │ │ │ │ │
│ │ ├───────────►│ │ │ │ │ │ │
│ │ │ │ enrich │ │ │ │ │ │
│ │ │ ├────────────►│ │ │ │ │ │
│ │ │ │ build XML │ │ │ │ │ │
│ │ │ │ M2MTransferRequest │ │ │ │ │
│ │ │ ├──── send via ИШ ─────────────────────►│ │ │ │
│ │ │ │ (ИШ сам подписывает пакет ЭДО) │ │ │
│ │ │ │ │ │ ├──#M2MTR──►│ │ │
│ │ │ │ │ │ │ квитанция ЭДО │ │
│ │ │ │ │ │ │◄──────────┤ │ │
│ │ │ │ WAIT (≤10→5 min) │ │ │ → Брокер 2 │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ #M2MTD (подтверждение от Брокера 2) │
│ │ │ │ │ │ │◄──────────┤◄───────┤◄────────┤
│ │ │ │ verify sig +│ │ │ │ │ │
│ │ │ │ apply Decision │ │ │ │ │
│ │ │ ├ → notify (e-mail + Yandex Messenger + WS) │ │ │
│ │ callback │ │ │ │ │ │ │ │
│ │◄─────────────┤ │ │ │ │ │ │ │
│ статус ОК │ │ │ │ │ │ │ │ │
│◄───────────┤ │ │ │ │ │ │ │ │
│ │ │ │ ждём SUB16 (черновики 16-х поручений) для депозитария │ │
│ │ │ │ │ │ │◄── #SUB16 ─────────────────── │
│ │ │ │ → передать в депозитарную систему / показать в admin-ui │ │
Ветка TIMEOUT: если Decision не пришёл за 10→5 мин — MOST сам шлёт Transfer_reject (#SUBER) → FSM в Rejected.
```
## Roadmap M1M5 (визуально)
```
2026
нед: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
├───────────────┤
M1: │ Каркас+стенды│
│ • моно-репо │
│ • XSD→Go │
│ • ИШ на ВМ │
│ • crypto-svc │
│ • контракт ЛК │
│ • DDL fansy │
├───────────────────────┤
M2: │ Сквозной донор TEST3 │
│ • lk-emulator v1 │
│ • FSM донор │
│ • #M2MTR/#M2MTD │
│ • метрики SLA │
├───────────────────────┤
M3: │ Реципиент+admin-ui v1 │
│ • Decision исх │
│ • Handbook+Participant│
│ • SUB16, SUBBR/SUBER │
│ • Справка о расходах │
│ • роли, сертификаты │
├───────────────┤
M4: │ Ручное+notify │
│ • manual-appr │
│ • smtp+ya360 │
│ • plug-ins │
│ • совм.с Fansy│
├───────────────────────┤
M5: │ ИБ+нагруз+Реестр+ПРОД │
│ • 57580 аудит │
│ • k6 SLA 2 мин │
│ • заявка в Реестр ПО │
│ • ПСИ на промконтуре │
└───── 01.09.2026 ──────┘
ДЕДЛАЙН (124-ФЗ)
```
## Маппинг сообщений и каналов (одна таблица)
| Этап | Тип пакета НРД | Кто формирует | Кто подписывает | Канал |
|------|----------------|---------------|------------------|--------|
| Заявление от инвестора | (внутренний JSON ESIA Finance) | ЛК клиента / эмулятор | ЛК | REST → `lk-gateway` |
| Запрос на перевод M2M | `#M2MTR` (M2MTransferRequest) | `m2m-core` | **ИШ НРД** | ИШ REST |
| Тех.ответ НРД на запрос | `#M2MER` (M2MTransferResponse) | НРД | НРД | ИШ → `nsd-adapter` |
| Решение принимающего | `#M2MTD` (M2MTransferDecision) | Брокер 2 / мы (если реципиент) | ИШ | ИШ |
| Авто-отказ по таймауту | `#SUBER` (Transfer_reject) | **MOST автоматически** | НРД | ИШ → нам |
| Черновики 16-х поручений | `#SUB16` | НРД | НРД | ИШ → нам → депозитарий |
| Справка о расходах | `Assets_investment_account_transfer_details` | Брокер 1 | ИШ | ИШ |
| Статус справки | `Assets_investment_details_status` | Брокер 2 | ИШ | ИШ |
| Действие оператора в admin-ui | внутр. подпись | оператор | **`crypto-service` серверной ЭП** | внутри ВМ |
## Готовность по Реестру российского ПО (ПП-1236) — матрица
```
Критерий ПП-1236 Статус
───────────────────────────────────────────────────── ──────────────────
1. Российский правообладатель, инокапитал ≤ 50% ⚠ проверить ЕГРЮЛ
2. Исключительное право — у правообладателя ⚠ договоры с разрабами на M1
3. Свободная гражданская реализация в РФ ✓ ОК
4. Выплаты за рубеж < 30% выручки ✓ нет иностр. лицензий
5. Не содержит гостайны ✓ ОК
6. Класс ПО (02.13 СЭД + 02.09 финсектор) ⚠ уточнить на M5
7. Исходники и сборки в РФ ✓ git.zetit.ru
8. Техподдержка в РФ ✓ M5
9. Документация на русском ✓ закладываем с M1
10. Совместимость с реестровой ОС (Astra/РЕД) ✓ M2 (CI на Astra)
СТЕК (всё в Реестре или open-source upstream):
ОС: РЕД ОС 7.3 (целевая) ✓
СУБД: PostgreSQL Pro Certified ✓
JDK: Liberica / Axiom JDK ✓
СКЗИ: КриптоПро CSP/JCP, КС1 ✓
Уведомления: Yandex 360 + smtp + WS ✓
Прочее: Go, MinIO, NATS — open-source ✓
```
## Старт работ — первая неделя M1
**Репозиторий**: `https://git.zetit.ru/zuevav/Bridge-and-Join-s` (РФ-хостинг, основной).
**Среда разработки — выделенная ВМ заказчика (dev-стенд)** на целевой ОС (Astra Linux SE 1.7+ или РЕД ОС 7.3). Решение: разрабатываем сразу на «живой» машине, чтобы не было разрыва между dev и прод-средой, и чтобы КриптоПро/ИШ/тестовые сертификаты НРД жили в одном защищённом контуре. На эту ВМ ставится **Claude Code CLI**, разработка идёт там же.
### Подготовка dev-ВМ (день 1–2, до старта Трека А)
| Что | Зачем |
|------|-------|
| ОС: **РЕД ОС 7.3** | Целевая ОС. На dev-этапе — бесплатная редакция РЕД ОС («Свободная»), без сертификата ФСТЭК; одну сертифицированную лицензию закупаем к M3-M4 для целевого stage-стенда |
| Учётные записи: `dev` (без sudo по умолчанию), `admin` (sudo) | Минимизация прав; разработка под `dev`, обслуживание — под `admin` |
| Сетевая сегментация: dev-ВМ в отдельном VLAN с доступом наружу только к whitelist (git.zetit.ru, gost-*.nsd.ru, rsa-*.nsd.ru, registry.npmjs.org/proxy, proxy.golang.org/proxy, anthropic.com для Claude Code) | Ограничение поверхности, контроль исходящего трафика |
| Прокси / NAT с журналированием | Аудит исходящих соединений (требование 57580) |
| Установлено: Go 1.23+, JDK 21 (Liberica), Docker/Podman, docker-compose, Git, Make, jq, xmlstarlet | Базовый dev-набор |
| Установлено: КриптоПро CSP + JCP (когда лицензия будет получена) | Для `crypto-service` |
| Установлено: ИШ НРД (когда дистрибутив получим) | Для интеграционного канала |
| Установлено: **Claude Code CLI** | Разработка в репо, доступ к gpu/контурам не требуется |
| Доступ: git.zetit.ru — SSH-ключ `dev` пользователя; push в основной репо | Чтобы коммиты шли напрямую |
| Доступ: тестовые сертификаты GUEST/TEST3 | Работа со стендами НРД |
| Бэкап: БД и `/etc` ежедневно на отдельный том | Безопасность работы |
| Ресурсы dev-ВМ: **8 vCPU / 16 GB RAM / 200 GB SSD** | Запас на полный стек: Go-сервисы, Postgres, MinIO, JVM (crypto-service + ИШ НРД), admin-ui dev-server, Claude Code, CI-раннер на той же ВМ, e2e-тесты с Playwright (Chromium), параллельная сборка/линтер, место под логи и эталонные XML в MinIO. Прод-ВМ — отдельно, конфигурируется к M3-M4. |
### Безопасность работы Claude Code на «живой» машине
- **Запуск Claude Code только под `dev` (без sudo).** Если нужно sudo (установка пакетов) — отдельная сессия `admin` вручную, не через Claude Code.
- **Ограничения файловой системы**: рабочая директория = клон репо в `/srv/dev/Bridge-and-Join-s`. Нет доступа к `/home/admin`, `/etc/cryptopro`, контейнерам ключей.
- **Закрытые ключи КриптоПро и сертификаты** хранятся в отдельной директории `/var/cryptopro/keys/`, владелец `crypto:crypto`, mode `0700`, доступ только из `crypto-service` через JCP. Claude Code и dev-пользователь туда не ходят.
- **`.claude/settings.json` в репо**: разрешённые директории — только корень репо; запрет команд `rm -rf`, `dd`, доступ к `/etc/`, `/var/cryptopro/`, `/etc/ipsec.d/`.
- **CI и сборки** — отдельный раннер, не на dev-ВМ. Прод-сборки и подпись релизов — на изолированной build-ВМ.
- **Журналирование действий**: shell history `dev` пользователя пишется с timestamp; журнал работы Claude Code сохраняется в `~/.claude/logs/` и регулярно архивируется.
- **Сетевой трафик Claude Code наружу** (anthropic.com) согласован с ИБ заказчика; если сегмент закрытый — Claude Code запускается только в момент когда нужен (не всегда), либо через корпоративный исходящий прокси с логированием.
- **Никаких ПДн в репо** (пример заявления для эмулятора — синтетические данные).
Параллельно три трека:
**Трек А — Код (наша команда, день 1–5)**
- Проинициализировать структуру моно-репо: `cmd/`, `internal/{m2m-core,nsd-adapter,lk-gateway,lk-emulator,notify,fansy-store}/`, `services/crypto-service/` (Java), `web/admin-ui/`, `docs/`, `deploy/docker-compose/`, `migrations/`.
- `go.mod`, `Makefile`, `.golangci.yml`, базовый CI на `git.zetit.ru` (lint + test, раннеры — на ВМ заказчика).
- Сгенерировать **Go-модели из XSD** (`DOC/M2MSchemas_260408/`) с (de)serializer windows-1251, кастомным `NSDDateTimeType` и валидатором pattern (ReferenceId `M2M[A-Z0-9]{13}`, ISIN, ИНН, DeponentCode, IIAContractType `T12|T03`).
- Round-trip тесты на эталонах `DOC/Эталонные сообщения/*.xml` и `DOC/Примеры/*.xml`.
- README на русском.
**Трек Б — Контракты для смежных команд (день 1–7)**
- **DDL `fansy-store` v0** в `docs/fansy-contract/v1/ddl/` + `data-dictionary.md` + `etl-requirements.md` → отправить команде Fansy на согласование. Это разблокирует их ETL.
- **OpenAPI `lk-gateway` v0** по контракту ESIA Finance API V1 (`/api/v1/back_office/claims/...`) → отправить команде ЛК как точку синхронизации.
**Трек В — Заказчик, фоном 2–4 недели**
- Запросить у НРД дистрибутив **Интеграционного шлюза** + ставить на тестовую ВМ.
- Инициировать выпуск **тестовых сертификатов GUEST и TEST3** (ГОСТ + RSA).
- Получить лицензию и дистрибутив **КриптоПро CSP + JCP** под РЕД ОС 7.3 (целевая).
- Юр-проверки для Реестра ПО: ЕГРЮЛ правообладателя (доля иноучастия ≤ 50%), договоры с разработчиками на отчуждение исключительного права.
**Definition of Done первой недели**
- [ ] Структура репо в `git.zetit.ru/zuevav/Bridge-and-Join-s` инициализирована, CI зелёный.
- [ ] Все 6 типов M2M-сообщений десериализуются/сериализуются в windows-1251 без потерь, эталоны проходят.
- [ ] DDL `fansy-store` v0 отправлен команде Fansy.
- [ ] OpenAPI-контракт `lk-gateway` отправлен команде ЛК ESIA Finance.
- [ ] Заявки заказчика поданы: ИШ, сертификаты GUEST/TEST3, КриптоПро, юр-аудит.
## Контекст
Репозиторий — green-field (только документация в `DOC/`). Задача — построить **внутренний связующий модуль брокера** для обмена с **НРД** сообщениями о переводе ценных бумаг (M2M, ЭДО НРД).
Существующий ландшафт у заказчика:
- **ЛК клиента — уже есть.** Инвестор сам формирует и **подписывает заявление через внутреннюю подсистему ЛК**. Наш сервис получает уже подписанное заявление через **API ЛК клиента**. Свой фронт инвестора не делаем.
- **Fansy (учётная система депозитария)** — система-источник по счетам, реквизитам, остаткам. **Сам ETL Fansy → БД делает ДРУГАЯ команда разработки в автоматизированном режиме.** Наша зона: спроектировать принимающую БД (схема, индексы, миграции, исходя из требований документации НРД к данным M2M), согласовать контракт с командой Fansy и **передать им перечень и структуру наших таблиц**, **читать и анализировать** эти данные. Сам процесс выгрузки в наш скоуп не входит.
- **Договор ЭДО с НРД** подписан, **лицензии КриптоПро / VipNet** есть.
- **Стек**: Go (бэкенд) + Java-sidecar для XMLDSig по ГОСТ (см. ниже).
- **Развёртывание**: **одна ВМ внутри контура компании** (не k8s; docker-compose или systemd-юниты).
- **Цель — Реестр российского ПО** (ПП РФ № 1236).
Поток (`Схема M2M от НРД.pdf`): инвестор инициирует и подписывает в ЛК → ЛК передаёт заявление в наш сервис → мы валидируем, обогащаем из Fansy, формируем `M2MTransferRequest`, подписываем и шлём в НРД → принимаем `M2MTransferResponse` (тех. ответ) → ждём `M2MTransferDecision` от встречного брокера (или сами формируем, если мы сторона-реципиент) → закрываем сделку, сообщаем ЛК и депозитарию.
## SLA и регуляторные сроки
- **Стартовое SLA**: ≤ **5 минут** на каждый этап (приём от ЛК, обогащение из `fansy-store`, отправка в НРД, обработка ответа, обработка Decision, передача в ЛК/депозитарий).
- **Целевое SLA**: ≤ **2 минуты** на этап без переписывания архитектуры — за счёт прогрева кэшей справочников, тёплого пула SOAP/HTTP-соединений, event-driven обработки, индексов БД.
- **Регуляторный таймаут MOST «нет ответа от Брокера 2»**: на старте — **10 минут**, целевой — **5 минут**. По истечении сервис MOST формирует автоматический `Transfer_reject.xml` (тип пакета `SUBER`) — это делает MOST, мы только отслеживаем тайминг и обрабатываем входящий отказ как штатную ветку FSM.
- **Регуляторный дедлайн прод-релиза — 01.09.2026.** Вступают в силу **Федеральный закон № 124-ФЗ от 23.05.2025** и Указание Банка России о проведении операций по зачислению ЦБ на счёт депо без поручения депонента (изменения п.5 ст.7 39-ФЗ «О рынке ценных бумаг»). На этот срок закладываем M5.
Проектные следствия:
- **Очередь на каждый этап** (in-memory worker pool на старте → внешняя шина при росте) с метриками длительности этапа (Prometheus histograms `m2m_stage_duration_seconds`).
- **SLA-budget alerting**: при > 80% бюджета — нотификация оператору.
- **Идемпотентность по GUID** на всех точках, чтобы повторы (ретраи в SLA-окне) не порождали дубли.
- Сначала **синхронная in-process архитектура** (быстрее всего и проще держит 2 минуты), внешняя шина — только если этапы выйдут на разные ВМ.
## Криптография: Go + ГОСТ — пересмотренный план
В Go нет зрелой реализации XMLDSig по ГОСТ Р 34.10-2012 / 34.11-2012, поэтому криптография изолирована в отдельный сервис **`crypto-service`** на Java + Apache Santuario с ГОСТ-патчем. gRPC через Unix Domain Socket (минимальная задержка — критично для SLA).
**Уточнение по результатам ре-аудита.** Основной канал отправки — **ИШ через REST API**, и **ИШ сам подписывает пакет ЭДО** на стороне НРД-шного софта. Поэтому для основного потока внешний XMLDSig нам не нужен. `crypto-service` остаётся обязательным для:
- проверки подписи **входящих** квитанций ЭДО, ответов НРД, сообщений от брокеров;
- **подписи действий оператора** в ручном согласовании (серверная подпись от имени оператора);
- **резервного канала через WS ONYX напрямую** — там подпись/упаковка пакета целиком на нашей стороне;
- криптографических проверок целостности эталонных архивов в MinIO.
**Решено: используем КриптоПро.** В `crypto-service`**КриптоПро JCP** на JVM, **КриптоПро CSP** на ВМ. Архитектурно сохраняем `Provider`-абстракцию (Валидата / VipNet / иное), чтобы при тиражировании другой компании можно было подключить иной провайдер без правки бизнес-логики, но реализация на M1 — только КриптоПро. Для проверки совместимости с эндпоинтами НРД (исторически ГОСТ-контуры МосБиржи — Валидата) — отдельная задача проверки на стенде GUEST/TEST3 в M1.
## Целевая архитектура (один моно-репозиторий, одна ВМ)
| # | Модуль | Стек | Назначение |
|---|--------|------|-----------|
| 1 | `lk-gateway` | **Go** (chi) | REST-интеграция с **ЛК клиента** на платформе **ESIA Finance** (`/api/v1/back_office/...`): получение заявок на M2M-перевод (`/claims/`), реквизитов (`/requisites`), пользователей (`/users`), сообщений (`/messages`), сертификатов (`/control_certificates`), Депо-счетов (`/depo_accounts`); проверка подписи заявления через `crypto-service`; callback статусов обратно в ЛК. Basic HTTP, кодировка UTF-8 — по контракту ESIA Finance API V1. |
| 1a | `lk-emulator` | **Go** + минимальный HTML/HTMX | **Эмулятор ЛК клиента** (временная заглушка). Веб-форма «загрузить заявление» с моделированием контракта **ESIA Finance API V1** (`POST /claims/`, статусные апдейты): оператор тестирования «как будто загрузил» заявление и нажимает «Отправить» — это запускает в нашей системе полный путь обработки документа. Используется на стендах GUEST/TEST3 и в регресс-сьюите. Когда реальный ЛК будет готов — эмулятор остаётся как тестовый инструмент в QA-окружении. |
| 2 | `m2m-core` | **Go** | FSM сделки, идемпотентность по GUID, валидация против XSD, **ручное согласование** как параллельная ветка автомата, метрики SLA |
| 3 | `fansy-store` | **PostgreSQL Pro** + Go-репозиторий | **Только принимающая БД** под выгрузку Fansy (схема и миграции — наши). Сам ETL делает другая команда. Внутри нашей системы — Go-репозиторий с типизированным API «получи реквизиты по ИНН/коду депонента», локальный кэш в памяти |
| 4 | `nsd-adapter` | **Go** | Три транспорта к НРД (см. раздел «Транспорт к НРД»): **(1) ИШ REST API — основной**, **(2) WS ONYX напрямую — резерв**, **(3) обменные папки ИШ — fallback**. Сериализация/парсинг XML в **windows-1251**; кастомный `NSDDateTimeType`; маршрутизация по типам пакетов (`#M2MTR`/`#M2MTD`/`#M2MER`/`SUBBR`/`SUBER`/`SUB16`/Справки/квитанции ЭДО) |
| 5 | `crypto-service` | **Java 21 (Liberica JDK) + КриптоПро JCP** (CSP на ВМ) | XMLDSig подпись/проверка (ГОСТ и RSA), gRPC по UDS. Для основного канала ИШ REST подпись пакета делает сам ИШ; здесь — проверка входящих, подпись действий оператора, резервный канал WS ONYX. Архитектурно сохранена `Provider`-абстракция (на случай добавления Валидата CSP / VipNet в будущем) |
| 6 | `notify` | **Go** | E-mail (SMTP внутренний) + **Yandex Messenger** (Yandex 360 для бизнеса, до-интеграция готового бота заказчика) + WS-push в `admin-ui`. **Архитектура — провайдеры-плагины**: единый интерфейс `Notifier`, реализации (smtp, yandex360, telegram, mattermost, webhook…), подключение и переключение через конфиг и UI без правки кода |
| 7 | `admin-ui` | React (SPA) + Go BFF в `lk-gateway` | Веб-интерфейс администратора и сотрудника депозитария: журнал приходов/уходов, статусы, ручное согласование, SLA-дашборд, **управление сертификатами для подписи** (загрузка/обновление/отзыв серверных ключей и сертификатов оператора и системного ключа НРД) |
| 8 | Хранилища | **PostgreSQL Pro Certified** (на той же ВМ), MinIO (локальный, для эталонных подписанных XML) | Состояние сделок, аудит, копия выгрузки Fansy |
Шина сообщений на старте — **встроенная in-process** (Go channels + worker pool); если выйдем за пределы одной ВМ или разнесём этапы — добавляем NATS JetStream (легче Kafka, в реестре через `Tarantool/NATS-форки` нет, но как open source ставится).
## Поток обработки одного заявления (целевой ≤ 2 мин)
1. **Приём от ЛК** (`lk-gateway`): REST POST с подписанным XML заявления → проверка подписи (`crypto-service`) → запись `incoming_request` в БД, ack ЛК.
2. **Валидация и обогащение** (`m2m-core` + `fansy-connector`): валидация по XSD, разрешение ИНН и кодов депонента из локальной копии Fansy.
3. **Формирование `M2MTransferRequest`** (`m2m-core`): сборка по схеме, GUID = идемпотентный ключ.
4. **Подпись** (`crypto-service`): XMLDSig по ГОСТ или RSA в зависимости от профиля.
5. **Отправка в НРД** (`nsd-adapter`): SOAP к ONYX, разбор `M2MTransferResponse` (INFO/ERROR).
6. **Ожидание `Decision`** (если мы — донор): входящий poll или callback от НРД, разбор Confirmation/Rejection.
7. **Формирование `Decision`** (если мы — реципиент): получение подтверждения сотрудника депозитария (авто или ручное согласование) → подпись → отправка.
8. **Финализация**: запись результата, callback в ЛК клиента, событие в `notify`, обновление статуса в `admin-ui`.
Каждый этап измеряется: `stage_started_at`, `stage_finished_at` → метрика `m2m_stage_duration_seconds{stage="..."}`. Алерт при превышении 80% SLA-бюджета.
## Ручное согласование
В FSM сделки добавлена ветка **manual-approval** на каждом критичном этапе (`AwaitingFansyEnrichment`, `AwaitingDecision`, `AwaitingNSDSend`):
- В `admin-ui` сотрудник депозитария видит сделку «на ручном согласовании» с кнопками `Подтвердить` / `Отклонить с кодом` / `Доработать` (с комментарием).
- Триггеры ручного режима:
- явный флаг в заявлении из ЛК (для теста/спецсценариев),
- правила (сумма, ISIN из white-list, нерезидент и т.п.) — конфигурируемые,
- таймаут авто-обработки (защитный fallback).
- **Подпись действий оператора — серверная, от имени оператора** (через `crypto-service` на серверном ГОСТ-ключе, выделенном на оператора). Решение принято ради SLA: подпись на рабочей станции через КриптоПро CSP добавляет 10–30 секунд на каждое действие плюс зависимость от состояния АРМ — это съедает бюджет 2 минут. Серверная подпись даёт стабильные миллисекунды.
- Требования к серверной подписи оператора (документируем в формуляре СКЗИ и регламенте):
- **Двухфакторная авторизация оператора** в `admin-ui` перед любым действием подписи (пароль + TOTP/корпоративный SSO).
- Контейнер ключа оператора на сервере защищён, доступ через HSM или закрытый раздел КриптоПро; ключ не извлекаем.
- Каждая операция подписи сопровождается **аудит-записью**: оператор, действие, IP/браузер, GUID сделки, timestamp, хэш подписанного XML — неизменяемая (append-only таблица + периодический хэш-сцепленный snapshot).
- Регламент отзыва ключа оператора при увольнении/смене роли.
- Документ «ОП личного кабинета оператора» (правила использования, ответственность) подключим к проекту позже, как только заказчик его передаст.
## Управление сертификатами через `admin-ui`
В веб-интерфейсе администратор имеет раздел «Сертификаты», в котором происходит **только обновление сертификатов для подписи** (без управления самими ключами на низком уровне). Закрытые ключи остаются в защищённом серверном хранилище (КриптоПро, HSM) и через UI **не выгружаются и не вводятся вручную** — UI работает только с открытой частью / привязкой.
Что делает раздел:
- Просмотр текущих сертификатов: системный (для подписи M2M в НРД, профили GUEST/TEST3/PROD ГОСТ и RSA), серверные сертификаты операторов.
- Срок действия, серийный номер, отпечаток, издатель, fingerprint — отображаются для контроля.
- **Загрузка нового сертификата** (`.cer`/`.crt`) для существующего ключевого контейнера — кнопка «Обновить сертификат», файл валидируется (срок действия, цепочка доверия, соответствие открытому ключу контейнера) и подменяет старый без рестарта сервиса.
- Привязка сертификата к роли (системный/оператор `<имя>`/конкретный профиль НРД).
- **Алерты об истечении** срока (за 30/14/7/1 день) — в `notify` (e-mail + Yandex Messenger) и в шапке `admin-ui`.
- Полный аудит-лог операций с сертификатами (кто, когда, какой fingerprint обновил).
Ограничения и безопасность:
- Доступ к разделу — только для роли `Администратор СКЗИ` (отдельная роль, не равна обычному админу).
- Все операции — под двухфакторной авторизацией.
- Регламент обновления оформляется как часть документа «Эксплуатация СКЗИ».
## Уведомления для депозитария (для соблюдения SLA)
Уведомления по двум каналам параллельно (`notify`):
1. **E-mail** — обязательный (внутренний SMTP).
2. **Yandex Messenger (Yandex 360 для бизнеса)** — мгновенная доставка в корпоративный мессенджер. У заказчика **уже есть готовый бот**, мы его до-интегрируем: передаём API-токен / webhook / список chat-id и user-id через конфиг и UI настроек. Российский сервис — важно для Реестра ПО.
3. **Push в `admin-ui`** через WebSocket — мгновенно, если оператор открыл вкладку (бесплатно, без внешних сервисов).
### Расширяемость провайдеров (важное требование тиражирования)
Сейчас сервис делается под заказчика (Yandex 360 + e-mail). Но другая компания, разворачивающая систему у себя, должна иметь возможность **легко переключиться на свои каналы** без правок кода. Поэтому:
- В коде — единый интерфейс `Notifier { Send(ctx, recipient, template, data) }`.
- Провайдеры — отдельные пакеты-плагины: `smtp`, `yandex360`, `telegram`, `mattermost`, `rocketchat`, `webhook` (универсальный POST по URL заказчика).
- Список активных провайдеров и их параметры — в конфиге (YAML/ENV) и в `admin-ui` в разделе «Уведомления»: можно включить/выключить, ввести токены, тестово отправить сообщение, настроить роутинг по ролям и типам событий.
- Шаблоны сообщений — версионируемые, на русском, с подстановками (`{{guid}}`, `{{stage}}`, `{{deadline}}`).
- Документация для интегратора: «как подключить новый канал» — описание интерфейса и пример провайдера.
Логика роутинга: критичный этап (ручное согласование, > 80% SLA, отказ НРД) → параллельно e-mail + Yandex Messenger + WS-push. Обычные события — только e-mail. Маршрутизация по ролям (администратор, сотрудник депозитария, оператор) — настраивается в `admin-ui`.
## Соответствие схемам НРД (привязка к XSD)
Из `DOC/M2MSchemas_260408/` (namespace `http://nsd.ru/schemas/m2m/...`, version `2026-04-08`):
- Сообщения: `M2MTransferRequest`, `M2MTransferResponse` (`StatusCode ∈ {INFO, ERROR}`), `M2MTransferDecision`, `M2MTransferHandbook(+Request)`, `M2MTransferParticipantForm`.
- **Кодировка XML — windows-1251**, обязательный учёт в (de)serializer.
- `NSDDateTimeType` — pattern `[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\(МСК([+-][0-9]{1,2})?\)`**только зона МСК** с опциональным сдвигом (например, `2026-03-02T14:30:45(МСК+2)`).
- `IsM2M` фиксировано `true`.
- Choice-типы: `CostInfo (Yes{Code} | No)`, `Quantity (Whole | Fractional)`, `SecurityDetails (ISIN | SecurityInfo)`, `SecurityInfo.IdentificationDetails (RegNumber | FundShares)`, `DecisionTransfer (Confirmation | Rejection)`.
- **Точные ограничения** (использовать в валидаторе):
- `ReferenceIdType`: длина 16, pattern `M2M[A-Z0-9]{13}`.
- `DeponentCodeType`: до 12 символов, `[A-Z0-9]*`.
- `ISINtype`: длина 12, `[A-Z]{2}[A-Z0-9]{9}[0-9]`.
- `OrganizationINNType`: ровно 10 цифр (юрлицо).
- `UUIDType`: стандартный UUID-pattern.
- `Decimal16`: до 38 цифр всего, до 16 после запятой.
- `IsolationStatus`: единственное значение `SGDN`.
- `SecurityClassificationEnum`: `BOND | SHAR | MFUN`.
- `SecurityCategoryEnum`: `ORDN | PREF | UKWN`.
- **`IIAContractTypeEnum`: `T12 | T03`** (T12 — обмен ИИС-1 ↔ ИИС-2, T03 — ИИС-3). Не путать с T01/T02.
- `IdentityDocumentCodeEnum`: 0114, 2127, 91 (полный список см. в `M2MTypesNSD.xsd`).
- `StatusCodeEnum`: `INFO | ERROR`.
- Эталоны из `DOC/Эталонные сообщения/` — fixtures для приёмочных тестов через `xml-exc-c14n`.
## Транспорт к НРД (три канала, рекомендация — ИШ REST)
Из `DOC/Ссылки для доступа в тестовые контуры.pdf`, `DOC/Инструкция по передаче эталонного запроса на перевод M2M 08.04 (1).pdf`, `DOC/Инструккия M2M.pdf`, `DOC/Презентация MOEX MOST.pdf`, `DOC/Презентация тестирование систем НРД.pdf`:
- Контуры: **GUEST** (текущая прод-версия для тестов с клиентами), **TEST3** (перспективная, для ОЭ), **PROD** (по «Анкете НРД»).
- Эндпоинты ГОСТ (`gost-*.nsd.ru`) и RSA (`rsa-*.nsd.ru`) — раздельно.
### Каналы взаимодействия
1. **Интеграционный шлюз НРД (ИШ) с REST API — ОСНОВНОЙ КАНАЛ.**
- НРД-шный софт, ставится локально на наш сервер, имеет **REST API**: `POST /api/package/{channel}/file` (отправка пакета как ZIP в base64), `GET /api/package/status/{id}` (статус), `GET /api/package?channel=&date=&type=...` (входящие).
- **ИШ сам формирует пакет ЭДО, подписывает его и шифрует по Правилам ЭДО НРД.** Это резко уменьшает наш скоуп: для основного пути нам не нужен XMLDSig.
- Альтернативный режим ИШ — обменные папки (OUTBOX/INBOX/`#M2MTR`/`#M2MTD`/`#M2MER`), как fallback при недоступности REST.
2. **Web-сервис ONYX (WSL) — резервный/прямой канал.**
- URL: `https://gost-t3.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo` (TEST3, ГОСТ), аналогично для GUEST/RSA.
- WSDL: `.../OnyxEdo/OnyxEdo.wsdl`.
- **Подпись и упаковка пакета — на нашей стороне** (через `crypto-service`).
- Используем для диагностики, при отказе ИШ, и в сценариях, где ИШ не подходит.
3. **Файловый шлюз НРД (ФШ).**
- Файловый обмен по тем же папкам, что и ИШ-обменные. Поддерживается «на всякий случай», в основном потоке не используем.
В `admin-ui` — переключатель «канал отправки» для теста и эксплуатационных сценариев. Для каждого сценария фиксируется фактический канал в журнале.
### Типы пакетов ЭДО (важно для маршрутизации в ИШ)
| Тип пакета | Содержимое | Сценарий |
|------------|-----------|----------|
| `#M2MTR` | M2MTransferRequest | Запрос на перевод M2M |
| `#M2MTD` | M2MTransferDecision | Решение принимающей стороны |
| `#M2MER` | M2MTransferResponse (ошибки сервиса MOST) | Тех. ошибка / отказ форматно-логического контроля |
| `SUBBR` | `Transfer_out_request.xml` / `Transfer_in_request.xml` / `Transfer_in_consent.xml` | Старый сценарий «брокер→брокер» (поддержка для совместимости) |
| `SUBER` | `Transfer_reject.xml` | Отказ в старом сценарии и **автоматический отказ MOST по таймауту** |
| `SUB16` | Черновики **16-х/16-1 поручений** (по одной ЦБ в одном сообщении) | Подготавливаются НРД после согласования M2M, отправляются обоим брокерам |
| Справка о расходах | `Assets_investment_account_transfer_details.xml` + `Assets_investment_details_status.xml` (статус) | Передача справки о расходах, связанных с приобретением и хранением ЦБ, между брокерами через MOST |
| Стандартная квитанция ЭДО | служебное | Подтверждение доставки от НРД на каждый отправленный пакет |
Конфиг — профили `guest-gost|guest-rsa|test3-gost|test3-rsa|prod-gost|prod-rsa`. Тёплый пул HTTP-соединений (`Transport.MaxIdleConnsPerHost`) для SLA.
## Тиражируемость продукта (внутренний MVP → другие компании)
Сейчас разрабатываем «для себя», но в архитектуру **с самого начала** закладываем возможность лёгкой передачи системы другим брокерам. Принципы:
- **Никаких хардкодов заказчика в коде.** ИНН, коды депонента, имена брокера, цвета бренда, тексты писем, шаблоны уведомлений — только через конфиг или БД настроек, доступных в `admin-ui`.
- **Конфигурация одной командой.** При первом запуске в новой компании — мастер-«первоначальная настройка»: реквизиты юрлица, профиль ЭДО НРД (контур, тип ключей), путь к ИШ, провайдеры уведомлений, контракты ESIA Finance ЛК (URL, basic-auth-токен), путь к контейнерам ключей КриптоПро.
- **Лёгкое обновление версий у клиентов.** Артефакт поставки — собранные docker-образы + один скрипт `install.sh` / `update.sh` (поднимает docker-compose на ВМ, накатывает миграции БД, перезапускает только изменённые сервисы). Версии семантические (semver), changelog обязателен. Откат — на предыдущий тег образа одной командой.
- **СКЗИ-абстракция.** На M1 реализация — только КриптоПро. Но интерфейс `Provider` остаётся, чтобы другая компания со своим СКЗИ (Валидата CSP, VipNet) подключила свой провайдер, не трогая бизнес-логику.
- **Уведомления — провайдеры-плагины** (см. соответствующий раздел). Сейчас smtp + Yandex 360 + webhook; другая компания может включить Mattermost/Telegram/SMS-провайдер через UI.
- **Канал ЛК клиента — конфигурируемый** (см. ниже про ESIA Finance). Если у другой компании ЛК на иной платформе — реализуется отдельный адаптер и подменяется через конфиг.
- **Документация поставки**: руководство администратора (установка, настройка, обновление), руководство оператора, формуляр СКЗИ. На русском.
- **Лицензионная модель**: код — собственность правообладателя (наша компания), поставка — лицензия + поддержка. В реестр ПО заявка от нашего юрлица.
Разделение «продуктовой части» (ядро, переиспользуется) и «настроек заказчика» (БД конфигов, шаблоны, реквизиты) — обязательно с самого первого спринта, иначе позже разбирать дороже.
## Контракт с командой Fansy — что мы передаём
Команда Fansy реализует ETL **на нашу БД**. Чтобы они могли начать, мы передаём им следующий пакет (готовится в M1, согласуется в начале M2):
1. **DDL-скрипты PostgreSQL** для всех таблиц `fansy-store`. Минимально нужны (по требованиям документации НРД к данным M2M):
- **Депоненты / клиенты** (ИНН, ФИО/наименование, тип, привязка к учётной записи в ESIA Finance).
- **Документы инвестора, удостоверяющие личность** (тип `IdentityDocumentCodeEnum` 0114/2127/91, серия, номер).
- **ИИС-договоры** (`IIAContractTypeEnum ∈ {T12, T03}`, номер, дата, ИНН брокера) — для ветки ИИС.
- **Депо-счета и разделы** (`AccountId`, `SectionId`, `DeponentCode`, привязка к клиенту, статус, признак торгового раздела).
- **Реквизиты расчётов** (ИНН депозитария, код депонента, банковские реквизиты при необходимости).
- **Портфели и остатки ЦБ** (счёт + раздел + ISIN/`SecurityCode` + `IsolationStatus = SGDN` + кол-во `Whole/Fractional`) — для проверки достаточности на момент инициации перевода.
- **Справочник ЦБ** (`SecurityCode`, `ISIN`, `SecurityClassification ∈ {BOND, SHAR, MFUN}`, `SecurityCategory`, для ПИФ — `RegNumber`/`Class`).
- **Контрагенты-участники сервиса MOST** (`Справочник пользователей`: БКС/Ренессанс/Альфа-банк, ИНН, ОГРН, статус «доступен для M2M»).
- **Audit/staging-таблицы** для каждой основной (`*_staging`, `*_history`) — чтобы команда Fansy писала в staging, а наш сервис читал готовое.
2. **Контракт данных** на каждую таблицу: семантика поля, источник в Fansy (если известен), nullable, единицы, примеры.
3. **Тип load**: предпочтительно **инкрементный UPSERT по бизнес-ключу** в staging-таблицу + хвост-триггер в основную; вариант полной перезаливки оговаривается отдельно (только для справочников).
4. **Окна обновления и SLA на свежесть данных**: например, портфели/остатки — не позднее 1 минуты после изменения в Fansy; справочники ЦБ и контрагентов — раз в сутки или по событию.
5. **Технические требования**: способ подключения (отдельная роль PostgreSQL `fansy_etl` с правом INSERT/UPDATE на staging-схему, без DDL-прав), формат timestamp (UTC + явная зона), способ передачи ошибок (отдельная таблица `etl_errors`).
6. **Пример заявки M2M «end-to-end»**: какие поля из Fansy потребуются `m2m-core` для одной заявки и какой запрос будет выполнен — чтобы команда Fansy убедилась, что все нужные данные у них есть.
7. **Тестовые данные**: 5–10 тестовых клиентов, портфелей и заявок — для совместного приёмочного теста на стенде.
8. **График интеграции**: даты передачи DDL, даты первой выгрузки в `fansy-store`, дата начала совместного тестирования (в M4).
Документ оформляется как `docs/fansy-contract/v1/...` в моно-репо: `ddl/`, `data-dictionary.md`, `etl-requirements.md`, `examples/`. Версионируется отдельно (`v1`, `v2`).
## Российское ПО — встроенные требования (Реестр ПП РФ № 1236)
### Что требуется по ПП-1236 для включения в Реестр
Постановление Правительства РФ от 16.11.2015 № 1236 (с поправками) и Приказ Минцифры № 486 определяют условия включения ПО в Единый реестр российских программ. Ключевые критерии и наша готовность:
| № | Требование ПП-1236 | Реализация в проекте | Статус |
|---|--------------------|----------------------|--------|
| 1 | **Правообладатель — российское лицо**: РФ, субъект РФ, муниципалитет, российская НКО (без преобладающего иностранного контроля) или гражданин РФ. Доля иностранного участия в УК ≤ 50% | Юрлицо заказчика — российское ООО/АО, проверяем долю иностранного капитала, готовим выписку из ЕГРЮЛ для заявки | **К проверке у заказчика** |
| 2 | **Исключительное право** на ПО принадлежит правообладателю на территории всего мира и на весь срок действия | Все договоры с разработчиками (штат + подряд) содержат пункты об отчуждении исключительного права; для open-source-зависимостей — лицензии совместимы (MIT/Apache 2.0/BSD/MPL/LGPL); GPL-копилефт исключаем | Закладываем в шаблоны договоров с M1 |
| 3 | **Свободная гражданская реализация** на территории РФ | Лицензионные договоры, ценник в рублях, оплата на расчётный счёт в РФ | Стандартная коммерческая модель — ОК |
| 4 | **Сумма выплат за рубеж < 30%** годовой выручки от реализации (роялти, лицензии иностранцам и т.п.) | Не используем платные иностранные SaaS/библиотеки; все облачные сервисы — российские | ОК (см. стек ниже) |
| 5 | **Сведения о ПО не составляют гостайну** | Не работаем с гостайной | ОК |
| 6 | **Класс ПО** по классификатору Минцифры | Заявляем как **«02.13 Системы электронного документооборота»** + **«02.09 Прикладное ПО для финансового сектора»** (уточнить с патентным поверенным при подаче) | На M5 |
| 7 | **Размещение исходного кода и сборок на территории РФ** | Git-репозиторий в РФ-хостинге: **`https://git.zetit.ru/zuevav/Bridge-and-Join-s`** (заказчиковый Gitea/GitLab on-prem). CI на РФ-инфраструктуре (раннеры этого же сервера или собственная ВМ заказчика) | **ОК — репо уже есть** |
| 8 | **Техподдержка на территории РФ** | Договор поддержки с юрлицом-правообладателем, контактные данные на сайте, телефон РФ, поддержка на русском, SLA в часовом поясе MSK | На M5 |
| 9 | **Документация на русском** | Все артефакты (руководства администратора, оператора, формуляр СКЗИ, описание архитектуры, OpenAPI/AsyncAPI, тексты UI) — на русском с самого начала | Закладываем с M1 |
| 10 | **Совместимость с реестровой ОС или независимость от ОС** | Сборки и приёмочные тесты на **Astra Linux SE 1.7+** и **РЕД ОС 7.3** (минимум одна из реестровых ОС обязательна) | M2 — добавить в CI |
### Стек — все компоненты соответствуют импортозамещению
| Слой | Выбор | Реестр ПО / российское |
|------|-------|------------------------|
| ОС | **Astra Linux SE 1.7+** (целевая) или **РЕД ОС 7.3** (альтернатива) | Да, в Реестре |
| СУБД | **PostgreSQL Pro Certified** (Postgres Professional) | Да, в Реестре |
| JDK для `crypto-service` | **Liberica JDK** (BellSoft) или **Axiom JDK** (BellSoft / Axiom) | Да, в Реестре |
| СКЗИ | **КриптоПро CSP/JCP**, класс КС1 | Сертифицировано ФСБ, в Реестре |
| Среда исполнения Go | Open-source upstream — допустимо, ограничений нет | Open-source — ОК |
| Сборка / контейнеризация | Docker / Podman + docker-compose / systemd | Open-source — ОК; при k8s — Deckhouse в Реестре |
| Корпоративная почта/мессенджер интеграция | Внутренний SMTP заказчика + **Yandex 360 для бизнеса** | Yandex — российский сервис |
| Объектное хранилище | **MinIO** (open source, локально на ВМ) | Open-source — ОК |
| Шина (если выйдем за in-process) | **NATS JetStream** или **Apache Kafka** | Open-source — ОК |
| Хостинг репозитория и CI | **`git.zetit.ru`** (РФ-хостинг заказчика) | Российская инфраструктура |
| Фронтенд | React + Vite (open-source upstream); UI-kit — **Yandex Cloud UI Kit** или собственный | Open-source — ОК |
| Артефакт-репозиторий | **Nexus** on-prem или собственный реестр Docker | Self-hosted — ОК |
### Что НЕ используем (и почему)
- **GitHub / GitLab.com / Atlassian Bitbucket** как первичный репозиторий — для подачи в Реестр требуется размещение в РФ. На GitHub допустимо «зеркало» в режиме read-only.
- **JetBrains Space, Confluence Cloud, Slack, Notion** — иностранные SaaS, заменяем российскими аналогами (Yandex 360, Mattermost on-prem, YouTrack on-prem допустим как self-hosted).
- **Microsoft .NET, MS SQL Server, Oracle DB, Windows Server** — не в Реестре, импортозамещаем (см. стек).
- **AWS / GCP / Azure / Cloudflare** — облака недружественной юрисдикции; всё on-prem или РФ-облака (Yandex Cloud, VK Cloud, MTS Cloud).
- **GPL/AGPL-зависимости** в основном коде — несовместимы с проприетарной поставкой; в SBOM ведём контроль лицензий, GPL разрешаем только для отдельно стоящих утилит, не линкующихся к ядру.
### Что уже учтено в архитектуре
- **Локализация**: UI и документы на русском, MSK timezone, формат даты ISO 8601 с явной зоной как требует `NSDDateTimeType`.
- **Тиражируемость** (см. отдельный раздел): отсутствие хардкодов заказчика, конфигурируемый `Provider` СКЗИ, провайдеры уведомлений плагинами — это и для других компаний, и для аккуратной заявки в Реестр (один артефакт ПО, разные настройки, без копий продукта на каждого заказчика).
- **СКЗИ КС1** на сертифицированной ОС.
- **57580.1/.2** (защита информации в финансовых организациях): сегментация ВМ, журналирование, контроль доступа, шифрование «в покое» (PostgreSQL Pro TDE).
- **152-ФЗ + ПП-1119**: УЗ-2 (ПДн категории «иные»), DPIA, согласие инвестора, журнал доступа к ПДн, маскирование в логах.
- **Документация поставки** (руководство администратора, оператора, формуляр СКЗИ) — на русском, в скоупе M5.
### Что нужно сделать дополнительно для подачи в Реестр
Эти задачи добавлены в M5, но подготовка идёт с M1:
1. **Юридический пакет** (готовится к моменту подачи):
- Выписка из ЕГРЮЛ правообладателя.
- Документы об отчуждении исключительного права (от каждого разработчика — трудовой договор + служебное задание / договор подряда).
- Договоры на технологии в составе (open-source — указать лицензии в SBOM; коммерческие — КриптоПро, Postgres Pro, Liberica, Astra/РЕД ОС — приложить копии).
- Анкета и формы Минцифры (заполняются через ЕСИА руководителя на портале reestr.digital.gov.ru).
2. **Технический пакет**:
- Описание процессов разработки и поддержки.
- SBOM (CycloneDX) — для контроля происхождения и лицензий.
- Инструкции по установке и эксплуатации на русском.
- Сборка-демонстратор для проверки экспертами Минцифры (типовая инсталляция на Astra/РЕД ОС, доступ предоставляется по запросу).
3. **Интеллектуальная собственность**:
- Регистрация ПО в Роспатенте (необязательно, но повышает доказательность исключительного права при споре).
- Свидетельство Роспатента — приложение к заявке в Минцифры.
4. **Соответствие классу ПО**: пройти классификатор и подать с правильным классом (02.13 / 02.09 / 02.04 «средства защиты информации» — уточнить с патентным поверенным).
5. **Сертификация ФСТЭК / ФСБ** (не для Реестра, но для применимости в финансовых организациях):
- Сертификат ФСТЭК на встроенные средства защиты (если потребуется по аттестации сегмента у заказчика) — обычно не нужен, если заказчик аттестует свой сегмент сам.
- Сертификат ФСБ на криптомодуль — у нас не нужен, мы используем сертифицированный КриптоПро (его сертификат прикладываем).
### Открытые проверки у заказчика
- Доля иностранного участия в УК правообладателя ≤ 50% (выписка из ЕГРЮЛ).
- Все разработчики — резиденты РФ или работают по договорам с правильными формулировками о передаче ИС.
- Расчёт суммы выплат за рубеж < 30% выручки от реализации (актуально, если есть лицензии иностранным правообладателям).
- Согласие правообладателя подавать заявку (решение собственников, протокол).
### Вердикт
С точки зрения архитектуры и стека — **всё закладывается корректно**, ни одно из выбранных технических решений не противоречит требованиям Реестра. Основные риски — **юридические/корпоративные** (правообладатель, ИС, выплаты за рубеж) и **процессные** (правильно выбранный класс ПО, грамотно оформленный пакет документов). Эти риски решаются на M5 при участии юриста и патентного поверенного, но проверки у заказчика стоит начать **уже на M1**, потому что несоответствие в составе УК или в договорах с разработчиками невозможно «дописать» позже.
## Roadmap (полный MVP)
**M1 — Каркас, контракты, стенды (4 нед)**
- Моно-репо, CI, линтеры, конвенции.
- Go-модели из XSD + (de)serializer windows-1251 + `NSDDateTimeType` + строгий валидатор по pattern (ReferenceId, ISIN, ИНН, DeponentCode).
- gRPC-контракт `crypto-service` с реализацией **КриптоПро JCP** (плюс сохранённая `Provider`-абстракция для тиражирования), установка КриптоПро CSP на ВМ.
- docker-compose: PostgreSQL Pro, MinIO, заглушки сервисов.
- **Установка и настройка Интеграционного шлюза НРД** на тестовой ВМ, проверка REST API (`POST /api/package/{channel}/file`).
- **Инициировать выпуск тестовых сертификатов GUEST/TEST3** (ГОСТ + RSA), снять противоречие СКЗИ (Валидата vs КриптоПро/VipNet) с НРД и заказчиком.
- Версионированный контракт `lk-gateway``lk-emulator`, **совместимый с ESIA Finance API V1** (`/api/v1/back_office/claims`); тот же контракт предлагаем команде реального ЛК.
**M2 — Сквозной сценарий «донор» через стенд (6 нед)**
- `lk-emulator` v1: веб-форма «загрузить заявление» (готовый XML или сборка из полей), эмуляция вызова `POST /api/v1/back_office/claims/`, кнопка «Подписать и отправить», просмотр статусов и callback-ответов от `lk-gateway`.
- `lk-gateway` принимает заявление от эмулятора, валидирует подпись.
- `fansy-store` v0: схема БД и миграции под принимаемые от Fansy данные; **передача командe Fansy перечня таблиц + DDL** как контракт; стартовое наполнение фикстурами.
- `m2m-core` FSM `Draft → Validated → SubmittedToNSD → AwaitingDecision → Confirmed/Rejected/TimedOut → Done`, с веткой `TimedOut` по регуляторному таймауту (10→5 мин).
- `crypto-service`: проверка подписи входящих квитанций ЭДО и ответов НРД, подпись действий оператора.
- `nsd-adapter` v1: **ИШ через REST API** как основной канал, прохождение эталонного запроса из `DOC/Инструкция по передаче эталонного запроса на перевод M2M 08.04 (1).pdf` на TEST3 с типом пакета `#M2MTR`, ожидание `#M2MTD`.
- Метрики SLA по этапам, дашборд в `admin-ui`.
**M3 — Сценарий «реципиент», справочники, admin-ui v1 (6 нед)**
- Приём входящих от НРД через ИШ REST (`GET /api/package?channel=&type=M2MTD|M2MER|...`), формирование `M2MTransferDecision`.
- `M2MTransferHandbookRequest` / `Handbook` / `ParticipantForm` + кэш в локальной БД, плюс загрузка `Справочник пользователей` (БКС, Ренессанс Брокер, Альфа-банк).
- Поддержка дополнительных типов пакетов: **`SUB16` (черновики 16-х/16-1 поручений)** — приём, парсинг, отображение в журнале и передача депозитарию.
- Поддержка `SUBBR`/`SUBER` (старый сценарий перевода) для совместимости и `Assets_investment_account_transfer_details` + `Assets_investment_details_status` (Справка о расходах).
- Стандартная квитанция ЭДО — обязательная проверка для каждого исходящего пакета.
- `admin-ui`: журнал входящих/уходящих, фильтры (GUID/инвестор/статус/период/тип пакета), просмотр эталонов, переключатель канала (ИШ/ONYX/ФШ).
- `admin-ui`: раздел «Сертификаты» — обновление сертификатов, сроки, алерты.
- Роли: администратор, **администратор СКЗИ**, сотрудник депозитария, оператор, аудитор.
**M4 — Ручное согласование, уведомления (4 нед)**
- Ветка manual-approval в FSM, UI кнопок согласования.
- `notify`: e-mail + Yandex Messenger (до-интеграция готового бота заказчика) + WS-push в `admin-ui`.
- **Архитектура провайдеров-плагинов** для notify (smtp, yandex360, webhook, telegram, mattermost) — реализуем минимум smtp + yandex360 + webhook, остальные — заглушками с примером.
- Раздел «Уведомления» в `admin-ui`: включение/выключение провайдеров, ввод токенов, тестовая отправка, маршрутизация.
- Конфигурируемые правила «отправить на ручное согласование».
- Совместное тестирование с командой Fansy-ETL: проверка наполнения `fansy-store` боевым потоком.
**M5 — ИБ, нагрузочное, оптимизация на SLA 2 мин, прод (6 нед, до 01.09.2026)**
- Аудит ГОСТ Р 57580, моделирование угроз, документы для ФСТЭК.
- Нагрузочное (k6) с целевым TPS, верификация SLA 2 мин и регуляторного таймаута 5 мин.
- Подача в Реестр ПО (заявка готовится параллельно с M3-M4).
- Подключение **резервного канала через WS ONYX напрямую** для ситуации недоступности ИШ.
- Подключение промконтура НРД, ПСИ.
- **Жёсткий дедлайн**: вступление 124-ФЗ + Указания Банка России **01.09.2026**.
## Критичные файлы и активы
- `DOC/M2MSchemas_260408/*.xsd` — единственный источник правды для моделей.
- `DOC/Примеры/*.xml` — fixtures unit-тестов.
- `DOC/Эталонные сообщения/*.xml` — приёмочные fixtures.
- `DOC/Ссылки для доступа в тестовые контуры.pdf` — конфиги стендов.
- `DOC/Инструкция по передаче эталонного запроса на перевод M2M 08.04 (1).pdf` — сценарий приёмки M2.
- `DOC/instr_podkl_stend_v3.pdf` — подключение к стендам.
- `DOC/Справочник пользователей.pdf`**перечень организаций-участников сервиса** (БКС ИНН 5406121446, Ренессанс Брокер 7709258228, Альфа-банк 7728168971 — последний на пилоте). Загружается в `fansy-store`/локальный справочник как white-list контрагентов и индикатор «доступен ли участник для M2M-перевода». Модель ролей операторов нашей системы — **отдельная**, проектируется в `admin-ui`.
- `DOC/so_cher_por.pdf` — схема обмена для **получения черновиков поручений** (типы пакетов `SUBBR`, `SUBER`, `SUB16` — черновики 16-х поручений на каждую ЦБ).
- `DOC/so_spravki.pdf` — схема обмена **Справки о расходах** (`Assets_investment_account_transfer_details.xml` + `Assets_investment_details_status.xml`) между Брокером 1 и Брокером 2 через MOST.
- `DOC/Презентация MOEX MOST.pdf` — целевая архитектура M2M, регуляторика (124-ФЗ, дедлайн 01.09.2026), таймауты 5/2 минуты, таймаут отсутствия ответа 10/5 минут.
- `DOC/Презентация тестирование систем НРД.pdf` — окружение тестирования: **СКЗИ «Валидата CSP»**, Криптосервис НРД (порты 48737/48200), требования к рабочему месту оператора для веб-кабинетов.
- `DOC/API ЛК ЕСИА.pdf` — это **НЕ ЕСИА Госуслуг**, а **API бэк-офиса платформы «ESIA Finance»** (`/api/v1/back_office/...`, Basic HTTP, JSON, UTF-8). Это и есть контракт ЛК клиента, через который работает наша интеграция; релевантные разделы: Заявки (`/claims`), Реквизиты (`/requisites`), Депо-счета (`/depo_accounts`), Сообщения (`/messages`), Сертификаты (`/control_certificates`), Пользователи (`/users`).
## Верификация
- **Unit**: round-trip сериализация всех 6 типов сообщений против эталонов (`xml-exc-c14n` сравнение).
- **Crypto**: подпись эталона `crypto-service` ГОСТ-ключом → проверка штатным верификатором СКЗИ (Валидата/КриптоПро) → green.
- **Контрактные тесты**: WireMock-стенд **ИШ REST API** (методы `/api/package/...`) и WS ONYX в CI; ночные прогоны на GUEST/TEST3.
- **Регуляторный таймаут**: интеграционный тест «отправили `#M2MTR` на стенде, не получили `#M2MTD` за 10 мин» → проверка, что MOST прислал `Transfer_reject.xml (SUBER)` и наша FSM перешла в `TimedOut`.
- **SLA**: синтетический тест каждого этапа в CI, fail при > 5 мин (старт) и > 2 мин (целевой).
- **E2E**: docker-compose, Playwright прокликивает сценарии **через `lk-emulator`** (загрузка заявления → подпись → отправка) и далее по `admin-ui` (приход → авто-обработка, приход → ручное согласование, приход → таймаут SLA → нотификация). Эмулятор — основной инструмент E2E на всём протяжении, пока реальный ЛК не подключён.
- **Fansy**: контрактный тест выгрузки против тестовой схемы Fansy.
- **Приёмка НРД**: эталонный сценарий 08.04 без ручных правок, GUID совпадает в Request/Response/Decision.
## Открытые вопросы (нужно уточнить перед M1)
- **API ЛК клиента**: подтверждено — концепция взаимодействия реального ЛК соответствует `API ЛК ЕСИА.pdf` (платформа **ESIA Finance**, `/api/v1/back_office/...`). Сами формы документа на стороне ЛК ещё не реализованы, поэтому в `lk-emulator` мы пишем «как-будто-ЛК», который вызывает наш `lk-gateway` точно по этому контракту; реальный ЛК подключится через тот же контракт без правок на нашей стороне.
- **СКЗИ — решено: КриптоПро.** В `crypto-service` поднимаем **КриптоПро JCP** (на JVM) и КриптоПро CSP на ВМ, согласуем версию и лицензию. Поддержку других провайдеров не убираем (`Provider`-абстракция остаётся), но в реализации — только КриптоПро.
- **Установка ИШ**: дистрибутив ИШ НРД получает заказчик (как участник ЭДО), наша сторона ставит ИШ на целевую ВМ и сопровождает.
- **Fansy-store**: ETL делает команда Fansy в автоматизированном режиме. Наша ответственность — спроектировать таблицы согласно требованиям документации НРД к данным M2M (поля `Header`, `Data`, реквизиты сторон, счета/разделы, остатки) и **передать команде Fansy перечень таблиц + DDL** как контракт. Согласуем тип load, частоту, окно простоя.
- **Подпись действий оператора**: решено — **серверная, от имени оператора** (через `crypto-service`) ради SLA 2 мин. Клиентская подпись отклонена.
- **Yandex Messenger**: используется **Yandex 360 для бизнеса**, на стороне заказчика **уже есть готовый бот** — мы его до-интегрируем (передаём токен/webhook/ID чатов через конфиг).
- **Класс СКЗИ — решено: КС1.** Программная защита без аппаратного ДСЧ/HSM. Используем сертифицированное исполнение КриптоПро CSP/JCP на сертифицированной ОС (РЕД ОС 7.3 (целевая)). На M5 — сборка формуляра и эксплуатационной документации СКЗИ под требования КС1.
- **Аутентификация в `admin-ui`**: внутренний SSO компании (LDAP/Keycloak) или собственная учётка?
---
## Что добавлено по результатам повторного аудита документации
Ниже — сводно, чтобы было видно, что план учёл все обнаруженные при ре-аудите факты:
1. **Три транспортных канала к НРД** (ИШ REST — основной, WS ONYX — резерв, ФШ — fallback) и таблица типов пакетов ЭДО (`#M2MTR`/`#M2MTD`/`#M2MER`/`SUBBR`/`SUBER`/`SUB16`/Справки/квитанции).
2. **ИШ сам подписывает пакеты** — пересмотрена роль `crypto-service` (он теперь нужен в первую очередь для проверки входящих, подписи действий оператора и резерва через WS ONYX).
3. **СКЗИ Валидата CSP** добавлено как поддерживаемый провайдер; противоречие с лицензиями заказчика вынесено в открытые вопросы; в `crypto-service` — абстракция `Provider`.
4. **`API ЛК ЕСИА.pdf` идентифицирован как API ESIA Finance** (не госЕСИА). Контракт `lk-gateway`/`lk-emulator` приводится к этому API (`/claims`, `/requisites`, `/depo_accounts`, `/messages`, `/control_certificates`, `/users`).
5. **Регуляторика**: 124-ФЗ от 23.05.2025, Указание ЦБ, **дедлайн прода 01.09.2026**, таймаут MOST 10→5 мин — учтены в SLA и M5.
6. **`Справочник пользователей`** переинтерпретирован: это перечень контрагентов (БКС, Ренессанс Брокер, Альфа-банк), не модель ролей операторов.
7. **Дополнительные сценарии**: справка о расходах (`Assets_investment_account_transfer_details` + статус), черновики поручений `SUB16`, старый сценарий `SUBBR`/`SUBER` — добавлены в скоуп M3.
8. **XSD-уточнения**: исправлен `IIAContractTypeEnum` (`T12 | T03`, не `T01/T02/T03`); зафиксированы pattern для `ReferenceId`, `ISIN`, `DeponentCode`, ИНН, `NSDDateTimeType` (только зона МСК); полный список `IdentityDocumentCodeEnum`.
9. **Установка ИШ НРД** включена в M1 как обязательный шаг подключения к стенду.
10. **Регуляторный таймаут MOST** оформлен как ветка FSM `TimedOut` с интеграционным тестом на стенде.