feat(m2m): сквозной поток с веб-интерфейсами — lk-gateway BFF + admin UI + lk-emulator + mock NSD
Реализован M2-шаг-1: первый рабочий сквозной поток M2M-заявки от ЛК
через нашу систему и обратно, с двумя видимыми веб-интерфейсами.
internal/nsdadapter/mock/:
- mock NSDSender с реалистичным синтетическим Response и асинхронной
эмиссией Decision через настраиваемую задержку (Confirm/Reject/Timeout)
- использует собственный жизненный цикл, чтобы HTTP-контексты вызывающего
не прерывали эмиссию Decision до истечения DecisionDelay
internal/lkgateway/:
- REST по контракту ESIA Finance V1 (POST/GET/PATCH/list claims)
- admin web UI (/admin/, /admin/claims, /admin/claims/{id}, /admin/status):
- дашборд со статусом подсистем (postgres, crypto-service UDS,
nsd-adapter, lk-emulator callback) и счётчиками сделок
- журнал и карточка заявки с историей FSM, ответом НРД, решением
принимающей стороны и последним callback'ом
- in-memory SeedStore с 5 тестовыми клиентами и счетами депо
- фоновый consumeDecisions: подписан на mock.Sender.Decisions(),
применяет ApplyDecision и отправляет PATCH callback в ЛК
internal/lkemulator/:
- имитация ЛК клиента (порт 8083)
- веб-формы: журнал, форма «новая заявка», карточка заявки
- HTTP-клиент к lk-gateway (создание заявки + регистрация callback URL)
- приёмник PATCH callback'ов, локальное хранилище заявок,
автообновление страницы каждые 3 сек
cmd/lk-gateway/main.go и cmd/lk-emulator/main.go — заглушки заменены
на полные сервисы с graceful shutdown.
Сквозной поток проверен smoke-test'ом: подача заявки через форму
эмулятора → создание сделки в lk-gateway → Send в mock NSD →
эмиссия Decision через 3 сек → ApplyDecision → PATCH callback в ЛК →
эмулятор показывает confirmed. Дашборд lk-gateway: Total=1, Подтверждено=1.
make ci зелёный.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
{{define "content"}}
|
||||
{{if .Error}}<div class="notice error">{{.Error}}</div>{{end}}
|
||||
|
||||
<div class="card">
|
||||
<h2>Подача заявки M2M</h2>
|
||||
<p class="muted">Минимальная форма; остальные поля заполняются автоматически по seed-данным (см. <code>docs/fansy-contract/v1/examples/seed-data.sql</code>).</p>
|
||||
<form method="post" action="/new">
|
||||
<div class="form-row">
|
||||
<label>Инвестор</label>
|
||||
<select name="investor_id" required>
|
||||
{{range .Clients}}
|
||||
<option value="{{.ID}}">{{.LastName}} {{.FirstName}} {{.MiddleName}} (id <code>{{slice .ID 0 8}}</code>)</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Передающий депозитарий ИНН</label>
|
||||
<input type="text" name="transferring_depository_inn" value="0702345678" required pattern="[0-9]{10}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Принимающий депозитарий ИНН</label>
|
||||
<input type="text" name="receiving_depository_inn" value="0710987654" required pattern="[0-9]{10}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Код источника учёта</label>
|
||||
<input type="text" name="cost_info_code" value="MC0010300032" placeholder="оставьте пустым = учёт не ведётся">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Тип ИИС</label>
|
||||
<select name="iia_type">
|
||||
<option value="">— нет ИИС —</option>
|
||||
<option value="T12">T12 (ИИС-1/ИИС-2)</option>
|
||||
<option value="T03" selected>T03 (ИИС-3)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Номер договора ИИС</label>
|
||||
<input type="text" name="iia_number" value="ИИС78/2024">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Дата ИИС</label>
|
||||
<input type="text" name="iia_date" value="2026-01-15" pattern="\d{4}-\d{2}-\d{2}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>ИНН брокера ИИС</label>
|
||||
<input type="text" name="iia_broker_inn" value="0707083893" pattern="[0-9]{10}">
|
||||
</div>
|
||||
|
||||
<h2 style="margin-top:24px">Ценная бумага (1 шт. в эмуляторе)</h2>
|
||||
<div class="form-row">
|
||||
<label>SecurityCode</label>
|
||||
<input type="text" name="security_code" value="MM0766162534" required pattern="[0-9A-Z_/-]{12}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>ISIN</label>
|
||||
<input type="text" name="isin" value="RU0007661625" required pattern="[A-Z]{2}[A-Z0-9]{9}[0-9]">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Количество (целое)</label>
|
||||
<input type="number" name="quantity" value="1500" min="1" required>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Имитировать ответ принимающей стороны</label>
|
||||
<select name="outcome">
|
||||
<option value="confirm" selected>Подтверждение (через 3 сек)</option>
|
||||
<option value="reject">Отказ с кодом 07</option>
|
||||
<option value="timeout">Таймаут — Decision не придёт</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:16px">
|
||||
<button class="btn" type="submit">Отправить заявку</button>
|
||||
<a class="btn btn-secondary" href="/" style="text-decoration:none; padding:10px 20px">Отмена</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user