From 43a366577525ad47bbe2e31263c21fbea32ef628 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sat, 13 Jun 2026 13:31:03 -0400 Subject: [PATCH] refactor(arena-colosseum): dedup colosseum_info source-of-truth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /mypage/index data.colosseum_info and /arena_colosseum/{top,get_fee_info} now both project through ColosseumLobbyInfoBuilder.Build(ColosseumSeasonConfig). One source of truth for the home-tab gating and the lobby reads — admins flip the season on by writing to GameConfigs (per the runbook), no second table to keep in sync. * New ColosseumLobbyInfoBuilder — static projection from ColosseumSeasonConfig to the wire ColosseumLobbyInfo. Replaces ArenaColosseumController's private BuildColosseumInfo and MyPageController's BuildColosseumInfo(ColosseumConfig). * MyPageController reads ColosseumSeasonConfig via IGameConfigService; the IGlobalsRepository.GetCurrentColosseum() call goes away. * MyPageIndexResponse.ColosseumInfo retyped to the new ColosseumLobbyInfo. * ColosseumSalesPeriodInfo relocated into the ArenaColosseum namespace alongside the rest of the family DTOs. * Drops: Colosseums DB table (migration DropColosseumsTable), ColosseumConfig entity, the captured-shape Models.Dtos.ColosseumInfo DTO, ColosseumSeed, MyPageGlobalsImporter.ImportColosseumAsync + seed file colosseum.json, IGlobalsRepository.GetCurrentColosseum + impl, the two related tests. Net: home-screen Grand Prix tab now hidden by default because the season ships with IsColosseumPeriod=false. Full suite: 1345/1345 (was 1347 — the 2 dropped tests covered the now-dead surface). --- SVSim.Bootstrap/Data/seeds/colosseum.json | 20 - .../Importers/MyPageGlobalsImporter.cs | 36 - SVSim.Bootstrap/Models/Seed/ColosseumSeed.cs | 24 - SVSim.Bootstrap/Program.cs | 1 - ...0613172735_DropColosseumsTable.Designer.cs | 4795 +++++++++++++++++ .../20260613172735_DropColosseumsTable.cs | 50 + .../Migrations/SVSimDbContextModelSnapshot.cs | 71 - SVSim.Database/Models/ColosseumConfig.cs | 42 - .../Repositories/Globals/GlobalsRepository.cs | 3 - .../Globals/IGlobalsRepository.cs | 1 - SVSim.Database/SVSimDbContext.cs | 1 - .../Controllers/ArenaColosseumController.cs | 29 +- .../Controllers/MyPageController.cs | 36 +- .../Dtos/ArenaColosseum/ColosseumInfo.cs | 10 +- .../ColosseumLobbyInfoBuilder.cs | 48 + .../ColosseumSalesPeriodInfo.cs | 16 + .../Models/Dtos/ColosseumInfo.cs | 97 - .../Models/Dtos/ColosseumSalesPeriodInfo.cs | 18 - .../Dtos/Responses/MyPageIndexResponse.cs | 7 +- .../Importers/MyPageGlobalsImporterTests.cs | 20 - .../Infrastructure/SVSimTestFactory.cs | 1 - .../Repositories/GlobalsRepositoryTests.cs | 11 - 22 files changed, 4924 insertions(+), 413 deletions(-) delete mode 100644 SVSim.Bootstrap/Data/seeds/colosseum.json delete mode 100644 SVSim.Bootstrap/Models/Seed/ColosseumSeed.cs create mode 100644 SVSim.Database/Migrations/20260613172735_DropColosseumsTable.Designer.cs create mode 100644 SVSim.Database/Migrations/20260613172735_DropColosseumsTable.cs delete mode 100644 SVSim.Database/Models/ColosseumConfig.cs create mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumLobbyInfoBuilder.cs create mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumSalesPeriodInfo.cs delete mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumInfo.cs delete mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumSalesPeriodInfo.cs diff --git a/SVSim.Bootstrap/Data/seeds/colosseum.json b/SVSim.Bootstrap/Data/seeds/colosseum.json deleted file mode 100644 index fecad57c..00000000 --- a/SVSim.Bootstrap/Data/seeds/colosseum.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "id": 1, - "colosseum_id": "165", - "colosseum_name": "Rivenbrandt Take Two Cup", - "card_pool_name": "Take Two (Dragonblade–Rivenbrandt)", - "deck_format": "3", - "start_time": "2026-05-21 06:00:00", - "end_time": "2026-05-25 19:59:59", - "now_round": "1", - "is_display_tips": "0", - "tips_id": "0", - "is_colosseum_period": true, - "is_round_period": true, - "is_normal_two_pick": "1", - "is_special_mode": "10", - "is_all_card_enabled": 0, - "sales_period_info": { - "sales_period_time": "2026-05-25 19:59:59" - } -} diff --git a/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs b/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs index 9373c812..0936cb3c 100644 --- a/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs +++ b/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs @@ -81,42 +81,6 @@ public class MyPageGlobalsImporter return seed.Count; } - public async Task ImportColosseumAsync(SVSimDbContext context, string seedDir) - { - var s = SeedLoader.LoadObject(Path.Combine(seedDir, "colosseum.json")); - if (s is null) - { - Console.WriteLine("[MyPageGlobalsImporter] No colosseum seed; skipping."); - return 0; - } - - var existing = await context.Colosseums.FirstOrDefaultAsync(e => e.Id == 1); - var entry = existing ?? new ColosseumConfig { Id = 1 }; - - entry.ColosseumId = s.ColosseumId; - entry.ColosseumName = s.ColosseumName; - entry.CardPoolName = s.CardPoolName; - entry.DeckFormat = s.DeckFormat; - entry.StartTime = ImporterBase.ParseWireDateTime(s.StartTime); - entry.EndTime = ImporterBase.ParseWireDateTime(s.EndTime); - entry.NowRound = s.NowRound; - entry.IsDisplayTips = s.IsDisplayTips; - entry.TipsId = s.TipsId; - entry.IsColosseumPeriod = s.IsColosseumPeriod; - entry.IsRoundPeriod = s.IsRoundPeriod; - entry.IsNormalTwoPick = s.IsNormalTwoPick; - entry.IsSpecialMode = s.IsSpecialMode; - entry.IsAllCardEnabled = s.IsAllCardEnabled; - entry.SalesPeriodInfo = s.SalesPeriodInfo.ValueKind == JsonValueKind.Undefined - ? "{}" - : JsonSerializer.Serialize(s.SalesPeriodInfo); - - if (existing is null) context.Colosseums.Add(entry); - await context.SaveChangesAsync(); - Console.WriteLine($"[MyPageGlobalsImporter] Colosseum: {(existing is null ? "+1" : "~1")}"); - return 1; - } - public async Task ImportSealedAsync(SVSimDbContext context, string seedDir) { var s = SeedLoader.LoadObject(Path.Combine(seedDir, "sealed-season.json")); diff --git a/SVSim.Bootstrap/Models/Seed/ColosseumSeed.cs b/SVSim.Bootstrap/Models/Seed/ColosseumSeed.cs deleted file mode 100644 index 325da6fa..00000000 --- a/SVSim.Bootstrap/Models/Seed/ColosseumSeed.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace SVSim.Bootstrap.Models.Seed; - -public sealed class ColosseumSeed -{ - [JsonPropertyName("id")] public int Id { get; set; } = 1; - [JsonPropertyName("colosseum_id")] public string ColosseumId { get; set; } = ""; - [JsonPropertyName("colosseum_name")] public string ColosseumName { get; set; } = ""; - [JsonPropertyName("card_pool_name")] public string CardPoolName { get; set; } = ""; - [JsonPropertyName("deck_format")] public string DeckFormat { get; set; } = ""; - [JsonPropertyName("start_time")] public string StartTime { get; set; } = ""; - [JsonPropertyName("end_time")] public string EndTime { get; set; } = ""; - [JsonPropertyName("now_round")] public string NowRound { get; set; } = ""; - [JsonPropertyName("is_display_tips")] public string IsDisplayTips { get; set; } = ""; - [JsonPropertyName("tips_id")] public string TipsId { get; set; } = ""; - [JsonPropertyName("is_colosseum_period")] public bool IsColosseumPeriod { get; set; } - [JsonPropertyName("is_round_period")] public bool IsRoundPeriod { get; set; } - [JsonPropertyName("is_normal_two_pick")] public string IsNormalTwoPick { get; set; } = ""; - [JsonPropertyName("is_special_mode")] public string IsSpecialMode { get; set; } = ""; - [JsonPropertyName("is_all_card_enabled")] public int IsAllCardEnabled { get; set; } - [JsonPropertyName("sales_period_info")] public JsonElement SalesPeriodInfo { get; set; } -} diff --git a/SVSim.Bootstrap/Program.cs b/SVSim.Bootstrap/Program.cs index 34110eb1..629c91e4 100644 --- a/SVSim.Bootstrap/Program.cs +++ b/SVSim.Bootstrap/Program.cs @@ -114,7 +114,6 @@ public static class Program var mypage = new MyPageGlobalsImporter(); await mypage.ImportBannersAsync(context, opts.SeedDir); - await mypage.ImportColosseumAsync(context, opts.SeedDir); await mypage.ImportSealedAsync(context, opts.SeedDir); await mypage.ImportMasterPointRankingPeriodAsync(context, opts.SeedDir); await mypage.ImportSpecialDeckFormatsAsync(context, opts.SeedDir); diff --git a/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.Designer.cs b/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.Designer.cs new file mode 100644 index 00000000..7520e0dc --- /dev/null +++ b/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.Designer.cs @@ -0,0 +1,4795 @@ +// +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("20260613172735_DropColosseumsTable")] + partial class DropColosseumsTable + { + /// + 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.ArenaTwoPickReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("RewardGroup") + .HasColumnType("integer"); + + b.Property("RewardId") + .HasColumnType("bigint"); + + b.Property("RewardNum") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("Weight") + .HasColumnType("integer"); + + b.Property("WinCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WinCount"); + + b.HasIndex("WinCount", "RewardGroup", "RewardType", "RewardId", "RewardNum") + .IsUnique(); + + b.ToTable("ArenaTwoPickRewards"); + }); + + 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.BotRosterEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AiId") + .HasColumnType("integer"); + + b.Property("BattlePoint") + .HasColumnType("integer"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DegreeId") + .HasColumnType("integer"); + + b.Property("EmblemId") + .HasColumnType("integer"); + + b.Property("FieldId") + .HasColumnType("integer"); + + b.Property("IsMasterRank") + .HasColumnType("integer"); + + b.Property("IsOfficial") + .HasColumnType("integer"); + + b.Property("MasterPoint") + .HasColumnType("integer"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("SleeveId") + .HasColumnType("integer"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("BotRoster"); + }); + + 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.ColosseumAvatarDeck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CardListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DeckNo") + .HasColumnType("integer"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("LeaderSkinId") + .HasColumnType("bigint"); + + b.Property("SleeveId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DeckNo") + .IsUnique(); + + b.ToTable("ColosseumAvatarDecks"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ColosseumHofDeck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CardListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DeckNo") + .HasColumnType("integer"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("LeaderSkinId") + .HasColumnType("bigint"); + + b.Property("SleeveId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DeckNo") + .IsUnique(); + + b.ToTable("ColosseumHofDecks"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ColosseumWindFallDeck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CardListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DeckNo") + .HasColumnType("integer"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("LeaderSkinId") + .HasColumnType("bigint"); + + b.Property("SleeveId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DeckNo") + .IsUnique(); + + b.ToTable("ColosseumWindFallDecks"); + }); + + 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.HomeDialogEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BeginTime") + .HasColumnType("timestamp with time zone"); + + b.Property("ButtonListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("TitleTextId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("HomeDialogEntries"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ItemEntry", 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.Property("ThumbnailPath") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ItemPurchaseCatalogEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsMonthlyReset") + .HasColumnType("boolean"); + + b.Property("PurchaseItemId") + .HasColumnType("bigint"); + + b.Property("PurchaseItemNum") + .HasColumnType("integer"); + + b.Property("PurchaseItemType") + .HasColumnType("integer"); + + b.Property("PurchaseLimit") + .HasColumnType("integer"); + + b.Property("PurchaseName") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequireItemId") + .HasColumnType("bigint"); + + b.Property("RequireItemNum") + .HasColumnType("integer"); + + b.Property("RequireItemType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ItemPurchaseCatalog"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("EmoteId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClassId"); + + b.ToTable("LeaderSkins"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinShopProductEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("CvNameKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IntroductionKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("LeaderSkinId") + .HasColumnType("integer"); + + b.Property("ProductNameKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("SeriesId") + .HasColumnType("integer"); + + b.Property("SinglePriceCrystal") + .HasColumnType("integer"); + + b.Property("SinglePriceRupy") + .HasColumnType("integer"); + + b.Property("SinglePriceTicket") + .HasColumnType("integer"); + + b.Property("TicketItemId") + .HasColumnType("bigint"); + + b.Property("TicketNumber") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("LeaderSkinShopProducts"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinShopSeriesEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("SetCompletionRewardStatus") + .HasColumnType("integer"); + + b.Property("SetPriceCrystal") + .HasColumnType("integer"); + + b.Property("SetPriceRupy") + .HasColumnType("integer"); + + b.Property("SetPriceTicket") + .HasColumnType("integer"); + + b.Property("SetPriceTicketId") + .HasColumnType("bigint"); + + b.Property("SetSalesStatus") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("LeaderSkinShopSeries"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LoadingExclusionCardEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("LoadingExclusionCards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MaintenanceCardEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MaintenanceCards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MasterPointRankingPeriodEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BeginTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("NecessaryScore") + .HasColumnType("bigint"); + + b.Property("PeriodNum") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MasterPointRankingPeriods"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MissionCatalogEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BattlePassPoint") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultFlag") + .HasColumnType("boolean"); + + b.Property("EndTime") + .HasColumnType("bigint"); + + b.Property("EventArg") + .HasColumnType("integer"); + + b.Property("EventType") + .HasColumnType("text"); + + b.Property("LotType") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequireNumber") + .HasColumnType("integer"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardNumber") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("LotType"); + + b.HasIndex("EventType", "EventArg"); + + b.ToTable("MissionCatalog"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MyPageBackgroundEntry", 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("MyPageBackgrounds"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MyRotationAbilityEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AbilityId") + .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.HasKey("Id"); + + b.ToTable("MyRotationAbilities"); + }); + + modelBuilder.Entity("SVSim.Database.Models.MyRotationSettingEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AbilitiesCsv") + .IsRequired() + .HasColumnType("text"); + + b.Property("CardSetIdsCsv") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("ReprintedCardIds") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RestrictedCardIds") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RotationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MyRotationSettings"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PackConfigEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BasePackId") + .HasColumnType("integer"); + + b.Property("CommenceDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CompleteDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("GachaDetail") + .IsRequired() + .HasColumnType("text"); + + b.Property("GachaType") + .HasColumnType("integer"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsHide") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("IsPreRelease") + .HasColumnType("boolean"); + + b.Property("OpenCountLimit") + .HasColumnType("integer"); + + b.Property("OverrideDrawEffectPackId") + .HasColumnType("integer"); + + b.Property("OverrideUiEffectPackId") + .HasColumnType("integer"); + + b.Property("PackCategory") + .HasColumnType("integer"); + + b.Property("PosterType") + .HasColumnType("integer"); + + b.Property("SalesPeriodTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SleeveId") + .HasColumnType("integer"); + + b.Property("SpecialSleeveId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Packs"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PackDrawCardWeightEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsAltArt") + .HasColumnType("boolean"); + + b.Property("IsLeader") + .HasColumnType("boolean"); + + b.Property("PackId") + .HasColumnType("integer"); + + b.Property("RatePct") + .HasColumnType("double precision"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("Tier") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PackId", "Slot", "Tier"); + + b.ToTable("PackDrawCardWeights"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PackDrawConfigEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AnimationRatePct") + .HasColumnType("double precision"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("HasBonusSlot") + .HasColumnType("boolean"); + + b.Property("ShortCode") + .HasColumnType("text"); + + b.Property("SpecialKind") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PackDrawConfigs"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PackDrawSlotRateEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("PackId") + .HasColumnType("integer"); + + b.Property("RatePct") + .HasColumnType("double precision"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("Tier") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PackId", "Slot", "Tier") + .IsUnique(); + + b.ToTable("PackDrawSlotRates"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PaymentItemEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ChargeCrystalNum") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("FreeCrystalNum") + .HasColumnType("integer"); + + b.Property("ImageName") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsResaleProduct") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("PurchaseLimit") + .HasColumnType("integer"); + + b.Property("RemainingTime") + .HasColumnType("integer"); + + b.Property("ResaleStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SpecialShopFlag") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("StoreProductId") + .HasColumnType("bigint"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PaymentItems"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PracticeOpponentEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AiDeckLevel") + .HasColumnType("integer"); + + b.Property("AiLogicLevel") + .HasColumnType("integer"); + + b.Property("AiMaxLife") + .HasColumnType("integer"); + + b.Property("Battle3dFieldId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DegreeId") + .HasColumnType("integer"); + + b.Property("IsCampaignPractice") + .HasColumnType("boolean"); + + b.Property("IsMaintenance") + .HasColumnType("boolean"); + + b.Property("PracticeId") + .HasColumnType("integer"); + + b.Property("TextId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PracticeOpponents"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PreReleaseInfo", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("CardMasterId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultCardMasterId") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisplayEndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("FreeMatchStartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsPreRotationFreeMatchTerm") + .HasColumnType("boolean"); + + b.Property("LatestReprintedBaseCardIds") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("NextCardSetId") + .IsRequired() + .HasColumnType("text"); + + b.Property("PreReleaseCardMasterId") + .IsRequired() + .HasColumnType("text"); + + b.Property("PreReleaseId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReprintedBaseCardIds") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RotationCardSetIdList") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("PreReleaseInfos"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PuzzleEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("GroupId") + .HasColumnType("integer"); + + b.Property("IsAdditional") + .HasColumnType("boolean"); + + b.Property("IsPlayable") + .HasColumnType("boolean"); + + b.Property("PuzzleDifficulty") + .HasColumnType("integer"); + + b.Property("PuzzleId") + .HasColumnType("integer"); + + b.Property("ReleaseConditionTextId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("Puzzles"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PuzzleGroupEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BasicTitleTextId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DifficultyNameListJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("PuzzleCharaId") + .HasColumnType("integer"); + + b.Property("PuzzleMasterId") + .HasColumnType("integer"); + + b.Property("SortType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("PuzzleGroups"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PuzzleMissionEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AchievedMessage") + .IsRequired() + .HasColumnType("text"); + + b.Property("CampaignCommenceTime") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("MissionName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("RequireNumber") + .HasColumnType("integer"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardNumber") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("TargetPuzzleGroupId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("PuzzleMissions"); + }); + + modelBuilder.Entity("SVSim.Database.Models.RankInfoEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("AccumulateMasterPoint") + .HasColumnType("integer"); + + b.Property("AccumulatePoint") + .HasColumnType("integer"); + + b.Property("BaseAddBp") + .HasColumnType("integer"); + + b.Property("BaseDropBp") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsPromotionWar") + .HasColumnType("integer"); + + b.Property("LoseBonus") + .HasColumnType("double precision"); + + b.Property("LowerLimitPoint") + .HasColumnType("integer"); + + b.Property("MatchCount") + .HasColumnType("integer"); + + b.Property("MaxLoseBonus") + .HasColumnType("integer"); + + b.Property("MaxWinBonus") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NecessaryPoint") + .HasColumnType("integer"); + + b.Property("NecessaryWin") + .HasColumnType("integer"); + + b.Property("ResetLose") + .HasColumnType("integer"); + + b.Property("StreakBonusPt") + .HasColumnType("integer"); + + b.Property("WinBonus") + .HasColumnType("double precision"); + + b.HasKey("Id"); + + b.ToTable("RankInfo"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ReprintedCardEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ReprintedCards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SealedConfig", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("CrystalCost") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DeckUsingNumMin") + .HasColumnType("integer"); + + b.Property("Enable") + .HasColumnType("integer"); + + b.Property("IsDeckCodeMaintenance") + .HasColumnType("boolean"); + + b.Property("IsJoin") + .HasColumnType("boolean"); + + b.Property("PackInfo") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RupyCost") + .HasColumnType("integer"); + + b.Property("SalesPeriodInfo") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScheduleId") + .HasColumnType("integer"); + + b.Property("TicketCost") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SealedSeasons"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SerialCodeEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("EndAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("StartAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("SerialCodes"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SerialCodeRewardEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("RewardCount") + .HasColumnType("integer"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("SerialCodeId") + .HasColumnType("integer"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SerialCodeId", "Slot"); + + b.ToTable("SerialCodeRewards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Attack") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("Defense") + .HasColumnType("integer"); + + b.Property("IsFoil") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PrimaryResourceCost") + .HasColumnType("integer"); + + b.Property("Rarity") + .HasColumnType("integer"); + + b.Property("ShadowverseCardSetEntryId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClassId"); + + b.HasIndex("ShadowverseCardSetEntryId"); + + b.ToTable("Cards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardSetEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsBasic") + .HasColumnType("boolean"); + + b.Property("IsInRotation") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("CardSets"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("Format") + .HasColumnType("integer"); + + b.Property("LeaderSkinId") + .HasColumnType("integer"); + + b.Property("MyRotationId") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("RandomLeaderSkin") + .HasColumnType("boolean"); + + b.Property("SleeveId") + .HasColumnType("integer"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ClassId"); + + b.HasIndex("LeaderSkinId"); + + b.HasIndex("SleeveId"); + + b.HasIndex("ViewerId"); + + b.ToTable("Decks"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SleeveEntry", 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("Sleeves"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SleeveShopProductEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("NameKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("PriceCrystal") + .HasColumnType("integer"); + + b.Property("PriceRupy") + .HasColumnType("integer"); + + b.Property("SeriesId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("SleeveShopProducts"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SleeveShopSeriesEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("SleeveShopSeries"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SpecialDeckFormatEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + 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.HasKey("Id"); + + b.ToTable("SpecialDeckFormats"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SpotCardEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("Cost") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("SpotCards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SpotCardExchangeEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("ExchangePoint") + .HasColumnType("integer"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsPreRelease") + .HasColumnType("boolean"); + + b.Property("TsRotationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SpotCardExchangeCatalog"); + }); + + modelBuilder.Entity("SVSim.Database.Models.StoryDeckEntry", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DeckFormat") + .HasColumnType("integer"); + + b.Property("DeckName") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeckNo") + .HasColumnType("integer"); + + b.Property("EntryNo") + .HasColumnType("integer"); + + b.Property("IsRecommend") + .HasColumnType("integer"); + + b.Property("Kind") + .HasColumnType("integer"); + + b.Property("LeaderSkinId") + .HasColumnType("integer"); + + b.Property("OrderNum") + .HasColumnType("integer"); + + b.Property("SleeveId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("StoryDecks"); + }); + + modelBuilder.Entity("SVSim.Database.Models.TutorialPresentEntry", b => + { + b.Property("PresentId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("RewardCount") + .HasColumnType("bigint"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.HasKey("PresentId"); + + b.ToTable("TutorialPresentEntries"); + }); + + modelBuilder.Entity("SVSim.Database.Models.UnlimitedRestrictionEntry", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("RestrictionValue") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("UnlimitedRestrictions"); + }); + + modelBuilder.Entity("SVSim.Database.Models.Viewer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastLogin") + .HasColumnType("timestamp with time zone"); + + b.Property("MyPageBgId") + .HasColumnType("integer"); + + b.Property("MyPageBgSelectType") + .HasColumnType("integer"); + + b.Property("ShortUdid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValueSql("nextval('\"ShortUdidSequence\"')"); + + NpgsqlPropertyBuilderExtensions.UseSequence(b.Property("ShortUdid"), "ShortUdidSequence"); + + b.Property("Udid") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ShortUdid"); + + b.HasIndex("Udid") + .IsUnique(); + + b.ToTable("Viewers"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerAchievement", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("AchievementType") + .HasColumnType("integer"); + + b.Property("AchievementStatus") + .HasColumnType("integer"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("NowAchievedLevel") + .HasColumnType("integer"); + + b.Property("ResultAnnounceSawLevel") + .HasColumnType("integer"); + + b.HasKey("ViewerId", "AchievementType"); + + b.ToTable("ViewerAchievements"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerAcquireHistoryEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AcquireTime") + .HasColumnType("timestamp with time zone"); + + b.Property("AcquireType") + .HasColumnType("integer"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("RewardCount") + .HasColumnType("integer"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId", "AcquireTime", "Id"); + + b.ToTable("ViewerAcquireHistory"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerArenaColosseumRun", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BattleCountThisRound") + .HasColumnType("integer"); + + b.Property("BreakthroughNumberThisRound") + .HasColumnType("integer"); + + b.Property("CandidateClassIdsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ChaosId") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("ConsumeItemType") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeckFormat") + .HasColumnType("integer"); + + b.Property("EntryId") + .HasColumnType("bigint"); + + b.Property("IsChampion") + .HasColumnType("boolean"); + + b.Property("IsPublished") + .HasColumnType("boolean"); + + b.Property("IsRankMatching") + .HasColumnType("boolean"); + + b.Property("IsSelectCompleted") + .HasColumnType("boolean"); + + b.Property("LeaderSkinId") + .HasColumnType("bigint"); + + b.Property("LossCount") + .HasColumnType("integer"); + + b.Property("MaxBattleCountThisRound") + .HasColumnType("integer"); + + b.Property("NextCandidateId") + .HasColumnType("bigint"); + + b.Property("PendingPickSetsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RegisteredDeckNoListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RestEntryNum") + .HasColumnType("integer"); + + b.Property("ResultListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RoundId") + .HasColumnType("integer"); + + b.Property("SeasonId") + .HasColumnType("integer"); + + b.Property("SelectTurn") + .HasColumnType("integer"); + + b.Property("SelectedCardIdsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("WinCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId") + .IsUnique(); + + b.ToTable("ViewerArenaColosseumRuns"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerArenaTwoPickRun", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CandidateClassIdsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ChallengeId") + .HasColumnType("integer"); + + b.Property("ClassId") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EntryId") + .HasColumnType("bigint"); + + b.Property("IsRetire") + .HasColumnType("boolean"); + + b.Property("IsSelectCompleted") + .HasColumnType("boolean"); + + b.Property("LeaderSkinId") + .HasColumnType("bigint"); + + b.Property("LossCount") + .HasColumnType("integer"); + + b.Property("MaxBattleCount") + .HasColumnType("integer"); + + b.Property("NextCandidateId") + .HasColumnType("bigint"); + + b.Property("PendingPickSetsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ResultListJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RewardScheduleId") + .HasColumnType("integer"); + + b.Property("SelectTurn") + .HasColumnType("integer"); + + b.Property("SelectedCardIdsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("WinCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId") + .IsUnique(); + + b.ToTable("ViewerArenaTwoPickRuns"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerBattleHistory", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("BattleId") + .HasColumnType("bigint"); + + b.Property("BattleStartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("BattleType") + .HasColumnType("integer"); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeckFormat") + .HasColumnType("integer"); + + b.Property("IsLimitTurn") + .HasColumnType("integer"); + + b.Property("IsWin") + .HasColumnType("boolean"); + + b.Property("OpponentCharaId") + .HasColumnType("integer"); + + b.Property("OpponentClassId") + .HasColumnType("integer"); + + b.Property("OpponentCountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("OpponentDegreeId") + .HasColumnType("bigint"); + + b.Property("OpponentEmblemId") + .HasColumnType("bigint"); + + b.Property("OpponentName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OpponentRotationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("OpponentSubClassId") + .HasColumnType("integer"); + + b.Property("SelfCharaId") + .HasColumnType("integer"); + + b.Property("SelfClassId") + .HasColumnType("integer"); + + b.Property("SelfRotationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("SelfSubClassId") + .HasColumnType("integer"); + + b.Property("TwoPickType") + .HasColumnType("integer"); + + b.HasKey("ViewerId", "BattleId"); + + b.HasIndex("ViewerId", "CreateTime") + .HasDatabaseName("IX_ViewerBattleHistories_ViewerId_CreateTime"); + + b.ToTable("ViewerBattleHistories"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerBattlePassClaimEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("SeasonId") + .HasColumnType("integer"); + + b.Property("Track") + .HasColumnType("integer"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId", "SeasonId"); + + b.HasIndex("ViewerId", "SeasonId", "Track", "Level") + .IsUnique(); + + b.ToTable("ViewerBattlePassClaims"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerBattlePassProgressEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CurrentPoint") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("IsPremium") + .HasColumnType("boolean"); + + b.Property("SeasonId") + .HasColumnType("integer"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("WeeklyPeriodStart") + .HasColumnType("timestamp with time zone"); + + b.Property("WeeklyPoints") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId", "SeasonId") + .IsUnique(); + + b.ToTable("ViewerBattlePassProgress"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerEventCounter", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("EventKey") + .HasColumnType("text"); + + b.Property("Period") + .HasColumnType("text"); + + b.Property("Count") + .HasColumnType("integer"); + + b.HasKey("ViewerId", "EventKey", "Period"); + + b.HasIndex("ViewerId", "Period"); + + b.ToTable("ViewerEventCounters"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerFriend", b => + { + b.Property("OwnerViewerId") + .HasColumnType("bigint"); + + b.Property("FriendViewerId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("OwnerViewerId", "FriendViewerId"); + + b.HasIndex("FriendViewerId"); + + b.HasIndex("OwnerViewerId", "CreatedAt"); + + b.ToTable("ViewerFriends"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerFriendApply", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FromViewerId") + .HasColumnType("bigint"); + + b.Property("MissionType") + .HasColumnType("integer"); + + b.Property("ToViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ToViewerId"); + + b.HasIndex("FromViewerId", "ToViewerId") + .IsUnique(); + + b.ToTable("ViewerFriendApplies"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerLeaderSkinSetClaim", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("SeriesId") + .HasColumnType("integer"); + + b.Property("ClaimedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("ViewerId", "SeriesId"); + + b.HasIndex("ViewerId"); + + b.ToTable("ViewerLeaderSkinSetClaims"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerMission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AssignedAt") + .HasColumnType("bigint"); + + b.Property("ClaimedAt") + .HasColumnType("bigint"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("MissionCatalogId") + .HasColumnType("integer"); + + b.Property("MissionStatus") + .HasColumnType("integer"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId"); + + b.HasIndex("ViewerId", "Slot") + .IsUnique(); + + b.ToTable("ViewerMissions"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerPlayedTogether", b => + { + b.Property("OwnerViewerId") + .HasColumnType("bigint"); + + b.Property("OpponentViewerId") + .HasColumnType("bigint"); + + b.Property("BattleType") + .HasColumnType("integer"); + + b.Property("DeckFormat") + .HasColumnType("integer"); + + b.Property("PlayedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PlayedMode") + .HasColumnType("integer"); + + b.Property("TwoPickType") + .HasColumnType("integer"); + + b.HasKey("OwnerViewerId", "OpponentViewerId"); + + b.HasIndex("OwnerViewerId", "PlayedAt"); + + b.ToTable("ViewerPlayedTogethers"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerPresent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ConditionNumber") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("PresentId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("PresentLimitType") + .HasColumnType("integer"); + + b.Property("RewardCount") + .HasColumnType("bigint"); + + b.Property("RewardDetailId") + .HasColumnType("bigint"); + + b.Property("RewardLimitTime") + .HasColumnType("bigint"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("Source") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ViewerId", "PresentId") + .IsUnique(); + + b.HasIndex("ViewerId", "Status", "CreatedAt"); + + b.ToTable("ViewerPresents"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerPuzzleClear", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("PuzzleId") + .HasColumnType("integer"); + + b.Property("BestRetryCount") + .HasColumnType("integer"); + + b.Property("ClearedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("ViewerId", "PuzzleId"); + + b.ToTable("ViewerPuzzleClears"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerSerialCodeRedemption", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("SerialCodeId") + .HasColumnType("integer"); + + b.Property("RedeemedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("ViewerId", "SerialCodeId"); + + b.HasIndex("SerialCodeId"); + + b.ToTable("ViewerSerialCodeRedemptions"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerSpotCardExchange", b => + { + b.Property("ViewerId") + .HasColumnType("bigint"); + + b.Property("CardId") + .HasColumnType("bigint"); + + b.Property("ExchangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsPreRelease") + .HasColumnType("boolean"); + + b.HasKey("ViewerId", "CardId"); + + b.HasIndex("ViewerId"); + + b.ToTable("ViewerSpotCardExchanges"); + }); + + modelBuilder.Entity("SleeveEntryViewer", b => + { + b.Property("SleevesId") + .HasColumnType("integer"); + + b.Property("ViewersId") + .HasColumnType("bigint"); + + b.HasKey("SleevesId", "ViewersId"); + + b.HasIndex("ViewersId"); + + b.ToTable("SleeveEntryViewer"); + }); + + modelBuilder.Entity("DegreeEntryViewer", b => + { + b.HasOne("SVSim.Database.Models.DegreeEntry", null) + .WithMany() + .HasForeignKey("DegreesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EmblemEntryViewer", b => + { + b.HasOne("SVSim.Database.Models.EmblemEntry", null) + .WithMany() + .HasForeignKey("EmblemsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LeaderSkinEntryViewer", b => + { + b.HasOne("SVSim.Database.Models.LeaderSkinEntry", null) + .WithMany() + .HasForeignKey("LeaderSkinsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MyPageBackgroundEntryViewer", b => + { + b.HasOne("SVSim.Database.Models.MyPageBackgroundEntry", null) + .WithMany() + .HasForeignKey("MyPageBackgroundsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Entities.Story.StoryChapter", b => + { + b.HasOne("SVSim.Database.Entities.Story.StorySection", "Section") + .WithMany() + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Entities.Story.SpecialBattleSetting", "SpecialBattleSetting") + .WithMany() + .HasForeignKey("SpecialBattleSettingId"); + + b.OwnsMany("SVSim.Database.Entities.Story.StoryChapterBattleSetting", "BattleSettings", b1 => + { + b1.Property("StoryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("Battle3dFieldIdOverride") + .HasColumnType("integer"); + + b1.Property("BgmIdOverride") + .HasColumnType("integer"); + + b1.Property("DeckClassId") + .HasColumnType("integer"); + + b1.Property("DeckSkinIdOverride") + .HasColumnType("integer"); + + b1.Property("EnemyEmotionOverride") + .HasColumnType("integer"); + + b1.Property("PlayerEmotionOverride") + .HasColumnType("integer"); + + b1.Property("SkinIdOverride") + .HasColumnType("integer"); + + b1.HasKey("StoryId", "Id"); + + b1.ToTable("StoryChapterBattleSetting"); + + b1.WithOwner() + .HasForeignKey("StoryId"); + }); + + b.OwnsMany("SVSim.Database.Entities.Story.StoryChapterReward", "Rewards", b1 => + { + b1.Property("StoryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.HasKey("StoryId", "Id"); + + b1.ToTable("StoryChapterReward"); + + b1.WithOwner() + .HasForeignKey("StoryId"); + }); + + b.OwnsMany("SVSim.Database.Entities.Story.StorySubChapter", "SubChapters", b1 => + { + b1.Property("StoryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("IsMaintenanceChapter") + .HasColumnType("boolean"); + + b1.Property("SubChapterId") + .HasColumnType("integer"); + + b1.Property("SubChapterStoryId") + .HasColumnType("integer"); + + b1.HasKey("StoryId", "Id"); + + b1.ToTable("StorySubChapter"); + + b1.WithOwner() + .HasForeignKey("StoryId"); + }); + + b.Navigation("BattleSettings"); + + b.Navigation("Rewards"); + + b.Navigation("Section"); + + b.Navigation("SpecialBattleSetting"); + + b.Navigation("SubChapters"); + }); + + modelBuilder.Entity("SVSim.Database.Entities.Story.StorySection", b => + { + b.HasOne("SVSim.Database.Entities.Story.StoryWorld", "World") + .WithMany() + .HasForeignKey("WorldId"); + + b.Navigation("World"); + }); + + modelBuilder.Entity("SVSim.Database.Models.BattlePassRewardEntry", b => + { + b.HasOne("SVSim.Database.Models.BattlePassSeasonEntry", "Season") + .WithMany("Rewards") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Season"); + }); + + modelBuilder.Entity("SVSim.Database.Models.BuildDeckProductEntry", b => + { + b.HasOne("SVSim.Database.Models.BuildDeckSeriesEntry", "Series") + .WithMany("Products") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsMany("SVSim.Database.Models.BuildDeckProductCardEntry", "Cards", b1 => + { + b1.Property("BuildDeckProductEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CardId") + .HasColumnType("bigint"); + + b1.Property("IsSpot") + .HasColumnType("boolean"); + + b1.Property("Number") + .HasColumnType("integer"); + + b1.HasKey("BuildDeckProductEntryId", "Id"); + + b1.ToTable("BuildDeckProductCardEntry"); + + b1.WithOwner() + .HasForeignKey("BuildDeckProductEntryId"); + }); + + b.OwnsMany("SVSim.Database.Models.BuildDeckProductRewardEntry", "Rewards", b1 => + { + b1.Property("BuildDeckProductEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("MessageId") + .HasColumnType("integer"); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardIndex") + .HasColumnType("integer"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.HasKey("BuildDeckProductEntryId", "Id"); + + b1.ToTable("BuildDeckProductRewardEntry"); + + b1.WithOwner() + .HasForeignKey("BuildDeckProductEntryId"); + }); + + b.Navigation("Cards"); + + b.Navigation("Rewards"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("SVSim.Database.Models.BuildDeckSeriesEntry", b => + { + b.OwnsMany("SVSim.Database.Models.BuildDeckSeriesRewardEntry", "SeriesRewards", b1 => + { + b1.Property("BuildDeckSeriesEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("ItemIndex") + .HasColumnType("integer"); + + b1.Property("MessageId") + .HasColumnType("integer"); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.Property("TierIndex") + .HasColumnType("integer"); + + b1.HasKey("BuildDeckSeriesEntryId", "Id"); + + b1.ToTable("BuildDeckSeriesRewardEntry"); + + b1.WithOwner() + .HasForeignKey("BuildDeckSeriesEntryId"); + }); + + b.Navigation("SeriesRewards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.CardCosmeticReward", b => + { + b.HasOne("SVSim.Database.Models.ShadowverseCardEntry", "Card") + .WithMany() + .HasForeignKey("CardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Card"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinEntry", b => + { + b.HasOne("SVSim.Database.Models.ClassEntry", "Class") + .WithMany("LeaderSkins") + .HasForeignKey("ClassId"); + + b.Navigation("Class"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinShopProductEntry", b => + { + b.HasOne("SVSim.Database.Models.LeaderSkinShopSeriesEntry", "Series") + .WithMany("Products") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsMany("SVSim.Database.Models.LeaderSkinShopProductRewardEntry", "Rewards", b1 => + { + b1.Property("LeaderSkinShopProductEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("OrderIndex") + .HasColumnType("integer"); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.HasKey("LeaderSkinShopProductEntryId", "Id"); + + b1.ToTable("LeaderSkinShopProductRewardEntry"); + + b1.WithOwner() + .HasForeignKey("LeaderSkinShopProductEntryId"); + }); + + b.Navigation("Rewards"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinShopSeriesEntry", b => + { + b.OwnsMany("SVSim.Database.Models.LeaderSkinShopSeriesRewardEntry", "SetCompletionRewards", b1 => + { + b1.Property("LeaderSkinShopSeriesEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("OrderIndex") + .HasColumnType("integer"); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.HasKey("LeaderSkinShopSeriesEntryId", "Id"); + + b1.ToTable("LeaderSkinShopSeriesRewardEntry"); + + b1.WithOwner() + .HasForeignKey("LeaderSkinShopSeriesEntryId"); + }); + + b.Navigation("SetCompletionRewards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PackConfigEntry", b => + { + b.OwnsMany("SVSim.Database.Models.PackBannerEntry", "Banners", b1 => + { + b1.Property("PackConfigEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("BannerName") + .IsRequired() + .HasColumnType("text"); + + b1.Property("DialogTitle") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("PackConfigEntryId", "Id"); + + b1.ToTable("PackBannerEntry"); + + b1.WithOwner() + .HasForeignKey("PackConfigEntryId"); + }); + + b.OwnsMany("SVSim.Database.Models.PackChildGachaEntry", "ChildGachas", b1 => + { + b1.Property("PackConfigEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CampaignName") + .HasColumnType("text"); + + b1.Property("CardCount") + .HasColumnType("integer"); + + b1.Property("Cost") + .HasColumnType("integer"); + + b1.Property("DailyFreeGachaCount") + .HasColumnType("integer"); + + b1.Property("FreeGachaCampaignId") + .HasColumnType("integer"); + + b1.Property("GachaId") + .HasColumnType("integer"); + + b1.Property("IsDailySingle") + .HasColumnType("boolean"); + + b1.Property("ItemId") + .HasColumnType("bigint"); + + b1.Property("OverrideIncreaseGachaPoint") + .HasColumnType("integer"); + + b1.Property("PurchaseLimitCount") + .HasColumnType("integer"); + + b1.Property("TypeDetail") + .HasColumnType("integer"); + + b1.HasKey("PackConfigEntryId", "Id"); + + b1.ToTable("PackChildGachaEntry"); + + b1.WithOwner() + .HasForeignKey("PackConfigEntryId"); + }); + + b.OwnsOne("SVSim.Database.Models.PackGachaPointConfig", "GachaPointConfig", b1 => + { + b1.Property("PackConfigEntryId") + .HasColumnType("integer"); + + b1.Property("ExchangeablePoint") + .HasColumnType("integer"); + + b1.Property("IncreaseGachaPoint") + .HasColumnType("integer"); + + b1.HasKey("PackConfigEntryId"); + + b1.ToTable("Packs"); + + b1.WithOwner() + .HasForeignKey("PackConfigEntryId"); + }); + + b.Navigation("Banners"); + + b.Navigation("ChildGachas"); + + b.Navigation("GachaPointConfig"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PuzzleEntry", b => + { + b.HasOne("SVSim.Database.Models.PuzzleGroupEntry", "Group") + .WithMany("Puzzles") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SerialCodeRewardEntry", b => + { + b.HasOne("SVSim.Database.Models.SerialCodeEntry", null) + .WithMany("Rewards") + .HasForeignKey("SerialCodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardEntry", b => + { + b.HasOne("SVSim.Database.Models.ClassEntry", "Class") + .WithMany() + .HasForeignKey("ClassId"); + + b.HasOne("SVSim.Database.Models.ShadowverseCardSetEntry", null) + .WithMany("Cards") + .HasForeignKey("ShadowverseCardSetEntryId"); + + b.OwnsOne("SVSim.Database.Models.CardCollectionInfo", "CollectionInfo", b1 => + { + b1.Property("ShadowverseCardEntryId") + .HasColumnType("bigint"); + + b1.Property("CraftCost") + .HasColumnType("integer"); + + b1.Property("DustReward") + .HasColumnType("integer"); + + b1.HasKey("ShadowverseCardEntryId"); + + b1.ToTable("Cards"); + + b1.WithOwner() + .HasForeignKey("ShadowverseCardEntryId"); + }); + + b.Navigation("Class"); + + b.Navigation("CollectionInfo"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b => + { + b.HasOne("SVSim.Database.Models.ClassEntry", "Class") + .WithMany() + .HasForeignKey("ClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.LeaderSkinEntry", "LeaderSkin") + .WithMany() + .HasForeignKey("LeaderSkinId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.SleeveEntry", "Sleeve") + .WithMany() + .HasForeignKey("SleeveId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany("Decks") + .HasForeignKey("ViewerId"); + + b.OwnsMany("SVSim.Database.Models.DeckCard", "Cards", b1 => + { + b1.Property("ShadowverseDeckEntryId") + .HasColumnType("uuid"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CardId") + .HasColumnType("bigint"); + + b1.Property("Count") + .HasColumnType("integer"); + + b1.HasKey("ShadowverseDeckEntryId", "Id"); + + b1.HasIndex("CardId"); + + b1.ToTable("DeckCard"); + + b1.HasOne("SVSim.Database.Models.ShadowverseCardEntry", "Card") + .WithMany() + .HasForeignKey("CardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner() + .HasForeignKey("ShadowverseDeckEntryId"); + + b1.Navigation("Card"); + }); + + b.Navigation("Cards"); + + b.Navigation("Class"); + + b.Navigation("LeaderSkin"); + + b.Navigation("Sleeve"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SleeveShopProductEntry", b => + { + b.HasOne("SVSim.Database.Models.SleeveShopSeriesEntry", "Series") + .WithMany("Products") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsMany("SVSim.Database.Models.SleeveShopProductRewardEntry", "Rewards", b1 => + { + b1.Property("SleeveShopProductEntryId") + .HasColumnType("integer"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("OrderIndex") + .HasColumnType("integer"); + + b1.Property("RewardDetailId") + .HasColumnType("bigint"); + + b1.Property("RewardNumber") + .HasColumnType("integer"); + + b1.Property("RewardType") + .HasColumnType("integer"); + + b1.HasKey("SleeveShopProductEntryId", "Id"); + + b1.ToTable("SleeveShopProductRewardEntry"); + + b1.WithOwner() + .HasForeignKey("SleeveShopProductEntryId"); + }); + + b.Navigation("Rewards"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("SVSim.Database.Models.Viewer", b => + { + b.OwnsMany("SVSim.Database.Models.MyPageBgRotationEntry", "MyPageBgRotation", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Slot") + .HasColumnType("integer"); + + b1.Property("BgId") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Slot"); + + b1.ToTable("ViewerMyPageBgRotation", (string)null); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.OwnedCardEntry", "Cards", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CardId") + .HasColumnType("bigint"); + + b1.Property("Count") + .HasColumnType("integer"); + + b1.Property("IsProtected") + .HasColumnType("boolean"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("CardId"); + + b1.HasIndex("ViewerId", "CardId") + .IsUnique(); + + b1.ToTable("OwnedCardEntry"); + + b1.HasOne("SVSim.Database.Models.ShadowverseCardEntry", "Card") + .WithMany() + .HasForeignKey("CardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + + b1.Navigation("Card"); + }); + + b.OwnsMany("SVSim.Database.Models.OwnedItemEntry", "Items", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("Count") + .HasColumnType("integer"); + + b1.Property("ItemId") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("ItemId"); + + b1.HasIndex("ViewerId", "ItemId") + .IsUnique(); + + b1.ToTable("OwnedItemEntry"); + + b1.HasOne("SVSim.Database.Models.ItemEntry", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner("Viewer") + .HasForeignKey("ViewerId"); + + b1.Navigation("Item"); + + b1.Navigation("Viewer"); + }); + + b.OwnsMany("SVSim.Database.Models.SocialAccountConnection", "SocialAccountConnections", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("AccountId") + .HasColumnType("numeric(20,0)"); + + b1.Property("AccountType") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("AccountType", "AccountId") + .IsUnique(); + + b1.ToTable("SocialAccountConnection"); + + b1.WithOwner("Viewer") + .HasForeignKey("ViewerId"); + + b1.Navigation("Viewer"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerBuildDeckProductPurchase", "BuildDeckPurchases", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("ProductId") + .HasColumnType("integer"); + + b1.Property("PurchaseCount") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("ViewerId", "ProductId") + .IsUnique(); + + b1.ToTable("ViewerBuildDeckProductPurchase"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerClassData", "Classes", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("ClassId") + .HasColumnType("integer"); + + b1.Property("Exp") + .HasColumnType("integer"); + + b1.Property("IsRandomLeaderSkin") + .HasColumnType("boolean"); + + b1.Property("LeaderSkinId") + .HasColumnType("integer"); + + b1.Property("Level") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("ClassId"); + + b1.HasIndex("LeaderSkinId"); + + b1.ToTable("ViewerClassData"); + + b1.HasOne("SVSim.Database.Models.ClassEntry", "Class") + .WithMany() + .HasForeignKey("ClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.HasOne("SVSim.Database.Models.LeaderSkinEntry", "LeaderSkin") + .WithMany() + .HasForeignKey("LeaderSkinId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner("Viewer") + .HasForeignKey("ViewerId"); + + b1.Navigation("Class"); + + b1.Navigation("LeaderSkin"); + + b1.Navigation("Viewer"); + }); + + b.OwnsOne("SVSim.Database.Models.ViewerCurrency", "Currency", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("AndroidCrystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("Crystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("DmmCrystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("FreeCrystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("IosCrystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("LifeTotalCrystals") + .HasColumnType("numeric(20,0)"); + + b1.Property("RedEther") + .HasColumnType("numeric(20,0)"); + + b1.Property("Rupees") + .HasColumnType("numeric(20,0)"); + + b1.Property("SpotPoints") + .HasColumnType("numeric(20,0)"); + + b1.Property("SteamCrystals") + .HasColumnType("numeric(20,0)"); + + b1.HasKey("ViewerId"); + + b1.ToTable("Viewers"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerFreePackClaim", "FreePackClaims", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("FreeGachaCampaignId") + .HasColumnType("integer"); + + b1.Property("ClaimCount") + .HasColumnType("integer"); + + b1.Property("LastClaimedAt") + .HasColumnType("timestamp with time zone"); + + b1.HasKey("ViewerId", "FreeGachaCampaignId"); + + b1.ToTable("ViewerFreePackClaim"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerGachaPointBalance", "GachaPointBalances", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("PackId") + .HasColumnType("integer"); + + b1.Property("Points") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("ViewerId", "PackId") + .IsUnique(); + + b1.ToTable("ViewerGachaPointBalance"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerGachaPointReceived", "GachaPointReceived", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CardId") + .HasColumnType("bigint"); + + b1.Property("PackId") + .HasColumnType("integer"); + + b1.Property("ReceivedAt") + .HasColumnType("timestamp with time zone"); + + b1.HasKey("ViewerId", "Id"); + + b1.HasIndex("ViewerId", "PackId", "CardId") + .IsUnique(); + + b1.ToTable("ViewerGachaPointReceived"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsOne("SVSim.Database.Models.ViewerInfo", "Info", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("BirthDate") + .HasColumnType("timestamp with time zone"); + + b1.Property("ChallengeTwoPickSleeveId") + .HasColumnType("bigint"); + + b1.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b1.Property("IsFoilPreferred") + .HasColumnType("boolean"); + + b1.Property("IsOfficial") + .HasColumnType("boolean"); + + b1.Property("IsOfficialMarkDisplayed") + .HasColumnType("boolean"); + + b1.Property("IsPrizePreferred") + .HasColumnType("boolean"); + + b1.Property("IsSkipGachaEffect") + .HasColumnType("boolean"); + + b1.Property("MaxFriends") + .HasColumnType("integer"); + + b1.Property("SelectedDegreeId") + .HasColumnType("integer"); + + b1.Property("SelectedEmblemId") + .HasColumnType("integer"); + + b1.Property("UseChallengeTwoPickPremiumCard") + .HasColumnType("boolean"); + + b1.HasKey("ViewerId"); + + b1.HasIndex("SelectedDegreeId"); + + b1.HasIndex("SelectedEmblemId"); + + b1.ToTable("Viewers"); + + b1.HasOne("SVSim.Database.Models.DegreeEntry", "SelectedDegree") + .WithMany() + .HasForeignKey("SelectedDegreeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.HasOne("SVSim.Database.Models.EmblemEntry", "SelectedEmblem") + .WithMany() + .HasForeignKey("SelectedEmblemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + + b1.Navigation("SelectedDegree"); + + b1.Navigation("SelectedEmblem"); + }); + + b.OwnsOne("SVSim.Database.Models.ViewerMissionData", "MissionData", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("HasReceivedPickTwoMission") + .HasColumnType("boolean"); + + b1.Property("MissionChangeTime") + .HasColumnType("timestamp with time zone"); + + b1.Property("MissionReceiveType") + .HasColumnType("integer"); + + b1.Property("TutorialState") + .HasColumnType("integer"); + + b1.HasKey("ViewerId"); + + b1.ToTable("Viewers"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.OwnsMany("SVSim.Database.Models.ViewerPackOpenCount", "PackOpenCounts", b1 => + { + b1.Property("ViewerId") + .HasColumnType("bigint"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("LastDailyFreeAt") + .HasColumnType("timestamp with time zone"); + + b1.Property("OpenCount") + .HasColumnType("integer"); + + b1.Property("PackId") + .HasColumnType("integer"); + + b1.HasKey("ViewerId", "Id"); + + b1.ToTable("ViewerPackOpenCount"); + + b1.WithOwner() + .HasForeignKey("ViewerId"); + }); + + b.Navigation("BuildDeckPurchases"); + + b.Navigation("Cards"); + + b.Navigation("Classes"); + + b.Navigation("Currency") + .IsRequired(); + + b.Navigation("FreePackClaims"); + + b.Navigation("GachaPointBalances"); + + b.Navigation("GachaPointReceived"); + + b.Navigation("Info") + .IsRequired(); + + b.Navigation("Items"); + + b.Navigation("MissionData") + .IsRequired(); + + b.Navigation("MyPageBgRotation"); + + b.Navigation("PackOpenCounts"); + + b.Navigation("SocialAccountConnections"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerAchievement", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany("Achievements") + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerAcquireHistoryEntry", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerEventCounter", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany("EventCounters") + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerFriend", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("FriendViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("OwnerViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerFriendApply", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("FromViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ToViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerMission", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany("Missions") + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerPlayedTogether", b => + { + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("OwnerViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerPresent", b => + { + b.HasOne("SVSim.Database.Models.Viewer", "Viewer") + .WithMany() + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viewer"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ViewerSerialCodeRedemption", b => + { + b.HasOne("SVSim.Database.Models.SerialCodeEntry", null) + .WithMany() + .HasForeignKey("SerialCodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SleeveEntryViewer", b => + { + b.HasOne("SVSim.Database.Models.SleeveEntry", null) + .WithMany() + .HasForeignKey("SleevesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SVSim.Database.Models.Viewer", null) + .WithMany() + .HasForeignKey("ViewersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SVSim.Database.Models.BattlePassSeasonEntry", b => + { + b.Navigation("Rewards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.BuildDeckSeriesEntry", b => + { + b.Navigation("Products"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ClassEntry", b => + { + b.Navigation("LeaderSkins"); + }); + + modelBuilder.Entity("SVSim.Database.Models.LeaderSkinShopSeriesEntry", b => + { + b.Navigation("Products"); + }); + + modelBuilder.Entity("SVSim.Database.Models.PuzzleGroupEntry", b => + { + b.Navigation("Puzzles"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SerialCodeEntry", b => + { + b.Navigation("Rewards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardSetEntry", b => + { + b.Navigation("Cards"); + }); + + modelBuilder.Entity("SVSim.Database.Models.SleeveShopSeriesEntry", b => + { + b.Navigation("Products"); + }); + + modelBuilder.Entity("SVSim.Database.Models.Viewer", b => + { + b.Navigation("Achievements"); + + b.Navigation("Decks"); + + b.Navigation("EventCounters"); + + b.Navigation("Missions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.cs b/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.cs new file mode 100644 index 00000000..cf9ba1aa --- /dev/null +++ b/SVSim.Database/Migrations/20260613172735_DropColosseumsTable.cs @@ -0,0 +1,50 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SVSim.Database.Migrations +{ + /// + public partial class DropColosseumsTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Colosseums"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Colosseums", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + CardPoolName = table.Column(type: "text", nullable: false), + ColosseumId = table.Column(type: "text", nullable: false), + ColosseumName = table.Column(type: "text", nullable: false), + DateCreated = table.Column(type: "timestamp with time zone", nullable: false), + DateUpdated = table.Column(type: "timestamp with time zone", nullable: true), + DeckFormat = table.Column(type: "text", nullable: false), + EndTime = table.Column(type: "timestamp with time zone", nullable: false), + IsAllCardEnabled = table.Column(type: "integer", nullable: false), + IsColosseumPeriod = table.Column(type: "boolean", nullable: false), + IsDisplayTips = table.Column(type: "text", nullable: false), + IsNormalTwoPick = table.Column(type: "text", nullable: false), + IsRoundPeriod = table.Column(type: "boolean", nullable: false), + IsSpecialMode = table.Column(type: "text", nullable: false), + NowRound = table.Column(type: "text", nullable: false), + SalesPeriodInfo = table.Column(type: "jsonb", nullable: false), + StartTime = table.Column(type: "timestamp with time zone", nullable: false), + TipsId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Colosseums", x => x.Id); + }); + } + } +} diff --git a/SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs b/SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs index 91baefe9..992a1109 100644 --- a/SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs +++ b/SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs @@ -1005,77 +1005,6 @@ namespace SVSim.Database.Migrations b.ToTable("ColosseumAvatarDecks"); }); - 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.ColosseumHofDeck", b => { b.Property("Id") diff --git a/SVSim.Database/Models/ColosseumConfig.cs b/SVSim.Database/Models/ColosseumConfig.cs deleted file mode 100644 index 1939bf61..00000000 --- a/SVSim.Database/Models/ColosseumConfig.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; -using SVSim.Database.Common; - -namespace SVSim.Database.Models; - -/// -/// Singleton row (Id=1) for the current Colosseum event from /mypage/index data.colosseum_info. -/// Time-bound — recapture per Colosseum cycle (every few weeks). -/// -public class ColosseumConfig : BaseEntity -{ - public string ColosseumId { get; set; } = string.Empty; - - public string ColosseumName { get; set; } = string.Empty; - - public string CardPoolName { get; set; } = string.Empty; - - public string DeckFormat { get; set; } = string.Empty; - - public DateTime StartTime { get; set; } - - public DateTime EndTime { get; set; } - - public string NowRound { get; set; } = string.Empty; - - public string IsDisplayTips { get; set; } = string.Empty; - - public string TipsId { get; set; } = string.Empty; - - public bool IsColosseumPeriod { get; set; } - - public bool IsRoundPeriod { get; set; } - - public string IsNormalTwoPick { get; set; } = string.Empty; - - public string IsSpecialMode { get; set; } = string.Empty; - - public int IsAllCardEnabled { get; set; } - - [Column(TypeName = "jsonb")] - public string SalesPeriodInfo { get; set; } = "{}"; -} diff --git a/SVSim.Database/Repositories/Globals/GlobalsRepository.cs b/SVSim.Database/Repositories/Globals/GlobalsRepository.cs index c3bb986e..38082e2b 100644 --- a/SVSim.Database/Repositories/Globals/GlobalsRepository.cs +++ b/SVSim.Database/Repositories/Globals/GlobalsRepository.cs @@ -72,9 +72,6 @@ public class GlobalsRepository : IGlobalsRepository .ThenBy(e => e.Id) .ToListAsync(); - public Task GetCurrentColosseum() => - _dbContext.Colosseums.AsNoTracking().FirstOrDefaultAsync(e => e.Id == 1); - public Task GetCurrentSealedSeason() => _dbContext.SealedSeasons.AsNoTracking().FirstOrDefaultAsync(e => e.Id == 1); diff --git a/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs b/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs index b9ec92e6..503fb56b 100644 --- a/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs +++ b/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs @@ -22,7 +22,6 @@ public interface IGlobalsRepository Task> GetDailyLoginBonus(); Task> GetBanners(); Task> GetActiveHomeDialogsAsync(DateTime nowUtc); - Task GetCurrentColosseum(); Task GetCurrentSealedSeason(); Task GetCurrentMasterPointPeriod(); Task> GetActiveSpecialDeckFormats(); diff --git a/SVSim.Database/SVSimDbContext.cs b/SVSim.Database/SVSimDbContext.cs index a4bacc7d..a6bb4472 100644 --- a/SVSim.Database/SVSimDbContext.cs +++ b/SVSim.Database/SVSimDbContext.cs @@ -63,7 +63,6 @@ public class SVSimDbContext : DbContext public DbSet DailyLoginBonuses => Set(); public DbSet Banners => Set(); public DbSet HomeDialogEntries => Set(); - public DbSet Colosseums => Set(); public DbSet SealedSeasons => Set(); public DbSet MasterPointRankingPeriods => Set(); public DbSet SpecialDeckFormats => Set(); diff --git a/SVSim.EmulatedEntrypoint/Controllers/ArenaColosseumController.cs b/SVSim.EmulatedEntrypoint/Controllers/ArenaColosseumController.cs index 44c9d59b..271b9a2f 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/ArenaColosseumController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/ArenaColosseumController.cs @@ -688,33 +688,8 @@ public class ArenaColosseumController : SVSimController // --- helpers --- - private static ColosseumLobbyInfo BuildColosseumInfo(ColosseumSeasonConfig season) - { - if (!season.IsColosseumPeriod) - { - return new ColosseumLobbyInfo { IsColosseumPeriod = false }; - } - - return new ColosseumLobbyInfo - { - IsColosseumPeriod = true, - DeckFormat = (int)season.DeckFormat, - IsNormalTwoPick = season.IsNormalTwoPick ? "1" : "0", - ColosseumName = season.ColosseumName, - IsRoundPeriod = true, - IsSpecialMode = season.IsSpecialMode, - CardPoolName = string.IsNullOrEmpty(season.CardPoolName) ? null : season.CardPoolName, - NowRound = 1, - StartTime = FormatTime(season.EventStartTime), - EndTime = FormatTime(season.EventEndTime), - IsAllCardEnabled = season.IsAllCardEnabled ? 1 : 0, - SalesPeriodInfo = new SVSim.EmulatedEntrypoint.Models.Dtos.ColosseumSalesPeriodInfo - { - SalesPeriodTime = FormatTime(season.SalesPeriodEnd), - }, - StrategyPickNum = season.StrategyPickNum > 0 ? season.StrategyPickNum : null, - }; - } + private static ColosseumLobbyInfo BuildColosseumInfo(ColosseumSeasonConfig season) => + ColosseumLobbyInfoBuilder.Build(season); /// Builds the colosseum_status block. When the viewer has no run, every /// property is null and global WhenWritingNull renders {} — the client diff --git a/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs b/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs index 2f0d3f16..14bce05b 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs @@ -9,6 +9,7 @@ using SVSim.Database.Services; using SVSim.EmulatedEntrypoint.Constants; using SVSim.EmulatedEntrypoint.Infrastructure; using SVSim.EmulatedEntrypoint.Models.Dtos; +using SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; using SVSim.EmulatedEntrypoint.Models.Dtos.Common; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.MyPage; @@ -61,7 +62,7 @@ public class MyPageController : SVSimController // Hydrate all the globals slices in parallel-ish — they're independent reads. var rotation = _config.Get(); - var colosseum = await _globalsRepository.GetCurrentColosseum(); + var colosseumSeason = _config.Get(); var sealedSeason = await _globalsRepository.GetCurrentSealedSeason(); var masterPointPeriod = await _globalsRepository.GetCurrentMasterPointPeriod(); var bannerEntries = await _globalsRepository.GetBanners(); @@ -93,7 +94,7 @@ public class MyPageController : SVSimController ArenaInfo = await BuildArenaInfosAsync(viewer.Id), IsArenaChallengePeriod = false, // TODO(mypage-stub): globals/ArenaSeason flag IsAvailableColosseumFreeEntry = false, // TODO(mypage-stub): viewer + globals free-entry quota - ColosseumInfo = BuildColosseumInfo(colosseum), + ColosseumInfo = ColosseumLobbyInfoBuilder.Build(colosseumSeason), SealedInfo = BuildSealedInfo(sealedSeason), Banner = bannerEntries.Select(BuildBannerInfo).ToList(), RoomTypeInSession = new RoomTypeInSession @@ -237,37 +238,6 @@ public class MyPageController : SVSimController }; } - private ColosseumInfo BuildColosseumInfo(ColosseumConfig? row) - { - if (row is null) return new ColosseumInfo(); - - ColosseumSalesPeriodInfo sales = new(); - if (!string.IsNullOrEmpty(row.SalesPeriodInfo) && row.SalesPeriodInfo != "{}") - { - sales = JsonSerializer.Deserialize(row.SalesPeriodInfo, JsonbReadOptions.Instance) - ?? new ColosseumSalesPeriodInfo(); - } - - return new ColosseumInfo - { - ColosseumId = row.ColosseumId, - IsDisplayTips = row.IsDisplayTips, - TipsId = row.TipsId, - CardPoolName = row.CardPoolName, - IsColosseumPeriod = row.IsColosseumPeriod, - IsRoundPeriod = row.IsRoundPeriod, - DeckFormat = row.DeckFormat, - IsNormalTwoPick = row.IsNormalTwoPick, - IsSpecialMode = row.IsSpecialMode, - IsAllCardEnabled = row.IsAllCardEnabled, - StartTime = row.StartTime.ToString(WireDateFormat, CultureInfo.InvariantCulture), - ColosseumName = row.ColosseumName, - NowRound = row.NowRound, - EndTime = row.EndTime.ToString(WireDateFormat, CultureInfo.InvariantCulture), - SalesPeriodInfo = sales, - }; - } - private SealedInfo BuildSealedInfo(SealedConfig? row) { if (row is null) return new SealedInfo(); diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumInfo.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumInfo.cs index 786192c8..dbae7533 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumInfo.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumInfo.cs @@ -1,6 +1,5 @@ using System.Text.Json.Serialization; using MessagePack; -using SVSim.EmulatedEntrypoint.Models.Dtos; namespace SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; @@ -10,10 +9,11 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; /// is false, the client skips parsing every other /// field — server still emits this minimal payload so the lobby renders cleanly. /// -/// Distinct from (the -/// captured prod /mypage/index shape — stringly-typed and read-only). This is the -/// per-endpoint Colosseum-family shape. /event_info uses yet a third shape — -/// . +/// Also drives /mypage/index data.colosseum_info — the home-screen tab gating and +/// the per-endpoint lobby reads share one source of truth (the +/// POCO) projected via +/// . /event_info uses a different, +/// event-level shape — . /// /// [MessagePackObject] diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumLobbyInfoBuilder.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumLobbyInfoBuilder.cs new file mode 100644 index 00000000..ead36a8c --- /dev/null +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumLobbyInfoBuilder.cs @@ -0,0 +1,48 @@ +using System.Globalization; +using SVSim.Database.Models.Config; + +namespace SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; + +/// +/// Single source of truth for projecting onto the wire +/// block. Used by both /arena_colosseum/{top,get_fee_info} +/// AND /mypage/index data.colosseum_info — the home-screen tab and the lobby reads +/// must agree on the season state, so they go through one builder. When +/// IsColosseumPeriod = false the minimal "no event" payload is emitted; the client +/// gates every other field on that flag (Wizard/ColosseumEntryInfoTask.cs:100). +/// +public static class ColosseumLobbyInfoBuilder +{ + private const string WireDateFormat = "yyyy-MM-dd HH:mm:ss"; + + public static ColosseumLobbyInfo Build(ColosseumSeasonConfig season) + { + if (!season.IsColosseumPeriod) + { + return new ColosseumLobbyInfo { IsColosseumPeriod = false }; + } + + return new ColosseumLobbyInfo + { + IsColosseumPeriod = true, + DeckFormat = (int)season.DeckFormat, + IsNormalTwoPick = season.IsNormalTwoPick ? "1" : "0", + ColosseumName = season.ColosseumName, + IsRoundPeriod = true, + IsSpecialMode = season.IsSpecialMode, + CardPoolName = string.IsNullOrEmpty(season.CardPoolName) ? null : season.CardPoolName, + NowRound = 1, + StartTime = FormatTime(season.EventStartTime), + EndTime = FormatTime(season.EventEndTime), + IsAllCardEnabled = season.IsAllCardEnabled ? 1 : 0, + SalesPeriodInfo = new ColosseumSalesPeriodInfo + { + SalesPeriodTime = FormatTime(season.SalesPeriodEnd), + }, + StrategyPickNum = season.StrategyPickNum > 0 ? season.StrategyPickNum : null, + }; + } + + private static string FormatTime(DateTime t) => + t == default ? "" : t.ToString(WireDateFormat, CultureInfo.InvariantCulture); +} diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumSalesPeriodInfo.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumSalesPeriodInfo.cs new file mode 100644 index 00000000..f7a117d4 --- /dev/null +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/ArenaColosseum/ColosseumSalesPeriodInfo.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; +using MessagePack; + +namespace SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; + +/// +/// Nested under colosseum_info.sales_period_info. Captured prod shape — single +/// sales_period_time field carrying the wall-clock end of the cup's sales window. +/// Format "yyyy-MM-dd HH:mm:ss" (PHP convention, not ISO). +/// +[MessagePackObject] +public sealed class ColosseumSalesPeriodInfo +{ + [JsonPropertyName("sales_period_time")] [Key("sales_period_time")] + public string SalesPeriodTime { get; set; } = string.Empty; +} diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumInfo.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumInfo.cs deleted file mode 100644 index f9dd5980..00000000 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumInfo.cs +++ /dev/null @@ -1,97 +0,0 @@ -using MessagePack; -using System.Text.Json.Serialization; - -namespace SVSim.EmulatedEntrypoint.Models.Dtos; - -/// -/// colosseum_info on /mypage/index, consumed by ColosseumEntryInfoTask.SetColosseumInfo -/// (Wizard/ColosseumEntryInfoTask.cs:99). The outer object is read unconditionally, and -/// is_colosseum_period gates everything else. When a cup IS active, the client reads -/// many more sub-fields inside the gate (deck_format, now_round, start_time, end_time, -/// sales_period_info, etc.) — we now mirror the full prod shape so the gate-true branch -/// works once we have colosseum data seeded. -/// -/// Prod-captured shape (15 fields): -/// -/// {"colosseum_id":"165","is_display_tips":"0","tips_id":"0", -/// "card_pool_name":"Take Two (Dragonblade–Rivenbrandt)", -/// "is_colosseum_period":true,"is_round_period":true,"deck_format":"3", -/// "is_normal_two_pick":"1","is_special_mode":"10","is_all_card_enabled":0, -/// "start_time":"2026-05-21 06:00:00","colosseum_name":"Rivenbrandt Take Two Cup", -/// "now_round":"1","end_time":"2026-05-25 19:59:59", -/// "sales_period_info":{"sales_period_time":"2026-05-25 19:59:59"}} -/// -/// -[MessagePackObject] -public class ColosseumInfo -{ - [JsonPropertyName("colosseum_id")] - [Key("colosseum_id")] - public string ColosseumId { get; set; } = string.Empty; - - /// Wire is "0"/"1" string. Client compares with == "1" (GetValueOrDefault-guarded). - [JsonPropertyName("is_display_tips")] - [Key("is_display_tips")] - public string IsDisplayTips { get; set; } = "0"; - - [JsonPropertyName("tips_id")] - [Key("tips_id")] - public string TipsId { get; set; } = "0"; - - [JsonPropertyName("card_pool_name")] - [Key("card_pool_name")] - public string CardPoolName { get; set; } = string.Empty; - - [JsonPropertyName("is_colosseum_period")] - [Key("is_colosseum_period")] - public bool IsColosseumPeriod { get; set; } - - [JsonPropertyName("is_round_period")] - [Key("is_round_period")] - public bool IsRoundPeriod { get; set; } - - /// - /// Wire is a stringified int in prod (e.g. "3"). DB stores as string. Client calls - /// jsonData["deck_format"].ToInt() inside the IsColosseumPeriod gate. - /// - [JsonPropertyName("deck_format")] - [Key("deck_format")] - public string DeckFormat { get; set; } = "0"; - - /// Wire is "1"/"0" string. Client compares with == "1". - [JsonPropertyName("is_normal_two_pick")] - [Key("is_normal_two_pick")] - public string IsNormalTwoPick { get; set; } = "0"; - - /// Used as ColorCodeId (stringified int). - [JsonPropertyName("is_special_mode")] - [Key("is_special_mode")] - public string IsSpecialMode { get; set; } = "0"; - - [JsonPropertyName("is_all_card_enabled")] - [Key("is_all_card_enabled")] - public int IsAllCardEnabled { get; set; } - - /// "yyyy-MM-dd HH:mm:ss" wire format. - [JsonPropertyName("start_time")] - [Key("start_time")] - public string StartTime { get; set; } = string.Empty; - - [JsonPropertyName("colosseum_name")] - [Key("colosseum_name")] - public string ColosseumName { get; set; } = string.Empty; - - /// Round number as string (e.g. "1"). Client casts to int. - [JsonPropertyName("now_round")] - [Key("now_round")] - public string NowRound { get; set; } = "0"; - - /// "yyyy-MM-dd HH:mm:ss" wire format. - [JsonPropertyName("end_time")] - [Key("end_time")] - public string EndTime { get; set; } = string.Empty; - - [JsonPropertyName("sales_period_info")] - [Key("sales_period_info")] - public ColosseumSalesPeriodInfo SalesPeriodInfo { get; set; } = new(); -} diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumSalesPeriodInfo.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumSalesPeriodInfo.cs deleted file mode 100644 index ca011429..00000000 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/ColosseumSalesPeriodInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MessagePack; -using System.Text.Json.Serialization; - -namespace SVSim.EmulatedEntrypoint.Models.Dtos; - -/// -/// Nested under /mypage/index data.colosseum_info.sales_period_info. Carries the wall-clock end of -/// the current cup's sales window. Captured from prod: -/// "sales_period_info": { "sales_period_time": "2026-05-25 19:59:59" }. -/// -[MessagePackObject] -public class ColosseumSalesPeriodInfo -{ - /// Wire format is "yyyy-MM-dd HH:mm:ss" (prod's PHP convention, not ISO). - [JsonPropertyName("sales_period_time")] - [Key("sales_period_time")] - public string SalesPeriodTime { get; set; } = string.Empty; -} diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs index 3e3613fb..f3aff694 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs @@ -1,5 +1,6 @@ using MessagePack; using SVSim.Database.Enums; +using SVSim.EmulatedEntrypoint.Models.Dtos.ArenaColosseum; using System.Text.Json.Serialization; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses; @@ -134,11 +135,13 @@ public class MyPageIndexResponse /// /// Required — ColosseumEntryInfoTask.SetColosseumInfo indexes this key /// directly (Wizard/ColosseumEntryInfoTask.cs:102) and reads - /// is_colosseum_period without a guard. + /// is_colosseum_period without a guard. Built by + /// from ColosseumSeasonConfig — + /// shared with /arena_colosseum/{top,get_fee_info}. /// [JsonPropertyName("colosseum_info")] [Key("colosseum_info")] - public ColosseumInfo ColosseumInfo { get; set; } = new(); + public ColosseumLobbyInfo ColosseumInfo { get; set; } = new(); // ── Convention / offline event ───────────────────────────────────────── diff --git a/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs b/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs index 728362e7..84f37674 100644 --- a/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs +++ b/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs @@ -25,22 +25,6 @@ public class MyPageGlobalsImporterTests Assert.That(count, Is.GreaterThan(0), "seed must contain banners"); } - [Test] - public async Task Imports_colosseum_singleton() - { - using var factory = new SVSimTestFactory(); - using var scope = factory.Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - - var importer = new MyPageGlobalsImporter(); - await importer.ImportColosseumAsync(db, SeedDir); - - var row = await db.Colosseums.FirstOrDefaultAsync(e => e.Id == 1); - Assert.That(row, Is.Not.Null); - Assert.That(row!.Id, Is.EqualTo(1)); - Assert.That(row.ColosseumId, Is.Not.Empty); - } - [Test] public async Task Imports_sealed_singleton() { @@ -145,14 +129,10 @@ public class MyPageGlobalsImporterTests var db = scope.ServiceProvider.GetRequiredService(); var importer = new MyPageGlobalsImporter(); - await importer.ImportColosseumAsync(db, SeedDir); await importer.ImportSealedAsync(db, SeedDir); - await importer.ImportColosseumAsync(db, SeedDir); await importer.ImportSealedAsync(db, SeedDir); - Assert.That(await db.Colosseums.CountAsync(), Is.EqualTo(1), - "Colosseum singleton must remain a single row on re-run"); Assert.That(await db.SealedSeasons.CountAsync(), Is.EqualTo(1), "SealedSeason singleton must remain a single row on re-run"); } diff --git a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs index ee76887f..c7efe03a 100644 --- a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs +++ b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs @@ -286,7 +286,6 @@ internal class SVSimTestFactory : WebApplicationFactory var mypage = new MyPageGlobalsImporter(); await mypage.ImportBannersAsync(ctx, seedDir); - await mypage.ImportColosseumAsync(ctx, seedDir); await mypage.ImportSealedAsync(ctx, seedDir); await mypage.ImportMasterPointRankingPeriodAsync(ctx, seedDir); await mypage.ImportSpecialDeckFormatsAsync(ctx, seedDir); diff --git a/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs b/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs index 9cfb4b4a..388e97d0 100644 --- a/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs +++ b/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs @@ -151,17 +151,6 @@ public class GlobalsRepositoryTests Assert.That(banners[0].Click, Is.EqualTo("account_transition_with_two")); } - [Test] - public async Task GetCurrentColosseum_returns_singleton_with_name() - { - var (factory, repo) = await SetupAsync(); - using var _ = factory; - var col = await repo.GetCurrentColosseum(); - Assert.That(col, Is.Not.Null); - Assert.That(col!.ColosseumName, Is.EqualTo("Rivenbrandt Take Two Cup")); - Assert.That(col.ColosseumId, Is.EqualTo("165")); - } - [Test] public async Task GetCurrentSealedSeason_returns_singleton_with_pack_info() {