Rafael de Carvalho

Rafael de Carvalho

Senior backend engineer. I make the scary parts of a system boring: event pipelines, payments and the migrations nobody wants to touch.

Two billion events a month.

Analytics ingestion rewritten from legacy PHP to Node.js and TypeScript, landing in a columnar store. Queries that used to time out now answer in ~250 ms.

Every message, once.

Queues retry, banks resend, networks lie. Idempotent consumers and transactional side effects make each event count exactly one time.

R$10M a month, reconciled.

Direct APIs with Bradesco, Banco do Brasil, Cielo and Omie replaced FTP files. ~15.5k transactions a month now match themselves.

Noise in. One entry out.

A double-entry ledger built from zero: every movement is a debit and a credit that agree. Six years of making systems add up.

Three rebuilds at once, one engineer.

At Chaves na Mão I am the only engineer on three simultaneous platform rebuilds, reporting directly to the CTO.

Analytics that stopped timing out

Analytics pipeline rebuild · Chaves na Mão

Every query timed out against ever-growing MySQL shards. I benchmarked Kinesis Firehose, Redis Streams and in-memory buffering, chose Tinybird as the columnar store, and rewrote ingestion end to end. Advertisers now get real-time dashboards that were impossible before.

~2Bevents a month
~250 msaverage query

Node.js, TypeScript, Kinesis, Tinybird, AWS

Average dashboard query, before and after

MySQL shards timeout
Tinybird pipeline ~250 ms

Drawn to scale against a 20 s gateway timeout.

Payments that reconcile themselves

Payments platform rebuild · Chaves na Mão

File and FTP bank exchanges became direct API integrations. Reconciliation now runs automatically across the internal admin, the fiscal system, every bank and the acquirer, on top of a double-entry ledger I designed from zero.

R$10M+reconciled a month
100%automated

Node.js, TypeScript, PIX, Bradesco, Banco do Brasil, Cielo, Omie

One PIX received, as the ledger records it

// every entry balances or the transaction rolls back
await ledger.post({
  idempotencyKey: 'pix:E1847…3f2a',
  lines: [
    { account: '1.1.02 bank:bradesco',    debit:  1240_00 },
    { account: '2.1.04 customer:credit', credit: 1240_00 },
  ],
});

A PHP monolith, strangled safely

PHP 5.6 to NestJS migration · Chaves na Mão

About 175,000 lines of PHP 5.6 moving into a NestJS monorepo with the strangler fig pattern. Architecture, module boundaries, tests and incremental cutover, while paying customers keep using the legacy system every day.

~175klines of PHP
800+commits

NestJS, TypeScript, monorepo, PHP 5.6

At the edge, each route goes to whoever owns it now

// migrated routes answer from NestJS, the rest still reach PHP
const migrated = new Set([
  '/api/listings', '/api/leads', '/api/billing',
]);

app.use((req, res, next) =>
  migrated.has(routeOf(req))
    ? next()
    : legacyProxy(req, res));

Send it twice. Count it once.

Banks resend webhooks. Fire the same payment again and watch the books. Then turn idempotency off and see what a retry costs.

Money receivedR$ 0,00
Credit bookedR$ 0,00
Books balanced. Nothing received yet.
POST /webhooks/pix0 requests
  1. Waiting for the bank. Press “Receive a new PIX”.

From intern to sole engineer in six years.

I switched careers at 31. Three promotions in my first two years, and another at Chaves na Mão after three months.

Oct 2025 – now

Senior Backend Engineer

Chaves na Mão · remote

  • Sole engineer on three platform rebuilds, reporting to the CTO
  • Promoted after three months, employee of the month
  • Analytics from timeout to ~250 ms at ~2B events a month
  • Direct bank APIs and automatic reconciliation on R$10M+ a month

Mar 2025 – Oct 2025

Backend Engineer

TODOS Empreendimentos · remote

  • Distributed systems in Node.js and TypeScript
  • Left for broader technical ownership at Chaves na Mão

Sep 2020 – Jan 2025

Intern to Specialist

BGC Brasil · remote

  • Recurring billing gateways moving ~R$18.5M a month for 600k+ subscribers
  • Payment processor, acquirer and bank integrations
  • Upwork in parallel: 225 hours, 100% job success, all in English

The stack, by years in production.

Languages & runtime

  • TypeScript 6 yr
  • Node.js 6 yr
  • SQL 6 yr
  • Python 2 yr

AWS & messaging

  • AWS 6 yr
  • Serverless 6 yr
  • SQS · SNS 5 yr
  • Kinesis 1 yr

Data

  • MySQL 6 yr
  • PostgreSQL 6 yr
  • MongoDB 6 yr
  • DynamoDB 6 yr
  • Tinybird 1 yr

Frameworks & infra

  • NestJS 2 yr
  • Docker 6 yr
  • Terraform 1 yr
Portrait of Rafael de Carvalho

My focus is correctness under load: idempotent consumers, transactional side effects, and enough observability to know before the customer does.

Based in Curitiba, Brazil. Fully remote, comfortable with US time zones, and every Upwork contract I have delivered was in English.

5.0Upwork rating
100%job success
225 hcontracted on Upwork
600k+subscribers billed at BGC