← projects

Tailor Cards

A live online store and card-buying tool for the trading-card business I run. I designed and built all of it: backend, database, frontend, payments, security and the tests that keep it working.

Role
Founder and sole developer
Status
Live and taking real orders; AI buylist in private beta
Stack
Java 21, Spring Boot, Spring Security, Spring Data JPA, PostgreSQL, Flyway, React, TypeScript, Stripe, Claude API, AWS, GitHub Actions
The Tailor Cards homepage: a dark storefront with the headline 'Chase cards and graded slabs, inspected up close', Shop and Sell buttons, and three featured Pokémon cards.
The storefront at tailorcards.com.

The problem

A business that ran on messages and in-person sales

I started Tailor Cards in September 2024, selling through Instagram, Facebook, in-person shows and eBay. It's self-funded and has done about 2,000 transactions and more than $30,000 in sales volume.

Every sale went through me by hand, from first message to shipping. That was the limit on how far the business could grow, so I taught myself full-stack development and built a site to move it online.

What I built

A store, a way to sell to me, and the tools behind them

Hard problems

Three things that took the most work

Never selling a one-of-a-kind card twice

The problem
Many cards are one-of-a-kind. A customer can open Stripe checkout, leave the tab, and pay after someone else has already bought the same card. Stripe can also send the same payment notification more than once.
What I did
JPA optimistic locking on each product, so two checkouts that collide fail cleanly instead of both succeeding, plus a stock re-check at checkout. Repeated payment notifications are recognised and never create a second order.

Using AI to read card lists without letting it set prices

The problem
Customers describe their cards in free text, pasted lists and spreadsheets, which is a good fit for a language model. But a model that can be talked into a higher price, or that makes one up, can't be trusted with money.
What I did
The model only identifies cards; Java looks up and calculates every price. Prompt injection is blocked by rejecting any price the model emits, server-side. Rate and spend limits cap the cost, and a weekly evaluation in CI replays golden conversations and fails on any regression from the baseline.

Making card matching fast, and keeping it fast

The problem
Matching a 60-item list took 35.3 seconds, and any later change could quietly make it slower again.
What I did
Cut matching time for a 60-item list from 35.3 s to 16.6 s, and added a benchmark to CI that fails the build if it regresses.

Keeping it reliable

Testing, security and data quality

Screenshots

The site today

The Sell your cards page: a chat box on the left where customers describe or paste their cards, and an empty 'Your list (0/1000)' panel on the right.
The AI buylist assistant. Customers can list up to 1,000 cards.
The All cards shop page: category filters for singles, graded slabs and sealed product on the left, and a grid of cards with condition, price and sold badges.
The shop, with condition labels and sold items marked.