Files
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

8.7 KiB
Raw Permalink Blame History

PR-1: Go-модели M2M + парсер windows-1251 + round-trip тесты

Цель

Реализовать типизированную доменную модель сообщений M2M по XSD НРД, парсер/сериализатор XML в windows-1251 и round-trip тесты на эталонах. Это первый осмысленный код в проекте, на нём основываются все последующие модули (nsd-adapter, m2m-core, lk-gateway, lk-emulator).

Источники правды

  • DOC/M2MSchemas_260408/*.xsd — все типы и структуры, namespace http://nsd.ru/schemas/m2m/..., version 2026-04-08.
  • DOC/Примеры/*.xml — примеры всех типов сообщений (windows-1251).
  • DOC/Эталонные сообщения/*.xml — эталоны для приёмочной проверки.

Состав PR

1. internal/m2m/types.go

Все simple-типы и enum'ы из XSD как Go-типы.

Enum'ы (со списком допустимых значений):

  • StatusCodeINFO | ERROR.
  • IIAContractTypeT12 | T03 (именно так — T12 = обмен ИИС-1/ИИС-2, T03 = ИИС-3; не T01/T02/T03).
  • SecurityClassificationBOND | SHAR | MFUN.
  • SecurityCategoryORDN | PREF | UKWN.
  • IdentityDocumentCode01 | 02 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 | 12 | 13 | 14 | 21 | 22 | 23 | 26 | 27 | 91.
  • IsolationStatus — только SGDN.

Simple-типы как Go-обёртки над string:

  • DeponentCode, ReferenceId, ISIN, OrganizationINN, UUID, AccountId, SecurityCode, IdentityDocSerial.

2. internal/m2m/validators.go

Метод Validate() error на каждом типе из пункта 1, проверяющий pattern и длину из XSD:

Тип Pattern Длина
ReferenceId ^M2M[A-Z0-9]{13}$ ровно 16
ISIN ^[A-Z]{2}[A-Z0-9]{9}[0-9]$ ровно 12
OrganizationINN ^[0-9]{10}$ ровно 10
DeponentCode ^[A-Z0-9]+$ до 12
UUID стандартный UUID v1-5 pattern 36
SecurityCode ^[0-9A-Z_/-]+$ ровно 12
IdentityDocSerial ^\S+$ от 1

Enum'ы валидируются проверкой принадлежности к допустимому множеству.

3. internal/m2m/messages.go

Структуры всех 6 типов сообщений M2M:

  • M2MTransferRequest — Header (UUID, NSDDateTime, SenderCode, ReceiverCode, CostInfo, опц. IIAAgreementDetails) + Data (IsM2M=true, InvestorInformation, TransferringDepository, ReceivingDepository, TransferredSecurities) + опц. NSDInfo.
  • M2MTransferDecision — Header (тот же набор минус IIAAgreementDetails)
    • Data (ReceivingDepository, Security[] с TransferDecision Choice).
  • M2MTransferResponse — GUID + StatusCode + Response[] (ReferenceId, Code, Text).
  • M2MTransferHandbook + M2MTransferHandbookRequest.
  • M2MTransferParticipantForm.

Choice-типы. Реализуй через указатели на взаимоисключающие поля:

  • CostInfo { Yes *Yes; No *No } — ровно один не nil.
  • Quantity { Whole *uint64; Fractional *Decimal16 }.
  • SecurityDetails { ISIN *ISIN; SecurityInfo *SecurityDescription }.
  • IdentificationDetails { RegNumber *string; FundShares *FundShares }.
  • DecisionTransfer { Confirmation *Confirmation; Rejection *Rejection }.

В Validate() каждого choice — проверка «ровно одно поле задано».

Фиксированные значения. IsM2M всегда true — захардкодь в MarshalXML (не выноси в поле, заполняй автоматически).

XML-теги. Для каждого поля укажи xml:"..." с правильным namespace из XSD. Используй namespace-aliases:

  • rt для http://nsd.ru/schemas/m2m/request,
  • dn для http://nsd.ru/schemas/m2m/decision,
  • hk для http://nsd.ru/schemas/m2m/handbook,
  • hr для http://nsd.ru/schemas/m2m/handbook/request,
  • pf для http://nsd.ru/schemas/m2m/participant/form,
  • m2m для http://nsd.ru/schemas/m2m/types.

4. internal/nsdxml/datetime.go

Тип NSDDateTime для нестандартного формата НРД.

  • Формат: YYYY-MM-DDThh:mm:ss(МСК[+-N]), пример: 2026-03-02T14:30:45(МСК+2).
  • Regex из XSD: ^[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})?\)$.
  • Внутреннее представление — time.Time в location Europe/Moscow плюс смещение (если есть).
  • Реализуй: MarshalXML, UnmarshalXML, MarshalText, UnmarshalText, String() string, Now() NSDDateTime.
  • Кейсы для тестов: (МСК), (МСК+2), (МСК-1), (МСК+12).

5. internal/nsdxml/codec.go

Marshal/Unmarshal XML в windows-1251.

  • Зависимость: golang.org/x/text/encoding/charmap.
  • Marshal(v any) ([]byte, error):
    1. Сериализуй в utf-8 через encoding/xml.
    2. Прогони через charmap.Windows1251.NewEncoder().
    3. Замени первую строку на <?xml version="1.0" encoding="windows-1251"?>.
  • Unmarshal(data []byte, v any) error:
    1. Создай xml.Decoder с CharsetReader, в котором при charset == "windows-1251" оборачиваем reader в charmap.Windows1251.NewDecoder().Reader(...).
    2. Декодируй в v.
  • Проверь, что кириллица в эталонах (ФИО инвестора, наименования организаций) читается и пишется корректно.

6. internal/m2m/messages_test.go

Round-trip тесты на всех эталонах.

  • Таблица «файл → ожидаемый тип сообщения» для всех XML в DOC/Примеры/ и DOC/Эталонные сообщения/.
  • Для каждого файла:
    1. Unmarshal → структура S1.
    2. S1.Validate() — без ошибок.
    3. Marshal(S1) → байты B2.
    4. Unmarshal(B2) → структура S2.
    5. reflect.DeepEqual(S1, S2) — true.
  • Юнит-тесты валидаторов на негативных кейсах (короткий ИНН, неверный префикс ReferenceId, неизвестное значение enum).
  • Юнит-тесты NSDDateTime на всех вариантах зоны.

Требования к коду

  • Без эмодзи в коде и комментариях.
  • Комментарии в коде — на русском.
  • Имена типов и полей — на английском, как в XSD (SettlementAccount, IsolationStatus, IIAAgreementDetails и т. п.).
  • go mod tidy после добавления зависимостей (понадобится golang.org/x/text/encoding/charmap).
  • make ci (tidy + fmt + vet + lint + test + build) — зелёный.
  • Покрытие тестами internal/m2m/ и internal/nsdxml/ — не менее 70%.

Коммит

Один commit, сообщение:

feat(m2m): доменная модель сообщений + парсер windows-1251 + round-trip тесты

- internal/m2m/types.go: enum'ы и simple-типы из XSD НРД (M2MSchemas_260408)
- internal/m2m/validators.go: pattern-валидаторы ReferenceId/ISIN/INN/...
- internal/m2m/messages.go: структуры 6 типов сообщений M2M
- internal/nsdxml/datetime.go: тип NSDDateTime (формат "YYYY-MM-DDThh:mm:ss(МСК+N)")
- internal/nsdxml/codec.go: Marshal/Unmarshal XML в windows-1251
- internal/m2m/messages_test.go: round-trip тесты на всех эталонах из DOC/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Push в main (история линейная, ревью через diff в Gitea постфактум).

Проверка перед коммитом

make ci

Если зелёное — push. Если красное — фиксируй ошибки до зелёного, не коммить промежуточные правки.

После коммита

  1. Обнови docs/tasks/README.md: PR-1 — «выполнено», sha коммита.
  2. Обнови internal/m2m/README.md и internal/nsdxml/README.md, убери пометку «реализация — задача M1» и добавь короткое описание что есть.