Комплект чертежей — избранные работы
Портфолио · Jeffrey Jorgensen

Строю системы, где деньги должны сходиться.

Бэкенд-инженер: кастодиальные кошельки, мультивалютные выплаты, учёт на двойной записи и конвейеры документов, которые их питают. Веду систему от схемы данных до продакшна и пишу тесты, которые держат её честной. Имена клиентов и внутренние детали не раскрываются — описан механизм, а это и есть та часть, что переносится на вашу задачу.

Объём работы — измерено по моим репозиториям, 12·09·2026
2 177
строк Go прочитать до найма, плюс 3 002 тестов — MIT
23 400
автоматических тестов
5 581
коммитов в этих репозиториях
367K
строк продового Go
4
блокчейн-сети биржи в проде
2
продукта на одном ядре: биржа и выплаты
313
операций API финансовой модели, один контракт
1 год
финансовая модель в эксплуатации
Лист A — Избранные работы

Что уже построено

Крипто · биржа — Роль: архитектура и вся серверная разработка

Крипто-биржа и рынок прогнозов на ledger-ядре

Go
324 000 строк
Тесты
4 019
Коммиты
1 234
Миграции схемы
164

Задача: платформа, где пользователи держат баланс в USDT, торгуют и делают ставки на исходы событий, а деньги при этом сходятся до копейки в любой момент.

Ядро вынесено в отдельный переиспользуемый модуль: двойная запись, счета, HD-кошельки, депозиты и выводы по четырём сетям, сверка с блокчейном, комиссии, compliance-скрининг. Над ядром — спотовый стакан и prediction-маркет. Приватные ключи не лежат в приложении: подпись изолирована в отдельный сервис. Аутентификация и персональные данные вынесены в самостоятельный сервис — биржа их не хранит вовсе.

Интерфейс — отдельное веб-приложение на Next.js, которое на телефоне должно ощущаться приложением: 80 000 строк TypeScript, 775 тестов, типизированный клиент сгенерирован из спецификации бэкенда, а расхождение версий контракта ловится проверкой на сборке.

Сборочная цепочка компилятора закреплена явно и обновляется как зависимость: расхождение версии означало бы сборку с другим набором закрытых уязвимостей. Это уже поймало семь дыр в стандартной библиотеке, до которых код доходил вызовами.

Консоль сверки резервов: три актива — USDT, BTC, ETH — в таблице с колонками обязательств, остатка в сети, переводов в пути на вывод и на ввод, комиссий, средств платформы и неопознанных монет, и итогового остатка по каждой строке. ETH помечен критическим и заморожен. Ниже журнал действий: заморозка и два прогона сверки.
Открыть лист целиком →
Рис. A-1Сверка резервов на демонстрационных данных: по каждому активу обязательства реестра против того, что лежит в сети, а переводы в пути, комиссии, средства платформы и неопознанные монеты вынесены отдельными колонками — поэтому каждая строка складывается в свой остаток, а не просит поверить. USDT сходится, по BTC необъяснимый избыток, по ETH недостача, и выводы заморозились автоматически.
Go 1.25 · PostgreSQL 16 · chi · pgx · Redis · WebSocket · Prometheus · Swagger · Vault · go-ethereum · btcd · tonutils · Next.js 16 · React 19
Крипто · платежи — Роль: продукт, бэкенд и фронтенд целиком

Платёжный контур для компаний с массовыми выплатами

Go + TS
74 000 строк
Тесты
1 015
Пар монета×сеть
8
Коммиты
154

Задача: партнёрским сетям нужно принимать платежи с опознанием источника и платить сотням получателей пачками — без ручных переводов по одному.

Множественные адреса приёма с атрибуцией, учёт остатка, пачки выплат как центральная сущность, повторяющиеся списания, скрининг входящего. Шесть монет в восьми парах «монета × сеть»: сумма, валюта и сеть всегда ходят вместе — валюта без сети здесь неполная величина, и это правило зашито в модели данных, а не в договорённости.

