Luka Petrovic
← Back

Dashi

Dashi is an exchange for Pokémon trading cards, run as a joint venture with Mirmex, one of the biggest trading card retailers in Italy. Collectors deposit their physical cards once, then buy, sell and swap them online with no shipping in between, and withdraw them whenever they want. I built the whole platform by myself.

Visit dashi.gg ↗
cards in custody
40,000+
apps in one monorepo
6
automated tests
1,700+
The Dashi home page

The problem

On a marketplace every trade is a parcel. You wait days, you pack, and a card worth a few cents can't be sold at all because shipping costs more than the card. Condition is whatever the seller says it is, so it's never consistent.

Dashi moves the physical part to two moments only, deposit and withdrawal. Every card is checked when it comes in, and from then on ownership changes hands instantly.

What I built

Six apps in one Bun and Turborepo monorepo. The exchange itself in Next.js 16. The hub app the staff use to take in deposits, check grading, manage stock and prepare withdrawals. An Expo app for iOS and Android. A collection tracker, a blog, and a small print server that drives the label printers and the card scanner in the warehouse.

Everything runs on one Convex backend: real-time data, scheduled jobs, workflows and aggregates for things like floor prices and portfolio value. Clerk for accounts, Stripe for wallet top-ups and payments, Resend for email, Sentry and PostHog to see what breaks and what people use.

Custody is the hard part

A card on Dashi is a physical object somebody trusted us with, so the data model is strict about it. A print is the catalogue entry, a card is the one physical copy in our custody. A card is never thrown away by the system: it gets corrected, quarantined, routed or returned, and every step leaves a trace.

Deposits go from intake to recognition, grading and storage, for single cards and for bulk lots of thousands.

Recognising cards

Scans are matched against the catalogue with multimodal embeddings first. Only when the match isn't clear does a language model look at the image, and it picks from the short list of candidates instead of guessing freely. AI grading works the same way, with a fallback model when the primary one fails.

To tune it I replay versioned sets of real scans with known answers against a separate deployment, and read precision per segment before changing anything in production.

How I work on it

Every feature starts as a written spec and a plan in the repo. Agents write most of the code, CI runs lint, tests, typecheck and build on every pull request, a review bot comments, and the backend and the apps deploy together. It's how one person keeps six apps moving.

Stack

Next.js · Expo · Convex · Bun · Turborepo · Clerk · Stripe · AI SDK · Sentry