Архитектура «Умного кредитного кабинета предпринимателя»¶
Платформа прототипа: каналы, модули, поток решения, данные, ИИ и безопасность. Кредитная логика и её обоснование — в docs/v2/SPEC.md, процесс и статусы — в docs/PROCESS.md, таблицы — в docs/DATA_MODEL.md, форматы обмена между модулями — в docs/v2/CONTRACTS.md.
1. Что построено¶
- Кабинет клиента — веб (
/) и Telegram Mini App (/mini/): один React-клиент с двумя оболочками. Путь клиента: ИНН и согласия → потребность → анализ заявки → предложения → подписание → выдача; история заявок и предодобренный овердрафт. - Рабочее место сотрудника (
/staff): очередь заявок на рассмотрении, досье, действия с кодом причины, вторая подпись комитета, страница валидации модели для риск-менеджера. - Кредитный конвейер — FastAPI-backend и worker из одной кодовой базы.
- Синтетический мир и мок-источники — данные, на которых работает конвейер и обучается модель.
Telegram выбран как допущение: в кейсе платформа mini app не названа. Для другой платформы меняется адаптер авторизации и оболочка, кредитная логика общая.
2. Общая схема¶
flowchart TB
Web[Веб-кабинет] --> API
Mini[Telegram Mini App] --> API
Staff[Рабочее место сотрудника] --> API
API[FastAPI: apps/api/main.py] --> DB[(PostgreSQL / SQLite)]
Worker[Worker: apps/api/worker.py] --> DB
Worker --> Workflow[Статусы и решение: workflow.py]
Workflow --> Enrichment[Обогащение: apps/sources/enrichment.py]
Enrichment --> Mock[Мок-источники: apps/sources/service.py]
Mock --> World[(Синтетический мир: apps/world/out)]
Workflow --> Engine[Движок: качество данных, стоп-факторы, скоринг, лимит, ставка, предложения, маршрут]
Engine --> Config[(config/: политика с версиями)]
Engine --> Cards[(Скоринговые карты: apps/ml, apps/api/scorecards)]
Worker --> Closing[Подписание, условия, выдача: disbursement.py]
Worker --> Pre[Предодобрение: preapproval.py]
API --> Assistant[ИИ-ассистент: assistant.py]
Assistant -.->|опционально| LLM[OpenAI-совместимый сервер]
Это модульный монолит: один backend с чёткими модулями и worker, который в Docker работает отдельным контейнером, а локально — в процессе API. Внешние системы — моки за адаптерами (apps/sources/): их можно заменить настоящими интеграциями без изменения движка.
Стек: Python 3.12 и FastAPI для backend и расчётов, Pydantic для контрактов, SQLAlchemy и Alembic для данных, PostgreSQL в Docker и SQLite локально; React и TypeScript (Vite) для клиентов.
3. Модули¶
| Модуль | Где | Ответственность |
|---|---|---|
| Синтетический мир | apps/world/ |
Компании со скрытым качеством q, обороты по счёту, кредитные истории, мошеннические архетипы, клиенты с неполными данными, исходы дефолта; демо-персоны (README, PERSONAS.md) |
| Источники и обогащение | apps/sources/ |
Мок-сервис восьми источников с задержками и сбоями; адаптеры, параллельный опрос, тайм-ауты, повторы, политика отказа по источнику; факты «заявлено / подтверждено» (README) |
| Признаки и качество данных | apps/api/features/ |
Одна библиотека признаков для обучения и движка; уровень качества данных FULL / PARTIAL / THIN (README) |
| Обучение модели | apps/ml/ |
WoE-разбиение, логистическая регрессия, перевод в баллы, выгрузка scorecard_v1.json; валидация: Gini, калибровка, PSI (README) |
| Хранилище фактов | apps/api/fact_store.py |
Факты заявки с источником, уровнем надёжности и временем |
| Стоп-факторы и флаги | apps/api/stop_factors.py |
Автоматический отказ и поводы для ручного рассмотрения (STOP_FACTORS.md) |
| Скоринг | apps/api/scoring.py |
Применение карты, PD и грейд, вклады признаков; претендент в теневом режиме (SCORING.md) |
| Лимит и ставка | apps/api/limits.py, pricing.py, credit_policy.py |
Лимит — минимум из ограничений; ставка по составляющим; политика из config/credit_policy.json (LIMITS.md) |
| Предложения | apps/api/offers.py |
До трёх вариантов и контрфактические подсказки (OFFERS.md) |
| Маршрутизация | apps/api/routing.py |
Матрица полномочий с причинами (ROUTING.md) |
| Статусы и журнал | apps/api/workflow.py, worker.py |
Таблица переходов, журнал событий, очередь worker, решение decide (WORKFLOW.md) |
| Действия сотрудников | apps/api/staff_actions.py |
Одобрить, изменить, отказать, запросить данные, перезапустить; комитет — две подписи (STAFF_ACTIONS.md) |
| Выписки | apps/api/statements.py |
Загрузка выписки из другого банка и пересчёт (STATEMENTS.md) |
| Подписание и выдача | apps/api/disbursement.py |
Документы, код подписания, отлагательные условия, выдача (DISBURSEMENT.md) |
| Предодобрение | apps/api/preapproval.py |
Ежедневный пакет овердрафтов для клиентов FULL (PREAPPROVAL.md) |
| Демо-доступ | apps/api/demo_companies.py, main.py |
Демо-профили, каталог компаний, вход сотрудника с выбором должности |
| ИИ-ассистент | apps/api/assistant.py |
Ответы по шаблону, опционально — через модель |
| Клиент и рабочее место | apps/web/src/ |
Экраны клиента и сотрудника (apps/web/README.md) |
| Контракты | apps/api/contracts.py, tests/fixtures/ |
Pydantic-модели между треками и примеры (CONTRACTS.md) |
4. Как принимается решение¶
sequenceDiagram
participant C as Клиент
participant A as API
participant W as Worker
participant S as Мок-источники
participant E as decide
C->>A: POST /api/v2/applications (ключ идемпотентности)
A-->>C: submitted
W->>A: захват заявки: submitted → enriching
W->>S: 8 источников параллельно, тайм-аут и повторы
S-->>W: ответы и статусы вызовов
W->>W: факты, качество данных → scoring
W->>E: стоп-факторы → признаки → скоринг → лимит и ставка → предложения → маршрут
E-->>W: Decision с причинами и версиями
W->>A: offered / declined / in_review / needs_data
C->>A: GET /api/v2/applications/{id} (опрос статуса и источников)
decide — чистая функция: на одних и тех же ответах источников, картах и версиях политики она даёт одно и то же решение. Стоп-факторы, признаки и балл считаются только по нашим данным и госисточникам; выписка клиента влияет на качество данных и лимит, но не на балл. Порядок вызовов и все исходы — WORKFLOW.md.
Пороги — кредитная политика в config/ с версиями (features, data_quality, credit_policy, world_outcomes); значения подтверждает экономический блок. Часть порогов пока константы в коде, они перечислены в docs/SIMPLIFICATIONS.md.
5. Каналы¶
| Возможность | Mini app | Веб-кабинет |
|---|---|---|
| Вход | Через Telegram (проверка initData) или демо-вход |
Демо-вход |
| Заявка | Те же шаги в мобильной вёрстке | Те же шаги |
| Анализ и решение | Общий экран анализа | Общий экран анализа |
| Заявки | История заявок и выдач | История заявок и выдач |
Оба канала — одна сборка React с общими компонентами; сервер — единственный источник правил, переходов и расчётов. Telegram-идентичность привязывается к аккаунту только после подтверждения владения обоими входами (одноразовый код); совпадение имени или телефона не объединяет аккаунты.
6. Роль ИИ¶
Кредитный движок работает детерминированно. ИИ не задаёт ставки и баллы, не меняет результат, не одобряет заявки и не запускает действия.
Подключение модели — только через OpenAI-совместимый API и переменные LLM_BASE_URL, LLM_API_KEY, LLM_MODEL; только модели с открытыми весами. Адаптер вызывает {LLM_BASE_URL}/chat/completions; без этих переменных или при ошибке модели помощник отвечает по шаблону, и сценарий работает так же. В контекст модели передаётся минимум: вопрос и справочный текст, без реквизитов, файлов и финансового профиля; ответ с числами, которых нет в контексте, отклоняется. Подробно — README, раздел «Языковая модель».
Объяснения клиенту и сотруднику строятся без модели: у каждой причины решения, флага и ограничения лимита есть код и готовый текст, отдельно для клиента и для сотрудника.
7. API¶
Методы — в OpenAPI: http://127.0.0.1:8000/docs и docs/api/openapi.json; сквозной сценарий — docs/api/requests.http. Методы v2 — под /api/v2, вход — под /api/auth.
Изменяющие запросы клиента передают версию строки заявки (revision): устаревшая версия даёт 409, поэтому два открытых окна не перезаписывают друг друга. Подача заявки идемпотентна по ключу: повтор возвращает ту же заявку.
8. Безопасность и эксплуатация¶
- Сессии. Cookie-сессии, проверка
Originу изменяющих запросов,COOKIE_SECUREза HTTPS. Данные входа mini app проверяются по HMAC и возрасту (до 5 минут); идентификатор, присланный клиентом без подписи платформы, не принимается. - Доступ. Клиент видит только свои заявки и сокращённое решение без флагов, баллов и PD (среди флагов есть признаки ПОД/ФТ); сотрудник видит всё. Вторая подпись комитета — только сотрудник с другой должностью.
- Журнал. Переход статуса и запись события — в одной транзакции; журнал только дополняется. Изменение политики — новая версия в
config/, уже принятые решения не пересчитываются. - Секреты. Только через
.env, в репозитории —.env.exampleсо всеми переменными. Код подписания хранится хэшем. - Устойчивость. Тайм-ауты и повторы по источникам, аренда заявки worker, повтор расчёта после сбоя — docs/SLA.md.
Прототип работает только на синтетических данных. Перед реальной эксплуатацией отдельно проектируются политика хранения и удаления, основания обработки данных (152-ФЗ, банковская тайна), реестр согласий на запрос кредитной истории (218-ФЗ) и требования банка.