feat(admin): вкладка «Инструкции» + русификация статусов в UI

В admin-панели lk-gateway добавлен раздел /admin/help — справка по
основным интеграциям, читается прямо на сервере, без выхода во
внешнюю документацию.

Состав /admin/help:
- /admin/help — hub-страница с 4 карточками-ссылками
- /admin/help/database — подключение PostgreSQL, схемы fansy/fansy_staging/m2m_core,
  что подгружается через ETL Fansy и что пишет сама система, роли,
  миграции, полезные запросы
- /admin/help/lk-api — REST-контракт ESIA Finance V1: аутентификация,
  POST/GET/PATCH/list, формат callback'ов и ошибок, эмулятор для тестов,
  примеры curl
- /admin/help/cryptopro — установка КриптоПро CSP на РЕД ОС и Ubuntu,
  ввод серийного номера лицензии (cpconfig), путь к PKCS#11 модулю
  libcppkcs11.so, подключение Рутокен ЭЦП 2.0 для подписи оператора,
  тестирование подписи через csptest и cryptcp
- /admin/help/systems — Интеграционный шлюз НРД (профили guest/test3/prod),
  команда Fansy (порядок согласования контракта), уведомления
  (SMTP/Yandex Messenger/Telegram), контакты команд

Русификация статусов:
- Добавлены template-функции ruState и ruOutcome (в lkgateway и lkemulator)
- "draft" → "Черновик", "confirmed" → "Подтверждена", "rejected" → "Отклонена" и т.д.
- CSS-классы бейджей сохраняются (по исходному state), меняется только
  отображаемый текст. Технические термины (PostgreSQL, ИНН, GUID, REST)
  остаются как есть — они являются именами программного обеспечения.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
