CardCore
Back to Blog

The Trading Refactor, Repack Oversight, and Our First Instagram Post

March 23, 20269 min readBy Dan Vohasek
building-in-publicstar-wars-unlimitedtradingrepacksocial-media

The biggest ship yet

Today marks the completion of the largest single feature overhaul in CardCore's history. The peer-to-peer trading system has been completely rebuilt from the ground up across three phases, 22 tickets, 14 new database tables, and over 40 new database functions. And alongside it, we built a repack management dashboard, fixed a critical order flow bug, cleaned up 230 files of AI-generated formatting, and launched our first Instagram post.

Let me walk through all of it.

The Trading Refactor - why it needed to happen

The original trading system was built around a simple idea: users manually curate a trade binder, other users browse it, someone proposes a trade. It worked, but it had a fundamental problem - nobody wants to manually add 200 cards to a binder. The activation energy was too high. Players with massive collections would sign up, see that they needed to manually list every card they're willing to trade, and just not bother.

The refactor flips the model. Your collection IS your trade inventory by default. Every card you've tracked is automatically available for trade unless you explicitly mark it otherwise. This is an opt-out model instead of opt-in, and it changes everything about how discovery works.

Phase 1 - the foundation

Phase 1 was the database architecture. We created a user_profiles table for extended trading profiles - bio, location, and payment method preferences (Venmo, CashApp, Zelle, PayPal, cash). The trade registration system got a proper status workflow with seven states: pending_partner, pending_store, verified, completed, cancelled, disputed, and expired.

We built a reputation system (user_reputation) that tracks trust scores per user per store. Every completed trade, especially store-verified ones, builds your trust score. The idea is that over time, high-trust traders can unlock features that newer traders can't - like shipping trades without store verification.

The reward system ties trading activity to the repack token economy. Complete a store-verified trade? Earn pack tokens. The trade_reward_config table lets each store configure six different trigger types with daily caps. This creates a flywheel - trade cards, earn tokens, open packs, get more cards to trade.

The DB layer alone is about 1,800 lines with 40+ exported functions covering profiles, binders, wishlists, trades, reputation, rewards, expiry, history, and pending counts.

Phase 2 - safety and the tradeable quantity engine

Phase 2 was about making the opt-out model safe. If your entire collection is visible by default, you need controls.

The tradeable quantity engine is the core of the new system. The formula is simple but the implementation is not:

tradeable = collection_qty - not_for_trade_qty - active_deck_reserved_qty

For every card in your collection, we subtract any copies you've explicitly locked via "not for trade" markers, then subtract any copies reserved by your active decks (if you've enabled that setting). Only the remainder shows up as available to other traders.

This required building a not_for_trade table for per-card manual locks, a deck reservation calculator that aggregates across all active decks, and a search engine that can find traders by card name while respecting all these constraints in real-time.

The blocking system was the safety feature we knew we'd need before going live. The user_blocks table is one-directional on write but bidirectional on search - if either party has blocked the other, neither appears in the other's search results, trade hub, or trader listings. No notification is sent. The blocked user doesn't know they've been blocked. This is deliberate - trading card communities are small, and drama about blocks is worse than the blocks themselves.

Trade expiry solves the "pending trade that never gets answered" problem. Every pending trade now has a 7-day TTL. A cron job runs daily, finds expired trades, auto-cancels them, and sends Discord DMs to both parties. This keeps the trade queue clean and prevents the frustration of having cards tied up in limbo.

Trading profiles give users four modes: open (default - collection visible), binder_only (only manually curated cards visible), browse_only (can search but not be found), and private (completely hidden). Switching to private auto-cancels all pending trades, because you can't have open trades when you've opted out of the system.

Phase 3 - markers, cross-store, and per-game control

Phase 3 added the features that make trading between real humans actually work.

Trade markers (IOUs) solve a real problem we saw at events. Two players agree on a trade but one doesn't have their cards with them. Or they agree on a trade where one side will be fulfilled next week. The marker system lets them record the debt - who owes what, the terms, the timeline. Either party can settle or void a marker. It's tracked in the system so nobody "forgets" they owe someone a Darth Vader Showcase.

Cross-store search opens up the trading network beyond a single store's community. If you're looking for a specific card and nobody at your local store has it, the search now reaches across all stores to find traders who have enabled shipping. This is a network effect - every new store that joins makes the platform more valuable for every existing store.