Продукт продаётся двумя способами: лицензия, когда ключи держит клиент, и сервис, когда средства держим мы. Это не переключатель в настройках — различаются обязанность скринить и то, чей ключ подписывает вывод.

Три правила, которые соблюдает этот прогон, — те, что дорого узнавать на практике. У непрошедшей строки остаётся прежний ключ, поэтому повторная загрузка не может создать второй платёж. «Ушла, подтверждения нет» — единственное состояние, которое система отказывается повторять: деньги уже могли уйти. А поиск платежа находит точное совпадение или ничего — правдоподобный неверный платёж хуже ненайденного.

Пробный прогон пачки выплат: плитки показывают, что уйдёт 487 строк, получатели получат 12 480,25 USDT, спишется 12 967,25 включая 487 комиссии, остаток 15 000, не уйдут 13 строк. Ниже две таблицы: шесть строк с адресом чужой сети и семь строк без достаточных средств, в каждой указано, сколько нужно против того, сколько доступно.
Открыть лист целиком →
Рис. A-2Пробный прогон, до того как что-либо уйдёт. Уйдут 487 строк, получатели получат 12 480,25 USDT, а со счёта спишется 12 967,25 — комиссия берётся сверх каждой строки, а не внутри неё. Тринадцать строк не уйдут: шесть адресов принадлежат другой сети, семи не хватает средств, и каждая называет, сколько ей было нужно против того, сколько оставалось. Тестовый стенд — суммы не настоящие.
Экран выплат: таблица из трёх строк, которые не прошли, у каждой время, полный адрес получателя, сумма и причина, по которой получатель не принят, а под ней кнопка загрузить эти три строки заново. Ниже форма одиночной выплаты с оценкой топлива, поле ввода пачки и список отправленных пачек, отфильтрованный по состоянию «ушла, подтверждения нет», с одним платежом, удержанным до разбора по хэшу.
Открыть лист целиком →
Рис. A-3Строки, которые не прошли, и что консоль с ними делает. Деньги ни по одной из трёх не двигались, поэтому их можно загрузить заново — ключ строки прежний, а уже отправленная строка не повторяется никогда. Внизу единственное состояние, которое система отказывается повторять: исход отправки неизвестен, средства остаются удержанными, и разбирается это по хэшу транзакции, а не повторной отправкой. Тестовый стенд.
Экран приёма: поиск платежа с введённым хэшем и пометкой, что ищется точное совпадение и угадывать система не станет; таблица из пяти источников с меткой, своей нумерацией, ключом загрузки, числом адресов и датой; один источник раскрыт и показывает полные адреса в Ethereum и Tron, у каждого кнопка копирования, сети, в которых ему ещё можно выдать адрес, и та, в которой приём не идёт, с причиной. Сверху баннер о том, что деньги ненастоящие.
Открыть лист целиком →
Рис. A-4Приём с атрибуцией по источникам — у каждого источника свой адрес в каждой сети, из которой он платит, поэтому деньги опознают себя самим фактом зачисления, а ключ загрузки не меняется никогда: именно он сводит итог по партнёру при переименованиях. Поиск находит точное совпадение и не угадывает — правдоподобный неверный платёж хуже ненайденного. Тестовый стенд.
Go · PostgreSQL · Next.js 16 · React 19 · TypeScript · Playwright · общее ledger-ядро
Аналитика · финансовое моделирование — продукт, архитектура, разработка

Малый бизнес как финансовая модель, которую читает кредитор

Python
333 000 строк
TypeScript
132 000
Тесты
9 333
Операций API
313

Малый бизнес приходит в банк за кредитом, в лизинг или в тендер с одним вопросом: как его хозяйственная деятельность выглядит для того, кто принимает решение. Ответ разбросан по движению на счетах, договорам аренды, графикам кредитов, эквайрингу, инкассации, зарплатным реестрам и налоговой нагрузке — и нигде не собран в одно целое. Система собирает его в одну работающую модель: кто, кому, за что и с какой периодичностью платит. Модель прогоняется по месяцам с учётом лимитов, договорных сроков и налогов и отвечает на три практических вопроса: что здесь риск, где остался запас и что увидит кредитный аналитик.

