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:
@@ -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» и добавь короткое описание
|
||||
что есть.
|
||||
Reference in New Issue
Block a user