Core Concept

Channels

A channel is anywhere a card can be live. SlabTrack tracks every card's channel state in one authoritative table — card_channels — so the system always knows whether a card is on ToT, on a Storefront, in a Showcase Break, or sitting quiet in your personal collection.

Why channels exist

Without a unified channel system, you'd have a card listed on ToT AND a Storefront AND eBay simultaneously, two buyers could pay for it, and you'd be issuing refunds and apologies. The channel layer prevents this by being the one place that knows where a card is.

The channels

SlugNameBehavior
personalPersonal collectionDefault. Card is private, not for sale anywhere.
thisorthatThisOrThatLive on ToT for Flip / Pull plays. Buyer pays variable price, always gets a card.
storefrontStorefrontLive on a vendor's storefront (the operator's own or a peer's). Direct-buy at fixed price.
showcaseShowcase BreaksReserved for an open showcase break. Card ships to whoever wins their spot.
repackRepack PackLocked into a sealed pack with other cards. Pack sells as a unit.
ebayeBayListed on eBay. Auto-pulled when sold or relisted.
whatnotWhatnotTagged for Whatnot live auction. Manual operator workflow.
⚠ Exclusivity rules vary

Some channels are exclusive (a card on Showcase can't also be on ToT — the showcase locks the card). Others allow dual listing (Storefront + ToT can both list the same card if DUAL_LISTING_ENABLED=true, with sale-locks coordinating to prevent double-sale). Check each channel's adapter in backend/services/channels/registry.js for the canonical exclusive flag.

The card_channels table

The schema (Postgres):

CREATE TABLE card_channels (
  id              SERIAL PRIMARY KEY,
  card_id         INTEGER REFERENCES cards(id),
  user_id         INTEGER REFERENCES users(id),
  workspace_id    INTEGER REFERENCES workspaces(id),
  channel_slug    TEXT NOT NULL,            -- 'thisorthat', 'storefront', etc.
  status          TEXT NOT NULL,            -- 'active' | 'inactive' | 'sold'
  external_ref    TEXT,                     -- satellite-side ID (ToT listing id, etc.)
  metadata        JSONB,                    -- per-channel context
  engaged_at      TIMESTAMP DEFAULT NOW(),
  disengaged_at   TIMESTAMP
);

The four state transitions

Engage

A card moves from personal to a channel. Triggered by:

Inserts a card_channels row with status='active' and notifies the satellite via webhook.

Disengage

A card pulls back from a channel without selling. Triggered by:

Sets status='inactive' and fires a disengage webhook to the satellite.

Sale

A card sells. The selling channel sets status='sold' on its own row and fires bulk-disengage webhooks to every OTHER active channel for that card so they pull their listings.

Reconcile

If state drifts (manual delete on ToT, network failure, etc.), the Sync Center's reconciler asks each satellite for its canonical active-card list and clears stale rows.

Where channels show up in the UI

Code references