Самое трудное — разместить поток платежей так, чтобы одновременно сошлись пять ограничений: каждый день сходится баланс, никто не превышает свой лимит и свою долю в обороте, месяц не выходит за потолок расходов, а на конец периода остаётся ровно заданный остаток. Решается послойно: план, проверка по дневному календарю, свип остатков и добивающий проход, который распределяет разрыв по тем, у кого остался запас, — или честно сообщает, что закрыть его нечем.

Один принцип держит всё остальное: модель — первоисточник. Помесячный денежный поток, аналитика, налоговая декларация и справка к разговору с банком — производные от неё: их можно выбросить и пересобрать, модель — нельзя. Деньги ходят строками и считаются на Decimal, никогда через float. Типы API на фронте генерируются из OpenAPI-схемы бэкенда, поэтому смена версии контракта ломает сборку, а не чей-то экран. Прогресс длинных задач идёт по SSE, а не по WebSocket: WebSocket потребовал бы токен в query-строке, а оттуда он попадает в логи. Год работы; внутренний продукт, два продакшн-стенда, публичной регистрации нет.

Задание на генерацию выписки: панель «Часть лимитов не будет заполнена» сообщает, что разместится 17 575 600 из 19 821 470, недобор 2 245 870, с разбивкой по трём контрагентам и указанием, что нужно изменить по каждому. Ниже сводка движения денег по статьям и панель замечаний: что не дойдёт до счёта и что выплатить излишек владельцу уже некуда.
Открыть лист целиком →
Рис. A-5Модель отказывается делать вид, что сойдётся. Из заказанных ₽19 821 470 разместить удастся ₽17 575 600; недобор в ₽2 245 870 разложен по контрагентам, и у каждого названо ограничение, которое пришлось бы сдвинуть. Замечания ниже прямо говорят, что выплатить излишек владельцу уже некуда. Выдуманный бизнес на засеянных цифрах.
Коридор расходов: двадцать четыре месячных столбца с октября 2024 по сентябрь 2026, в каждом сложены аренда, зарплата, налог с фонда оплаты труда, прибыль владельца, кредиты, налог по режиму и банковское обслуживание, сверху дискреционный слой и запас до потолка месяца, поперёк идёт линия поступлений, а под каждым столбцом полоска показывает, чем месяц ограничен. Ниже разбор одного месяца.
Открыть лист целиком →
Рис. A-6Тот же бизнес по месяцам на два года вперёд: сначала обязательный пол — аренда, зарплата и налог с неё, прибыль владельца, банковское обслуживание, а квартальный налог по режиму даёт стопке пилообразный край, — затем лимит трат этого месяца поверх него и остаток запаса до потолка. Полоска под каждым столбцом называет, чем месяц связан: месячным лимитом или тем, сколько способны принять поставщики.
Next.js 16 · React 19 · TypeScript strict · Tailwind v4 · Zustand · FastAPI · PostgreSQL · Redis · объектное хранилище · Docker
CRM · конвейер — Роль: единственный разработчик

Конвейер кредитных историй между БКИ, Google и AmoCRM

Python
117 000 строк
Тесты
4 125
Источников БКИ
3
Воркеров
3

Задача: менеджеры вручную вычитывали PDF кредитных историй из трёх разных бюро и переносили данные в таблицы и карточки сделок. Нужно было убрать ручной этап целиком.

Вебхук из AmoCRM попадает в очередь, воркеры забирают PDF с Google Drive, разбирают форматы трёх бюро — НБКИ, Credistory, Scoring, — сводят результаты в одну картину, заполняют семь блоков рабочей таблицы и возвращают итог заметкой в сделку. Отдельным потоком карточка лида обогащается данными по компании из внешнего реестра. Часть документов — сканы, поэтому в пайплайне есть распознавание текста.

