{{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}}
