About CardLedger: Engineering a Modern TCG Platform
CardLedger began with a strict engineering constraint: handle massive, relationship-heavy datasets (22,000+ cards and 6.3M+ price records) over the web, but make the experience feel as instant and fluid as a locally installed desktop app. Born from the frustration of slow, pagination-heavy web interfaces, it serves as both a functional TCG collection manager and a technical case study in building a high-performance, local-first architecture from the ground up.
For a deeper dive into the architectural decisions, I published a two-part engineering series detailing the backend infrastructure and client-side state management:
The Backend & Real-Time Infrastructure
- The ETL Ingestion Engine: A Node.js pipeline extracts raw API data and normalizes it into a relational schema. Sequential processing with retry logic and circuit breakers ensures resilience against API rate limits, while Prisma's idempotent upserts allow daily automation via GitHub Actions.
- Backend Analytics vs. Local Search: Prisma manages the 6.3M+ price history records on the backend to execute complex analytical queries. However, to make catalog browsing instant, the entire 22,000+ card dataset is indexed client-side. Using uFuzzy and custom intersection maps, filtering executes in sub-milliseconds without ever hitting the server.
- Postgres Pub/Sub & SSE Tower: To achieve real-time cross-device sync, database mutations trigger
pg_notifychannels. A dedicated Node.js VPS running behind an Nginx reverse proxy listens to the raw Postgres TCP stream and broadcasts Server-Sent Events (SSE) to specific clients.
A Local-First, Offline-Capable Architecture
To achieve a zero-latency “native app” feel regardless of network conditions, the application completely decouples the UI from the network layer. I break down the mechanics of this custom sync engine in Part 2 of the architecture series.
- Offline PWA Routing: A custom Service Worker intercepts network requests. If the connection is flaky, slow, or completely offline, the app seamlessly falls back to a locally cached router, keeping the entire catalog searchable in airplane mode.
- Static CDN Delivery & Dictionary Compression: To bypass traditional database latency, read-only catalog data is pre-generated as versioned JSON files and hosted on Cloudflare R2. These files utilize dictionary compression to reduce payloads from 10MB to 3.5MB, halving parse times and saving ~20MB of JS heap memory.
- The Outbox Mutation Engine: Collection interactions update instantly via client-side UUID generation. If the network drops, changes are queued in a local Outbox. To prevent data loss on captive portals (like coffee shop Wi-Fi), a custom network guard verifies true internet connectivity before silently syncing the queue in the background.
- Conflict Resolution & Delta Syncs: The server acts as a Last-Write-Wins (LWW) referee to gracefully handle stale offline edits. Devices sync efficiently by requesting only what changed since their last update. To prevent missing data from slow asynchronous database saves, the sync cursor automatically overlaps by a few seconds to catch delayed transactions.
Security & Asset Optimization
- Robust Authentication: Security is handled via Better Auth (Google, Discord, Email). The implementation focuses on Server-Side Authentication to eliminate layout shifts and ensure a stutter-free user experience.
- Cost-Optimized Asset Pipeline: A custom Node.js/Sharp script processes card images into highly optimized AVIF formats stored in Cloudflare R2, proactively generating variants for all target breakpoints to prevent runtime processing costs.
About the Creator
My name is Viet Le, and I'm a full-stack developer with a passion for building high-quality, performant web applications. CardLedger is my capstone portfolio project, built from the ground up to demonstrate mastery of modern application architecture, from database design to frontend optimization.