Это второе поколение. Первое было одной большой системой — 444 коммита, 96 500 строк, вместе с ботом, аналитикой и работой с таблицами — и тестов в ней почти не было. Она работала, но менять её было страшно. Поэтому конвейер я вынес в отдельный сервис и переписал, и на этот раз тесты шли первыми. Два поколения вместе: 735 коммитов, около 213 000 строк.

FastAPI · Redis Streams · RQ · pymupdf · pdfplumber · tesseract · OpenCV · Google Drive/Sheets API · AmoCRM API · Kubernetes
Безопасность · доступ — Роль: владелец сервиса в команде из пяти ролей

Сервис входа и учётных записей

Python
29 000 строк
Эндпоинты
73
Миграции
25
Коммиты
175

Задача: единственная точка в системе, которая выпускает пользовательские токены, — чтобы остальные сервисы не хранили ни паролей, ни персональных данных.

Вход через Telegram, сессии, токены на эллиптической подписи с публичным набором ключей для проверки соседними сервисами, ключи доступа без пароля (WebAuthn), одноразовые коды, хеширование Argon2, профили и роли, хранение персональных данных в одном месте, связка внутренних идентификаторов с денежными счетами.

Свежие релизы зависимостей выдерживают карантин: скомпрометированный пакет опаснее всего в первые часы после публикации, до того как его снимут. Неделя выдержки закрывает это окно и, как проверено на реальных обновлениях, не мешает ставить срочные исправления безопасности.

FastAPI · EdDSA / JWKS · WebAuthn · Argon2 · TOTP · arq · basedpyright · GitHub Actions
Open source · AI-tooling — Роль: автор

Канал координации между AI-агентами

Python
14 000 строк
Тесты
406
Лицензия
MIT

Задача: когда над одной системой работают несколько AI-агентов в разных репозиториях, им нужен способ договариваться — иначе каждый чинит границу по-своему.

Сервер протокола MCP с общим почтовым ящиком: сообщения адресуются ролям, у тредов есть жизненный цикл и статус работы, решения фиксируются машиночитаемым согласием, а общие договорённости живут закреплёнными записями с версией. Два режима: локальный на одной машине и размещённый на сервере, с изолированными каналами и авторизацией по токенам.

На этом инструменте построена реальная разработка: пять ролей — деньги, вход, редакция, фронт, инфраструктура — с уставом команды, границами владения репозиториями и правилом «контракт согласовывается до кода».

Он открыт и лежит под MIT. Но чтобы судить, как я пишу код для систем, где лежат деньги, начинать стоит не с него, а с ledger-reconcile: 2 177 строк библиотеки и команды плюс 3 002 теста, которые находят тринадцать из четырнадцати режимов расхождения из разбора, честно называют четырнадцатый недостижимым и сообщают, чего прогон проверить не смог.

MCP · SQLite · ASGI · Docker + Caddy · pytest-asyncio
Лист B — Также построено

Более короткие записи из той же мастерской

Восстановление бухгалтерии малого бизнеса по выписке — кредитному брокеру нужен пакет документов для банка по клиенту, у которого есть только банковская выписка и чеки ОФД.
Декларация УСН и пакет электронного документооборота — из выписки и чеков ОФД получить готовую к сдаче декларацию УСН 6% по форме КНД 1152017 со штампами ЭДО и архивом пакета.
Проверка контрагентов по ИНН в Telegram — перед сделкой нужно быстро понять, что за компания на другой стороне, — без похода в три разных сервиса.
Генератор сайтов и редакционный конвейер на языковых моделях — два продукта, где модель должна давать предсказуемый результат, а не «что-то похожее на текст».
Лидогенерация в Telegram на потоке — искать и квалифицировать заявки внутри Telegram — это задача объёма. Разговоры, на которые стоит отвечать, разбросаны по сотням чатов, и пока человек до них доберётся, они остывают. Нужно было сделать этот поиск непрерывным.
Лист C — Метод

