Skip to content

Repository files navigation

MysticArchive

A full-stack web app for Magic: The Gathering collectors to catalog the cards they own and add new ones by scanning them with a camera — at its core, a card scanner and collection tracker.

Status: Portfolio project, actively developed. Scoped for a small user base (Commander-first), with maintainability and clean architecture as the primary goals.


Features

The two core features:

  • Collection tracking — add, edit, and remove cards with per-copy quantity, finish (non-foil / foil / etched), condition, language, and notes. Import and export via CSV or pasted lists (Moxfield / Archidekt compatible).
  • Card scanner — identify physical cards through your device camera using an OpenCV + OCR pipeline and add them straight to your collection.

Supporting the collection:

  • Card search — search the full MTG catalog (~96k cards) by name, oracle text, mana cost, color, type, rarity, and set, with representative-printing selection and infinite scroll — to find cards to add.
  • Card detail view — every printing, oracle text, legalities, finishes, live prices, high-res imagery, and a price-history chart.
  • Watchlist — track cards or specific printings with target prices and price trends.
  • Dashboard — total collection value, value-over-time trend, value by set, 24h price movers, and set-completion progress.
  • Pricing — current and ~90 days of historical prices per finish, synced daily from MTGJSON via a scheduled job.
  • Accounts — email/password auth (argon2), Google sign-in, profiles with avatars.

Tech Stack

Frontend — React 19 · Vite · React Router · Zustand · TanStack Query · Tailwind CSS · Radix UI / shadcn · Recharts · OpenCV.js + Tesseract.js (scanner)

Backend — NestJS · Prisma · PostgreSQL · Passport (JWT + Google OAuth) · argon2 · MinIO (S3-compatible avatar storage) · Swagger/OpenAPI

Tooling — Docker Compose · GitHub Actions (CI + scheduled price sync) · ESLint · Prettier · Jest · Vitest


Architecture

Monorepo with independent frontend/ and backend/ npm projects:

MagicCollectionManager/
├── frontend/          React + Vite SPA
│   └── src/
│       ├── pages/         route screens
│       ├── components/    UI
│       ├── hooks/         data-fetching + logic (per domain)
│       ├── services/      thin API-client wrappers (per domain)
│       ├── stores/        Zustand client state
│       └── lib/           adapters, helpers, scanner vision, import parsers
├── backend/           NestJS API
│   ├── src/               one module per feature (auth, cards, collection,
│   │                      watchlist, prices, dashboard, users, …)
│   └── prisma/            schema + migrations + seeds
├── scripts/           standalone jobs (MTGJSON price sync)
├── docker-compose.yml
└── .github/workflows/ CI + daily price sync

Request flow (backend): HTTP controller → service (business logic) → Prisma → Postgres.


Getting Started

Prerequisites

  • Node 22 (see .nvmrc)
  • Docker + Docker Compose

1. Configure environment

Copy the backend env template and fill in the values:

cp backend/.env.example backend/.env

At minimum set a strong JWT_SECRET. Google OAuth (GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET) is optional — leave blank to disable Google sign-in. The default DATABASE_URL and MinIO values already match the Docker Compose services below.

2. Run with Docker Compose

The quickest path — starts Postgres, MinIO, the backend, and the frontend together:

docker compose up --build

3. Set up the database

Run migrations and seed the card catalog (imports MTG cards from Scryfall bulk data):

cd backend
npm run prisma:migrate      # apply schema
npm run prisma:seed         # seed reference data (tags, etc.)
npm run cards:seed          # import the card catalog from Scryfall (~96k cards)

The card import is large and runs once. Price history is populated separately by the price-sync job (see below).


Local Development (without full Docker)

Run only Postgres + MinIO in Docker, and the apps directly for hot reload:

# infra only
docker compose up postgres minio

# backend
cd backend
npm install
npm run prisma:generate
npm run start:dev           # http://localhost:3000

# frontend (separate terminal)
cd frontend
npm install
npm run dev                 # http://localhost:5173

Scripts

Backend (backend/)

Command Description
npm run start:dev Start the API in watch mode
npm run build Compile the API
npm run test Run the Jest test suite
npm run lint / type-check Lint / type-check
npm run prisma:migrate Apply database migrations
npm run cards:seed Import the card catalog from Scryfall

Frontend (frontend/)

Command Description
npm run dev Start the Vite dev server
npm run build Production build
npm run lint Lint
npm run format:check Check formatting
npm run test:run Run the Vitest suite

Pricing Sync

scripts/sync-prices.mjs pulls market prices from MTGJSON and maintains a rolling ~90-day daily history per card/finish. It runs automatically via GitHub Actions (.github/workflows/sync-prices.yml) on a daily cron (15:00 UTC), and can be run manually:

node scripts/sync-prices.mjs

Continuous Integration

.github/workflows/ci.yml runs on every pull request and push to main, with path-filtered jobs so frontend and backend only run when their code changes:

  • frontend-ci — lint, format check, tests, build
  • backend-ci — lint, type-check, then tests against a real postgres:16-alpine service container (prisma migrate deploy), and build

Data Sources

  • Scryfall — card metadata and imagery (imported into the local catalog).
  • MTGJSON — market pricing data.

Prices are indicative estimates, refreshed roughly daily — MysticArchive is a tracking tool, not a financial or trading service.


License

This is a personal portfolio project. All Magic: The Gathering card data, names, and imagery are property of Wizards of the Coast; this project is unofficial and not affiliated with or endorsed by Wizards of the Coast.

About

Simple Collection Manager for Magic The Gathering

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages