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
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, Tailwind CSS 4, shadcn/ui, Recharts |
| Backend | ASP.NET Core 10, Entity Framework Core 10, SignalR |
| Auth | ASP.NET Identity, FIDO2 (passkeys), OAuth 2.0, magic links |
| Database | PostgreSQL 15 |
| Pricing | 7 price sources (Scrydex primary), daily CronJob |
| Card Data | pokemon-tcg-data (git submodule, ~15,000+ cards) |
| Postfix (SMTP) | |
| Infrastructure | Kubernetes, Terraform, Traefik, Keel (auto-deploy) |
| CI/CD | GitHub 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
- .NET 10 SDK
- Node.js 22+
- PostgreSQL 15 (or Docker)
- Git (for submodule)
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-alpineStatefulSet 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.