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» и добавь короткое описание
|
||||
что есть.
|
||||
@@ -0,0 +1,148 @@
|
||||
# PR-2: DDL принимающей БД для команды Fansy
|
||||
|
||||
## Цель
|
||||
|
||||
Спроектировать DDL принимающей БД `fansy-store` под требования
|
||||
документации НРД к данным M2M и передать его команде Fansy как
|
||||
контракт для их ETL.
|
||||
|
||||
ETL **делает команда Fansy** в автоматизированном режиме. Наша
|
||||
ответственность — схема таблиц, индексы, миграции, типизированный
|
||||
Go-репозиторий чтения и контракт данных.
|
||||
|
||||
## Источники правды
|
||||
|
||||
- `DOC/M2MSchemas_260408/*.xsd` — какие поля и типы нужны для
|
||||
формирования M2M-сообщений.
|
||||
- `DOC/Справочник пользователей.pdf` — перечень контрагентов
|
||||
(БКС 5406121446, Ренессанс Брокер 7709258228, Альфа-банк 7728168971).
|
||||
- `docs/architecture/plan.md` — контракт с командой Fansy (раздел
|
||||
«Контракт с командой Fansy — что мы передаём»).
|
||||
|
||||
## Состав PR
|
||||
|
||||
### 1. `docs/fansy-contract/v1/ddl/` — SQL-миграции
|
||||
|
||||
PostgreSQL 16 / PostgreSQL Pro Certified. Используй `goose` или
|
||||
просто пронумерованные файлы `001__init.sql`, `002__staging.sql` и т. д.
|
||||
|
||||
Схема разделена на две:
|
||||
- `fansy_staging` — куда пишет команда Fansy (только их роль может
|
||||
делать INSERT/UPDATE);
|
||||
- `fansy` — рабочая, куда переливаются актуальные данные триггерами
|
||||
или процедурами после валидации.
|
||||
|
||||
Минимальный набор таблиц (повторяй структуру и в staging, и в
|
||||
рабочей):
|
||||
|
||||
- `clients` — депоненты/инвесторы:
|
||||
- `id` (uuid), `inn` (для юрлиц), `last_name`, `first_name`,
|
||||
`middle_name`, `birth_date`, `created_at`, `updated_at`.
|
||||
- `client_documents` — документы инвестора:
|
||||
- `id`, `client_id (FK)`, `document_type` (enum по
|
||||
`IdentityDocumentCode`), `series`, `number`, `issued_at`,
|
||||
`issuer`.
|
||||
- `iia_contracts` — ИИС-договоры:
|
||||
- `id`, `client_id (FK)`, `agreement_type` (`T12` | `T03`),
|
||||
`agreement_number`, `agreement_date`, `broker_inn`.
|
||||
- `depo_accounts` — депо-счета и разделы:
|
||||
- `id`, `client_id (FK)`, `deponent_code`, `account_id`,
|
||||
`section_id`, `depository_inn`, `is_active`, `is_trading`.
|
||||
- `settlement_requisites` — реквизиты расчётов:
|
||||
- `id`, `inn`, `display_name`, `created_at`.
|
||||
- `portfolios` — портфели/остатки ЦБ:
|
||||
- `id`, `client_id (FK)`, `depo_account_id (FK)`, `security_code`,
|
||||
`isin`, `quantity_whole` (numeric), `quantity_fractional`
|
||||
(numeric(38,16)), `isolation_status` (`SGDN`), `valued_at`.
|
||||
- `securities` — справочник ЦБ:
|
||||
- `id`, `security_code` (PK), `isin`, `classification`
|
||||
(`BOND`|`SHAR`|`MFUN`), `category` (`ORDN`|`PREF`|`UKWN`),
|
||||
`security_type`, `security_series`, `reg_number`,
|
||||
`fund_class`, `display_name`.
|
||||
- `participants` — контрагенты-участники сервиса MOST:
|
||||
- `id`, `inn` (PK), `ogrn`, `full_name_rus`, `short_name_rus`,
|
||||
`display_name_rus`, `full_name_eng`, `short_name_eng`,
|
||||
`display_name_eng`, `depository_participant_code`,
|
||||
`broker_participant_code`, `is_available_for_m2m`, `comment`.
|
||||
- Предзаполни записями из `Справочник пользователей.pdf`.
|
||||
|
||||
Дополнительно:
|
||||
- `etl_errors` — таблица для ошибок выгрузки Fansy (id, source_table,
|
||||
source_pk, payload jsonb, error_message, created_at).
|
||||
- В `_staging`-таблицах поле `loaded_at timestamptz default now()`.
|
||||
|
||||
**Индексы.** Минимум: PK, FK, индекс по `inn` и `deponent_code` в
|
||||
основных таблицах, индекс по `valued_at` в `portfolios`.
|
||||
|
||||
**Роль `fansy_etl`.** В отдельном `000__roles.sql`:
|
||||
- роль `fansy_etl` с правами INSERT/UPDATE/SELECT на схему
|
||||
`fansy_staging`;
|
||||
- роль `bj_reader` с SELECT на схему `fansy` — для нашего
|
||||
`m2m-core`/`lk-gateway`;
|
||||
- DDL-права (CREATE/ALTER/DROP) — только у миграционной роли,
|
||||
не у Fansy-ETL.
|
||||
|
||||
### 2. `docs/fansy-contract/v1/data-dictionary.md`
|
||||
|
||||
Таблица: «поле → семантика → источник в Fansy (если известен) →
|
||||
nullable → пример». На каждую колонку каждой таблицы.
|
||||
|
||||
### 3. `docs/fansy-contract/v1/etl-requirements.md`
|
||||
|
||||
Технические требования к процессу выгрузки от команды Fansy:
|
||||
|
||||
- Подключение: PostgreSQL, роль `fansy_etl`, отдельная учётная запись.
|
||||
- Тип load: **инкрементный UPSERT в staging-таблицы** по бизнес-ключу;
|
||||
полная перезаливка — только для справочников (`securities`,
|
||||
`participants`), не чаще раза в сутки.
|
||||
- SLA свежести данных:
|
||||
- `portfolios` — не позднее 1 минуты после изменения в Fansy;
|
||||
- `clients`, `depo_accounts`, `client_documents`, `iia_contracts`
|
||||
— не позднее 5 минут;
|
||||
- `securities`, `participants` — раз в сутки или по событию.
|
||||
- Формат timestamp — UTC с явной зоной (`timestamptz`).
|
||||
- Обработка ошибок: запись в `etl_errors`.
|
||||
- Окно простоя для регламентных работ — согласовать.
|
||||
|
||||
### 4. `docs/fansy-contract/v1/examples/`
|
||||
|
||||
- `example-claim.md` — какие поля из БД нужны `m2m-core` для одной
|
||||
типовой M2M-заявки (с конкретными SQL-запросами).
|
||||
- `seed-data.sql` — 5–10 тестовых клиентов, портфелей, заявок для
|
||||
совместного приёмочного теста.
|
||||
|
||||
### 5. `migrations/fansy-store/`
|
||||
|
||||
Скопировать `*.sql` из `docs/fansy-contract/v1/ddl/` — отсюда будут
|
||||
исполняться миграциями в нашем сервисе.
|
||||
|
||||
### 6. Обновить `docs/fansy-contract/v1/README.md`
|
||||
|
||||
Описать состав каталога и порядок согласования с командой Fansy.
|
||||
|
||||
## Требования к коду
|
||||
|
||||
- Все DDL-файлы — на одной кодировке UTF-8.
|
||||
- Имена таблиц и колонок — `snake_case` английский.
|
||||
- Комментарии в DDL (`COMMENT ON COLUMN ... IS '...'`) — на русском.
|
||||
- Без эмодзи.
|
||||
|
||||
## Коммит
|
||||
|
||||
```
|
||||
feat(fansy-store): DDL принимающей БД + контракт данных для команды Fansy
|
||||
|
||||
- docs/fansy-contract/v1/ddl/ — миграции PostgreSQL
|
||||
- docs/fansy-contract/v1/data-dictionary.md — словарь данных
|
||||
- docs/fansy-contract/v1/etl-requirements.md — требования к ETL
|
||||
- docs/fansy-contract/v1/examples/ — пример заявки + seed-data
|
||||
- migrations/fansy-store/ — рабочие копии миграций
|
||||
- предзаполнен справочник контрагентов из DOC/Справочник пользователей.pdf
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## После коммита
|
||||
|
||||
1. Обновить `docs/tasks/README.md`: PR-2 — «выполнено».
|
||||
2. Сообщить заказчику, что DDL готов и можно отправлять команде Fansy.
|
||||
@@ -0,0 +1,113 @@
|
||||
# PR-3: OpenAPI контракт `lk-gateway` (ESIA Finance API V1)
|
||||
|
||||
## Цель
|
||||
|
||||
Зафиксировать REST-контракт между `lk-gateway` (наш сервис) и ЛК
|
||||
клиента на платформе ESIA Finance. Контракт — отправная точка для:
|
||||
|
||||
- собственного эмулятора ЛК (`lk-emulator`, PR будет позже);
|
||||
- интеграции с командой реального ЛК (когда формы документа на
|
||||
стороне ЛК будут готовы).
|
||||
|
||||
## Источники правды
|
||||
|
||||
- `DOC/API ЛК ЕСИА.pdf` — официальное описание API V1 платформы
|
||||
ESIA Finance (`/api/v1/back_office/...`, Basic HTTP, JSON, UTF-8).
|
||||
- `DOC/M2MSchemas_260408/*.xsd` — поля заявления должны быть
|
||||
достаточны для формирования `M2MTransferRequest`.
|
||||
|
||||
## Состав PR
|
||||
|
||||
### 1. `docs/lk-contract/v1/openapi.yaml`
|
||||
|
||||
Спецификация OpenAPI 3.0. Покрывает следующие операции:
|
||||
|
||||
- `POST /api/v1/back_office/claims/` — создание заявки на M2M-перевод.
|
||||
- Тело: подписанное заявление инвестора (XML или JSON, согласовать
|
||||
с командой ЛК; XML с XMLDSig — предпочтительнее, проще
|
||||
верифицировать на нашей стороне через `crypto-service`).
|
||||
- Ответ: `{ id, status, created_at, success: true }`.
|
||||
- `GET /api/v1/back_office/claims/{id}` — получение заявки и её
|
||||
статуса.
|
||||
- `PATCH /api/v1/back_office/claims/{id}` — обновление статуса от
|
||||
нашей стороны (callback).
|
||||
- `GET /api/v1/back_office/claims` — список заявок (фильтры по статусу,
|
||||
периоду, инвестору).
|
||||
- Аутентификация: Basic HTTP (как в API V1 ESIA Finance).
|
||||
- Формат ошибок — как в `API ЛК ЕСИА.pdf`:
|
||||
`{ error: true, status, code, title, meta: { message, errors } }`.
|
||||
|
||||
### 2. Состав модели «Заявка»
|
||||
|
||||
Минимальный набор полей, нужный для формирования
|
||||
`M2MTransferRequest`:
|
||||
|
||||
- `id` (uuid),
|
||||
- `created_at`, `updated_at`,
|
||||
- `status` — enum (`draft|signed|submitted|in_progress|confirmed|rejected|timed_out`),
|
||||
- `investor` — ссылка на пользователя в ЛК (или встроенные ФИО+документ);
|
||||
- `transferring_depository_inn`, `receiving_depository_inn`,
|
||||
- `securities[]` — список с `security_code`, `isin` (или
|
||||
`security_info`), `quantity_whole|fractional`, `settlement_accounts[]`,
|
||||
- `cost_info` — `yes { code } | no`,
|
||||
- `iia_agreement` (опц., для ИИС) — `agreement_type T12|T03`,
|
||||
`agreement_number`, `agreement_date`, `broker_inn`,
|
||||
- `signed_document` (base64) — подписанный XML заявления,
|
||||
- `signature_format` — `XMLDSig-GOST` или `XMLDSig-RSA`.
|
||||
|
||||
### 3. Состав модели «Callback статуса»
|
||||
|
||||
Что мы отправляем обратно в ЛК:
|
||||
|
||||
- `claim_id`,
|
||||
- `new_status` (по тому же enum),
|
||||
- `reason_code` (для отказов — код причины из M2MTransferResponse),
|
||||
- `reason_text`,
|
||||
- `updated_at`,
|
||||
- `nsd_response` — оригинал ответа НРД (опц., для аудита).
|
||||
|
||||
### 4. `docs/lk-contract/v1/examples/`
|
||||
|
||||
- `examples/claim-request.json` — пример заявки на перевод
|
||||
(3 ЦБ, ИИС, заполненные реквизиты).
|
||||
- `examples/claim-response.json` — пример ответа.
|
||||
- `examples/callback-confirmed.json` — пример callback подтверждения.
|
||||
- `examples/callback-rejected.json` — пример callback отказа.
|
||||
- `examples/error-422.json` — пример ошибки валидации.
|
||||
|
||||
### 5. `docs/lk-contract/v1/changelog.md`
|
||||
|
||||
Версионирование контракта. Первая запись — `v1.0.0`.
|
||||
|
||||
### 6. Обновить `docs/lk-contract/v1/README.md`
|
||||
|
||||
Описать состав, способ работы и порядок согласования с командой ЛК.
|
||||
|
||||
## Требования к коду
|
||||
|
||||
- OpenAPI 3.0.x, валидный по `spectral` или `openapi-cli`.
|
||||
- Имена операций (operationId) — `snake_case`.
|
||||
- Описания (description) — на русском.
|
||||
- Все поля с `description` и примерами.
|
||||
- Без эмодзи.
|
||||
|
||||
## Коммит
|
||||
|
||||
```
|
||||
feat(lk-contract): OpenAPI контракт lk-gateway по ESIA Finance API V1
|
||||
|
||||
- docs/lk-contract/v1/openapi.yaml — спецификация
|
||||
- docs/lk-contract/v1/examples/ — примеры запросов/ответов/callback
|
||||
- docs/lk-contract/v1/changelog.md — v1.0.0
|
||||
|
||||
Контракт предлагается команде реального ЛК как точка синхронизации.
|
||||
В lk-emulator (отдельный PR) контракт реализуется как «как-будто-ЛК»
|
||||
для проверки сквозного потока.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## После коммита
|
||||
|
||||
1. Обновить `docs/tasks/README.md`: PR-3 — «выполнено».
|
||||
2. Сообщить заказчику, что OpenAPI готов и можно отправлять команде ЛК.
|
||||
@@ -0,0 +1,186 @@
|
||||
# PR-4: Каркас `m2m-core` — FSM сделки, репозитории, идемпотентность
|
||||
|
||||
## Цель
|
||||
|
||||
Реализовать ядро бизнес-логики M2M-перевода: конечный автомат сделки,
|
||||
типизированный доступ к БД, идемпотентность по GUID, метрики SLA по
|
||||
этапам. Сетевые интеграции (НРД, ЛК, crypto-service) пока
|
||||
**заглушками через интерфейсы** — реальные клиенты подключаются
|
||||
в PR-5 и далее.
|
||||
|
||||
## Зависимости
|
||||
|
||||
- PR-1 (Go-модели M2M) — для типизированных сообщений.
|
||||
- PR-2 (DDL Fansy) — на схему БД.
|
||||
|
||||
## Источники
|
||||
|
||||
- `docs/architecture/plan.md` — раздел «Поток одной заявки end-to-end»
|
||||
и «SLA и регуляторные сроки».
|
||||
- `internal/m2m/` — модели сообщений (после PR-1).
|
||||
|
||||
## Состав PR
|
||||
|
||||
### 1. Конечный автомат сделки
|
||||
|
||||
`internal/m2mcore/fsm.go`:
|
||||
|
||||
```
|
||||
Draft → Validated → SubmittedToNSD → AwaitingDecision →
|
||||
Confirmed → AwaitingSUB16 → Done
|
||||
↘ Rejected
|
||||
↘ TimedOut (после 10→5 мин без Decision)
|
||||
↘ ManualApproval (опц. ветка)
|
||||
```
|
||||
|
||||
Переходы — явные методы:
|
||||
- `(d *Deal) Validate() error`,
|
||||
- `(d *Deal) Submit(ctx) error`,
|
||||
- `(d *Deal) ReceiveDecision(ctx, m2m.M2MTransferDecision) error`,
|
||||
- `(d *Deal) Timeout(ctx) error`,
|
||||
- `(d *Deal) SendToManualApproval(ctx, reason string) error`,
|
||||
- `(d *Deal) ApproveManually(ctx, operator string) error`,
|
||||
- `(d *Deal) RejectManually(ctx, operator, code, comment string) error`.
|
||||
|
||||
Каждый переход:
|
||||
- проверяет текущее состояние (нельзя `Submit` если не `Validated`);
|
||||
- пишет событие в `deal_events` (event sourcing для аудита);
|
||||
- эмитит метрику `m2m_stage_duration_seconds{stage=...}`.
|
||||
|
||||
### 2. Доменная модель сделки
|
||||
|
||||
`internal/m2mcore/deal.go`:
|
||||
|
||||
```go
|
||||
type Deal struct {
|
||||
ID uuid.UUID
|
||||
GUID m2m.UUID // тот, что в M2MTransferRequest.Header.GUID
|
||||
State State
|
||||
InvestorID uuid.UUID
|
||||
SignedClaim []byte // подписанный XML от ЛК
|
||||
Request *m2m.M2MTransferRequest
|
||||
Response *m2m.M2MTransferResponse
|
||||
Decision *m2m.M2MTransferDecision
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Stages []StageRecord // история состояний с timestamp
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Репозиторий
|
||||
|
||||
`internal/m2mcore/repo.go`:
|
||||
|
||||
Интерфейс `Repository` с реализацией на pgx:
|
||||
|
||||
```go
|
||||
type Repository interface {
|
||||
Create(ctx, *Deal) error
|
||||
GetByGUID(ctx, m2m.UUID) (*Deal, error)
|
||||
Update(ctx, *Deal) error
|
||||
List(ctx, Filter) ([]*Deal, error)
|
||||
AppendEvent(ctx, *Deal, Event) error
|
||||
}
|
||||
```
|
||||
|
||||
Идемпотентность: `Create` использует `INSERT ... ON CONFLICT (guid) DO NOTHING RETURNING ...` —
|
||||
повторный запрос с тем же GUID не создаёт дубль, а возвращает существующий.
|
||||
|
||||
### 4. Внешние зависимости — интерфейсы (для PR-5+)
|
||||
|
||||
`internal/m2mcore/ports.go`:
|
||||
|
||||
```go
|
||||
type NSDSender interface {
|
||||
Send(ctx, *m2m.M2MTransferRequest) (*m2m.M2MTransferResponse, error)
|
||||
SendDecision(ctx, *m2m.M2MTransferDecision) error
|
||||
}
|
||||
|
||||
type LKCallbackClient interface {
|
||||
UpdateStatus(ctx, claimID, status, reason string) error
|
||||
}
|
||||
|
||||
type CryptoVerifier interface {
|
||||
VerifyXMLDSig(ctx, payload []byte) (CertInfo, error)
|
||||
}
|
||||
|
||||
type FansyStore interface {
|
||||
GetClientByID(ctx, uuid.UUID) (*Client, error)
|
||||
GetDepoAccount(ctx, deponentCode, accountID string) (*DepoAccount, error)
|
||||
CheckBalance(ctx, depoAccountID uuid.UUID, isin string) (Quantity, error)
|
||||
}
|
||||
```
|
||||
|
||||
В PR-4 — заглушки `noopNSDSender`, `noopLKCallbackClient` и т. п.
|
||||
Реальные клиенты подключаются в PR-5, PR-6.
|
||||
|
||||
### 5. Сборка enrichment Request из заявки
|
||||
|
||||
`internal/m2mcore/enrich.go`:
|
||||
|
||||
Функция «из заявки от ЛК + данные из `fansy-store` → `M2MTransferRequest`».
|
||||
|
||||
Шаги:
|
||||
1. Распарсить подписанное заявление (XML от ЛК).
|
||||
2. Поднять реквизиты сторон, депо-счета, остатки из FansyStore.
|
||||
3. Проверить достаточность остатков по каждой ЦБ.
|
||||
4. Сгенерировать `GUID` (uuid v4) и `ReferenceId` для каждой ЦБ
|
||||
(`M2M` + дата `YYYYMMDD` + 5 случайных символов A-Z0-9).
|
||||
5. Заполнить `Header.CreationTimestamp` = `nsdxml.NSDDateTime.Now()`.
|
||||
6. Вернуть готовый `*m2m.M2MTransferRequest`, валидированный.
|
||||
|
||||
### 6. Метрики SLA
|
||||
|
||||
`internal/m2mcore/metrics.go`:
|
||||
|
||||
Prometheus метрики:
|
||||
- `m2m_stage_duration_seconds{stage="..."}` — histogram длительности этапа,
|
||||
- `m2m_deals_total{state="..."}` — counter сделок по итоговому состоянию,
|
||||
- `m2m_sla_breaches_total{stage="...",budget="5m|2m"}` — counter
|
||||
превышений 80% бюджета SLA.
|
||||
|
||||
Endpoint `/metrics` поднимается в `cmd/m2m-core/main.go`.
|
||||
|
||||
### 7. Заменить заглушку `cmd/m2m-core/main.go`
|
||||
|
||||
Минимальный рабочий сервер:
|
||||
- читает конфиг (env: `BJ_DSN`, `BJ_LOG_LEVEL`, ...),
|
||||
- открывает соединение с Postgres,
|
||||
- инициализирует Repository,
|
||||
- поднимает HTTP-эндпоинты `/healthz`, `/metrics`,
|
||||
- логирует все запуски.
|
||||
|
||||
### 8. Тесты
|
||||
|
||||
- Юнит-тесты FSM (все переходы, в т. ч. недопустимые).
|
||||
- Интеграционный тест с PostgreSQL через `testcontainers-go` (или
|
||||
`dockertest`): создал сделку, обновил, прочитал, проверил
|
||||
идемпотентность по GUID.
|
||||
- Тест `enrich.go` на эталонной заявке (fixtures из примеров ESIA
|
||||
Finance API).
|
||||
|
||||
## Требования
|
||||
|
||||
- Без эмодзи. Комментарии — на русском.
|
||||
- `make ci` зелёный.
|
||||
- Покрытие тестами `internal/m2mcore/` — не менее 60%.
|
||||
|
||||
## Коммит
|
||||
|
||||
```
|
||||
feat(m2m-core): FSM сделки, репозиторий на pgx, идемпотентность по GUID, метрики SLA
|
||||
|
||||
- internal/m2mcore/fsm.go: конечный автомат с переходами и аудит-событиями
|
||||
- internal/m2mcore/deal.go: доменная модель сделки
|
||||
- internal/m2mcore/repo.go: репозиторий на pgx с идемпотентным Create
|
||||
- internal/m2mcore/ports.go: интерфейсы для внешних зависимостей (заглушки)
|
||||
- internal/m2mcore/enrich.go: сборка M2MTransferRequest из заявки + Fansy
|
||||
- internal/m2mcore/metrics.go: Prometheus-метрики этапов и SLA
|
||||
- cmd/m2m-core/main.go: минимальный сервер с /healthz и /metrics
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## После коммита
|
||||
|
||||
Обновить `docs/tasks/README.md`: PR-4 — «выполнено».
|
||||
@@ -0,0 +1,132 @@
|
||||
# PR-5: Каркас `nsd-adapter` — клиент к ИШ НРД (REST), резерв через WS ONYX
|
||||
|
||||
## Цель
|
||||
|
||||
Реализовать транспорт к НРД. Основной канал — Интеграционный шлюз НРД
|
||||
через REST API (ИШ сам подписывает и упаковывает пакеты ЭДО, нам
|
||||
XMLDSig не нужен). Резерв — WS ONYX (с подписью на нашей стороне через
|
||||
`crypto-service`, реализуется когда КриптоПро JCP будет доступен).
|
||||
|
||||
## Зависимости
|
||||
|
||||
- PR-1 (Go-модели).
|
||||
- PR-4 (`m2m-core` — туда инжектим `NSDSender`).
|
||||
- Внешние: установленный ИШ НРД на ВМ, тестовые сертификаты GUEST/TEST3.
|
||||
|
||||
## Состояние блокеров
|
||||
|
||||
Этот PR можно начать **только после**:
|
||||
|
||||
- НРД выдал тестовые сертификаты GUEST/TEST3 (ГОСТ или RSA);
|
||||
- получен и установлен дистрибутив Интеграционного шлюза;
|
||||
- доступен REST-эндпоинт ИШ (обычно `http://localhost:8080/api/...`).
|
||||
|
||||
До этого — оставить PR-5 в очереди, не блокировать другие PR.
|
||||
|
||||
## Источники
|
||||
|
||||
- `DOC/Инструкция по передаче эталонного запроса на перевод M2M 08.04 (1).pdf`
|
||||
- `DOC/Презентация MOEX MOST.pdf`
|
||||
- `DOC/instr_podkl_stend_v3.pdf`
|
||||
- `DOC/Ссылки для доступа в тестовые контуры.pdf`
|
||||
|
||||
## Состав PR
|
||||
|
||||
### 1. REST-клиент ИШ
|
||||
|
||||
`internal/nsdadapter/igw/client.go`:
|
||||
|
||||
Методы:
|
||||
- `SendPackage(ctx, channel, packageType, body []byte) (packageID string, err error)`
|
||||
→ `POST /api/package/{channel}/file`, тело: ZIP в base64 в JSON.
|
||||
- `GetStatus(ctx, packageID) (Status, err error)`
|
||||
→ `GET /api/package/status/{id}`.
|
||||
- `ListIncoming(ctx, channel, since time.Time, packageType string) ([]Package, error)`
|
||||
→ `GET /api/package?channel=&date=&type=...`.
|
||||
|
||||
Поддержка типов пакетов: `#M2MTR`, `#M2MTD`, `#M2MER`, `SUBBR`, `SUBER`,
|
||||
`SUB16`, Assets_investment_*, стандартные квитанции ЭДО.
|
||||
|
||||
### 2. Маршрутизация и пакетирование
|
||||
|
||||
`internal/nsdadapter/router.go`:
|
||||
|
||||
Функция «доменное сообщение → тип пакета ЭДО + содержимое ZIP».
|
||||
|
||||
Каждое сообщение M2M упаковывается в ZIP вместе с `config.xml` по
|
||||
Правилам ЭДО — но если ИШ работает в режиме «принимаю XML, сам
|
||||
формирую пакет», достаточно отправить чистый XML и тип пакета.
|
||||
|
||||
### 3. Реализация `NSDSender` из PR-4
|
||||
|
||||
`internal/nsdadapter/sender.go`:
|
||||
|
||||
Реализует интерфейс `m2mcore.NSDSender`, использует REST-клиент ИШ.
|
||||
|
||||
### 4. Конфигурация
|
||||
|
||||
`internal/nsdadapter/config.go`:
|
||||
|
||||
Профили: `guest-gost`, `guest-rsa`, `test3-gost`, `test3-rsa`,
|
||||
`prod-gost`, `prod-rsa`.
|
||||
|
||||
Каждый профиль: URL ИШ, путь к ключевому контейнеру (на стороне ИШ),
|
||||
таймауты, retry-политика.
|
||||
|
||||
### 5. Резервный канал WS ONYX (опц., если время позволяет)
|
||||
|
||||
`internal/nsdadapter/onyx/`:
|
||||
|
||||
SOAP-клиент к `OnyxEdoWSService`. Подпись пакета через
|
||||
`crypto-service` (gRPC). Реализуется когда `crypto-service` будет
|
||||
готов (PR-6).
|
||||
|
||||
В PR-5 — структуры и заглушка с TODO.
|
||||
|
||||
### 6. Опрос входящих
|
||||
|
||||
`cmd/nsd-adapter/main.go`:
|
||||
|
||||
Минимальный сервис: каждые N секунд (конфиг) делает
|
||||
`ListIncoming` для актуальных типов пакетов, скачивает новые,
|
||||
сохраняет в БД (`incoming_packages` таблица), эмитит событие в
|
||||
`m2m-core` через шину или прямой вызов.
|
||||
|
||||
### 7. Интеграционный тест на стенде
|
||||
|
||||
`internal/nsdadapter/igw/integration_test.go`:
|
||||
|
||||
- Помечен `//go:build integration`.
|
||||
- Запускает эталонный запрос из
|
||||
`DOC/Инструкция по передаче эталонного запроса на перевод M2M 08.04 (1).pdf`
|
||||
на TEST3.
|
||||
- Проверяет, что приходит `#M2MTD` (от тестового брокера 2) или
|
||||
`#M2MER` (тех. ошибка).
|
||||
- Поднимается только когда `BJ_INTEGRATION_TEST_NSD=1`.
|
||||
|
||||
## Требования
|
||||
|
||||
- Логировать каждое обращение к ИШ (метод, URL, HTTP-статус,
|
||||
package_id, длительность). **Не логировать содержимое пакета**
|
||||
(там могут быть ПДн).
|
||||
- Маскировать ПДн (ФИО, документы) в любых логах.
|
||||
- Без эмодзи.
|
||||
|
||||
## Коммит
|
||||
|
||||
```
|
||||
feat(nsd-adapter): REST-клиент ИШ НРД + маршрутизация типов пакетов
|
||||
|
||||
- internal/nsdadapter/igw/: REST-клиент ИШ (SendPackage, GetStatus, ListIncoming)
|
||||
- internal/nsdadapter/router.go: маршрутизация по типам пакетов ЭДО
|
||||
- internal/nsdadapter/sender.go: реализация m2mcore.NSDSender
|
||||
- internal/nsdadapter/config.go: профили GUEST/TEST3/PROD x ГОСТ/RSA
|
||||
- internal/nsdadapter/onyx/: каркас резервного канала WS ONYX
|
||||
- cmd/nsd-adapter/main.go: опрос входящих пакетов
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## После коммита
|
||||
|
||||
Обновить `docs/tasks/README.md`: PR-5 — «выполнено».
|
||||
@@ -0,0 +1,166 @@
|
||||
# PR-6: Каркас `crypto-service` — Java + КриптоПро JCP, gRPC по UDS
|
||||
|
||||
## Цель
|
||||
|
||||
Реализовать сервис криптографических операций по ГОСТ:
|
||||
|
||||
- проверка подписи входящих квитанций ЭДО, ответов НРД и сообщений
|
||||
от брокеров;
|
||||
- **серверная подпись действий оператора** в `admin-ui` (ради
|
||||
соблюдения SLA 2 мин);
|
||||
- резервный канал отправки в НРД через WS ONYX напрямую (когда ИШ
|
||||
не задействован — упаковка и подпись на нашей стороне);
|
||||
- криптографические проверки целостности эталонов в MinIO.
|
||||
|
||||
## Зависимости
|
||||
|
||||
- PR-1 (Go-модели).
|
||||
- PR-4 (`m2m-core` — реализуем `CryptoVerifier`).
|
||||
- Внешние: лицензия и дистрибутив КриптоПро CSP + JCP под РЕД ОС.
|
||||
|
||||
## Состояние блокеров
|
||||
|
||||
Этот PR можно начать **только после**:
|
||||
|
||||
- получены лицензии КриптоПро CSP и JCP;
|
||||
- установлен КриптоПро CSP на dev-ВМ;
|
||||
- доступны тестовые ключевые контейнеры.
|
||||
|
||||
До этого — заглушка с gRPC-протоколом, без реальной криптографии.
|
||||
|
||||
## Источники
|
||||
|
||||
- `docs/architecture/plan.md` — раздел «Криптография: Go + ГОСТ» и
|
||||
«Подпись действий оператора».
|
||||
- Документация КриптоПро JCP.
|
||||
- Apache Santuario (XMLDSig).
|
||||
|
||||
## Состав PR
|
||||
|
||||
### 1. gRPC-протокол
|
||||
|
||||
`services/crypto-service/proto/crypto.proto`:
|
||||
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
package bridge_and_joins.crypto.v1;
|
||||
|
||||
service CryptoService {
|
||||
// Проверка подписи XMLDSig в пакете ЭДО.
|
||||
rpc VerifyXMLDSig(VerifyRequest) returns (VerifyResponse);
|
||||
|
||||
// Подпись XML по ГОСТ — для резервного канала WS ONYX и для
|
||||
// действий оператора.
|
||||
rpc SignXMLDSig(SignRequest) returns (SignResponse);
|
||||
|
||||
// Health-check.
|
||||
rpc Health(HealthRequest) returns (HealthResponse);
|
||||
}
|
||||
|
||||
message VerifyRequest {
|
||||
bytes payload = 1; // XML с подписью
|
||||
string profile = 2; // "guest-gost" | "test3-gost" | "prod-gost" | ...
|
||||
}
|
||||
|
||||
message VerifyResponse {
|
||||
bool valid = 1;
|
||||
string signer_cn = 2; // CN из сертификата
|
||||
string signer_inn = 3; // ИНН из сертификата (если есть)
|
||||
string serial = 4;
|
||||
int64 not_before = 5; // unix epoch
|
||||
int64 not_after = 6;
|
||||
repeated string errors = 7;
|
||||
}
|
||||
|
||||
message SignRequest {
|
||||
bytes payload = 1; // канонизированный XML
|
||||
string key_alias = 2; // алиас ключа в JCP-keystore
|
||||
string profile = 3;
|
||||
}
|
||||
|
||||
message SignResponse {
|
||||
bytes signed_xml = 1;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Java-проект
|
||||
|
||||
Структура:
|
||||
```
|
||||
services/crypto-service/
|
||||
├── build.gradle.kts — Gradle с Liberica JDK 21
|
||||
├── src/main/java/.../CryptoServer.java — main, gRPC сервер
|
||||
├── src/main/java/.../VerifyHandler.java — Santuario verify
|
||||
├── src/main/java/.../SignHandler.java — Santuario sign
|
||||
├── src/main/java/.../KeystoreProvider.java — Provider-абстракция
|
||||
│ (КриптоПро / Валидата / ...)
|
||||
└── src/test/java/.../*Test.java
|
||||
```
|
||||
|
||||
Зависимости:
|
||||
- gRPC Java + protoc-gen-java,
|
||||
- Apache Santuario с ГОСТ-патчем,
|
||||
- КриптоПро JCP (jar поставляется заказчиком вместе с лицензией).
|
||||
|
||||
### 3. Бинд на UDS
|
||||
|
||||
Сервер слушает Unix Domain Socket по пути из конфига (`/run/bj/crypto.sock`),
|
||||
а не TCP — минимальная задержка, изоляция от сети.
|
||||
|
||||
### 4. Provider-абстракция
|
||||
|
||||
`KeystoreProvider` — интерфейс с реализациями `CryptoProJcpProvider`,
|
||||
`ValidataJcpProvider` (заглушка), `VipNetProvider` (заглушка). Выбор —
|
||||
через конфиг (env: `BJ_CRYPTO_PROVIDER=cryptopro`).
|
||||
|
||||
### 5. Go-клиент
|
||||
|
||||
`internal/cryptocli/client.go`:
|
||||
|
||||
Клиент gRPC по UDS, реализует `m2mcore.CryptoVerifier`. Используется
|
||||
из `lk-gateway` (верификация заявления), `m2m-core` (верификация
|
||||
квитанций НРД), `nsd-adapter/onyx` (подпись для резервного канала).
|
||||
|
||||
### 6. Тесты
|
||||
|
||||
- Юнит-тесты Java на эталонах: подпиши тестовым ключом → провер'
|
||||
→ должен быть `valid=true`.
|
||||
- Юнит-тесты Go-клиента на mock-сервере gRPC.
|
||||
- Интеграционный тест (помечен `//go:build integration`): запускает
|
||||
crypto-service как процесс и проверяет подпись/проверку
|
||||
эталонной квитанции.
|
||||
|
||||
### 7. Сборка и упаковка
|
||||
|
||||
- `Dockerfile` для `crypto-service` (Liberica JDK 21 base).
|
||||
- Подключение к `deploy/docker-compose/docker-compose.yml` (mount UDS
|
||||
как volume).
|
||||
|
||||
## Требования
|
||||
|
||||
- **Закрытые ключи КриптоПро никогда не логируются и не выгружаются**
|
||||
через API. Только handle на keystore.
|
||||
- Каждая операция подписи — аудит-запись в журнале (`audit.log` или
|
||||
отдельный gRPC stream): кто (оператор/системный ключ), что
|
||||
подписано (sha256 от payload), когда.
|
||||
- Без эмодзи.
|
||||
|
||||
## Коммит
|
||||
|
||||
```
|
||||
feat(crypto-service): gRPC-каркас сервиса криптографии (КриптоПро JCP)
|
||||
|
||||
- services/crypto-service/proto/crypto.proto — protobuf-контракт
|
||||
- services/crypto-service/ — Java 21 + gRPC, заглушки Verify/Sign
|
||||
- internal/cryptocli/ — Go-клиент по UDS, реализует CryptoVerifier
|
||||
- deploy/docker-compose/docker-compose.yml — подключение сервиса
|
||||
|
||||
Реальная подпись КриптоПро подключается после получения лицензии и
|
||||
ключевых контейнеров от заказчика.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## После коммита
|
||||
|
||||
Обновить `docs/tasks/README.md`: PR-6 — «выполнено».
|
||||
@@ -0,0 +1,48 @@
|
||||
# docs/tasks — задачи разработки
|
||||
|
||||
Здесь лежат **готовые промпты** для Claude Code, выполняемые в порядке
|
||||
PR-1 → PR-N. Каждая задача — самостоятельный осмысленный PR в `main`.
|
||||
|
||||
Архитектурный контекст и обоснование решений — в
|
||||
`docs/architecture/plan.md` (полный план проекта) и
|
||||
`docs/architecture/overview.md` (краткая выжимка).
|
||||
|
||||
## Очередь задач
|
||||
|
||||
| PR | Файл | Статус | Зависит от |
|
||||
|----|------|--------|-----------|
|
||||
| PR-1 | `PR-1-go-models-m2m.md` | готово к запуску | — |
|
||||
| PR-2 | `PR-2-fansy-ddl.md` | готово к запуску | — (параллельно с PR-1) |
|
||||
| PR-3 | `PR-3-lk-openapi.md` | готово к запуску | — (параллельно с PR-1) |
|
||||
| PR-4 | `PR-4-m2m-core-skeleton.md` | готово к запуску | PR-1 |
|
||||
| PR-5 | `PR-5-nsd-adapter-skeleton.md` | ждёт ИШ НРД и сертификаты | PR-1, PR-4 |
|
||||
| PR-6 | `PR-6-crypto-service-skeleton.md` | ждёт КриптоПро JCP | PR-1 |
|
||||
|
||||
## Как запустить задачу
|
||||
|
||||
На dev-ВМ под `dev`, в корне репо:
|
||||
|
||||
```bash
|
||||
cd /srv/dev/Bridge-and-Join-s
|
||||
git pull
|
||||
claude
|
||||
```
|
||||
|
||||
В сессии Claude Code:
|
||||
|
||||
> Прочитай `docs/tasks/PR-1-go-models-m2m.md` и выполни задачу полностью.
|
||||
> По завершении сделай commit и push в `main` (или открой MR, если так
|
||||
> принято), обнови статус задачи в `docs/tasks/README.md` с «готово к
|
||||
> запуску» на «выполнено» с указанием sha коммита.
|
||||
|
||||
## Соглашения
|
||||
|
||||
- **Без эмодзи** в коде и комментариях.
|
||||
- Комментарии в коде — на русском, имена типов и полей — на английском
|
||||
как в XSD/контрактах.
|
||||
- Каждый PR проходит `make ci` зелёным.
|
||||
- Перед коммитом — `go mod tidy`, `make fmt`, `make lint`.
|
||||
- Сообщение коммита: `<тип>(<область>): <короткое описание>` +
|
||||
расшифровка в теле.
|
||||
- Документация изменений — в README соответствующего модуля
|
||||
(`internal/<...>/README.md`).
|
||||
Reference in New Issue
Block a user