diff --git a/internal/lkgateway/admin.go b/internal/lkgateway/admin.go index e8a7dc2..76f010f 100644 --- a/internal/lkgateway/admin.go +++ b/internal/lkgateway/admin.go @@ -171,6 +171,10 @@ var templateFuncs = template.FuncMap{ "handbookDepos": handbookDepos, "timeZones": func() any { return wizTimeZones }, "timeZoneKnown": timeZoneKnown, + "clientVer": clientVersion, + "verTitle": versionTitle, + "contourRu": contourRu, + "looksErr": looksErr, "intList": func(v ...int) []int { return v }, "nsdSegTip": nsdSegTip, "devOn": authTemplateFuncs["devOn"], diff --git a/internal/lkgateway/npr_proxy_test.go b/internal/lkgateway/npr_proxy_test.go index 1dfef00..b7275be 100644 --- a/internal/lkgateway/npr_proxy_test.go +++ b/internal/lkgateway/npr_proxy_test.go @@ -70,9 +70,15 @@ func TestSetupPageShowsVersions(t *testing.T) { t.Fatalf("код %d: %s", rec.Code, rec.Body.String()) } body := rec.Body.String() - for _, want := range []string{"Версии систем", "21.3.0", "QUIK — Модуль неторговых поручений: 21.3.0 · обновлена 05.06.2026", "не определена", "нет связи"} { + // клиенту (без режима разработчика) — простое название и версия, без подробностей источника + for _, want := range []string{"Версии систем", "21.3.0", "QUIK — модуль неторговых поручений: 21.3.0", "не определена"} { if !strings.Contains(body, want) { t.Errorf("в странице нет %q", want) } } + for _, not := range []string{"обновлена 05.06.2026"} { + if strings.Contains(body, not) { + t.Errorf("клиенту видно %q", not) + } + } } diff --git a/internal/lkgateway/uiclient.go b/internal/lkgateway/uiclient.go new file mode 100644 index 0000000..3b6a62a --- /dev/null +++ b/internal/lkgateway/uiclient.go @@ -0,0 +1,50 @@ +package lkgateway + +// uiclient.go — что интерфейс показывает клиенту, а что только в режиме разработчика (devOn). +// Клиенту — состояние и действия; версии сторонних систем — только те, о которых спрашивает +// поддержка НРД и Московской биржи. Пути, службы, Java, внутренние модули — разработчикам. + +import "strings" + +// clientVersionTitles — версии для клиента и их названия без внутренних имён. +var clientVersionTitles = map[string]string{ + "bj-server": "bj", + "ish": "Шлюз НРД", + "validata": "СКЗИ «Валидата Клиент L»", + "quik-mnp": "QUIK — модуль неторговых поручений", + "depo": "Fancy DEPO", +} + +func clientVersion(key string) bool { _, ok := clientVersionTitles[key]; return ok } + +// versionTitle — название строки версии: разработчику — полное (с внутренним именем), клиенту — простое. +func versionTitle(v SystemVersion) string { + if t, ok := clientVersionTitles[v.Key]; ok && !devMode(globalRC) { + return t + } + return v.Title +} + +// contourRu — контур НРД по-русски (prod-gost, test3, manual… → «боевой», «тестовый (TEST3)»). +func contourRu(s string) string { + l := strings.ToLower(strings.TrimSpace(s)) + switch { + case strings.HasPrefix(l, "prod"): + return "боевой" + case strings.HasPrefix(l, "test"): + return "тестовый (TEST3)" + case strings.HasPrefix(l, "guest"): + return "гостевой" + case l == "manual": + return "добавлен вручную" + case l == "": + return "—" + } + return s +} + +// looksErr — в журнале есть ошибка (журнал клиенту показываем только тогда). +func looksErr(s string) bool { + l := strings.ToLower(s) + return strings.Contains(l, "ошиб") || strings.Contains(l, "не удалось") || strings.Contains(l, "error") || strings.Contains(l, "откат") +} diff --git a/internal/lkgateway/versions.go b/internal/lkgateway/versions.go index fa4bc61..b4b7d63 100644 --- a/internal/lkgateway/versions.go +++ b/internal/lkgateway/versions.go @@ -137,7 +137,7 @@ func versionProbes(rc *RuntimeConfig) []versionProbe { fn: func(ctx context.Context) (string, string, error) { return componentVersion(ctx, "bj-component-install") }}, - {key: "bj-npr", title: "Модуль «НПР / УДС» (bj-npr)", section: "npr", when: comp("bj-npr"), + {key: "bj-npr", title: "Модуль «НПР / УДС» (bj-npr)", section: "quikexport", when: comp("bj-npr"), fn: func(ctx context.Context) (string, string, error) { return componentVersion(ctx, "bj-npr") }}, {key: "bj-quikexport", title: "Модуль «Экспорт QUIK» (bj-quikexport)", section: "quikexport", when: comp("bj-quikexport"), fn: func(ctx context.Context) (string, string, error) { diff --git a/internal/lkgateway/web/templates/admin_setup.html b/internal/lkgateway/web/templates/admin_setup.html index 20c02a5..ae44ae0 100644 --- a/internal/lkgateway/web/templates/admin_setup.html +++ b/internal/lkgateway/web/templates/admin_setup.html @@ -45,14 +45,14 @@
Что установлено на этом сервере и с чем работает bj: собственные компоненты и внешние системы. Та же версия показана в разделе каждого модуля. Сведения на {{msk .Versions.At}}.
+bj и системы, с которыми он работает. Сведения на {{msk .Versions.At}}.
| Система | Версия | Подробности | |
|---|---|---|---|
| {{if and .Section (ne .Section "overview")}}{{.Title}}{{else}}{{.Title}}{{end}} | +|||
| Система | Версия | {{if devOn}}Подробности | {{end}}|
| {{if and .Section (ne .Section "overview")}}{{verTitle .}}{{else}}{{verTitle .}}{{end}} | {{if .Version}}{{.Version}}{{else}}не определена{{end}} | -{{.Detail}}{{with .Err}} {{.}}{{end}} | -{{.Detail}}{{with .Err}} {{.}}{{end}} | {{end}} + {{end}}{{end}}
Журнал сделок m2m-core и принимающая БД. Сейчас: {{if .Settings.Postgres.DSN}}подключено{{else}}in-memory (данные не сохраняются){{end}}.
Здесь bj хранит переводы, журнал и настройки. Сейчас: {{if .Settings.Postgres.DSN}}подключена{{else}}не подключена — данные не сохраняются{{end}}.
{{if and devOn (not .Settings.Postgres.DSN)}}| Роль | Что разрешено |
|---|---|
{{.Title}}{{.Key}} | {{.Desc}} |
{{.Title}}{{if devOn}}{{.Key}}{{end}} | {{.Desc}} |
| {{.Title}} | Недоступна: в лицензии нет модуля «{{.Missing}}». |
{{if $U.Modules}}Подключённые модули ({{range $i, $m := $U.Modules}}{{if $i}}, {{end}}«{{$m.Title}}»{{end}}) можно выдать любому пользователю дополнительно к роли. {{end}}Роли и модули показываются по лицензии: права модуля, которого нет в лицензии, не действуют. Настройки и пользователи — только администратор.
@@ -219,7 +219,7 @@ {{else}}Перепроверка групп выключена: роль доменного пользователя меняется только при следующем входе. Укажите сервисную учётную запись выше.{{end}}Если потерян доступ администратора — удалите файл /var/lib/bj/.bj/users.json на сервере: система вернётся в режим первичной настройки.
Если потерян доступ администратора — удалите файл /var/lib/bj/.bj/users.json на сервере: система вернётся в режим первичной настройки.
Если потерян доступ администратора — обратитесь в поддержку ZETIT.
{{end}} @@ -252,18 +252,7 @@Сертификат «{{index $kc "Owner"}}», выдан: {{index $kc "Issuer"}} — действует до {{index $kc "Until"}} (осталось {{index $kc "Days"}} дн.).
- {{if lt (index $kc "Days") 30}}⚠ Сертификат скоро закончится. Получите новый ключ в Удостоверяющем центре Московской биржи и установите его — без этого обмен с НРД остановится.
- Установить новый ключ → - {{else}}Перевыпустили ключ (новый сертификат) или нужен ключ другого контура — заменить ключ: bj поможет подключить флешку или записать новый ключ из архива.
{{end}} -Комплект доверенных сертификатов крипто-сервера НРД поставляется вместе с bj и при обновлении приезжает всем клиентам. bj сам сверяет справочник активного профиля ИШ{{if .NSDCerts.Profile}} ({{.NSDCerts.Profile}}){{end}}: недостающие добавляет (только если их УЦ уже есть в справочнике — боевой сертификат не попадёт в тестовый профиль), старые удаляет строго после разрешённого НРД срока. Каждое изменение — с бэкапом, проверкой подписи и откатом при ошибке; ИШ перезапускается на несколько секунд.
Сертификаты НРД приходят вместе с обновлениями bj. bj сам добавляет недостающие в справочник шлюза НРД и удаляет старые после срока, разрешённого НРД; перед каждым изменением — резервная копия.{{if devOn}}{{if .NSDCerts.Profile}} Профиль {{.NSDCerts.Profile}}.{{end}}{{end}}
| Сертификат | Контур | Действует | Статус | |||
|---|---|---|---|---|---|---|
| {{.Title}} {{.SubjectCN}} · выдан: {{.IssuerCN}} · серийный {{.Serial}} |
- {{.Contour}} | +{{.Title}}{{if devOn}} {{.SubjectCN}} · выдан: {{.IssuerCN}} · серийный {{end}}{{.Serial}} |
+ {{contourRu .Contour}} | {{.ValidFrom}} — {{.ValidTo}} | {{if eq .Kind "ok"}}✓ {{.Status}}{{else if eq .Kind "add"}}⬆ {{.Status}}{{else}}{{.Status}}{{end}}{{if .RemoveNote}} {{.RemoveNote}} {{end}} |
| Владелец | Издатель | Серийный | До | Хранилище |
|---|---|---|---|---|
| {{if eq .Kind "crl"}}CRL{{else}}{{.SubjectCN}}{{if .SelfSigned}} (УЦ){{end}}{{end}} | {{.IssuerCN}} | {{.Serial}} | {{.NotAfter}}{{if .CertNotAfter}} ключ; сертификат до {{.CertNotAfter}} {{end}} | {{.Store}} |
Свои сертификаты можно положить в /var/lib/bj/.bj/nsd-certs/*.cer — они добавляются по тем же правилам и никогда не удаляются автоматически.
Свои сертификаты можно положить в /var/lib/bj/.bj/nsd-certs/*.cer — они добавляются по тем же правилам и никогда не удаляются автоматически.
Анкета участника M2MTransferParticipantForm — НРД требует её перед работой: без регистрации сервис МОСТ отбивает запросы кодом M2M14. bj заполняет анкету по реквизитам фирмы (настройки НРД и справочник участников), даёт проверить и показывает XML, затем отправляет в боевой контур через ИШ (пакет #M2MPF) или письмом на M2MOST@nsd.ru.
НРД требует анкету участника перед началом работы: без регистрации НРД не принимает запросы на переводы. bj заполняет анкету по реквизитам организации, даёт проверить и отправляет в НРД через шлюз (или её можно отправить письмом на M2MOST@nsd.ru).
{{if not .Settings.NSD.IGWBaseURL}}{{if devOn}}mock-режим — без реального ИШ.{{else}}ИШ не настроен — обмен с НРД не выполняется.{{end}}{{else}}Профиль {{.Settings.NSD.Profile}}, ИШ {{.Settings.NSD.IGWBaseURL}}.{{end}}
Ядро и модули работают отдельными службами: если служба модуля не запущена, его раздел в bj отвечает ошибкой связи. Здесь видно состояние и можно перезапустить службу, не заходя на сервер.
| Служба | Что делает | Состояние | С | |||
|---|---|---|---|---|---|---|
| Служба | {{end}}Что делает | Состояние | С | |||
{{.Unit}} |
+ {{if devOn}}{{.Unit}} | {{end}}
{{.Title}} | -{{if .OK}}работает{{else}}{{.State}}{{with .Sub}} / {{.}}{{end}}{{with .Result}} ({{.}}){{end}}{{end}} | +{{if .OK}}работает{{else}}не работает{{if devOn}}: {{.State}}{{with .Sub}} / {{.}}{{end}}{{with .Result}} ({{.}}){{end}}{{end}}{{end}} | {{if .Since}}{{.Since}}{{else}}—{{end}} | -
Запрос актуального справочника участников сервиса (пакет #M2MHR в НРД). В ответ НРД присылает #M2MTH — карту ИНН → MC-код депозитариев/брокеров и перечень мест расчётов. Нужно для сопоставления ИНН контрагента с кодом участника (блокеры вида M2M14/M2M15) и понимания, кто вообще зарегистрирован.
Справочник участников M2M из НРД: по нему bj узнаёт код участника по ИНН контрагента. bj запрашивает его сам; кнопка — запросить сейчас.
Ответ придёт во входящие ИШ (~30-60с). Список появится в логе bj-server и в m2m-handbook.json.
Ответ НРД приходит через 30–60 секунд.
{{.Key}}{{if not .On}}— не входит в лицензию{{end}}{{.Key}}{{end}}{{if not .On}}— не входит в лицензию{{end}}| Подключение к базе DEPO | {{if .Settings.Fancy.Server}}✓ {{.Settings.Fancy.Server}}, база {{.DepoTables.DB}}, логин bj «{{.Settings.Fancy.User}}»{{else}}не настроено{{end}} |
| Таблицы обмена FTV_M2M | {{if .Settings.Fancy.DepoTablesCheckOK}}✓ на месте{{else}}✗ {{.Settings.Fancy.DepoTablesCheck}}{{end}} |
| Таблицы обмена в базе DEPO | {{if .Settings.Fancy.DepoTablesCheckOK}}✓ на месте{{else}}✗ {{.Settings.Fancy.DepoTablesCheck}}{{end}} |
| Запуск обработки | {{if .Settings.Fancy.DepoJobCheckOK}}✓ {{.Settings.Fancy.DepoJobCheck}}{{else}}✗ {{.Settings.Fancy.DepoJobCheck}}{{end}} |
| Обработка событий (процедуры) | {{if .Settings.Fancy.DepoProcCheckOK}}✓ {{.Settings.Fancy.DepoProcCheck}}{{else if .Settings.Fancy.DepoProcCheck}}⚠ {{.Settings.Fancy.DepoProcCheck}}{{else}}не проверялась — «Перепроверить всё»{{end}} |
При сохранении выполняется проверка подключения (Ping). Если БД недоступна — будет ошибка.
+ + +При сохранении bj проверит подключение; если база недоступна — покажет ошибку.
СКЗИ «Валидата Клиент L» проверяет подписи НРД на квитанциях и сообщениях и нужно для работы с ключами и сертификатами (раздел «Ключ»).
{{if .ValidataVer}} -/opt/Validata/VDCSP/opt/Validata/VDCSPbj работает с Валидатой через свою службу криптографии bj-crypto{{if eq .CryptoSvc "active"}} — она запущена{{else}} — сейчас она не запущена: служба ставится обновлением с сервера лицензий (раздел «Лицензия», кнопка «Обновить сейчас»), а работает с ключом, установленным в разделе «Ключ»{{end}}.
bj работает с Валидатой через свою службу криптографии bj-crypto{{if eq .CryptoSvc "active"}} — она запущена{{else}} — сейчас она не запущена: служба ставится обновлением с сервера лицензий (раздел «Лицензия», кнопка «Обновить сейчас»), а работает с ключом, установленным в разделе «Ключ»{{end}}.
⚠ Компонент подписи bj не запущен — установите обновление bj (шаг «Обновление»).
{{end}} {{else}}Валидата на этом сервере не найдена.
{{.Title}}: {{if .Version}}{{.Version}}{{else}}не определена{{end}}{{with .Detail}} · {{.}}{{end}}{{with .Err}} · {{.}}{{end}}
{{end}}{{end}} +{{define "verline"}}{{if and .Title (or devOn (clientVer .Key))}}{{verTitle .}}: {{if .Version}}{{.Version}}{{else}}не определена{{end}}{{if devOn}}{{with .Detail}} · {{.}}{{end}}{{with .Err}} · {{.}}{{end}}{{end}}
{{end}}{{end}} {{/* Сводка «Обмен с DEPO» (Настройка): что подключено и проверено — одним взглядом; формы — под «Перенастроить». */}} {{define "fancyStatus"}}{{$f := .Settings.Fancy}}{{$ok := and $f.Server $f.DepoTablesCheckOK $f.DepoJobCheckOK}} @@ -204,13 +204,13 @@| Компонент | Установлена | Доступна | Служба | |||
|---|---|---|---|---|---|---|
| Компонент | Установлена | Доступна | {{if devOn}}Служба | {{end}}|||
{{.Title}}{{.Name}}{{if eq .Name "crypto-service.jar"}}{{with $.Versions.Get "validata"}}{{if .Version}} · работает с «Валидата Клиент L» {{.Version}}{{end}}{{end}}{{end}} |
+ {{.Title}}{{if devOn}}{{.Name}}{{if eq .Name "crypto-service.jar"}}{{with $.Versions.Get "validata"}}{{if .Version}} · работает с «Валидата Клиент L» {{.Version}}{{end}}{{end}}{{end}} |
{{if .Present}}{{if .Installed}}{{.Installed}}{{else}}неизвестна{{end}}{{else}}не установлен{{end}} | {{if .Available}}{{.Available}}{{if .New}} к установке{{else if .Update}} новее{{end}}{{if .Blocked}} {{.Blocked}} {{end}}{{else}}нет данных{{end}} |
- {{.Unit}} |
+ {{if devOn}}{{.Unit}} | {{end}}
{{if .Update}} |