Per-Finish externalIds Array + HOLOFOIL Global-Enum Finish Mapping
| Date | 2026-06-10 |
| Status | Accepted |
| Decision Makers | @GaultierRomon |
Context and Problem Statement
Dragon Ball Super: Fusion World cards are sold on TCGplayer (category 80) in two treatments: a non-foil Standard and a foil Holofoil. On TCGplayer the same card has a distinct product ID per finish, and prices differ between them.
Two things had to be decided to model this correctly:
- How to store the per-finish TCGplayer product IDs on a printing.
- Which global
CardFinishvalue the foil treatment maps to. Fusion World’s foil is labelled “Holofoil”, which did not exist in the platform-wideCardFinishenum — every existing game usedSTANDARD/FOIL(and richer foil variants for SWU). UsingFOILwould be a lie (it is specifically a holofoil treatment, named so by Bandai/TCGplayer) and would collide with how other games and the finish hierarchy reason aboutFOIL.
Decision Drivers
- A product must be resolvable by a single indexed query on its marketplace ID, regardless of finish.
- The finish stored on a printing must match the real-world finish name so badges, filters, and i18n are correct.
- The global finish enum is shared by all games and feeds the PostgreSQL finish enums (price, inventory, list-product, journal) — any new value must be added everywhere exhaustively.
- Fusion World’s finish model is genuinely just two values (Standard / Holofoil); no complex variant parsing is needed.
Decision Outcome
1. Per-finish externalIds array. Each printing stores TCGplayer IDs as an array of { finish, id } entries, consistent with the platform-wide array format adopted for all games (see SWU: externalIds array format):
externalIds: {
TCGplayer: [
{ finish: "Standard", id: 123456 },
{ finish: "Holofoil", id: 123457 },
],
}This enables a single indexed lookup (externalIds.TCGplayer.id) and keeps Standard and Holofoil prices on the correct printing.
2. Add HOLOFOIL to the global CardFinish enum. Rather than reuse FOIL, a new HOLOFOIL value was added to the platform-wide CardFinish enum and propagated through every exhaustive consumer. Fusion World’s per-game finish enum is exactly Standard / Holofoil, and the game→global mapping is by exact string identity.
// dbs-fusion.types.ts
export enum DbsFusionFinish {
STANDARD = "Standard",
HOLOFOIL = "Holofoil",
}Masters (dbs-masters) uses Standard/Foil, which predates this change and is unaffected. HOLOFOIL is Fusion-World-specific.
Why HOLOFOIL and not FOIL
- Accuracy — TCGplayer’s
subTypeNamefor these products is “Holofoil”, and Bandai prints them as holofoils. Mapping to a genericFOILwould mislabel the finish. - No collision with foil semantics —
FOILis used by other games and participates in finish-hierarchy logic; overloading it for Fusion World would muddy badges, theFOIL_FINISHESset, and lowest-foil resolution. - Exhaustive maps force correctness — adding a new enum value surfaces every place that must handle it (attribute value maps, finish badge set, mobile finish icon, the four PG finish enums), so nothing is silently dropped.
Consequences
Positive
- Single indexed query resolves a product by TCGplayer ID across both finishes.
- The finish name on each printing matches reality, so badges/filters/SEO are correct.
HOLOFOILis now a first-class global finish other games can reuse if needed.
Negative
- Adding a value to the global
CardFinishenum touches every exhaustiveRecord<CardFinish, …>and all four PostgreSQL finishpgEnums. Becausedb:pushderives the PG enums at runtime, a stale PG environment will rejectHolofoilinserts until re-pushed (or until a committedALTER TYPE … ADD VALUE 'Holofoil'migration lands). Masters is unaffected because it never usesHolofoil. - A global
holofoili18n key must exist for the global finish-attribute code path; the per-gamedbs-fusionattribute namespace already carries its ownholofoil/foillabels.
Impacted Files
| File | Role |
|---|---|
dbs-fusion.types.ts | DbsFusionFinish = Standard / Holofoil |
game-configuration.types.ts | HOLOFOIL added to global CardFinish enum |
dbs-fusion-importer.ts | Emits per-finish externalIds array; maps TCGCSV subtype → finish |
products.types.ts | Per-finish externalIds array shape |
| PG finish enums (price / inventory / list-product / journal) | Derive from Object.values(CardFinish) — must include Holofoil |