# PR-2: DDL принимающей БД для команды Fansy

## Цель

Спроектировать DDL принимающей БД `fansy-store` под требования
документации НРД к данным M2M и передать его команде Fansy как
контракт для их ETL.

ETL **делает команда Fansy** в автоматизированном режиме. Наша
ответственность — схема таблиц, индексы, миграции, типизированный
Go-репозиторий чтения и контракт данных.

## Источники правды

- `DOC/M2MSchemas_260408/*.xsd` — какие поля и типы нужны для
  формирования M2M-сообщений.
- `DOC/Справочник пользователей.pdf` — перечень контрагентов
  (БКС 5406121446, Ренессанс Брокер 7709258228, Альфа-банк 7728168971).
- `docs/architecture/plan.md` — контракт с командой Fansy (раздел
  «Контракт с командой Fansy — что мы передаём»).

## Состав PR

### 1. `docs/fansy-contract/v1/ddl/` — SQL-миграции

PostgreSQL 16 / PostgreSQL Pro Certified. Используй `goose` или
просто пронумерованные файлы `001__init.sql`, `002__staging.sql` и т. д.

Схема разделена на две:
- `fansy_staging` — куда пишет команда Fansy (только их роль может
  делать INSERT/UPDATE);
- `fansy` — рабочая, куда переливаются актуальные данные триггерами
  или процедурами после валидации.

Минимальный набор таблиц (повторяй структуру и в staging, и в
рабочей):

- `clients` — депоненты/инвесторы:
  - `id` (uuid), `inn` (для юрлиц), `last_name`, `first_name`,
    `middle_name`, `birth_date`, `created_at`, `updated_at`.
- `client_documents` — документы инвестора:
  - `id`, `client_id (FK)`, `document_type` (enum по
    `IdentityDocumentCode`), `series`, `number`, `issued_at`,
    `issuer`.
- `iia_contracts` — ИИС-договоры:
  - `id`, `client_id (FK)`, `agreement_type` (`T12` | `T03`),
    `agreement_number`, `agreement_date`, `broker_inn`.
- `depo_accounts` — депо-счета и разделы:
  - `id`, `client_id (FK)`, `deponent_code`, `account_id`,
    `section_id`, `depository_inn`, `is_active`, `is_trading`.
- `settlement_requisites` — реквизиты расчётов:
  - `id`, `inn`, `display_name`, `created_at`.
- `portfolios` — портфели/остатки ЦБ:
  - `id`, `client_id (FK)`, `depo_account_id (FK)`, `security_code`,
    `isin`, `quantity_whole` (numeric), `quantity_fractional`
    (numeric(38,16)), `isolation_status` (`SGDN`), `valued_at`.
- `securities` — справочник ЦБ:
  - `id`, `security_code` (PK), `isin`, `classification`
    (`BOND`|`SHAR`|`MFUN`), `category` (`ORDN`|`PREF`|`UKWN`),
    `security_type`, `security_series`, `reg_number`,
    `fund_class`, `display_name`.
- `participants` — контрагенты-участники сервиса MOST:
  - `id`, `inn` (PK), `ogrn`, `full_name_rus`, `short_name_rus`,
    `display_name_rus`, `full_name_eng`, `short_name_eng`,
    `display_name_eng`, `depository_participant_code`,
    `broker_participant_code`, `is_available_for_m2m`, `comment`.
  - Предзаполни записями из `Справочник пользователей.pdf`.

Дополнительно:
- `etl_errors` — таблица для ошибок выгрузки Fansy (id, source_table,
  source_pk, payload jsonb, error_message, created_at).
- В `_staging`-таблицах поле `loaded_at timestamptz default now()`.

**Индексы.** Минимум: PK, FK, индекс по `inn` и `deponent_code` в
основных таблицах, индекс по `valued_at` в `portfolios`.

**Роль `fansy_etl`.** В отдельном `000__roles.sql`:
- роль `fansy_etl` с правами INSERT/UPDATE/SELECT на схему
  `fansy_staging`;
- роль `bj_reader` с SELECT на схему `fansy` — для нашего
  `m2m-core`/`lk-gateway`;
- DDL-права (CREATE/ALTER/DROP) — только у миграционной роли,
  не у Fansy-ETL.

### 2. `docs/fansy-contract/v1/data-dictionary.md`

Таблица: «поле → семантика → источник в Fansy (если известен) →
nullable → пример». На каждую колонку каждой таблицы.

### 3. `docs/fansy-contract/v1/etl-requirements.md`

Технические требования к процессу выгрузки от команды Fansy:

- Подключение: PostgreSQL, роль `fansy_etl`, отдельная учётная запись.
- Тип load: **инкрементный UPSERT в staging-таблицы** по бизнес-ключу;
  полная перезаливка — только для справочников (`securities`,
  `participants`), не чаще раза в сутки.
- SLA свежести данных:
  - `portfolios` — не позднее 1 минуты после изменения в Fansy;
  - `clients`, `depo_accounts`, `client_documents`, `iia_contracts`
    — не позднее 5 минут;
  - `securities`, `participants` — раз в сутки или по событию.
- Формат timestamp — UTC с явной зоной (`timestamptz`).
- Обработка ошибок: запись в `etl_errors`.
- Окно простоя для регламентных работ — согласовать.

### 4. `docs/fansy-contract/v1/examples/`

- `example-claim.md` — какие поля из БД нужны `m2m-core` для одной
  типовой M2M-заявки (с конкретными SQL-запросами).
- `seed-data.sql` — 5–10 тестовых клиентов, портфелей, заявок для
  совместного приёмочного теста.

### 5. `migrations/fansy-store/`

Скопировать `*.sql` из `docs/fansy-contract/v1/ddl/` — отсюда будут
исполняться миграциями в нашем сервисе.

### 6. Обновить `docs/fansy-contract/v1/README.md`

Описать состав каталога и порядок согласования с командой Fansy.

## Требования к коду

- Все DDL-файлы — на одной кодировке UTF-8.
- Имена таблиц и колонок — `snake_case` английский.
- Комментарии в DDL (`COMMENT ON COLUMN ... IS '...'`) — на русском.
- Без эмодзи.

## Коммит

```
feat(fansy-store): DDL принимающей БД + контракт данных для команды Fansy

- docs/fansy-contract/v1/ddl/ — миграции PostgreSQL
- docs/fansy-contract/v1/data-dictionary.md — словарь данных
- docs/fansy-contract/v1/etl-requirements.md — требования к ETL
- docs/fansy-contract/v1/examples/ — пример заявки + seed-data
- migrations/fansy-store/ — рабочие копии миграций
- предзаполнен справочник контрагентов из DOC/Справочник пользователей.pdf

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
```

## После коммита

1. Обновить `docs/tasks/README.md`: PR-2 — «выполнено».
2. Сообщить заказчику, что DDL готов и можно отправлять команде Fansy.
