dd-cards · Reference

Database

The two tables dd-cards creates, what each column holds, and how templates and orders relate.

dd-cards creates two InnoDB tables. Both are created automatically at boot when AutoInsertSql is true, or by importing install/sql/dd-cards.sql by hand.

Every statement is CREATE TABLE IF NOT EXISTS, so importing repeatedly is safe and never migrates or resets existing data.

dd_card_templates

One row per saved design. This holds both the player's own save slots and a frozen snapshot of the design each order was placed from.

CREATE TABLE IF NOT EXISTS `dd_card_templates` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `owner_citizenid` VARCHAR(50) NOT NULL,
    `slot_index` TINYINT UNSIGNED DEFAULT NULL COMMENT '1-5 = player save slot; NULL = order snapshot, not a slot',
    `name` VARCHAR(60) NOT NULL DEFAULT 'Untitled Card',
    `canvas_json` LONGTEXT NOT NULL,
    `material_paper` VARCHAR(30) NOT NULL DEFAULT 'paper_standard',
    `material_foil` VARCHAR(30) DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_dd_card_templates_owner` (`owner_citizenid`),
    UNIQUE KEY `idx_dd_card_templates_owner_slot` (`owner_citizenid`, `slot_index`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ColumnNotes
owner_citizenidThe framework's citizenid, not the server id
slot_index15 for one of the player's save slots, NULL for an order snapshot
nameThe card name set in the designer
canvas_jsonThe serialised design — text, images, shapes, strokes and layer order
material_paperpaper_standard or paper_glossy
material_foilgold_foil, or NULL when no foil was chosen

The unique key on (owner_citizenid, slot_index) is what enforces the five-slot limit — a player cannot occupy the same slot twice.

Note

Snapshots exist so that editing or deleting a saved template does not retroactively change what an already-placed order will print. That is why slot_index is nullable rather than the table being split in two.

dd_card_orders

One row per order.

CREATE TABLE IF NOT EXISTS `dd_card_orders` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `owner_citizenid` VARCHAR(50) NOT NULL,
    `template_id` INT UNSIGNED NOT NULL,
    `status` ENUM('processing', 'ready', 'completed', 'cancelled') NOT NULL DEFAULT 'processing',
    `quantity` SMALLINT UNSIGNED NOT NULL DEFAULT 1,
    `rush` TINYINT(1) NOT NULL DEFAULT 0,
    `price_paid` INT UNSIGNED NOT NULL DEFAULT 0,
    `materials_used` JSON NOT NULL,
    `ready_at` INT UNSIGNED NOT NULL COMMENT 'unix timestamp, os.time()',
    `notified_at` INT UNSIGNED DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `completed_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `idx_dd_card_orders_owner` (`owner_citizenid`),
    KEY `idx_dd_card_orders_status` (`status`),
    CONSTRAINT `fk_dd_card_orders_template` FOREIGN KEY (`template_id`)
        REFERENCES `dd_card_templates` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ColumnNotes
template_idThe snapshot this order prints from. ON DELETE CASCADE — removing a template removes its orders
statusMust match Config.OrderStatus; see the warning below
quantityHow many cards, within Config.BoxQuantity
rush1 if the rush surcharge was paid
price_paidThe total actually charged, in whole units
materials_usedJSON map of material key to units consumed
ready_atUnix timestamp from os.time(), not a MySQL datetime
notified_atWhen the "order ready" message was sent; NULL until then

Caution

The status ENUM and Config.OrderStatus in config/shared.lua must agree. Renaming a status in the config without altering the column — or the reverse — breaks every existing order.

Useful queries

Orders currently printing, oldest first:

SELECT id, owner_citizenid, quantity, rush,
       FROM_UNIXTIME(ready_at) AS ready_at
FROM dd_card_orders
WHERE status = 'processing'
ORDER BY ready_at;

Orders that finished but were never collected:

SELECT id, owner_citizenid, quantity, price_paid,
       FROM_UNIXTIME(ready_at) AS ready_at
FROM dd_card_orders
WHERE status = 'ready'
ORDER BY ready_at;

A player's save slots:

SELECT slot_index, name, material_paper, material_foil, updated_at
FROM dd_card_templates
WHERE owner_citizenid = 'ABC12345' AND slot_index IS NOT NULL
ORDER BY slot_index;

Warning

Deleting rows from dd_card_templates cascades to dd_card_orders. Clearing out old templates will take any orders still attached to them with it — filter on slot_index IS NOT NULL if you only mean to prune save slots.