Skip to content

Repository files navigation

A card-game backend and web client — ASP.NET Core · PostgreSQL · Blazor WASM

CI .NET PostgreSQL License Live app API Docs Scalar

Exec Magica API is the backend and web client for the collectible card game EXEC_MAGICA. This repository is a production-deployed ASP.NET Core service — role-based auth, a card catalog with server-side filtering, per-user deck building, and server-side SVG card rendering — paired with a Blazor WebAssembly frontend, in a clean layered architecture.

Exec Magica — card catalog


Card catalog with server-side filtering and live SVG card rendering

▶ Live app

The app is deployed and running — browse the catalog, register an account and build decks, no setup required:

🌐 Web app exec-magica.kuzmenkoff.dev
🧪 API playground (Scalar) /scalar/v1
📚 API reference (DocFX) kuzmenkoff.github.io/exec_magica-api

Table of Contents

About

Exec Magica API is the server side and web client of the collectible card game EXEC_MAGICA — a standalone, production-grade ASP.NET Core application built on top of the game and its card data. It manages the card database, player accounts and decks, and renders cards on the server.

The goal was a clean, real-world .NET backend end-to-end: layered (Clean) architecture, a real relational database with migrations, token auth with roles, automated tests and CI, and a one-command Docker deployment — fronted by a Blazor WebAssembly UI so the whole thing is usable in the browser.

Highlights

  • 🧱 Clean/layered architecture — Domain · Application · Infrastructure · Api, dependencies point inward
  • 🔐 JWT auth with roles — ASP.NET Identity; Admin (card CRUD) vs User (browse + own decks)
  • 🃏 Server-side SVG card renderingGET /api/cards/{id}/render composites frame + art + DB stats
  • 🔎 Server-side catalog filtering — one composable EF Core query (class · mana · keywords · stats · sort)
  • 🗃 PostgreSQL + EF Core — real migrations, relations and primitive collections (not in-memory)
  • 🖥 Blazor WebAssembly client — catalog, auth, deck editor and admin, served single-origin by the API
  • Tested + CI — xUnit unit tests · GitHub Actions build+test
  • 🐳 One-command deploy — Docker Compose (API + Postgres), live behind Caddy with automatic HTTPS

Roles & use cases

Use case diagram — Guest / User / Admin
  • Guest — browse and filter the catalog, view rendered cards, register, log in.
  • User — everything a guest can do, plus build and manage their own decks.
  • Admin — everything a user can do, plus full card CRUD.

Architecture

A Clean/layered architecture across five projects under src/, plus a test project. Dependencies point inwardDomain references nothing; the database, web framework and UI live at the edges (Infrastructure, Api, Client). The graph below shows the projects and how they depend on one another.

flowchart TD
    CLI["ExecMagica.Client<br/><i>Blazor WASM — catalog · decks · admin</i>"]
    API["ExecMagica.Api<br/><i>controllers · DI root · JWT auth · hosts the client</i>"]
    INF["ExecMagica.Infrastructure<br/><i>EF Core repos · Identity · JWT · SVG renderer</i>"]
    APP["ExecMagica.Application<br/><i>services · interfaces · DTOs · CardQuery / ApplyQuery</i>"]
    DOM["ExecMagica.Domain<br/><i>entities · enums · DeckRules</i>"]
    TST["tests/ExecMagica.Tests<br/><i>xUnit</i>"]

    API --> CLI
    API --> INF
    INF --> APP
    APP --> DOM
    TST --> APP

    INF -. Npgsql .-> DB[(PostgreSQL)]
    CLI -. HTTPS · Caddy .-> API
Loading

