CardApp

A full-stack Pokémon and Magic: The Gathering collection manager, price tracker, and trading platform. Browse the complete card catalog, manage your collection, trade with other collectors, track portfolio value with daily market prices, and run a vendor storefront.

Features

Card Catalog

  • Two games: Pokémon TCG and Magic: The Gathering, switchable on the search page
  • Full-text search across card name, artist, flavor text, abilities, and attacks (Magic: type line and rules text)
  • Advanced filtering by set, type, rarity, supertype, subtype, and artist
  • Sorting by name, number, rarity, HP, release date, or market price
  • Artist browsing with aggregate collection and pricing stats
  • Infinite scroll pagination

Collection Management

  • Inventory tracking with per-card quantities and purchase prices
  • Portfolio valuation with per-card and total market value, gain/loss calculation
  • Wishlist for tracking cards you want
  • Tags for organizing your collection with color-coded labels
  • Bulk CSV import/export for managing large collections

Pricing & Alerts

  • Multi-source pricing from 7 Pokémon sources (Scrydex, TCGdex, PokeTrace, PokemonPriceTracker, PriceCharting, TAG, PokemonAPI) plus Scryfall for Magic
  • Price history charts with configurable date range
  • Price alerts when market prices change beyond your configured threshold
  • Exchange rate support for multi-currency display

Grading

  • Population data from grading services (PSA, CGC, TAG, ACE)
  • EV calculator for expected grading value analysis

Trading

  • Trade proposals between users with counter-offer flow
  • Real-time updates via SignalR when both parties are online
  • Atomic inventory transfer on trade acceptance
  • Trade notifications with unread count badge
  • Trade animation with Pokemon-inspired card swap effect

Vendor Features

  • Public storefront with custom pricing and shop branding
  • Custom pricing strategies (fixed, markup percent, markup flat)
  • Margin rules for automated pricing
  • Batch operations on inventory (update quantity, tag, delete)
  • Analytics dashboard with collection value trends and top cards

Authentication & Accounts

  • Passwordless auth via passkeys (WebAuthn/FIDO2), OAuth (Google, Microsoft, Discord), or magic link email
  • Cookie-based sessions (no client-side tokens)
  • Account linking to connect multiple sign-in methods
  • Role-based access (User, Vendor, Admin, Owner)

Admin

  • User management with role assignment
  • Price sync control panel for on-demand price fetching
  • Expense ledger for tracking operational costs
  • Rarity rank editor for custom rarity ordering

UI

  • Dark mode with Catppuccin Macchiato theme and light mode toggle
  • Responsive design with shadcn/ui components

Tech Stack

LayerTechnology
FrontendNext.js 16, React 19, Tailwind CSS 4, shadcn/ui, Recharts
BackendASP.NET Core 10, Entity Framework Core 10, SignalR
AuthASP.NET Identity, FIDO2 (passkeys), OAuth 2.0, magic links
DatabasePostgreSQL 15
Pricing7 price sources (Scrydex primary), daily CronJob
Card Datapokemon-tcg-data (git submodule, ~15,000+ cards)
EmailPostfix (SMTP)
InfrastructureKubernetes, Terraform, Traefik, Keel (auto-deploy)
CI/CDGitHub Actions, GitHub Container Registry

Project Structure

CardApp/
├── backend/              # ASP.NET Core API
│   ├── CardApp.Api/      #   Controllers, models, services, migrations
│   └── CardApp.Api.Tests/ #  xUnit tests
├── frontend/             # Next.js app
│   └── src/
│       ├── app/          #   Pages (19 routes)
│       ├── components/   #   UI components (27+)
│       ├── contexts/     #   Auth and currency contexts
│       ├── hooks/        #   Custom React hooks
│       ├── lib/          #   API client, passkey helper, utilities
│       └── types/        #   TypeScript DTOs
├── data/                 # pokemon-tcg-data submodule (card/set JSON)
└── docs/                 # Documentation

Getting Started

Prerequisites

Clone

git clone --recurse-submodules https://github.com/matt-edmondson/CardApp.git
cd CardApp

If you already cloned without submodules:

git submodule update --init --recursive

Database

Start a PostgreSQL instance. The simplest way with Docker:

docker run -d --name cardapp-db \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=cardapp \
  -p 5432:5432 \
  postgres:15

The backend auto-runs EF Core migrations on startup, so no manual migration step is needed.

Backend

cd backend/CardApp.Api
dotnet restore
dotnet run

Runs on http://localhost:5000. Uses appsettings.Development.json which connects to localhost:5432 with postgres/postgres credentials by default.

Frontend

cd frontend
npm install
npm run dev

Runs on http://localhost:3000. Create a .env.local file if one doesn't exist:

NEXT_PUBLIC_API_URL=http://localhost:5000

Price Fetching (Optional)

Fetch market prices from Scrydex:

cd backend/CardApp.Api
SCRYDEX_API_KEY=your_key SCRYDEX_TEAM_ID=your_team dotnet run -- --price-fetch

Fetch specific sets only:

PRICE_FETCH_SETS="sv01,sv02" dotnet run -- --price-fetch

Deployment

The app runs on the homelab Kubernetes cluster at https://foildogs.com. Its Terraform lives in the homelab repo (matt-edmondson/homelab, terraform/cardapp.tf), alongside the cluster's other apps.

Key resources:

  • Backend and frontend deployments with GHCR images, rolled by Keel when CI pushes new images
  • PostgreSQL (plain postgres:17-alpine StatefulSet on Longhorn)
  • Traefik IngressRoute with TLS
  • The homelab's shared mail server for magic link email (the backend signs in as noreply@foildogs.com)
  • CronJobs for daily price fetching (6 AM UTC) and data exports, plus a one-off TCGdex backfill Job
# From the homelab repo
cd terraform
make apply-cardapp

Documentation

  • Developer Guide — architecture, API reference, data model, services, infrastructure
  • Feature Map — complete catalog of all implemented features and endpoints
  • Authentication — auth system details (passkeys, OAuth, magic links, roles)

License

This project uses card data from the pokemon-tcg-data project, and Magic: The Gathering card data, images and prices from Scryfall. Magic: The Gathering is © Wizards of the Coast; CardApp is not affiliated with or endorsed by Wizards of the Coast or Scryfall.