diff --git a/SVSim.Bootstrap/Data/seeds/story-decks.json b/SVSim.Bootstrap/Data/seeds/story-decks.json
new file mode 100644
index 0000000..8c2a914
--- /dev/null
+++ b/SVSim.Bootstrap/Data/seeds/story-decks.json
@@ -0,0 +1,1346 @@
+[
+ {
+ "deck_no": 1,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Sterling Archer",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 2,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Hour of the Banquet",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 3,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Quintessence of Conjury",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 4,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Dark Wyrmdriver",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 5,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Roar of the Netherflame",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 6,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Kiss of the Queen",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 7,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Ivory Battlefield",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 201,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Thorned Anomaly",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 202,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Lightning Speed",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 203,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Hulking Rage",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 204,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Aura of the Waterwyrm ",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 205,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Death's Puppeteer",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 206,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Crimson Pact",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 207,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Alabaster Shield",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 301,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Dazzling Stars",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 302,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Stillflame General",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 303,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Enchanted Illusions",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 304,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Primal Flames",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 305,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Giant Obliteration",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 306,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Cruel Abyss",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 307,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Winged Blessings",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 401,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Law of the Forest",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 402,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "The Heroes Four",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 403,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Genius Alchemy ",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 404,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Verdict: Armageddon ",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 405,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Love's Last Knell",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 406,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Dazzling Sword Dance",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 407,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Eternal Testament ",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 408,
+ "kind": "build",
+ "class_id": 8,
+ "deck_name": "Warriors of Steel",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 8,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 501,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Silent Maiden",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 502,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Unsheathed Fury",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 503,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Sugar-sweet Magic!",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 504,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Wrath of the Empress",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 505,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "The Corpsewyrm Beckons",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 506,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Crimson Flowerbed",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 507,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Hallowed Crusade",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 508,
+ "kind": "build",
+ "class_id": 8,
+ "deck_name": "Sins of the Heartless",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 8,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 601,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Crystalline Viridian",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 602,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Break of Twilight",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 603,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Sapphire: Insurgence",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 604,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Champions of the Zenith",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 605,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Amethyst: Resistance",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 606,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Garnet: Defiance",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 607,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Guardians of Elysium",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 608,
+ "kind": "build",
+ "class_id": 8,
+ "deck_name": "Steel Autocracy",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 8,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 701,
+ "kind": "build",
+ "class_id": 1,
+ "deck_name": "Pure Devotion",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 1,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 702,
+ "kind": "build",
+ "class_id": 2,
+ "deck_name": "Gallant Gourmand",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 2,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 703,
+ "kind": "build",
+ "class_id": 3,
+ "deck_name": "Let's Get Catty",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 3,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 704,
+ "kind": "build",
+ "class_id": 4,
+ "deck_name": "Ready, Set, Brawl!",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 4,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 705,
+ "kind": "build",
+ "class_id": 5,
+ "deck_name": "Messages from Beyond",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 5,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 706,
+ "kind": "build",
+ "class_id": 6,
+ "deck_name": "Midnight Mistress",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 6,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 707,
+ "kind": "build",
+ "class_id": 7,
+ "deck_name": "Highborn Lady",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 7,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 708,
+ "kind": "build",
+ "class_id": 8,
+ "deck_name": "All-seeing Tyrant",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 8,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": null
+ },
+ {
+ "deck_no": 10001,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Control Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10002,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Levin Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10003,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Natura Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10004,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Natura Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10005,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Natura Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10006,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Midrange Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10007,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Machina Elana Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 10008,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Artifact Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 11901,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Aggro Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 11902,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Walfrid Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 11905,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Aggro Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 11906,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12003,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Mysteria Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12004,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Ramp Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12007,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Sanctuary Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12008,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Artifact Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12104,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Natura Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12106,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Epitaph Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12108,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Machina Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12201,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Fairy Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12204,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Ramp Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12206,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12302,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Rally Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12307,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Ward Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12308,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Artifact Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12403,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Earth Rite Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12406,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Festive Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12408,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Puppet Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12501,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Combo Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12504,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Ramp Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12506,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12603,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Chess Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12604,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Armed Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12607,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Crystallize Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12702,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Loot Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12705,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Last Words Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12708,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Condemned Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12801,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Fairy Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12802,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Rally Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12806,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12807,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Restoration Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12901,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Fairy Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12902,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Rally Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12903,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Earth Rite Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12904,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Ramp Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12905,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Ghost Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12906,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Vengeance Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12907,
+ "kind": "trial",
+ "class_id": 7,
+ "deck_name": "Restoration Havencraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 12908,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Artifact Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13001,
+ "kind": "trial",
+ "class_id": 1,
+ "deck_name": "Tempo Forestcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13002,
+ "kind": "trial",
+ "class_id": 2,
+ "deck_name": "Rally Swordcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13003,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Earth Rite Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13006,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13103,
+ "kind": "trial",
+ "class_id": 3,
+ "deck_name": "Mysteria Runecraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13105,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Last Words Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 0,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13108,
+ "kind": "trial",
+ "class_id": 8,
+ "deck_name": "Artifact Portalcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13204,
+ "kind": "trial",
+ "class_id": 4,
+ "deck_name": "Natura Dragoncraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13205,
+ "kind": "trial",
+ "class_id": 5,
+ "deck_name": "Machina Shadowcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ },
+ {
+ "deck_no": 13206,
+ "kind": "trial",
+ "class_id": 6,
+ "deck_name": "Wrath Bloodcraft",
+ "sleeve_id": 3000011,
+ "leader_skin_id": 0,
+ "is_recommend": 1,
+ "order_num": 0,
+ "entry_no": 0,
+ "deck_format": 1
+ }
+]
diff --git a/SVSim.Bootstrap/Importers/StoryDeckImporter.cs b/SVSim.Bootstrap/Importers/StoryDeckImporter.cs
new file mode 100644
index 0000000..42b0025
--- /dev/null
+++ b/SVSim.Bootstrap/Importers/StoryDeckImporter.cs
@@ -0,0 +1,52 @@
+using Microsoft.EntityFrameworkCore;
+using SVSim.Bootstrap.Models.Seed;
+using SVSim.Database;
+using SVSim.Database.Enums;
+using SVSim.Database.Models;
+
+namespace SVSim.Bootstrap.Importers;
+
+///
+/// Idempotent upsert of story-deck presentation rows from seeds/story-decks.json.
+/// Card lists are NOT imported here — they belong to BuildDeckProductEntry (deck_no == product_id),
+/// so this importer should run AFTER BuildDeckImporter.ImportPackageAsync. Rows missing from the
+/// seed are left intact.
+///
+public class StoryDeckImporter
+{
+ public async Task ImportAsync(SVSimDbContext context, string seedDir)
+ {
+ var seed = SeedLoader.LoadList(Path.Combine(seedDir, "story-decks.json"));
+ if (seed.Count == 0)
+ {
+ Console.WriteLine("[StoryDeckImporter] No seed rows; skipping.");
+ return 0;
+ }
+
+ var existing = await context.StoryDecks.ToDictionaryAsync(e => e.Id);
+ int created = 0, updated = 0;
+
+ foreach (var s in seed)
+ {
+ if (s.DeckNo == 0) continue;
+ var entry = existing.TryGetValue(s.DeckNo, out var ex) ? ex : new StoryDeckEntry { DeckNo = s.DeckNo };
+ entry.Kind = string.Equals(s.Kind, "trial", StringComparison.OrdinalIgnoreCase)
+ ? StoryDeckKind.Trial : StoryDeckKind.Build;
+ entry.ClassId = s.ClassId;
+ entry.DeckName = s.DeckName;
+ entry.SleeveId = s.SleeveId;
+ entry.LeaderSkinId = s.LeaderSkinId;
+ entry.IsRecommend = s.IsRecommend;
+ entry.OrderNum = s.OrderNum;
+ entry.EntryNo = s.EntryNo;
+ entry.DeckFormat = s.DeckFormat;
+
+ if (ex is null) { context.StoryDecks.Add(entry); existing[s.DeckNo] = entry; created++; }
+ else updated++;
+ }
+
+ await context.SaveChangesAsync();
+ Console.WriteLine($"[StoryDeckImporter] +{created}/~{updated}");
+ return created + updated;
+ }
+}
diff --git a/SVSim.Bootstrap/Models/Seed/StoryDeckSeed.cs b/SVSim.Bootstrap/Models/Seed/StoryDeckSeed.cs
new file mode 100644
index 0000000..9afe87a
--- /dev/null
+++ b/SVSim.Bootstrap/Models/Seed/StoryDeckSeed.cs
@@ -0,0 +1,17 @@
+using System.Text.Json.Serialization;
+
+namespace SVSim.Bootstrap.Models.Seed;
+
+public sealed class StoryDeckSeed
+{
+ [JsonPropertyName("deck_no")] public int DeckNo { get; set; }
+ [JsonPropertyName("kind")] public string Kind { get; set; } = "build";
+ [JsonPropertyName("class_id")] public int ClassId { get; set; }
+ [JsonPropertyName("deck_name")] public string DeckName { get; set; } = "";
+ [JsonPropertyName("sleeve_id")] public int SleeveId { get; set; }
+ [JsonPropertyName("leader_skin_id")] public int LeaderSkinId { get; set; }
+ [JsonPropertyName("is_recommend")] public int IsRecommend { get; set; }
+ [JsonPropertyName("order_num")] public int OrderNum { get; set; }
+ [JsonPropertyName("entry_no")] public int EntryNo { get; set; }
+ [JsonPropertyName("deck_format")] public int? DeckFormat { get; set; }
+}
diff --git a/SVSim.Bootstrap/Program.cs b/SVSim.Bootstrap/Program.cs
index 92e501a..b10ecb2 100644
--- a/SVSim.Bootstrap/Program.cs
+++ b/SVSim.Bootstrap/Program.cs
@@ -124,6 +124,7 @@ public static class Program
await buildDeck.ImportSeriesAsync(context, opts.ReferenceDataDir);
await buildDeck.ImportCatalogAsync(context, opts.SeedDir);
await buildDeck.ImportPackageAsync(context, opts.ReferenceDataDir);
+ await new StoryDeckImporter().ImportAsync(context, opts.SeedDir);
}
else
{
diff --git a/SVSim.Database/Enums/StoryDeckKind.cs b/SVSim.Database/Enums/StoryDeckKind.cs
new file mode 100644
index 0000000..b5eef1b
--- /dev/null
+++ b/SVSim.Database/Enums/StoryDeckKind.cs
@@ -0,0 +1,11 @@
+namespace SVSim.Database.Enums;
+
+///
+/// Which story deck-select group a prebuilt deck belongs to. Build = the named story decks
+/// (build_deck_list); Trial = archetype trial decks (trial_deck_list). Stored as int.
+///
+public enum StoryDeckKind
+{
+ Build = 0,
+ Trial = 1,
+}
diff --git a/SVSim.Database/Migrations/20260529142631_AddStoryDeck.Designer.cs b/SVSim.Database/Migrations/20260529142631_AddStoryDeck.Designer.cs
new file mode 100644
index 0000000..8c85277
--- /dev/null
+++ b/SVSim.Database/Migrations/20260529142631_AddStoryDeck.Designer.cs
@@ -0,0 +1,3823 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using SVSim.Database;
+
+#nullable disable
+
+namespace SVSim.Database.Migrations
+{
+ [DbContext(typeof(SVSimDbContext))]
+ [Migration("20260529142631_AddStoryDeck")]
+ partial class AddStoryDeck
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.HasSequence("ShortUdidSequence")
+ .StartsAt(400000000L);
+
+ modelBuilder.Entity("DegreeEntryViewer", b =>
+ {
+ b.Property("DegreesId")
+ .HasColumnType("integer");
+
+ b.Property("ViewersId")
+ .HasColumnType("bigint");
+
+ b.HasKey("DegreesId", "ViewersId");
+
+ b.HasIndex("ViewersId");
+
+ b.ToTable("DegreeEntryViewer");
+ });
+
+ modelBuilder.Entity("EmblemEntryViewer", b =>
+ {
+ b.Property("EmblemsId")
+ .HasColumnType("integer");
+
+ b.Property("ViewersId")
+ .HasColumnType("bigint");
+
+ b.HasKey("EmblemsId", "ViewersId");
+
+ b.HasIndex("ViewersId");
+
+ b.ToTable("EmblemEntryViewer");
+ });
+
+ modelBuilder.Entity("LeaderSkinEntryViewer", b =>
+ {
+ b.Property("LeaderSkinsId")
+ .HasColumnType("integer");
+
+ b.Property("ViewersId")
+ .HasColumnType("bigint");
+
+ b.HasKey("LeaderSkinsId", "ViewersId");
+
+ b.HasIndex("ViewersId");
+
+ b.ToTable("LeaderSkinEntryViewer");
+ });
+
+ modelBuilder.Entity("MyPageBackgroundEntryViewer", b =>
+ {
+ b.Property("MyPageBackgroundsId")
+ .HasColumnType("integer");
+
+ b.Property("ViewersId")
+ .HasColumnType("bigint");
+
+ b.HasKey("MyPageBackgroundsId", "ViewersId");
+
+ b.HasIndex("ViewersId");
+
+ b.ToTable("MyPageBackgroundEntryViewer");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.SpecialBattleSetting", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("BanishEffectOverride")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ClassDestroyEffectOverride")
+ .HasColumnType("integer");
+
+ b.Property("EnemyAttachSkill")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EnemyStartLife")
+ .HasColumnType("integer");
+
+ b.Property("EnemyStartPp")
+ .HasColumnType("integer");
+
+ b.Property("IdOverrideInBattleLog")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Note")
+ .HasColumnType("text");
+
+ b.Property("PlayerAttachSkill")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PlayerFirstTurn")
+ .HasColumnType("integer");
+
+ b.Property("PlayerStartLife")
+ .HasColumnType("integer");
+
+ b.Property("PlayerStartPp")
+ .HasColumnType("integer");
+
+ b.Property("ResultSkip")
+ .HasColumnType("integer");
+
+ b.Property("SpecialTokenDrawEffectOverride")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TokenDrawEffectOverride")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("VsEffectOverride")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("SpecialBattleSettings");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.StoryChapter", b =>
+ {
+ b.Property("StoryId")
+ .HasColumnType("integer");
+
+ b.Property("Battle3dFieldId")
+ .HasColumnType("integer");
+
+ b.Property("BattleExists")
+ .HasColumnType("boolean");
+
+ b.Property("BgFileName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BgmId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ChapterClearTextId")
+ .HasColumnType("text");
+
+ b.Property("ChapterEffectPath")
+ .HasColumnType("text");
+
+ b.Property("ChapterId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CharaId")
+ .HasColumnType("integer");
+
+ b.Property("EnemyAiId")
+ .HasColumnType("integer");
+
+ b.Property("EnemyCharaId")
+ .HasColumnType("integer");
+
+ b.Property("EnemyClass")
+ .HasColumnType("integer");
+
+ b.Property("IsCameraMovable")
+ .HasColumnType("integer");
+
+ b.Property("IsMaintenanceChapter")
+ .HasColumnType("boolean");
+
+ b.Property("IsPlayAnotherEndAppearanceAnimation")
+ .HasColumnType("boolean");
+
+ b.Property("IsReleasedAnotherEnd")
+ .HasColumnType("boolean");
+
+ b.Property("IsSkipEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("NextChapterId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ReleasePoint")
+ .HasColumnType("integer");
+
+ b.Property("RequiredChapterId")
+ .HasColumnType("text");
+
+ b.Property("SectionId")
+ .HasColumnType("integer");
+
+ b.Property("SelectionDisplayPosition")
+ .HasColumnType("text");
+
+ b.Property("SelectionTextId")
+ .HasColumnType("text");
+
+ b.Property("ShowCoordinate")
+ .HasColumnType("integer");
+
+ b.Property("ShowSubtitles")
+ .HasColumnType("integer");
+
+ b.Property("SpecialBattleSettingId")
+ .HasColumnType("integer");
+
+ b.Property("UnlockText")
+ .HasColumnType("text");
+
+ b.Property("XCoordinate")
+ .HasColumnType("numeric");
+
+ b.Property("YCoordinate")
+ .HasColumnType("numeric");
+
+ b.HasKey("StoryId");
+
+ b.HasIndex("NextChapterId");
+
+ b.HasIndex("SpecialBattleSettingId");
+
+ b.HasIndex("SectionId", "CharaId", "ChapterId");
+
+ b.ToTable("StoryChapters");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.StorySection", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("AllStoryOrderId")
+ .HasColumnType("integer");
+
+ b.Property("BackGroundId")
+ .HasColumnType("integer");
+
+ b.Property("ChapterSelectType")
+ .HasColumnType("integer");
+
+ b.Property("ImageName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsLeaderSelect")
+ .HasColumnType("boolean");
+
+ b.Property("IsPlayAnotherEndAppearanceAnimation")
+ .HasColumnType("boolean");
+
+ b.Property("IsSpoiler")
+ .HasColumnType("integer");
+
+ b.Property("IsUnderMaintenance")
+ .HasColumnType("boolean");
+
+ b.Property("NameTextKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OrderId")
+ .HasColumnType("integer");
+
+ b.Property("SpoilerMessage")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("StoryApiType")
+ .HasColumnType("integer");
+
+ b.Property("StoryTypeOverwrite")
+ .HasColumnType("integer");
+
+ b.Property("WorldId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorldId");
+
+ b.ToTable("StorySections");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.StoryWorld", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("PanelImageName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RibbonText")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TitleTextKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("StoryWorlds");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.ViewerStoryBranchUnlock", b =>
+ {
+ b.Property("ViewerId")
+ .HasColumnType("bigint");
+
+ b.Property("StoryId")
+ .HasColumnType("integer");
+
+ b.Property("UnlockedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("ViewerId", "StoryId");
+
+ b.ToTable("ViewerStoryBranchUnlocks");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Entities.Story.ViewerStoryProgress", b =>
+ {
+ b.Property("ViewerId")
+ .HasColumnType("bigint");
+
+ b.Property("StoryId")
+ .HasColumnType("integer");
+
+ b.Property("FinishedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsFinish")
+ .HasColumnType("boolean");
+
+ b.Property("IsSkipped")
+ .HasColumnType("boolean");
+
+ b.Property("SkippedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("ViewerId", "StoryId");
+
+ b.ToTable("ViewerStoryProgress");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.AchievementCatalogEntry", b =>
+ {
+ b.Property("AchievementType")
+ .HasColumnType("integer");
+
+ b.Property("Level")
+ .HasColumnType("integer");
+
+ b.Property("EventArg")
+ .HasColumnType("integer");
+
+ b.Property("EventType")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OrderNum")
+ .HasColumnType("integer");
+
+ b.Property("RequireNumber")
+ .HasColumnType("integer");
+
+ b.Property("RewardDetailId")
+ .HasColumnType("bigint");
+
+ b.Property("RewardNumber")
+ .HasColumnType("integer");
+
+ b.Property("RewardType")
+ .HasColumnType("integer");
+
+ b.HasKey("AchievementType", "Level");
+
+ b.HasIndex("AchievementType");
+
+ b.HasIndex("EventType", "EventArg");
+
+ b.ToTable("AchievementCatalog");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.ArenaSeasonConfig", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("Cost")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Enable")
+ .HasColumnType("integer");
+
+ b.Property("FormatInfo")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("IsJoin")
+ .HasColumnType("boolean");
+
+ b.Property("Mode")
+ .HasColumnType("integer");
+
+ b.Property("RupyCost")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("TicketCost")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("ArenaSeasons");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.AvatarAbilityEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("Ability")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AbilityCost")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AbilityDesc")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BattleStartFirstPlayerTurnBp")
+ .HasColumnType("integer");
+
+ b.Property("BattleStartMaxLife")
+ .HasColumnType("integer");
+
+ b.Property("BattleStartSecondPlayerTurnBp")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LeaderSkinId")
+ .HasColumnType("integer");
+
+ b.Property("PassiveAbility")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PassiveAbilityDesc")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("AvatarAbilities");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BannerEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("ChangeTime")
+ .HasColumnType("integer");
+
+ b.Property("Click")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ImageName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ImagePaths")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("RemainingTime")
+ .HasColumnType("integer");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Banners");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BattlePassLevelEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Level")
+ .HasColumnType("integer");
+
+ b.Property("RequiredPoint")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("BattlePassLevels");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BattlePassMonthlyMissionEntry", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BattlePassPoint")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("EventArg")
+ .HasColumnType("integer");
+
+ b.Property("EventType")
+ .HasColumnType("text");
+
+ b.Property("Month")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OrderNum")
+ .HasColumnType("integer");
+
+ b.Property("RequireNumber")
+ .HasColumnType("integer");
+
+ b.Property("RewardDetailId")
+ .HasColumnType("bigint");
+
+ b.Property("RewardNumber")
+ .HasColumnType("integer");
+
+ b.Property("RewardType")
+ .HasColumnType("integer");
+
+ b.Property("Year")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Year", "Month");
+
+ b.HasIndex("Year", "Month", "OrderNum")
+ .IsUnique();
+
+ b.ToTable("BattlePassMonthlyMissions");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BattlePassRewardEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("bigint");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsAppealExclusion")
+ .HasColumnType("boolean");
+
+ b.Property("Level")
+ .HasColumnType("integer");
+
+ b.Property("RewardDetailId")
+ .HasColumnType("bigint");
+
+ b.Property("RewardNumber")
+ .HasColumnType("integer");
+
+ b.Property("RewardType")
+ .HasColumnType("integer");
+
+ b.Property("SeasonId")
+ .HasColumnType("integer");
+
+ b.Property("Track")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SeasonId", "Track", "Level")
+ .IsUnique();
+
+ b.ToTable("BattlePassRewards");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BattlePassSeasonEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("CanPurchase")
+ .HasColumnType("boolean");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EndDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MaxLevel")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PriceCrystal")
+ .HasColumnType("integer");
+
+ b.Property("StartDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("StartDate", "EndDate");
+
+ b.ToTable("BattlePassSeasons");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BattlefieldEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsOpen")
+ .HasColumnType("boolean");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Battlefields");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BuildDeckProductEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeckCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("FeaturedCardId")
+ .HasColumnType("bigint");
+
+ b.Property("IntroPriceCrystal")
+ .HasColumnType("integer");
+
+ b.Property("IntroPriceRupy")
+ .HasColumnType("integer");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("LeaderId")
+ .HasColumnType("integer");
+
+ b.Property("ProductNameKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PurchaseNumMax")
+ .HasColumnType("integer");
+
+ b.Property("RegularPriceCrystal")
+ .HasColumnType("integer");
+
+ b.Property("RegularPriceRupy")
+ .HasColumnType("integer");
+
+ b.Property("SeriesId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SeriesId");
+
+ b.ToTable("BuildDeckProducts");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.BuildDeckSeriesEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DrumrollPath")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IntroKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("IsNew")
+ .HasColumnType("boolean");
+
+ b.Property("NameKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OrderIndex")
+ .HasColumnType("integer");
+
+ b.Property("TitlePath")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("BuildDeckSeries");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.CardCosmeticReward", b =>
+ {
+ b.Property("CardId")
+ .HasColumnType("bigint");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.Property("CosmeticId")
+ .HasColumnType("bigint");
+
+ b.Property("Quantity")
+ .HasColumnType("integer");
+
+ b.HasKey("CardId", "Type", "CosmeticId");
+
+ b.HasIndex("CardId");
+
+ b.ToTable("CardCosmeticRewards");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.ClassEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Classes");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.ClassExpEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("NecessaryExp")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("ClassExpCurve");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.ColosseumConfig", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("CardPoolName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ColosseumId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ColosseumName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeckFormat")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EndTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsAllCardEnabled")
+ .HasColumnType("integer");
+
+ b.Property("IsColosseumPeriod")
+ .HasColumnType("boolean");
+
+ b.Property("IsDisplayTips")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsNormalTwoPick")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsRoundPeriod")
+ .HasColumnType("boolean");
+
+ b.Property("IsSpecialMode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("NowRound")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SalesPeriodInfo")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("StartTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("TipsId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Colosseums");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.DailyLoginBonusEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("BonusData")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("BonusId")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("DailyLoginBonuses");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.DefaultDeckEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("CardIdArray")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("ClassId")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeckName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DeckNo")
+ .HasColumnType("integer");
+
+ b.Property("LeaderSkinId")
+ .HasColumnType("integer");
+
+ b.Property("SleeveId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.ToTable("DefaultDecks");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.DegreeEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("Degrees");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.EmblemEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("Emblems");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.FeatureMaintenanceEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("Data")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("FeatureKey")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("FeatureMaintenances");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.GameConfigSection", b =>
+ {
+ b.Property("SectionName")
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ValueJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.HasKey("SectionName");
+
+ b.ToTable("GameConfigs");
+ });
+
+ modelBuilder.Entity("SVSim.Database.Models.ItemEntry", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("integer");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property