From a legacy Web Forms app to an owned remittance platform
We replaced the ASP.NET system of a network that takes pesos in Colombia and pays out bolívares in Venezuela. The new platform has 8 roles, mandatory MFA and every money movement inside Postgres functions.
We replaced the ASP.NET Web Forms system of a money-transfer network running from Colombia to Venezuela. The new platform covers all 8 roles in the operation, from the shop that takes the cash to the operator who pays out in bolívares, with MFA mandatory for everyone and every money movement inside database functions. The first commit is dated 14 September 2026; by the end of October the platform was running with the network's real users.
- Client
- Remittance network · Colombia → Venezuela
- Sector
- Remittances and exchange houses
- Where
- Colombia → Venezuela
- Year
- 2026
- Deliverables
- Web platform with 8 roles
- TOTP MFA and invite-only access
- Money moved in Postgres functions
- Migration from SQL Server
- Reports with XLSX and CSV export
A Web Forms system moving real money
The network works with two exchange houses and a set of shops in Colombia that take cash in pesos. A shop creates a transfer to a bank account or to Pago Móvil, and sells phone top-ups and TV plans against a prepaid peso balance. In Venezuela, operators pay out from the exchange house's bolívar accounts and attach the bank's proof of payment.
All of this ran on an ASP.NET Web Forms application over SQL Server. In September 2026 we received the app and a backup of its database. We wrote the new core from scratch and used the old system as a reference for business rules and as a data source.
Money only moves inside the database
Every money operation is a SECURITY DEFINER function in Postgres (Supabase, sa-east-1 region), and the browser never writes a balance. Behind it sit a double-entry ledger, an audit schema that only accepts inserts, idempotency keys so a double click can't create two transfers, and step-up codes bound to each request's hash. The schema lives in 73 migrations and the app calls about 100 distinct functions.
The interface is Next.js 16.4 with React 19.2 and TypeScript, on Vercel, with 66 pages and 22 API routes. Access is by invitation only, with authenticator-app MFA (TOTP), a 30-minute idle timeout, an 8-hour session cap and one session per user. Payment proofs land in a private quarantine bucket, go through an isolated scanner and are rejected if their SHA-256 already exists. The old system's data moved from SQL Server to Postgres through an ETL written for the project.
-
01
The shop creates the transfer
It looks up sender and recipient by ID number, picks bank or Pago Móvil, and sees live how much comes off its balance and how many bolívares the recipient gets. Pago Móvil applies the rate × 1.01. A 6-digit code confirms it, and the shop gets a receipt with an operational ID.
-
02
The operator pays out in Venezuela
The queue refreshes every 10 seconds and splits the work by exchange house. Opening an ID reserves it for that operator, who picks the source account, uploads the proof and sees the 0.3% interbank commission before paying.
-
03
8 roles, 38 actions
Shop, payouts, admin, distributor, senior distributor, purchasing, super seller and seller. The 38 permissioned actions come from the role, and an admin can allow or block one action for one person without changing their role.
-
04
132 automated tests
Vitest runs 132 unit and component tests, all passing. Another 11 Playwright files with axe-core walk through the full flows and check accessibility, and GitHub Actions runs the CI.
The project in pictures
8 images · Open any image to see it full size.
Six weeks from first commit to operation
Between 14 September and 29 October 2026 there were 71 commits, with client reviews on 6, 8 and 13 October. By the end of October the platform was running with the network's real users, on an invite-only URL.
We don't yet have volume or payout-time figures we can publish. The client is confidential, so the screenshots use invented data and two fictional exchange houses, Andina and Orinoco.
- ASP.NET Web Forms system replaced by an owned platform
- 8 roles and 38 permissioned actions, MFA mandatory for everyone
- 73 migrations and about 100 database functions
- 132 automated tests, all passing
The questions we hear often
Why move money in database functions?
Because one Postgres function checks the balance, writes the double-entry posting and records the audit row in the same transaction. If anything fails, nothing is left half-done, and no browser can write a balance.
Can the data from the old exchange-house software be migrated?
Yes. The project's ETL reads the SQL Server .bak backup and loads it into Postgres. Legacy balances become the starting point, and every later movement is posted by the new functions.
Is MFA mandatory for every user?
Yes, across all 8 roles. A user joins by invitation, sets a password, enrols an authenticator app with a QR code or manual key, and from then on every sign-in asks for the 6-digit code. That code is never sent over WhatsApp.
Cases close to this one
Read more
IB Group · Planet Fitness Mexico
One room-booking app, deployed for three offices
A door tablet for every room and an admin console, synced with Exchange. First for Planet Fitness Mexico, then for IB Group's Fashion Depot and Grimatex: 22 rooms across three deployments.
Learn more →
Read more
Sí, Jefa · AI agent office
Sí, Jefa: 18 AI agents run a lunch company
Office lunches in Madrid: one dish a day at €8.90 excl. VAT, orders locked at 10:00. Seven surfaces in one app and La Oficina, a 3D scene where 18 AI agents run the operation.
Learn more →
Read more
Steel Bastion · Tower defense
A military tower defense on six fronts
Flutter game for Android and iOS: 60 missions against armoured columns, 10 weapons, a daily operation and survival fronts, with no ads.
Learn more →Let's put it in production
Tell us your challenge. We reply within 24 business hours with an honest first read: if we can help, we'll say how; if not, we'll say who can.
I reply personally. No endless forms, no canned replies.


