Selected Work - Engineering

MintCollect - the trading-card commerce platform

A trading-card data and commerce platform: real-time card identification, a multi-mode marketplace, a portfolio/price-tracking engine, and a subscription layer - built mobile-first and scaled for influencer-driven traffic spikes.

Role

Founding Software Engineer

Stack

React Native · Flask · PostgreSQL · AWS

Links

App Store · GitHub

Timeline

2024 - present

01Overview

MintCollect lets collectors scan, value, organize, and trade trading cards from their phone. As founding engineer I own the React Native mobile client end-to-end and a large share of the Python/Flask backend - from the card-scanning pipeline and the portfolio/ledger engine to the marketplace and the subscription/payments layer - working alongside a small backend team and a remote contractor.

The system today backs 50k+ registered accounts against a catalog of 185k+ cards, 1,642 sets, and 4,044 sealed products, served by 230+ API endpoints and a PostgreSQL schema spanning 9 namespaces and 100+ tables.

02What I built

  • Card identification pipeline - phone-camera capture wired to the Ximilar vision API for server-side recognition, mapping a photo to a specific card, variant, and printing across 185k+ catalog entries.

  • Portfolio & ledger engine - an append-only collection ledger with FIFO cost-basis accounting, idempotent writes, and pre-aggregated rollup tables so net-profit and collection-value math stays correct and fast.

  • Multi-mode marketplace - a unified Product → Listing → Inventory model with pool-based inventory, SKIP LOCKED reservation at checkout, Stripe-hosted payment, and a full order → shipment → refund → dispute lifecycle.

  • Subscription layer - tiered access (free + paid tiers) with server-side receipt verification via RevenueCat / StoreKit webhooks, so entitlements are provable, not claimed.

  • Data layer - a React Query fetching/caching strategy on the client and a fail-open Redis cache with per-account epoch invalidation on the server.

  • Internationalization - the full UI localized into 7 languages (en/es/fr/de/ja/ko/zh).

  • Admin dashboard - a Vite + React control plane for catalog, marketplace, orders/disputes, news, and app-control (maintenance mode, forced updates, version gating).

  • Load readiness - a pre-launch stress-testing plan for influencer-driven concurrency spikes.

03Architecture

Mobile App

React Native · Expo

Admin Dashboard

Vite · React

API Layer

Flask · Gunicorn behind Nginx on AWS EC2

Scanner

Ximilar Vision API

Data

PostgreSQL 16.8 · AWS RDS

Cache

Redis · rate limiting

Payments

Stripe · RevenueCat

Media

S3 + CloudFront

Two clients - a React Native mobile app and a Vite/React admin dashboard - talk over HTTPS to a Flask API served by Gunicorn behind Nginx on AWS EC2. The API fans out to PostgreSQL on RDS for relational data, Redis for caching and rate limiting, S3 + CloudFront for card imagery, and external services for recognition (Ximilar), payments (Stripe), and subscriptions (RevenueCat / StoreKit). CloudFlare fronts DNS and SSL; Expo Push delivers notifications, SendGrid sends transactional email, and Sentry + BetterStack cover error tracking and uptime.

04Technical challenges

Reliable card identification

Problem
cards must be recognized from a phone camera, in poor lighting, across thousands of near-identical printings and variants.
Approach
routed camera capture to the Ximilar vision API for server-side recognition, then resolved the match against a 185k-card catalog (card → variant → printing) with trigram (pg_trgm) fuzzy search as a fallback lookup.
Result
a fast capture-to-match flow that reliably disambiguates variants instead of guessing.

Trustworthy subscription billing

Problem
client-reported entitlements can be spoofed, exposing paid features for free.
Approach
moved entitlement checks server-side, verifying purchases through RevenueCat / StoreKit webhooks with idempotency on the provider event id, persisted to a subscription_events audit trail.
Result
closed the billing bypass - entitlements are provable from server state, not claimed by the client.

Correct money math at scale

Problem
collection value and net profit must stay correct as users add, remove, and sell items, with no double-counting under concurrent writes.
Approach
an append-only ledger with FIFO cost-basis lots, idempotency keys, SELECT … FOR UPDATE validation, and condensed rollup tables for fast aggregates.
Result
durable, auditable portfolio math and instant net-profit reporting.

