Drawing set — selected work
Portfolio · Jeffrey Jorgensen

I build systems where the money has to add up.

Backend engineer working on custodial wallets, multi-chain payouts, double-entry ledgers and the document pipelines that feed them. I take a system from database schema to production, and I write the tests that keep it honest. Client names and internal details are withheld — what's described is the mechanism, which is the part that transfers to your problem.

Track record — measured from my own repositories, 12·09·2026
2,177
lines of Go to read before hiring me, plus 3,002 of tests — MIT
23,400
automated tests
5,581
commits in those repositories
367K
lines of production Go
4
blockchain rails at the exchange
2
products on one core: exchange and payouts
313
API operations, financial model, one contract
1 yr
financial model in daily production
Sheet A — Selected work

What I've actually built

Exchange · ledger — architecture & all server-side engineering

Crypto exchange and prediction market on a ledger-first core

Go
324K
Tests
4,019
Commits
1,234
Chains
4

Users hold a USDT balance, trade, and take positions on event outcomes. The requirement that shaped everything: the books have to balance at any moment, including mid-trade and mid-withdrawal.

I put the accounting core in its own reusable module — double-entry postings, accounts, HD wallets, deposits and withdrawals across four networks, on-chain reconciliation, fees, compliance screening. The order book and prediction market sit on top of it. Private keys never live in the application: signing is isolated in a separate service.

The same core now backs a second, unrelated product. That's the test of whether a ledger was built properly: it survives being reused.

Reserve reconciliation console: three assets — USDT, BTC, ETH — in a table whose columns are liabilities, on-chain holdings, in-flight withdrawals and deposits, fees, platform-owned and unattributed funds, and the residual each row adds up to. ETH is marked critical and frozen. Below, an action log of the freeze and two reconciliation runs.
Open the full sheet →
Fig. A-1Reserve reconciliation, on sample data: for each asset the ledger’s liabilities against what is held on chain, with transfers in flight, fees, platform-owned funds and unattributed coins as columns of their own — so every row adds up to its residual rather than asking you to trust one. USDT reconciles, BTC carries an unexplained surplus, ETH is short and its withdrawals froze automatically.
Go 1.25 · PostgreSQL 16 · chi · pgx · Redis · WebSocket · Prometheus · Vault · go-ethereum · btcd · tonutils
Payments — product design, backend & frontend · in active development

Payment rail for companies that pay many people, often

Endpoints
48
Tests
1,015
Coin×net
8
Status
Build

Multiple receiving addresses with source attribution, balance accounting, batches of payouts as the central object, recurring debits, screening on the way in. Six coins across eight coin-and-network pairs, because a currency without its network is an incomplete quantity — that rule lives in the data model, not in a convention people are asked to remember.

The part I'd point at first: a batch runs as a dry run before it sends. Every row comes back with its fee on top of the amount and the exact debit that will hit the account. Nobody discovers the cost of a two-hundred-line payout after the money has left. Built on the ledger core above rather than from scratch — which is why it reached 48 endpoints and a full batch lifecycle in weeks, not quarters.

Three rules the dry run enforces, because they are the ones that cost money to learn. A row that failed keeps its key, so loading it again cannot produce a second payment. “Sent, no confirmation” is the one state the system refuses to retry, because the money may already have left. And a payment lookup matches exactly or returns nothing — a plausible wrong match is worse than no match at all.

Payout batch dry run: tiles showing 487 rows will go, recipients get 12 480.25 USDT, 12 967.25 is debited including 487 in fees, balance 15 000, and 13 rows will not go. Two tables follow: six rows whose address belongs to another network, and seven rows short of funds, each stating the amount needed against the amount available.
Open the full sheet →
Fig. A-2The dry run, before anything is sent. 487 rows will go, recipients get 12 480.25 USDT, and 12 967.25 leaves the account because the fee sits on top of each row rather than inside it. Thirteen rows will not go: six addresses belong to another network, seven are short of funds, and each says what it needed against what was left. Test stand — the amounts are not real.
Payouts screen: a table of three rows that did not go, each with the time, the full recipient address, the amount and the reason the recipient was not accepted, above a button to load the three rows again. Below it the single-payout form with its fuel estimate, the batch input, and the sent-batches list filtered to the state sent, no confirmation, showing one payout held for resolution by its transaction hash.
Open the full sheet →
Fig. A-3Rows that did not go, and what the console does about them. No money moved on any of the three, so they can be loaded again — the row key is unchanged, and a row already broadcast is never repeated. At the foot, the one state the system refuses to retry: the send outcome is unknown, the funds stay held, and it is resolved by the transaction hash rather than by sending again. Test stand.
Receiving screen: a payment lookup with a hash filled in and a note that it matches exactly and will not guess; a table of five sources with label, own reference, import key, address count and date; one source expanded to show its full Ethereum and Tron addresses, each with a copy button, the networks it can still be issued an address in, and the one it is not accepting, with the reason. A banner at the top says the funds are not real.
Open the full sheet →
Fig. A-4Receiving with source attribution — each source gets its own address in every network it is paid from, so money identifies itself by where it lands, and the import key never changes: that is what makes a partner’s total add up across renames. The lookup matches exactly and will not guess, because a plausible wrong payment is worse than one not found. Test stand.
Go · PostgreSQL · Next.js 16 · React 19 · TypeScript · Playwright
Analytics · financial modelling — product, architecture and engineering

