# What it is

***Note:** Since the application is still in development, it is common
for components to be unavailable, unresponsive, or outright
unusable. If you're able to, please [submit a message](/contact) with
the text of the page with Copy/Paste (Ctrl+A, Ctrl+C, Ctrl+V) and any
additional information.*

**cl-deck-builder2** is really three things:

- [Inventory Management](#inventory)
- [Deck Builder](#builder)
- [Unifying User Interface](#ui)

This application merges these things into a web interface where you
can create, modify, and update decks, pricing, and inventory data.

It is a web app written in [Common Lisp](https://lisp-lang.org/learn/first-steps)
using [Caveman2](https://github.com/fukamachi/caveman).

## Inventory Management

The inventory manager is located here: [/cards](/cards).

**cl-deck-builder2** aims to suppliment Crystal Commerce Product
Manager tools.

The original intent was to allow CSV upload of Product Names from
Crystal Commerce. This proved to be unnecessary, as YGOProDeck has all
of the information in the `card_sets` arrays for each card.

The Inventory editor has been superseded by the YGOProDeck editor.

The CSV components and all of the Crystal Commerce code is in
maintenance mode, and due to be removed, as there is no way to access
or update this information currently.

### How To Use It

Currently the following features are supported:

- Partial List of Inventory Items: [Inventory List](/cards)

- Clicking on the card image will take you to the Inventory for that card

- Each Card has a `YGO-SET` associated with it, and each `YGO-SET` has
  one of five `VARIANT-CONDITION` associated with that. The two
  together create a `YGO-SET-ITEM` which is where the inventory and
  pricing information is contained.

- The information displayed is: `Card Name - Set Code - Set Edition - Set Rarity - Set Price`

- Clicking the Gear displays the `YGO-SET-ITEM` for this particular card.

- Editing of individual inventory items: [Edit #1](/cards/1/view)

- Extraction of additional data on import: exact card name, set
  Code, Rarity, and Edition.

- Import of YGOProDeck Extra data: passcodes and linked images based
  on passcodes

## Deck Builder

The deck builder is located here: [/builder](/builder).

The Deck Builder component currently supports searching by full card
name name, e.g. `Magician of Faith`. Any text matching this pattern
entered into the Deck List box will return a list of matching results.

Currently, there are approximately 12000 entries in the database. This
list came from the YGOProDeck API.

### How To Use It

Simply paste a list of matching cards into the list.

YGOProDeck Decks with extension `.ydk` can be uploaded with an
incomplete public interface which can be found at [/ydk/](/ydk).

## User Interface

The user interface is a [Caveman2](https://github.com/fukamachi/caveman)
web app with Common Lisp back-end. All of the things that can be done on
the web front-end have supporting code in the CL back-end. You may load
the source code into your editor and mess around with card information
yourself.

### How To Use It

You're using it right now!

## Source Code

The source code is available [here](http://[2601:198:100:1261:d250:99ff:fe2e:566a]/git/).

# Completed Feature List

## Categories

We're using the [Nested Set Model](https://en.wikipedia.org/wiki/Nested_set_model#Example).

You may create Parent Nodes (Left) and Child Nodes (Right). It needs a lot of work and is pretty SQL heavy.

## Sort By Many Fields

When searching for results, we try to support "Not Just Alphabetical,"
e.g. more than alphabetical sort. You may sort by Qty, Category, Race,
Type, Card Text...

Some of these aren't actually implemented because it's quite a bit of
work. But the majority of the sort patterns are there.

## Deck Constraints

The constraints placed on a deck during construction at the `/builder`
resource are kind-of arbitrary. Here is the breakdown.

First of all, at the database level, there are no restrictions on a
deck. See [here](https://www.formatlibrary.com/decktypes/inzektor?format=ravine_ruler)
for an example. You will notice in the "Popular Extra Deck Cards" area
there are *20* cards. You may download the `.ydk` file from the
`Download` button at the top. If you import this deck into the app, it
will accept it as is. You will end up with an Extra Deck with 20 cards
in it. This is intended.

You may also notice, that, by design, when you create a new deck,
there will be zero cards in it. This is allowed as well.

However, if you continue to construct a deck, you will eventually be
constrained to 60 cards in your main deck, as well as 15 cards in
extra and side decks. There is no way to prevent this limiting from
occurring.

Ideally, I would like to have a way to switch between "free builder"
and "constrained builder." A problem thus far has been "Where does the
constraint checking happen?" And the current solution lies in the way
the app is structured.

So if you imagine each deck you construct as a template, then the deck
builder is really a template constructor. There is a queue of Saved
Deck Configurations, which can be categorized, with the
[Categories](#categories) feature above.

- Main deck max cards 60
- Side Deck max cards 15
- Extra Deck max cards 15

As it stands, these constraints are hard coded. I'm not sure how I would
implement this, but if I were to, it would be something like, setting
a cookie and doing constraint checking in-line with some kind of CLOS
object.

### Card Priority

Cards will be added in this order:

- Drag and drop: the card goes where you dropped it, provided the above numeric constraints are met.
- Right click: the card is added at the "end" of the deck list, in
  this order: main deck, extra deck, side deck, trying to meet the
  above numeric constraints.

Following this, when you save a deck, a priority number is assigned to
the card as follows:

- "normal" 0
- "effect" 1
- "ritual" 2
- "fusion" 3
- "link" 4
- "skill" 5
- "synchro" 6
- "token" 7
- "xyz" 8
- "spell" 9
- "trap" 10
- "effect_pendulum" 11
- "fusion_pendulum" 12
- "normal_pendulum" 13
- "ritual_pendulum" 14
- "synchro_pendulum" 15
- "xyz_pendulum" 16
- Everything Else 17

Lower numbers get put "earlier" in the deck listing. The next time you
load the deck it will be sorted in this order.

## User Profiles

You may currently register, login, logout, view the user list. This
code has hardly been touched since it was implemented. If I spent more
time working on the user code, I could also implement the "free
builder" toggle system.

The web framework system we're using gives us access to request and
session information, and we can store cookies. There is also a
database extension for managing all of this information persistently
in a database. Our current database model is very simple. There is a
user, with a password, and some metadata.

We currently hash passwords, as well. So your passwords are stored
securely. You currently may not change your password.

When you register an account we ask for an email. We currently do
nothing with this. An email server would take additional time to
configure. A rudimentary setup would most likely be caught in your
spam filters. This also highlights another issue with the app. We don't
currently have a domain name. But that is another topic.

### Trade Between Profiles

Theoretically this is no different than assigning a `category_id` to a
`ydk_deck`. Simply add a `user_id` field to indicate the user which
created the deck. However, this is not implemented, because I have not
spent the required time looking at user management, as stated above.

## Charts / Metrics

We have rudimentary charts and metrics provided by
[RRDtool](https://oss.oetiker.ch/rrdtool/). These charts are just host
information.  We can feed it all kinds of data. It will take time to
research the data format it ingests and how to produce a chart.

I'm not sure if Crystal Commerce offers pricing or inventory charts or metrics.

## Picture of Finalized Deck

We use [ImageMagick](https://www.imagemagick.org/) to generate deck
images and other various image manipulations. We have complete control
over the process. Currently output is very rudimentary. However I have
complete control over the pipeline, and at this stage, more time could
be spent developing this pipeline. It is currently sufficient for our
purposes.

The output is currently four static images, the main deck, extra, and
side decks, then a concatenation of the three images. Additionally, we
output the intermediate concatenation images as well.

## Different Card Games

This is possible, all of the application is currently hard-coded to
use Yu-Gi-Oh!. It would take a quite a bit of time to re-factor all of
the routes to handle this scenario instead of possibly just running
multiple copies of the app, or having dedicated instances of the app
connected to dedicated database back-ends.

Regardless, currently we only support Yu-Gi-Oh!. If more work were
done on the User component, I could make it configurable as a cookie.

## Builder Controls

Click on a card in the search results to see its information (card text, ATK, DEF, ...).

### Advanced Search

In the Advanced Search menu you may search by card type, e.g. `frame_type` => `trap` will show you all trap cards.

## Decks Overview

There is currently a rudimentary decks overview page.

## Constructed Deck Workflow

The workflow for constructing decks is as follows:

1. Create deck of cards. Currently we select from all cards.  Maybe we
   should just select cards from inventory.  The majority of this
   functionality in place and isn't expected to change. A deck will
   always just be a list of cards plus metadata.

2. The deck of cards has metadata about author, name of deck, time of
   creation. The main content of the deck is three lists, comprising
   the main, extra, and side decks.  This information is not expected
   to change in the future. Decks created by a particular user for
   example.  The underlying metadata representation is what's being
   worked on. Currently each item in the database has all information
   duplicated from the rest of the database. Changing the price for
   one card changes the price for only that one card matching that row
   in the database. There will be additional tables to store pricing
   information in the next step.

3. On the Deck Overview page, selecting "Pull Deck" will decrease the
   inventory of the lowest priced card in inventory by one for every
   card in the deck. This is like "add to cart" in an online shopping
   platform, with additional inventory keeping.  This is analogous to
   the deck construction step, except instead of selecting cards to be
   put into a deck, that information is provided prior, and we use
   that list of information to construct secondary lists.

4. On the pulled deck page, for every card in the deck, you will be
   able to select cards by edition, condition, and rarity of every
   card in the inventory matching that card's passcode.  I can
   conceive a very simple concept where you attempt to check out, and
   then are returned with error messages saying which items had
   errors. This is the current approach.

5. There will be an intermediate stage. Once there is enough inventory
   and the deck is "pulled" it will enter an area where each
   individual card will be selected. e.g. selecting the rarity or set
   of a particular card in each deck.

6. Once all "errors" are resolved (banlists, constraints, etc), the
   "pulled" deck will allow you to "construct" it, which will finalize
   the state of this pulled deck in the database, moving it to another
   table, the list of decks for sale.

7. The list of decks for sale is just pulled, constructed decks with
   pricing information attached and whether or not it was sold and
   what price it was sold at and when.

## Formats

It appears that I began working on format integration from
YGOProDeck. I have not found a way to integrate this information into
the builder yet.
