Arbolito
- React
- Vite
- NestJS
- Prisma
- PostgreSQL
- Socket.io
- Turborepo
P2P · USD/ARS · Argentina
A “Tinder” for the blue-dollar rate: see offers near you at the current rate, send a request for the amount you want, and if they accept, a chat opens to coordinate the exchange.
USD / ARS 1,482.00/1,515.00 live rate — the anchor of every screen
What problem does Arbolito solve?
In Argentina the informal dollar —the “blue”— is exchanged every day in cash, face to face, through arbolitos and cuevas. It is a huge market that lives in WhatsApp groups, referrals and gut-feel trust: you rarely know who you are buying from, the real rate, or whether the meeting is safe.
Arbolito started from a simple question: what if that exchange had the clarity of a fintech app and the discovery mechanics of a dating app? See offers near you, with the current rate, the other party’s reputation, and a channel to coordinate — without exposing your identity or location until there is a deal.
How was Arbolito built?
We started with the identity. With my designer partner we defined a full design system before writing any product: the “cueva” aesthetic —deep navy, mint green, elevation by color rather than shadows, tabular-nums for every figure— and the signature element, the CurrencyPill that keeps the rate alive in the header of every screen.
On that foundation I built the product end-to-end: a Turborepo monorepo with a NestJS API and a React PWA, real-time over Socket.io, and a set of domain modules (offers, requests, chat, geo, KYC, reviews, notifications).
What technical decisions does Arbolito have under the hood?
The decisions that make Arbolito are not in the feature list, they are in the details. These are the ones I care about most.

Privacy-preserving location
Exchanging cash means meeting a stranger. That is why an offer’s exact location is never exposed: it is fuzzed server-side, and the real position is only revealed once the other party accepts the exchange.
- Coordinates deterministically fuzzed with SHA-256 over the offer id
- Uniform displacement within a 300 m radius (√ distribution so it does not cluster in the center)
- Precise position only visible to the owner or once a request is accepted

The live blue rate, with a safety net
The rate is the heart of the product, so it could not fail. I pull it from a public source (Bluelytics) behind a custom circuit breaker, with an in-memory cache and a Postgres fallback. Ads can fix a price or track the market with a “±%”, and recompute themselves whenever the blue moves.
- Custom circuit breaker (CLOSED / OPEN / HALF_OPEN) over the external API
- In-memory cache (TTL) → Postgres fallback → staleness flag to the client
MARKET_PERCENTprices recomputed by cron when the rate changes

From request to chat, as a state machine
The core mechanic is an explicit ask: you send a request for an amount, and the other party accepts or rejects it. Each request is a state machine (pending → accepted / rejected / expired) and its creation is transactional: request, conversation and first message are born together or not at all.
- Atomic creation of request + conversation + message in one transaction
- The chat stays locked until acceptance — no cold-messaging
- Automatic cron-based expiry and event-driven notifications on every change

A chat that feels instant and never lies
The chat runs over Socket.io with JWT auth and a room per user. The UI is optimistic so it feels immediate, but every message waits for server confirmation: if it fails, it rolls back. A custom rate-limiter keeps anyone from flooding a conversation.
- JWT-authenticated gateway with per-user rooms
- ACK-based delivery that rolls back the optimistic update on failure
- Custom rate-limiter (5 msg/s) and strict server-side validation

Verification, visibility and blocking
In a trust market, control is part of the product. There is identity verification (KYC) as an isolated module, fine-grained visibility controls —who sees your name, your photo, your ads— and user blocking applied at the query level, not as a cosmetic filter.
- KYC as a decoupled module, ready to plug in an automated provider
- Per-field visibility: everyone / verified only / nobody
- Blocked users filtered in the database across all relevant queries
A tour through the product






Closing
Arbolito never reached production, but it did become a real product: a coherent design system, a domain-driven architecture, and a handful of decisions —location privacy, rate resilience, reliable real-time— that solved concrete problems of the Argentine context.
For me it was the exercise of taking an idea end-to-end with a design partner, and of knowing when to stop. I leave it here as a case: the code and the screens speak for themselves.