Per-game trading toggles let users opt in or out of trading on a per-game basis. Right now it's Star Wars Unlimited only, but the architecture is ready for when we add more games. The setting is stored as JSONB, merged on update rather than replaced, so adding games doesn't reset existing preferences.

The Trade Hub redesign

The /traders page was rebuilt as a search-first interface. Type a card name and you get four result sections in parallel:

  1. Traders with this card - open-mode users with tradeable copies
  2. Also at your store - live store inventory you can buy right now
  3. Ships from other stores - cross-store traders who will mail cards
  4. Looking for this card - wishlist matches (potential trade partners)

The search runs all four queries in parallel and applies the block filter before returning results. It shows trust score badges, shipping badges, and a wishlist match counter that tells you how many cards they want that you have. The goal is to make finding a trade partner as fast as searching for a card.

The repack order flow was broken

Alongside the trading work, we found and fixed a critical bug in the repack system. When a customer accepts a pack (choosing to keep the cards instead of selling back), the system creates an order for physical pickup. That order was skipping the entire store review process - jumping straight to "ready for pickup" without staff ever confirming the cards were actually available.

This came to light when a tester opened seven packs and accepted all of them. The cards got deducted from inventory, the orders bypassed staff review, and the store had no way to see what happened or reverse it.

The fix was more nuanced than just changing a status field. Repack orders deduct inventory at creation time (to reserve the cards from the pack), while normal checkout orders deduct at confirmation. So the confirm, cancel, and reject functions all needed to understand the difference - skip deduction on confirm for repacks, restore inventory on cancel/reject even when the order is still pending. Three functions in the order system were updated with order_source checks.

Stores can now see repack purchases

The repack system had a visibility gap. Customers could see their own history, but staff had zero insight into what was happening. We built a new Purchases tab on the staff repack management page with:

  • Summary stats across the top - total packs opened, accepted vs. sold back, unique customers, total market value
  • Filterable list of every pack purchase with customer name, outcome badge, card count, and value
  • Expandable card grids showing every card in the pack with images and prices
  • A cancel button on accepted packs that reverses the order and restores inventory with a confirmation dialog

With the new tools, we reversed all seven of the tester's accepted packs. Seven orders cancelled, inventory restored, repack history updated. Clean slate.

230 files and zero em-dashes

When you build with AI assistance, a certain typographic fingerprint creeps into your codebase - em-dashes everywhere. The long dash that technically looks fine but screams "a language model wrote this." It was in toast messages, button labels, error strings, section comments, page descriptions. 230 files across the entire TypeScript and TSX codebase.

One bulk operation replaced every single one with a standard hyphen. It's a small thing that matters more than you'd think. Your product should feel like it was built by humans who happen to use great tools, not generated by a machine.

First Instagram post

CardCore has existed for months with zero social media presence. Today that changed. Our first post went live on Instagram - a dark-themed announcement card showcasing the P2P trading feature with a screenshot of the trade builder UI.

One post doesn't build a following. But it starts the clock. Every feature we ship is content. Every bug we fix is a story. Every tournament we run is a photo opportunity. The hard part is always starting, and today we started.

By the numbers

Here's what shipped today in concrete terms:

  • 22 Plane tickets closed across the trading refactor (P1 + P2 + P3)
  • 14 new database tables for trading profiles, blocks, markers, rewards, and reputation
  • 40+ new DB functions in the P2P layer alone
  • 230 files cleaned of AI formatting artifacts
  • 2 new API endpoints for repack store management (history admin + pack cancel)
  • 3 order system functions updated for repack-aware inventory handling
  • 7 data corrections (tester's repack orders reversed)
  • 1 first Instagram post launching social media presence
  • 1 new staff dashboard tab for repack purchase visibility

What's next

The trading system is in testing. Real users will start making trades this week, and we'll be watching closely for UX friction, edge cases, and performance issues. The per-copy tracking system for collections is on the horizon - right now, if you have 3 copies of a card and two decks each want 2, the system doesn't know there's a conflict. That's the next big data model question.

But today was the kind of day where you step back and realize the platform just made a major leap forward. From isolated binders to a network-wide trading economy with safety rails, reputation, rewards, and real discovery. That's not an incremental improvement. That's a new product.

If you're in the Star Wars Unlimited community and you want to trade smarter, check out store.cardcore.gg. And if you're a store owner curious about what a modern TCG platform looks like - we're just getting started.