Настройки: «Кабинет клиента» (наш модуль) и «ЕСИА Финанс» (внешняя платформа) — отдельные разделы

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-18 14:46:20 +03:00
parent 4f4f70c530
commit bdaef4dc39
6 changed files with 26 additions and 18 deletions
+5 -5
View File
@@ -102,7 +102,7 @@ func lkDistFiles(s Settings, coreURL string) ([]struct {
BJ_MODE=%s
# Адрес ядра bj, к которому обращается кабинет (только для режима direct):
%s
# Ключ доступа модуля — из настроек ядра, раздел «Личный кабинет». Оставьте пустым,
# Ключ доступа модуля — из настроек ядра, раздел «Кабинет клиента». Оставьте пустым,
# чтобы ввести его в установщике; заполните — если ставите без браузера.
BJ_KEY=
# Адрес и порт, на которых кабинет слушает (за ним обычно стоит nginx с TLS):
@@ -186,7 +186,7 @@ echo "Проверка службы: curl -s http://127.0.0.1:8099/health"
спросит способ связи с ядром и ключ доступа, проверит связь и предложит
завести администратора кабинета. Настройки он сохранит в файл lk.json
(каталог LK_DATA, права 0600). Ключа в этом архиве нет — берите его из
настроек ядра, раздел «Личный кабинет».
настроек ядра, раздел «Кабинет клиента».
4. Проверка службы: curl -s http://127.0.0.1:8099/health — "ok":true.
Установка без браузера: заполните BJ_KEY (и BJ_URL для режима direct) в lk.env и
@@ -194,7 +194,7 @@ echo "Проверка службы: curl -s http://127.0.0.1:8099/health"
Настройки (файл /etc/bj-lk/lk.env):
BJ_URL — адрес ядра bj: %s
BJ_KEY — ключ доступа модуля, он же в настройках ядра, раздел «Личный кабинет»
BJ_KEY — ключ доступа модуля, он же в настройках ядра, раздел «Кабинет клиента»
LISTEN — адрес и порт кабинета (по умолчанию 127.0.0.1:8099)
LK_TITLE — заголовок кабинета: %s
После изменения файла: sudo systemctl restart bj-lk
@@ -220,7 +220,7 @@ echo "Проверка службы: curl -s http://127.0.0.1:8099/health"
ждёт, пока ядро само подключится к нему по имени %s, заберёт запросы
клиентов и вернёт ответы. Наружу из сети депозитария идёт только
исходящее соединение, порты открывать не нужно. В настройках ядра
(«Личный кабинет» → связь) выберите «Ядро подключается к кабинету» и
(«Кабинет клиента» → связь) выберите «Ядро подключается к кабинету» и
укажите адрес этого сервера.
Сеть и безопасность:
@@ -236,7 +236,7 @@ echo "Проверка службы: curl -s http://127.0.0.1:8099/health"
страница не запрашивает;
Обновления. Кабинет обновляется отдельно от ядра: новую версию скачивайте на
странице настроек ядра, раздел «Личный кабинет», и ставьте тем же install.sh —
странице настроек ядра, раздел «Кабинет клиента», и ставьте тем же install.sh —
настройки при этом сохраняются. Версии кабинета и ядра должны быть совместимы;
если ядро старше, кабинет покажет предупреждение администратору.
@@ -14,7 +14,7 @@
<p>В обоих случаях ключа в архиве нет — его вводят в установщике, открыв адрес кабинета в браузере. Способы связи с ядром (кабинет → ядро или ядро → кабинет) одинаковы для всех вариантов.</p>
<h3>Шаг 1. Ключ и архив</h3>
<p>Настройки → «Личный кабинет» → «Кабинет клиента на своём сервере»: создайте ключ доступа (он показан на странице целиком — его нужно ввести в установщике) и скачайте архив. В архиве — исполняемый файл, служба systemd, файл настроек службы, установщик и README. Ключа в архиве нет.</p>
<p>Настройки → «Кабинет клиента» → «Кабинет клиента на своём сервере»: создайте ключ доступа (он показан на странице целиком — его нужно ввести в установщике) и скачайте архив. В архиве — исполняемый файл, служба systemd, файл настроек службы, установщик и README. Ключа в архиве нет.</p>
<h3>Шаг 2а. PHP-хостинг: файлы в каталог сайта</h3>
<p>Создайте в панели хостинга домен (например, <code>lk.депозитарий.ru</code>) с сертификатом, скопируйте <code>index.php</code> и <code>.htaccess</code> в его каталог и откройте адрес в браузере — запустится установщик (шаг 3). Настройки ретранслятор положит в каталог <code>bj-lk-data</code> рядом с сайтом, если хостинг разрешает туда писать, иначе — в <code>data</code> внутри сайта, закрытый правилами <code>.htaccess</code>. Если у хостинга nginx без <code>.htaccess</code> — правила из README архива.</p>
@@ -12,7 +12,8 @@
<button data-sec="users"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.5"/><path d="M3 20c0-3.3 2.7-6 6-6s6 2.7 6 6"/><circle cx="17" cy="9" r="2.5"/><path d="M15.5 14.5c2.8.3 5.5 2.5 5.5 5.5"/></svg></span>Пользователи<span class="ind {{if .Users.Open}}warn{{else}}ok{{end}}"></span></button>
<button data-sec="crypto"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg></span>Криптография<span class="ind {{if .Settings.Crypto.Profile}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="nsd"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18M4 21V10M20 21V10M3 10l9-6 9 6M8 21v-7M12 21v-7M16 21v-7"/></svg></span>НРД<span class="ind {{if .Settings.NSD.IGWBaseURL}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="lk"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M6 16c.4-1.4 1.6-2.2 3-2.2s2.6.8 3 2.2"/><path d="M15 10h4M15 13h3"/></svg></span>Личный кабинет <span class="muted" style="font-size:10px;font-weight:500">ЕСИА Финанс</span><span class="ind {{if .Settings.LK.PublicURL}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="cabinet"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="9" r="3.2"/><path d="M6 19c.6-3 3-4.6 6-4.6s5.4 1.6 6 4.6"/><rect x="3" y="4" width="18" height="16" rx="2"/></svg></span>Кабинет клиента<span class="ind {{if .Settings.LK.APIKey}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="lk"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M6 16c.4-1.4 1.6-2.2 3-2.2s2.6.8 3 2.2"/><path d="M15 10h4M15 13h3"/></svg></span>ЕСИА Финанс<span class="ind {{if .Settings.LK.PublicURL}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="tests"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6M10 3v6l-5 8.5A2 2 0 0 0 6.7 21h10.6a2 2 0 0 0 1.7-3.5L14 9V3"/><path d="M8 15h8"/></svg></span>Диагностика</button>
<button data-sec="alerts"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg></span>Оповещения<span class="ind {{if or .Settings.Alerts.SMTP.Enabled .Settings.Alerts.Zabbix.Enabled}}ok{{end}}"></span></button>
<button data-sec="update"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20V8M6 12l6-6 6 6"/><path d="M5 4h14"/></svg></span>Обновления{{if .Settings.Update.Available}}<span class="ind warn"></span>{{end}}</button>
@@ -614,9 +615,10 @@ function hbBind(inp,box,list,onPick){
</section>
{{/* ============ ЛИЧНЫЙ КАБИНЕТ ============ */}}
<section class="settings-section" id="sec-lk">
<h1>Личный кабинет <span class="muted" style="font-size:16px;font-weight:500">· ЕСИА Финанс</span></h1>
<p class="muted" style="margin:-8px 0 16px">Интеграция с платформой ЛК <strong>ЕСИА Финанс</strong>: адрес для клиента, приём заявок M2M, возврат статуса и подключение к API (тест/бой). НРД настраивается отдельно — в разделе «НРД».</p>
{{/* ============ КАБИНЕТ КЛИЕНТА (наш модуль bj-lk) ============ */}}
<section class="settings-section" id="sec-cabinet">
<h1>Кабинет клиента</h1>
<p class="muted" style="margin:-8px 0 16px">Наш личный кабинет для клиентов депозитария: модуль <code>bj-lk</code> на своём сервере или PHP-хостинге, связь с ядром, учётные записи клиентов и сотрудников. Интеграция с платформой ЕСИА Финанс — отдельный раздел.</p>
{{template "verline" (.Versions.Get "bj-lk")}}
<div class="card" id="sec-lk-dist">
@@ -728,6 +730,12 @@ function hbBind(inp,box,list,onPick){
</div>
</div>
</section>
{{/* ============ ЕСИА ФИНАНС (внешняя платформа ЛК) ============ */}}
<section class="settings-section" id="sec-lk">
<h1>ЕСИА Финанс</h1>
<p class="muted" style="margin:-8px 0 16px">Интеграция с внешней платформой личного кабинета <strong>ЕСИА Финанс</strong>: адрес для клиента, приём заявок M2M, возврат статуса и подключение к API (тест/бой). Наш собственный кабинет настраивается в разделе «Кабинет клиента».</p>
<div class="card">
<h2><span class="dot {{if .Settings.LK.PublicURL}}ok{{else}}warn{{end}}"></span>Личный кабинет — интеграция</h2>
<p class="muted">Адрес ЛК (стенд/бой), куда клиент подаёт заявку M2M. Заявка приходит к нам по контракту <code>POST /api/v1/back_office/claims/</code>, а мы возвращаем статус через <strong>Callback URL</strong>.</p>
+1 -1
View File
@@ -217,7 +217,7 @@ func (s *Server) installConnect(w http.ResponseWriter, r *http.Request, d instal
d.Cfg = cfg
switch {
case cfg.BJKey == "":
d.Error = "Укажите ключ доступа модуля — он создаётся в настройках ядра, раздел «Личный кабинет»."
d.Error = "Укажите ключ доступа модуля — он создаётся в настройках ядра, раздел «Кабинет клиента»."
case !cfg.Agent && cfg.BJURL == "":
d.Error = "Укажите адрес ядра или выберите режим «ядро подключается к кабинету»."
case !cfg.Agent && !strings.HasPrefix(cfg.BJURL, "https://") && cfg.insecureCore():
+4 -4
View File
@@ -486,7 +486,7 @@ function installer(array $cfg): never
$vals['bj_url'] = rtrim($vals['bj_url'], '/');
$new = ['mode' => $vals['mode'] === 'agent' ? 'agent' : 'direct', 'bj_url' => $vals['bj_url'], 'bj_key' => $vals['bj_key'], 'title' => $vals['title']];
if ($new['bj_key'] === '') {
$error = 'Укажите ключ доступа модуля — он создаётся в настройках ядра, раздел «Личный кабинет».';
$error = 'Укажите ключ доступа модуля — он создаётся в настройках ядра, раздел «Кабинет клиента».';
} elseif ($new['mode'] === 'direct' && $new['bj_url'] === '') {
$error = 'Укажите адрес ядра или выберите режим «ядро подключается к кабинету».';
} elseif ($new['mode'] === 'direct' && !str_starts_with($new['bj_url'], 'https://') && !preg_match('~^http://(127\.0\.0\.1|localhost)~', $new['bj_url'])) {
@@ -557,7 +557,7 @@ function installer(array $cfg): never
. '<label class="radio"><input type="radio" name="mode" value="direct"' . ($vals['mode'] !== 'agent' ? ' checked' : '') . '> <span><b>Кабинет обращается к ядру</b> — у ядра есть адрес, доступный с этого хостинга.</span></label>'
. '<label class="radio"><input type="radio" name="mode" value="agent"' . ($vals['mode'] === 'agent' ? ' checked' : '') . '> <span><b>Ядро подключается к кабинету</b> — у ядра нет адреса в интернете; оно само дозвонится сюда.</span></label></div>'
. '<div><label class="l">Адрес ядра (только для первого способа)</label><input type="text" name="bj_url" value="' . h($vals['bj_url']) . '" placeholder="https://bj.депозитарий.ru" autocomplete="off"></div>'
. '<div><label class="l">Ключ доступа модуля</label><input type="password" name="bj_key" value="' . h($vals['bj_key']) . '" autocomplete="off" placeholder="lk-…"><p class="mut" style="margin-top:6px">Создаётся в настройках ядра: «Личный кабинет» → «Создать ключ».</p></div>'
. '<div><label class="l">Ключ доступа модуля</label><input type="password" name="bj_key" value="' . h($vals['bj_key']) . '" autocomplete="off" placeholder="lk-…"><p class="mut" style="margin-top:6px">Создаётся в настройках ядра: «Кабинет клиента» → «Создать ключ».</p></div>'
. '<button class="btn" type="submit">Проверить связь и сохранить</button></form>';
page('Три шага — и кабинет работает', $f, $side, $steps);
}
@@ -578,13 +578,13 @@ function adminForm(string $csrf, string $notice, string $error, array $steps, st
function done(string $side): never
{
page('Кабинет установлен', '<div class="box"><h2>Готово</h2><p class="mut">Клиенты входят по логину и паролю, которые выдаёт депозитарий. Учётные записи заводятся в настройках ядра, раздел «Личный кабинет». Настройки ретранслятора — в ' . h(dataDir()) . '/config.php; чтобы пройти установку заново, удалите его.</p><a class="btn" href="/login">Перейти ко входу</a></div>', $side);
page('Кабинет установлен', '<div class="box"><h2>Готово</h2><p class="mut">Клиенты входят по логину и паролю, которые выдаёт депозитарий. Учётные записи заводятся в настройках ядра, раздел «Кабинет клиента». Настройки ретранслятора — в ' . h(dataDir()) . '/config.php; чтобы пройти установку заново, удалите его.</p><a class="btn" href="/login">Перейти ко входу</a></div>', $side);
}
function installWait(array $cfg): never
{
securityHeaders();
$side = 'В настройках ядра (раздел «Личный кабинет») выберите «Ядро подключается к кабинету» и укажите адрес этого сайта. Ключ должен совпадать.';
$side = 'В настройках ядра (раздел «Кабинет клиента») выберите «Ядро подключается к кабинету» и укажите адрес этого сайта. Ключ должен совпадать.';
if (coreSeen()) {
adminForm(csrfToken(), 'Ядро подключилось к кабинету. Осталось завести администратора.', '', [['Проверка сервера', true], ['Связь с ядром', true], ['Администратор кабинета', true]], $side);
}
+3 -3
View File
@@ -331,7 +331,7 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
{{if $d.Waiting}}
<meta http-equiv="refresh" content="5">
<div class="msg ok">Настройки сохранены. Ждём, когда ядро подключится к кабинету по адресу <b>{{$d.Host}}</b>… Страница обновляется сама.</div>
<p class="mut" style="margin:0">В настройках ядра (раздел «Личный кабинет») выберите «Ядро подключается к кабинету» и укажите этот адрес. Ключ должен совпадать.</p>
<p class="mut" style="margin:0">В настройках ядра (раздел «Кабинет клиента») выберите «Ядро подключается к кабинету» и укажите этот адрес. Ключ должен совпадать.</p>
<input type="hidden" name="step" value="wait">
{{else}}
<input type="hidden" name="step" value="connect">
@@ -356,7 +356,7 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
<div>
<label for="bj_key">Ключ доступа модуля</label>
<input id="bj_key" name="bj_key" type="password" value="{{$d.Cfg.BJKey}}" autocomplete="off" placeholder="lk-…">
<p class="mut" style="margin:6px 0 0">Создаётся в настройках ядра: «Личный кабинет» → «Создать ключ».</p>
<p class="mut" style="margin:6px 0 0">Создаётся в настройках ядра: «Кабинет клиента» → «Создать ключ».</p>
</div>
<button class="btn main" type="submit">Проверить связь и сохранить</button>
{{end}}
@@ -382,7 +382,7 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
{{define "install_done"}}{{template "head" .}}
<div class="login"><section class="side"><span class="brand">{{template "mark" .}}<span class="lbl" style="font-size:12px;letter-spacing:.14em;color:#f3f0e7">Установка кабинета</span></span><div><h1>Кабинет установлен</h1></div><p class="mut" style="color:#8e8879;margin:0">Настройки — в файле <span class="n">{{.File}}</span>. Чтобы пройти установку заново, удалите его.</p></section>
<section class="form"><form action="/login" method="get" style="max-width:420px"><h1 style="margin:0">Готово</h1><p class="mut" style="margin:0">Клиенты входят по логину и паролю, которые выдаёт депозитарий. Учётные записи заводятся в настройках ядра, раздел «Личный кабинет».</p><button class="btn main" type="submit">Перейти ко входу</button></form></section></div>
<section class="form"><form action="/login" method="get" style="max-width:420px"><h1 style="margin:0">Готово</h1><p class="mut" style="margin:0">Клиенты входят по логину и паролю, которые выдаёт депозитарий. Учётные записи заводятся в настройках ядра, раздел «Кабинет клиента».</p><button class="btn main" type="submit">Перейти ко входу</button></form></section></div>
</body></html>{{end}}
{{define "installed"}}{{template "head" .}}