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>
This commit is contained in:
zuevav
2026-05-13 22:48:21 +03:00
parent d5b5597c67
commit 3fdc526031
8 changed files with 1651 additions and 0 deletions
+185
View File
@@ -0,0 +1,185 @@
# 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'ы (со списком допустимых значений):**
- `StatusCode``INFO | ERROR`.
- `IIAContractType`**`T12 | T03`** (именно так — T12 = обмен ИИС-1/ИИС-2,
T03 = ИИС-3; не T01/T02/T03).
- `SecurityClassification``BOND | SHAR | MFUN`.
- `SecurityCategory``ORDN | PREF | UKWN`.
- `IdentityDocumentCode``01 | 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 постфактум).
## Проверка перед коммитом
```bash
make ci
```
Если зелёное — push. Если красное — фиксируй ошибки до зелёного,
не коммить промежуточные правки.
## После коммита
1. Обнови `docs/tasks/README.md`: PR-1 — «выполнено», sha коммита.
2. Обнови `internal/m2m/README.md` и `internal/nsdxml/README.md`,
убери пометку «реализация — задача M1» и добавь короткое описание
что есть.