Модель данных¶
Что конвейер хранит и как из сохранённого воспроизвести решение. Форматы обмена между модулями (Pydantic-модели и примеры JSON) — в CONTRACTS.md; здесь — таблицы базы данных и файлы, в которых эти форматы лежат.
База — PostgreSQL в Docker, SQLite (data/alfa.db) при локальном запуске; доступ через SQLAlchemy (apps/api/db.py), схема ведётся миграциями Alembic (MIGRATIONS.md).
Таблицы¶
erDiagram
users ||--o{ sessions : "входы"
users ||--o{ loan_applications : "подаёт"
loan_applications ||--o{ application_events : "журнал"
loan_applications ||--o{ application_facts : "факты"
preapprovals }o..o{ loan_applications : "по ИНН, без связи"
| Таблица | Одна строка — это | Основные поля |
|---|---|---|
users |
Пользователь: клиент или сотрудник | role (customer / staff), identity — способ входа (demo:<имя> для демо-профиля, Telegram-идентичность), staff_position — underwriter / risk_manager, выбранная при входе сотрудника |
sessions |
Cookie-сессия | token, user_id, срок действия |
loan_applications |
Заявка | См. ниже |
application_events |
Событие журнала заявки, только добавление | at, actor (system, client:<id>, staff:<id>), kind (status, source, action, decision, error, review, proposal, signature), from_status / to_status, message, data |
application_facts |
Факт по заявке: одно значение из одного источника | name, declared_value, verified_value, source, trust_level (bank > registry > client_document > declared), fetched_at, discrepancy; уникален по паре «название — источник» |
preapprovals |
Последний результат предодобрения по ИНН | approved, amount, computed_at, valid_until (30 дней), result — расчёт целиком |
loan_applications¶
Заявка хранит вход, результаты каждого этапа и служебные поля очереди. JSON-колонки содержат модели из apps/api/contracts.py.
| Поле | Что | Модель |
|---|---|---|
id, user_id, idempotency_key |
Заявка, её автор и ключ идемпотентности подачи (повтор с тем же ключом возвращает ту же заявку) | — |
status |
Статус (PROCESS.md) | ApplicationStatus |
revision |
Версия строки: устаревшая версия в запросе даёт 409 | — |
request |
Что просил клиент: ИНН, цель, сумма, срок, заявленная выручка, оборудование, согласия | ApplicationRequest |
enrichment |
Ответы источников с конвертом вызова (статус, время, попытки, ошибка); факты лежат отдельно в application_facts |
SourceResponse по каждому источнику |
data_quality |
Показатели и уровень качества данных по счёту | DataQuality |
decision |
Последнее решение: статус, маршрут и причины, стоп-факторы, флаги, баллы, PD, грейд, вклады признаков, результат претендента, предложения с расчётом лимита и ставки, контрфактические подсказки, запрошенные документы, дата повторного обращения, версии | Decision |
statements |
Выписки, загруженные клиентом: распознанные обороты, имя файла, размер, SHA-256. null — клиент ещё не отвечал на запрос, [] — продолжил без выписки |
UploadedStatement (apps/api/statements.py) |
offer_valid_until, selected_offer_id |
Срок предложений и выбранное предложение | — |
pending_review |
Предложение комитета, которое ждёт второй подписи | — |
closing |
Сформированные документы с текстом и временем подписи, хэш кода подписания и число попыток, подпись, отлагательные условия, выдача | — (apps/api/disbursement.py) |
attempts, lease_until |
Число запусков расчёта и аренда worker (или «не раньше» для повтора) | — |
created, updated |
Время создания и изменения | — |
Документы формируются один раз при выборе предложения и дальше не меняются; при подписи у каждого появляется время подписи. Файлы выписок не хранятся — только результат разбора и хэш.
Файлы вне базы¶
| Что | Где | Кто пишет |
|---|---|---|
| Синтетический мир: компании, обороты, кредитные истории, исходы | apps/world/out/ (не в git; в Docker — в образе) |
python -m apps.world (apps/world/README.md) |
| Демо-персоны и их выписки из другого банка | apps/world/demo/ |
python -m apps.world.personas (PERSONAS.md) |
| Обученная скоринговая карта, её паспорт и отчёт валидации | apps/ml/scorecard_v1.json, scorecard_v1.training.json, scorecard_v1.validation.json |
python -m apps.ml (apps/ml/README.md) |
| Экспертная карта-претендент | apps/api/scorecards/scorecard_v0.json |
вручную |
| Кредитная политика: признаки, качество данных, лимит и ставка, исходы мира | config/features.json, config/data_quality.json, config/credit_policy.json, config/world_outcomes.json |
экономический блок |
Воспроизводимость решения¶
Решение — результат чистой функции decide (apps/api/workflow.py) от сохранённых данных, поэтому его можно пересчитать и получить тот же результат:
- Вход:
request,enrichment, факты,statements— всё в базе. - Модель:
Decision.model_version— версия основной карты; версия набора признаков — в паспорте карты (scorecard_vN.training.json). - Политика:
Decision.policy_version=credit=<версия>;data_quality=<версия>;features=<версия>— версии трёх файловconfig/. - Контракт:
Decision.contract_version— версия форматов (CONTRACT_VERSION). - Дата: признаки считаются на дату среза синтетического мира (
WORLD_AS_OF), срок предложений — от дня решения.
Журнал application_events показывает, кто и когда менял статус, что ответил каждый источник, какое решение принято и какие действия сотрудники совершили с кодом причины и комментарием.
Что видит клиент и что — сотрудник¶
Клиент получает сокращённое решение (client_decision): клиентские тексты причин, предложения без ожидаемой прибыли, контрфактические подсказки, уровень данных с фразой для клиента, дату повторного обращения, статусы источников без текста ошибок. Флаги, баллы, PD, претендент и журнал с исполнителями клиенту не отдаются: среди флагов есть признаки ПОД/ФТ (SPEC §1.11). Сотрудник видит всё. Подробно — WORKFLOW.md, раздел «API».