Marketplace concurrency

Problem
two buyers can race for the last copy of an item.
Approach
pool-based inventory with SKIP LOCKED reservation at checkout, and the Stripe webhook as the source of truth for order creation rather than the client.
Result
no oversells; orders only materialize on confirmed payment.

Surviving traffic spikes

Problem
an influencer post can drive a large concurrent-user spike in minutes.
Approach
a fail-open Redis cache (per-account epoch invalidation), Flask-Limiter rate limiting backed by Redis, pre-aggregated analytics tables, and a pre-launch stress-testing plan.
Result
identified scaling limits before launch rather than during an outage.

Snappy, consistent data

Problem
marketplace and pricing data change constantly; naive fetching means stale UI and jank.
Approach
centralized fetching/caching with React Query - background refetch, optimistic updates, and hierarchical query-key invalidation.
Result
fewer requests, instant-feeling UI, predictable state.

Performance & scale

Rendering a 185k-card catalog on a phone

Problem
a single set or search can return thousands of high-resolution card images; naive lists drop frames and balloon memory on mid-range phones.
Approach
@shopify/flash-list with row-batched cells and per-card recyclingKey; expo-image with a memory-disk cache, placeholders, and startup prefetch of set artwork; React.memo + useMemo across tiles, with entry animations capped to the first 12 items; live search debounced to 400 ms with a 2-character minimum.
Result
smooth scrolling and instant-feeling filtering over large sets, without runaway image memory.

Live-as-you-type search across 185k cards

Problem
the original search was a substring scan over three fields - sequential scans that couldn't keep up with as-you-type queries from power users and vendors.
Approach
a unified /catalog/search endpoint backed by pg_trgm GIN trigram indexes, a small power-search query language (multi-term AND, quoted exact match, -exclusion, card-number and type facets), and an index-backed fuzzy fallback that only fires when the exact pass is thin.
Result
fuzzy matches return in ~29 ms (verified with EXPLAIN ANALYZE) over 185k+ live cards, with the endpoint rate-limited to 120 req/min.

Aggregating a 3.5M-row collection ledger

Problem
portfolio value and ownership counts were computed by SUM-ing an append-only ledger of 3.5M+ rows on every read - too slow for social and collection screens.
Approach
condensed rollup tables keyed by (account, variant, condition) with UNIQUE NULLS NOT DISTINCT, rebuilt from the ledger in a single grouped pass and kept in sync via on-write ON CONFLICT upserts.
Result
hot reads hit the rollups instead of scanning millions of rows; a full rebuild runs in seconds, with a drift audit confirming zero divergence.

Pricing the whole catalog every night

Problem
pricing ~185k cards from multiple marketplaces with a simple average produced fragile prices on thin or stale data.
Approach
an idempotent, resume-safe nightly batch that ingests ~1.45M marketplace price rows and computes a confidence-weighted robust median per (card, grade), blending sources by freshness and liquidity.
Result
stable prices even for illiquid cards, recomputed daily and safely re-runnable.
Pokédex catalog
Portfolio analytics
Marketplace
Card scanner

05Stack & why

React Native + Expo to ship one codebase to iOS and Android and move fast on UI. Flask / Python for the API because the data and pricing work is Python-heavy and the team's strength. PostgreSQL for relational catalog, ledger, and marketplace data with strong integrity guarantees. Redis for caching and distributed rate limiting. AWS (EC2 / RDS / S3 / CloudFront) for compute, managed data, and image delivery. Ximilar for card recognition, Stripe for marketplace payments, and RevenueCat to abstract cross-platform billing.

React NativeTypeScriptReact QueryNativeWindZustandFlaskPythonPostgreSQLRedisAWSNginxGunicornStripeRevenueCatXimilarSentry

06Outcomes

iOS / Android

Shipped to both stores

50k+

Registered accounts

185k+

Cards cataloged · 1,642 sets · 4,044 sealed

230+

API endpoints

9 / 100+

Postgres schemas / tables

7

Localized languages