Как я работаю

Эти правила видны в коде проектов выше — их можно проверить, а не принимать на слово.

Контракт до кода Всё, что пересекает границу между сервисами — формат ответа, имена переменных окружения, порты, схема базы, — сначала согласуется, потом пишется. Это дешевле, чем чинить рассинхрон под нагрузкой.
Тесты как условие сдачи Около 23 400 автотестов, интеграционные — на настоящих Postgres и хранилище в контейнерах, сквозные — в браузере. Тест на реальной базе ловит то, что заглушка пропускает по определению.
Документация, которую нельзя обмануть Договорённости хранятся дословными цитатами, а расхождение ловит проверка перед коммитом. Пересказ непроверяем: это другой текст, и никакое сравнение не скажет, верен ли он.
Безопасность встроена, а не дописана Секреты только в окружении и Vault. Версия компилятора закреплена и обновляется как зависимость. Карантин на свежие релизы пакетов. Приватные ключи — в отдельном сервисе. Проверка недоступна — значит отказ, а не пропуск.
Проверки в путях, а не в памяти Каждое правило, которое можно привязать к хуку или команде, туда привязано. Инструкция срабатывает, только если о ней вспомнили; гейт перед коммитом срабатывает всегда.
Разработка с AI-агентами Мультиагентная команда из пяти ролей с уставом, границами владения репозиториями и каналом согласований — рабочая практика, а не эксперимент. Скорость выше, но правило «чужой репозиторий читаю, но не правлю» соблюдается строже, чем в командах из людей.
Лист D — Инструменты

С чем работаю

Языки
Python 3.11–3.12 · Go 1.25 · TypeScript 5 · SQL
Бэкенд
FastAPI · Pydantic v2 · SQLAlchemy 2 (async) · Alembic · chi · pgx · aiogram 3 · Telethon
Данные
PostgreSQL 16–17 · Redis (Streams, очереди, кеш) · MinIO и S3 · Decimal и NUMERIC для денег · двойная запись
Очереди
RQ · arq · rq-scheduler · APScheduler · Redis Streams · фоновые воркеры и планировщики
Фронтенд
Next.js 16 · React 19 · Tailwind 4 · shadcn/ui · Zustand · TanStack Query · Vue 3 · Pinia · Vite
Блокчейн
Bitcoin · Ethereum и ERC-20 · Tron и TRC-20 · TON · HD-кошельки BIP-32/39 · изоляция ключей подписи
Документы
PDF: reportlab, pypdf, pdfplumber, pymupdf · OCR: tesseract, OpenCV · Excel: openpyxl · 1С ClientBankExchange · XML ФНС
Языковые модели
Anthropic · OpenAI · Langfuse · структурированный вывод · vision · серверы MCP
Интеграции
AmoCRM · Google Drive и Sheets · Checko · реестр МСП ФНС · DaData · Telegram Bot API и MTProto · Контур.Эльба и СБИС
Инфраструктура
Docker и Compose · Kubernetes · Nginx с TLS · Vault · Prometheus и Grafana · GitHub Actions · бэкапы с PITR
Лист E — Форматы работы

Расскажите, что ломается.

Тридцать минут, без подготовки. Опишите, что происходит сейчас и как должно быть, а я скажу, тот ли я человек для задачи — в том числе когда ответ «нет».

$1 800
Аудит · пять рабочих дней. Разбор архитектуры, места расхождений, план с оценкой. Остаётся у вас без обязательств. Пилот — от $4 000.
от $14 000
Сложный узел — учёт, выплаты, разбор документов, интеграция. Встраиваюсь в ваш код и его правила.
от $35 000
Продукт целиком — схема, бэкенд, интерфейс, деплой, мониторинг. Когда нужен результат, а не участник команды.