Commerce and payments
Checkout, registration, and subscription flows built against the client's own payment account.
Payment work is unusual in that the most important decision is contractual rather than technical: whose account the money lands in. We build against the client's own, always, and never sit between a business and its funds.
The client is the merchant of record. Their payment account, their name on the statement, their relationship with the processor, their disputes to answer. We never hold funds, never aggregate payments, and never become an intermediary, because doing so changes the regulatory position of everyone involved.
Payment details never touch the application. Card data is collected by the processor's own hosted elements and the system sees only a token, which keeps the compliance surface as small as it can be made, not merely well managed.
The processor's own confirmation is the source of truth, not the browser. A customer closing the tab after paying is a normal event, and a system that records the payment only when the browser reports back will lose those. Confirmation comes from the processor's server-to-server notification, and the browser redirect is treated as a convenience.
Confirmations are safe to receive twice and are signature-verified. Providers retry, sometimes aggressively, and a handler that acts on every delivery will eventually act twice. Verification is what stops that address being an open door for anyone who learns it.
Amounts are held as integer minor units, never as floating point. Currency arithmetic in floating point produces rounding errors that appear at exactly the moment someone reconciles a month, and the fix afterward requires touching historical records.
Refunds, partial refunds, failed renewals, and disputes are specified before launch rather than handled when the first one occurs. The unhappy paths in a payment flow are more numerous than the happy one and considerably more expensive to improvise.
Where a flow collects both a participant and a payer — a registration made by a parent, a booking made by an assistant — those are modeled as separate parties from the start, because merging them later is a data exercise and separating them now is a single field.
Receipts and confirmations are sent by the system, not left to the processor's defaults, so the business controls what its customer reads and can include the details the processor knows nothing about — what was booked, for whom, and what happens next.
What this does not cover.
- Custody of client funds, payment aggregation, or acting as merchant of record.
- Handling raw card data in application code under any circumstances.
- Formal PCI attestation. The integration minimizes scope; certification is not claimed.
Software Engineering
Specification before code
The document that names every entity, every state, and every failure path — and why a project that cannot produce it should not start.
Types as guarantees
Making the likeliest mistake in a system impossible to express, rather than merely against the rules.
Internal tools
Authenticated back-office systems for the work currently living in a spreadsheet.
Moving data between systems
Reversible where possible, rehearsed against a copy, and always producing a record of what changed.
Interfaces between systems
The interfaces a system exposes, and the contracts it holds itself to once something depends on them.
Testing
Coverage aimed at what would actually be expensive to get wrong, instead of at a percentage.