fontvielle
2026-05-14 13:53:37 +03:00
parent 978777ff6a
commit 67e81e5d7f
12 changed files with 574 additions and 13 deletions
@@ -0,0 +1,126 @@
{{define "content"}}
<p style="margin-bottom:16px"><a href="/admin/help">← все инструкции</a></p>
<div class="card">
<h2>База данных</h2>
<p class="muted">PostgreSQL 16 (или PostgreSQL Pro Certified). Хранит сделки, журнал событий, справочники и данные, поступающие из внешних систем через ETL.</p>
</div>
<div class="card">
<h2>1. Подключение</h2>
<p>DSN указывается в разделе <a href="/admin/setup">Настройка → PostgreSQL</a>. Формат:</p>
<pre>postgres://USER:PASSWORD@HOST:PORT/DBNAME?sslmode=disable</pre>
<p>Локальный дев-стенд:</p>
<pre>postgres://bj:bj_dev@127.0.0.1:5432/bj?sslmode=disable</pre>
<p class="muted">При сохранении выполняется <code>pgx.Connect</code> и <code>Ping</code>. Если БД недоступна, форма покажет ошибку.</p>
</div>
<div class="card">
<h2>2. Схемы</h2>
<table>
<thead><tr><th>Схема</th><th>Назначение</th><th>Кто пишет</th><th>Кто читает</th></tr></thead>
<tbody>
<tr>
<td><code>fansy_staging</code></td>
<td>Промежуточные таблицы для ETL Fansy</td>
<td>Команда Fansy (роль <code>fansy_etl</code>)</td>
<td>Наша процедура перелива в <code>fansy</code></td>
</tr>
<tr>
<td><code>fansy</code></td>
<td>Рабочие данные: клиенты, документы, ИИС, депо-счета, портфели, справочники ЦБ и участников</td>
<td>Наша процедура перелива (после валидации)</td>
<td>Наша система (роль <code>bj_reader</code>): m2m-core при формировании заявок</td>
</tr>
<tr>
<td><code>m2m_core</code></td>
<td>Сделки M2M, журнал событий FSM</td>
<td>bj-server</td>
<td>bj-server, admin-ui</td>
</tr>
</tbody>
</table>
</div>
<div class="card">
<h2>3. Что подгружается из внешних систем</h2>
<p>Команда Fansy через инкрементный <strong>UPSERT в staging-таблицы</strong>:</p>
<table>
<thead><tr><th>Таблица staging</th><th>SLA свежести</th><th>Что в ней</th></tr></thead>
<tbody>
<tr><td><code>clients</code></td><td>≤ 5 минут</td><td>Анкеты инвесторов (ФИО, дата рождения, ИНН)</td></tr>
<tr><td><code>client_documents</code></td><td>≤ 5 минут</td><td>Документы (паспорт, ИНН и др.)</td></tr>
<tr><td><code>iia_contracts</code></td><td>≤ 5 минут</td><td>Договоры ИИС (тип T12/T03, номер, дата, ИНН брокера)</td></tr>
<tr><td><code>depo_accounts</code></td><td>≤ 5 минут</td><td>Депо-счета и разделы у разных депозитариев</td></tr>
<tr><td><code>portfolios</code></td><td>≤ 1 минута</td><td>Остатки ЦБ (целое/дробное количество, статус обособления)</td></tr>
<tr><td><code>securities</code> / <code>participants</code></td><td>раз в сутки</td><td>Справочники ЦБ и участников MOST</td></tr>
</tbody>
</table>
<p class="muted" style="margin-top:8px">Полный data-dictionary: <code>docs/fansy-contract/v1/data-dictionary.md</code>. Требования к ETL: <code>docs/fansy-contract/v1/etl-requirements.md</code>.</p>
</div>
<div class="card">
<h2>4. Что пишет сама система</h2>
<p>Только в схему <code>m2m_core</code>:</p>
<ul>
<li><code>deals</code> — корневая запись сделки. Уникальность по <code>guid</code> = идемпотентность приёма заявок.</li>
<li><code>deal_events</code> — журнал FSM-событий (event sourcing).</li>
</ul>
<p>Старт сделки происходит при <code>POST /api/v1/back_office/claims/</code>. FSM проходит этапы:</p>
<pre>draft → validated → submitted_to_nsd → awaiting_decision →
confirmed → awaiting_sub16 → done
↘ rejected
↘ timed_out
↘ manual_approval</pre>
</div>
<div class="card">
<h2>5. Учётные записи и роли</h2>
<table>
<thead><tr><th>Роль</th><th>Права</th><th>Создаёт</th></tr></thead>
<tbody>
<tr><td><code>fansy_etl</code></td><td>SELECT/INSERT/UPDATE на <code>fansy_staging.*</code></td><td>миграция <code>000__roles.sql</code></td></tr>
<tr><td><code>bj_reader</code></td><td>SELECT на <code>fansy.*</code></td><td>миграция <code>000__roles.sql</code></td></tr>
<tr><td><code>bj_migrator</code></td><td>Владелец схем, DDL-права</td><td>миграция <code>000__roles.sql</code></td></tr>
</tbody>
</table>
<p class="muted">Пароли проставляются администратором БД через <code>ALTER ROLE</code>, в репозиторий не попадают.</p>
</div>
<div class="card">
<h2>6. Накатывание миграций</h2>
<p>Файлы лежат в <code>migrations/fansy-store/</code> и <code>migrations/m2m-core/</code>. Применить локально:</p>
<pre>cd /home/fontvielle/Bridge-and-Join-s
for f in migrations/fansy-store/*.sql migrations/m2m-core/*.sql; do
podman exec -i bj-postgres psql -U bj -d bj -v ON_ERROR_STOP=1 &lt; "$f"
done</pre>
<p>Порядок:</p>
<ol>
<li><code>fansy-store/000__roles.sql</code> — роли</li>
<li><code>fansy-store/001__schemas.sql</code> — схемы и гранты</li>
<li><code>fansy-store/002__working.sql</code> — рабочая схема</li>
<li><code>fansy-store/003__staging.sql</code> — staging</li>
<li><code>fansy-store/004__seed_participants.sql</code> — справочник участников (НРД, БКС, Ренессанс, Альфа-Банк)</li>
<li><code>m2m-core/001__deals.sql</code> — сделки M2M</li>
<li><code>m2m-core/002__stages.sql</code> — jsonb-колонка истории FSM</li>
</ol>
</div>
<div class="card">
<h2>7. Полезные запросы</h2>
<pre>-- Состояние сделок за последний час
SELECT state, count(*) FROM m2m_core.deals
WHERE created_at &gt; now() - interval '1 hour'
GROUP BY state;
-- Журнал событий по сделке
SELECT created_at, type, actor, payload
FROM m2m_core.deal_events
WHERE deal_id = '...'
ORDER BY created_at;
-- Свежесть данных Fansy
SELECT 'portfolios' AS t, max(loaded_at) FROM fansy_staging.portfolios
UNION ALL SELECT 'clients', max(loaded_at) FROM fansy_staging.clients;</pre>
</div>
{{end}}