A small business as a financial model a lender can read

Python
333K
TypeScript
132K
Tests
9,333
API ops
313

A small business goes to a bank, a leasing company or a tender with one question: what does its trading look like to whoever decides. The answer is scattered across account movement, lease agreements, loan schedules, card acquiring, cash collection, payroll and tax load, and it is nowhere assembled. The system assembles it into one working model — who pays whom, for what, on what schedule — runs that model month by month against limits, contractual dates and taxes, and answers three practical questions: where the risk is, where headroom is left, and what a credit analyst will see.

The hard part is placing a flow of payments so that five constraints hold at once: the balance reconciles every day, no counterparty exceeds its limit or its share of turnover, the month stays under its ceiling, and the period closes on exactly the balance asked for. It is solved in layers — a plan, a check against the daily calendar, a sweep of the remainders, and a final pass that distributes the gap across whoever still has headroom, or says plainly that there is nothing left to close it with.

One principle holds the rest up: the model is the source. Monthly cash flow, analytics, the tax return and the note you carry into the bank meeting are derivatives — throw them away and they rebuild; the model cannot. Money moves as strings and is computed on Decimal, never through a float. The frontend's API types are generated from the backend's own OpenAPI contract, so a version bump breaks the build instead of someone's screen. Progress on long jobs goes over SSE rather than WebSocket, because a WebSocket would have needed the token in a query string, and from there it lands in the logs. A year of work; an internal product, in production on two stands, with no public sign-up.

Statement generation brief: a panel headed
Open the full sheet →
Fig. A-5The model refusing to pretend. Of ₽19,821,470 asked for, ₽17,575,600 can be placed; the ₽2,245,870 that cannot is broken down by counterparty, each with the constraint that would have to move. The notes below say plainly that there is no room left to pay the surplus out to the owner. An invented business on seeded figures.
Spending corridor: twenty-four monthly bars from October 2024 to September 2026, each stacking rent, payroll, payroll tax, owner profit, loans, regime tax and account fees under a discretionary layer and the headroom to that month's ceiling, with an inflow line across the top and a strip under each bar marking what binds it. Below, the breakdown for one month.
Open the full sheet →
Fig. A-6The same business month by month across two years: the mandatory floor first — rent, payroll and its tax, owner profit, account fees, with the quarterly regime tax giving the stack its saw-tooth edge — then the month’s spending limit above it and the headroom left to the ceiling. The strip under each bar names what binds that month: the monthly limit, or how much the suppliers can absorb.
Next.js 16 · React 19 · TypeScript strict · Tailwind v4 · Zustand · FastAPI · PostgreSQL · Redis · object storage · Docker
Pipeline · integrations — sole engineer

Credit-file pipeline between three bureaus, cloud storage and a CRM

Python
117K
Tests
4,125
Formats
3
Workers
3

Account managers were reading PDF credit reports from three different bureaus by eye and retyping the figures into spreadsheets and deal records. The brief was to remove the manual step entirely, not to speed it up.

A CRM webhook lands in a queue, workers pull the PDFs from cloud storage, parse three unrelated report formats, merge them into one picture, fill seven blocks of a working spreadsheet and write the result back onto the deal. Some documents are scans, so recognition is part of the pipeline rather than a prerequisite for it. This is the second generation — the first had almost no tests and was hard to change without fear, so I pulled the pipeline out and rebuilt it, tests first. The 4,125 tests exist because a misparsed credit figure is not a cosmetic bug — that lesson cost me a rewrite.

FastAPI · Redis Streams · RQ · pymupdf · pdfplumber · tesseract · OpenCV · Kubernetes
Security · access — service owner within a five-role team

Identity service: the only issuer of user tokens

Endpoints
73
Auth
4
Commits
175
Open src
MIT*

One place in the system issues user tokens, so no other service has to store a password or a piece of personal data. Sessions, EdDSA-signed tokens with a published key set for neighbouring services to verify, passwordless keys via WebAuthn, one-time codes, Argon2 hashing, profiles and roles, and the mapping between identity and money accounts.

Fresh dependency releases sit in a one-week quarantine before they can be installed. A compromised package is most dangerous in the hours after publication, before it's pulled; a week closes that window without delaying real security fixes.

FastAPI · EdDSA / JWKS · WebAuthn · Argon2 · TOTP · arq · basedpyright  ·  *the coordination tool below is the MIT-licensed one you can read
Open source · MIT — author

A coordination channel for AI coding agents

Python
14K
Tests
406
Licence
MIT
Public
Yes

When several AI agents work on one system across separate repositories, they need a way to agree — otherwise each fixes the boundary its own way. An MCP server with a shared mailbox: messages addressed to roles, threads with a lifecycle and work status, machine-readable agreement on decisions, and shared contracts held as pinned, versioned entries. Two transports: local, and hosted with isolated channels and token auth.

This is public and MIT, and you can open it. But to judge how I write code for systems that hold money, start with ledger-reconcile instead: 2,177 lines of library and command, and 3,002 of tests, implementing thirteen of the fourteen failure modes from the teardown, name the fourteenth as out of reach, and report what a run could not check.

MCP · SQLite · ASGI · Docker + Caddy · pytest-asyncio
Sheet B — Also built

Shorter entries from the same shop

Tax filing pipeline — statements and receipts to a filed return with stamped e-document package; print correctness verified pixel by pixel against the official form.
SME books reconstruction — a bank statement turned into the five reports a bank asks for, each figure carrying its source, rule version and confidence.
Counterparty screening bot — company risk card from a tax ID: registry data, key-pool API access, risk flags. In production since 2025.
LLM pipelines — a site generator and a newsroom pipeline with a configurable eight-step scoring chain; providers interchangeable, every call traced.
Production infrastructure — a 37-service contract: Nginx with TLS, PostgreSQL with backups and restore drills, Vault, monitoring, deploy on push.
Financial front ends — trading screens, wallet, statement workspace: 251,000 lines of TypeScript with clients generated from OpenAPI.
Sheet C — Straight answers

The things you're going to ask anyway

You're one person. What happens to my project if you disappear?
You lose speed, not the project. Code goes into your repository from day one, not mine. Every repository carries an orientation document that gets a new engineer productive in a day — I keep 25 of them. Payment is per milestone, never up front. Code, credentials and IP transfer to you by contract. If you want, I'll walk a developer of yours through the architecture before we finish.
You work with AI agents. Isn't that generated code of unknown quality?
The agent supplies speed; the discipline supplies quality. Around 23,400 automated tests, integration tests against real Postgres and object storage in containers, checks that run before every commit, dependency vulnerability scanning, a quarantine on fresh package releases, a pinned compiler toolchain. I also wrote and open-sourced the tool my agents coordinate through — you can read it. Most teams adopting agents in 2026 have no governance model at all; that's the part I built first.
We have an NDA. Will our project end up on this page?
I show the mechanism, never the client — no names, no data, no recognisable screens. Case text is approved by you before it's published, and if you'd rather have no case at all, there's no case. The work above is written that way already.
We already have a system, built by someone else. Will you take it on?
Yes, and not by rewriting it. The first step is a fixed-price audit: architecture review, the specific places where figures diverge or the design won't survive growth, and a plan with estimates. That document is yours whether or not we work together after it.
Sheet D — Bill of materials

Stack, all of it from the work above

Languages
Go 1.25 · Python 3.11–3.12 · TypeScript 5 · SQL
Backend
chi · pgx · FastAPI · Pydantic v2 · SQLAlchemy 2 async · Alembic · golang-migrate
Money & data
PostgreSQL 16–17 · Redis (streams, queues, cache) · MinIO / S3 · decimal arithmetic · double-entry accounting
Chains
Bitcoin · Ethereum & ERC-20 · Tron & TRC-20 · TON · BIP-32/39 HD wallets · isolated signing service
Frontend
Next.js 16 · React 19 · Tailwind 4 · shadcn/ui · TanStack Query · Zustand · Vue 3
Documents
reportlab · pypdf · pdfplumber · pymupdf · tesseract · OpenCV · openpyxl · pixel-diff verification
LLM
Anthropic · OpenAI · Langfuse tracing · structured outputs · vision · MCP servers
Infra
Docker & Compose · Kubernetes · Nginx + TLS · Vault · Prometheus & Grafana · GitHub Actions · PITR backups
Quality
pytest · testcontainers · Playwright · Vitest · MSW · golangci-lint · ruff · basedpyright · govulncheck · bandit
Sheet E — Three ways in

Tell me what's breaking.

Thirty minutes, no preparation needed. Describe what happens today and what should happen instead, and I'll tell you whether I'm the right person — including when the answer is no.

$1,800
Fixed-price audit · five working days. Architecture review, the places numbers diverge, a costed plan. Yours to keep. A scoped pilot starts at $4,000.
from $14,000
One hard component — a ledger, a payout flow, a document pipeline, an integration. I fit into your codebase and its rules.
from $35,000
The whole system — schema, backend, interface, deployment, monitoring. For a result rather than an extra person in a team.