Solid arrows are compile-time dependencies; dotted arrows are runtime connections.

  • ExecMagica.Domain — the core model of what the game is. Holds the entities (Card, CardEffect, Deck, DeckCard), the enums (CardClass, KeywordType, effect triggers/types/targets) and the invariants in DeckRules (max copies per card, deck size, decks per user). It references nothing — no EF Core, no ASP.NET — so the business concepts stay framework-free and every other layer is built on top of them.
  • ExecMagica.Applicationwhat the app does. Contains the use-case services (CardService, DeckService), the interfaces the core needs (ICardRepository, IDeckRepository, …) without knowing how they're fulfilled, the DTOs that shape the API contract, and the composable CardQuery / ApplyQuery catalog filter. Depends only on Domain, which keeps the application logic independent of the database and the web stack and makes it unit-testable. (ApplyQuery is deliberately EF-agnostic — plain LINQ over IQueryable<Card>, so it both translates to SQL via Npgsql and runs in-memory in tests.)
  • ExecMagica.Infrastructurehow the abstractions are actually fulfilled, against real technology. Provides EF Core (AppDbContext, repositories, migrations, seeding), ASP.NET Identity (users & roles), JWT token generation, and the SVG card renderer that composites the frame, artwork and DB stats. It implements the Application interfaces and depends on Application + Domain, so all the external-tech detail lives at the edge and never leaks into the core.
  • ExecMagica.Api — the HTTP entry point and composition root. Exposes the controllers (Cards, Decks, Auth, Rules), wires the Application interfaces to their Infrastructure implementations through DI, runs the auth middleware (JWT validation + roles), and hosts the Blazor client single-origin (serves the WASM/static files with an index.html fallback). Depends on Application, Infrastructure and Client — it is the one place where the outside world (HTTP, DI, hosting) meets the core.
  • ExecMagica.Client — the user-facing Blazor WebAssembly single-page app: the pages (catalog, deck editor, admin, login/register), typed API clients, JWT auth state and the themed card view. It has no project references — it talks to the backend purely over the HTTP/JSON contract, so the frontend stays a fully independent app that could be replaced by any other client.
  • tests/ExecMagica.Tests — xUnit unit tests over the core logic (catalog filtering/sorting via ApplyQuery, DTO mapping, deck rules). References Application (Domain flows transitively) and nothing heavier, so the business rules are verified fast and without a database or the ASP.NET/EF stack.

Data model

PostgreSQL via EF Core. Game tables (Cards, CardEffects, Decks, DeckCards) alongside the ASP.NET Identity tables (users & roles). Keywords are stored as a Postgres array column on Cards rather than a join table.

Database schema
  • Cards — one row per card definition; Keywords is a Postgres enum[] array column.
  • CardsCardEffects — one-to-many (cascade delete). The effects table backs a future effect system and is currently unpopulated (cards carry keywords + rules text only).
  • DecksDeckCardsCards — a deck holds many entries; each entry links one card with a Quantity. The (DeckId, CardId) pair is the composite key; copies/size are bounded by DeckRules.
  • AspNetUsersDecks — a user owns many decks (cascade delete when the user is removed).
  • AspNetUsersAspNetRoles via AspNetUserRoles — the Admin / User roles that gate card CRUD vs deck management.

Getting started

You may run the app locally to try or study it. Deploying, modifying or redistributing it is not permitted — see LICENSE.

Prerequisites: Docker with Docker Compose. (Optionally the .NET 10 SDK if you want to run the API or the tests outside a container.)

  1. Clone and configure

    git clone https://github.com/kuzmenkoff/exec_magica-api.git
    cd exec_magica-api
    cp .env.example .env

    Edit .env:

    • POSTGRES_PASSWORD — any value.
    • JWT_KEY — a long random secret (32+ chars).
    • SEED_ADMIN_EMAIL / SEED_ADMIN_PASSWORD — the admin account created on first run. The password must meet ASP.NET Identity rules: ≥6 chars with an uppercase letter, a lowercase letter and a digit (e.g. Admin1234).
  2. Run

    docker compose up -d --build

    Postgres starts first; the API then applies EF Core migrations and seeds the card catalog and the admin account on startup.

  3. Open

Run the tests

dotnet test

Card frames: the renderer expects card_back.png, entity_front.png and spell_front.png in src/ExecMagica.Api/wwwroot/cards/. Those templates derive from third-party assets and are not included (see THIRD-PARTY-NOTICES.md) — supply your own for framed cards. Rendering still works without them, just unframed.

Project structure

src/
├── ExecMagica.Domain/          # core model — no dependencies
│   ├── Entities/               #   Card · CardEffect · Deck · DeckCard
│   └── Enums/                  #   CardClass · KeywordType · effect triggers/types/targets
├── ExecMagica.Application/     # use cases — depends only on Domain
│   ├── Dtos/                   #   API-facing DTOs + CardQuery
│   ├── Extensions/             #   ApplyQuery — composable, EF-agnostic catalog filter
│   ├── Interfaces/             #   repository/service abstractions
│   └── Services/               #   CardService · DeckService
├── ExecMagica.Infrastructure/  # implementations against real technology
│   ├── Data/                   #   AppDbContext · migrations · seeding
│   ├── Identity/               #   ASP.NET Identity user · JWT token generator
│   ├── Rendering/              #   SvgCardRenderService
│   └── Repositories/           #   EF Core repositories
├── ExecMagica.Api/             # HTTP entry point + DI composition root; hosts the client
│   ├── Controllers/            #   Cards · Decks · Auth · Rules
│   ├── art/                    #   card artwork (AI-generated), served at /art
│   └── wwwroot/                #   fonts · card frame templates (not in repo) · served client
└── ExecMagica.Client/          # Blazor WebAssembly UI — no project references
    ├── Pages/                  #   Home · DeckEditor · MyDecks · AdminCards · Login/Register
    ├── Components/             #   CardView · CardFilters
    ├── Services/               #   typed API clients
    ├── Auth/                   #   JWT auth state + handlers
    └── wwwroot/                #   app.css · js · bootstrap
tests/ExecMagica.Tests/         # xUnit unit tests — ApplyQuery · mapping · deck rules
docs/                           # README assets
Dockerfile · docker-compose.yml · docker-compose.prod.yml   # image + dev / prod stacks
docfx.json · index.md · toc.yml                             # DocFX config (API reference)
LICENSE · THIRD-PARTY-NOTICES.md

The layered split maps directly to the projects under src/: Domain (pure model) → Application (use cases + interfaces) → Infrastructure (EF Core, Identity, rendering) → Api (HTTP + composition root), with Client as a standalone Blazor WASM frontend the API hosts. Tests target the core (Application/Domain) only.

Tech stack

Area Tech
Backend / language ASP.NET Core (.NET 10) · C#
Architecture Clean/layered — Domain · Application · Infrastructure · Api
Database / ORM PostgreSQL 16 · EF Core (Npgsql) · migrations
Auth ASP.NET Core Identity · JWT (Bearer) · Admin/User roles
Frontend Blazor WebAssembly · scoped CSS
Card rendering Server-side SVG compositing (frame + artwork + Peaberry font)
API docs OpenAPI · Scalar (playground) · DocFX (XML docs → GitHub Pages)
Testing xUnit · Moq
CI/CD GitHub Actions — build + test, DocFX deploy to Pages
Deployment Docker · Docker Compose · Caddy (reverse proxy, automatic HTTPS)

API

Interactive docs are generated from OpenAPI and served by Scalar at /scalar/v1. Authentication is a Bearer JWT obtained from POST /api/auth/login.

Method Route Auth Description
POST /api/auth/register Create a user account
POST /api/auth/login Log in — returns a JWT
GET /api/cards List / filter the catalog (search · class · mana · keywords · stats · sort)
GET /api/cards/{id} Get one card
GET /api/cards/{id}/render Render the card as SVG
POST /api/cards Admin Create a card
PUT /api/cards/{id} Admin Update a card
DELETE /api/cards/{id} Admin Delete a card
GET /api/rules Deck-building limits (copies · size · decks per user)
GET /api/decks User List the current user's decks
GET /api/decks/{id} User Get one of the user's decks
POST /api/decks User Create a deck
PUT /api/decks/{id} User Rename a deck
DELETE /api/decks/{id} User Delete a deck
POST /api/decks/{deckId}/cards User Add a card to a deck
DELETE /api/decks/{deckId}/cards/{cardId} User Remove a card from a deck

Testing

xUnit unit tests over the core logic — fast and database-free (mocked repositories and in-memory IQueryable), so they run in CI on every push.

Suite Tests Covers
CardQueryTests 11 ApplyQuery filters (collectible · search · class · mana incl. 7+ · keywords · attack/health ranges) and sort (field + direction)
CardServiceTests 4 Domain→DTO mapping and card lookups over a mocked repository
DeckServiceTests 6 Deck operations and DeckRules (copy limit · deck size · decks per user)

Run the full suite:

dotnet test

Documentation

📖 API reference — auto-generated from the code's XML doc comments (DocFX), redeployed to GitHub Pages on every push.

Roadmap

  • Card effect system — populate the CardEffects table and execute effects at runtime (the data model is already in place).
  • Server-authoritative multiplayer — real-time matches over SignalR, reusing this database and domain.
  • Admin: effect editor & artwork upload — extend the card admin form beyond the current base fields.

License

Source code is released under the PolyForm Strict License 1.0.0 — see LICENSE. You may view and study the code, but distributing, modifying or deploying it is not permitted.

Bundled third-party components (the Peaberry font and Bootstrap) remain under their own licenses — see THIRD-PARTY-NOTICES.md. The card artwork is AI-generated; the card frame templates derive from third-party Unity assets and are not included in this repository.

About

Card-game backend & web client — ASP.NET Core (Clean Architecture), PostgreSQL, JWT auth, server-side SVG card rendering, Blazor WASM.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages