using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable namespace Infrastructure.Migrations.AppDb { /// public partial class AddStoreSchema : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( name: "DonationAmount", table: "WithdrawalRequest", type: "int", nullable: false, defaultValue: 0, comment: "후원 수익(Donation) 잔액에서 차감되는 금액"); migrationBuilder.AddColumn( name: "StoreRevenueAmount", table: "WithdrawalRequest", type: "int", nullable: false, defaultValue: 0, comment: "상품 판매 수익(StoreRevenue) 잔액에서 차감되는 금액"); migrationBuilder.CreateTable( name: "Game", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false, comment: "게임 이름"), Publisher = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false, comment: "게임사/퍼블리셔"), Thumbnail = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), Description = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), CommissionRate = table.Column(type: "decimal(5,2)", precision: 5, scale: 2, nullable: false, comment: "게임사 수익률(%)"), ChannelCommissionRate = table.Column(type: "decimal(5,2)", precision: 5, scale: 2, nullable: false, comment: "후원 채널 보상률(%)"), IsActive = table.Column(type: "bit", nullable: false), Order = table.Column(type: "int", nullable: false), CreatedAt = table.Column(type: "datetime2", nullable: false), UpdatedAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_Game", x => x.ID); }, comment: "상점 제휴 게임"); migrationBuilder.CreateTable( name: "MemberAddress", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), MemberID = table.Column(type: "int", nullable: false), IsDefault = table.Column(type: "bit", nullable: false), RecipientName_Encrypted = table.Column(type: "nvarchar(max)", nullable: false, comment: "수령인명 (암호화)"), RecipientName_Hash = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false, comment: "수령인명 SHA-256 hex (검색용)"), Phone_Encrypted = table.Column(type: "nvarchar(max)", nullable: false, comment: "연락처 (암호화)"), ZipCode = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: false), Address1_Encrypted = table.Column(type: "nvarchar(max)", nullable: false, comment: "기본 주소 (암호화)"), Address2_Encrypted = table.Column(type: "nvarchar(max)", nullable: false, comment: "상세 주소 (암호화)"), KeyVersion = table.Column(type: "int", nullable: false, comment: "암호화 키 버전"), CreatedAt = table.Column(type: "datetime2", nullable: false), UpdatedAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_MemberAddress", x => x.ID); table.ForeignKey( name: "FK_MemberAddress_Member_MemberID", column: x => x.MemberID, principalTable: "Member", principalColumn: "ID", onDelete: ReferentialAction.Cascade); }, comment: "회원 배송 주소 (AES-GCM 암호화)"); migrationBuilder.CreateTable( name: "Order", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), OrderNumber = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: false, comment: "주문 번호 (UNIQUE)"), MemberID = table.Column(type: "int", nullable: false), ChannelID = table.Column(type: "int", nullable: true, comment: "후원 채널 (선택)"), TotalAmount = table.Column(type: "int", nullable: false, comment: "총 결제 금액"), PlatformFeeAmount = table.Column(type: "int", nullable: false, comment: "dpot 몫"), GameRevenueAmount = table.Column(type: "int", nullable: false, comment: "게임사 정산 큐 적재 금액"), ChannelRewardAmount = table.Column(type: "int", nullable: false, comment: "채널주 StoreRevenue 입금 금액"), Status = table.Column(type: "int", nullable: false, comment: "주문 상태"), CancelReason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), RefundReason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), CreatedAt = table.Column(type: "datetime2", nullable: false), PaidAt = table.Column(type: "datetime2", nullable: true), RowVersion = table.Column(type: "rowversion", rowVersion: true, nullable: false) }, constraints: table => { table.PrimaryKey("PK_Order", x => x.ID); table.ForeignKey( name: "FK_Order_Channel_ChannelID", column: x => x.ChannelID, principalTable: "Channel", principalColumn: "ID"); table.ForeignKey( name: "FK_Order_Member_MemberID", column: x => x.MemberID, principalTable: "Member", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }, comment: "상점 주문 헤더"); migrationBuilder.CreateTable( name: "GameSettlement", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), GameID = table.Column(type: "int", nullable: false), Year = table.Column(type: "int", nullable: false), Month = table.Column(type: "int", nullable: false), TotalRevenueAmount = table.Column(type: "int", nullable: false), OrderCount = table.Column(type: "int", nullable: false), Status = table.Column(type: "int", nullable: false, comment: "정산 상태 (1=Pending, 2=Settled)"), CreatedAt = table.Column(type: "datetime2", nullable: false), SettledAt = table.Column(type: "datetime2", nullable: true), SettledByAdminID = table.Column(type: "int", nullable: true), AdminMemo = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true) }, constraints: table => { table.PrimaryKey("PK_GameSettlement", x => x.ID); table.ForeignKey( name: "FK_GameSettlement_Game_GameID", column: x => x.GameID, principalTable: "Game", principalColumn: "ID", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_GameSettlement_Member_SettledByAdminID", column: x => x.SettledByAdminID, principalTable: "Member", principalColumn: "ID"); }, comment: "게임사 월별 정산 큐"); migrationBuilder.CreateTable( name: "Product", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), GameID = table.Column(type: "int", nullable: false, comment: "게임 ID (필수)"), Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false, comment: "상품명"), Description = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), Thumbnail = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), Type = table.Column(type: "int", nullable: false, comment: "상품 유형 (1=Physical, 2=Digital)"), Price = table.Column(type: "int", nullable: false, comment: "판매가 (KRW)"), Stock = table.Column(type: "int", nullable: false, comment: "재고 (-1=무제한)"), IsActive = table.Column(type: "bit", nullable: false), Order = table.Column(type: "int", nullable: false), SaleStartAt = table.Column(type: "datetime2", nullable: true), SaleEndAt = table.Column(type: "datetime2", nullable: true), CreatedAt = table.Column(type: "datetime2", nullable: false), UpdatedAt = table.Column(type: "datetime2", nullable: true), RowVersion = table.Column(type: "rowversion", rowVersion: true, nullable: false) }, constraints: table => { table.PrimaryKey("PK_Product", x => x.ID); table.ForeignKey( name: "FK_Product_Game_GameID", column: x => x.GameID, principalTable: "Game", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }, comment: "상점 상품"); migrationBuilder.CreateTable( name: "OrderRefund", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), OrderID = table.Column(type: "int", nullable: false), Type = table.Column(type: "int", nullable: false, comment: "유형 (1=Cancel, 2=Return, 3=Exchange, 4=Refund)"), Status = table.Column(type: "int", nullable: false, comment: "상태 (1=Requested, 2=Approved, 3=Rejected, 4=Completed)"), Amount = table.Column(type: "int", nullable: false), Reason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), AdminMemo = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), AdminID = table.Column(type: "int", nullable: true), RequestedAt = table.Column(type: "datetime2", nullable: false), ResolvedAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_OrderRefund", x => x.ID); table.ForeignKey( name: "FK_OrderRefund_Member_AdminID", column: x => x.AdminID, principalTable: "Member", principalColumn: "ID"); table.ForeignKey( name: "FK_OrderRefund_Order_OrderID", column: x => x.OrderID, principalTable: "Order", principalColumn: "ID", onDelete: ReferentialAction.Cascade); }, comment: "통합 환불 이력 (취소/반품/교환/환불)"); migrationBuilder.CreateTable( name: "Shipment", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), OrderID = table.Column(type: "int", nullable: false), RecipientName_Encrypted = table.Column(type: "nvarchar(max)", nullable: false), Phone_Encrypted = table.Column(type: "nvarchar(max)", nullable: false), ZipCode = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: false), Address1_Encrypted = table.Column(type: "nvarchar(max)", nullable: false), Address2_Encrypted = table.Column(type: "nvarchar(max)", nullable: false), KeyVersion = table.Column(type: "int", nullable: false), Status = table.Column(type: "int", nullable: false), Carrier = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), TrackingNumber = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), CreatedAt = table.Column(type: "datetime2", nullable: false), ShippedAt = table.Column(type: "datetime2", nullable: true), DeliveredAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_Shipment", x => x.ID); table.ForeignKey( name: "FK_Shipment_Order_OrderID", column: x => x.OrderID, principalTable: "Order", principalColumn: "ID", onDelete: ReferentialAction.Cascade); }, comment: "배송 (주문 시점 주소 스냅샷, 암호화)"); migrationBuilder.CreateTable( name: "Coupon", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), ProductID = table.Column(type: "int", nullable: false), GameID = table.Column(type: "int", nullable: false, comment: "게임 ID (필수)"), Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), ExpiresAt = table.Column(type: "datetime2", nullable: true), UsagePolicy = table.Column(type: "int", nullable: false), GeneratedCount = table.Column(type: "int", nullable: false), UsedCount = table.Column(type: "int", nullable: false), LowStockThreshold = table.Column(type: "int", nullable: false, defaultValue: 10), CreatedAt = table.Column(type: "datetime2", nullable: false), UpdatedAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_Coupon", x => x.ID); table.ForeignKey( name: "FK_Coupon_Game_GameID", column: x => x.GameID, principalTable: "Game", principalColumn: "ID", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_Coupon_Product_ProductID", column: x => x.ProductID, principalTable: "Product", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }, comment: "쿠폰 메타 (코드 풀의 상위)"); migrationBuilder.CreateTable( name: "CouponCode", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), CouponID = table.Column(type: "int", nullable: false), Code = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false, comment: "코드 평문 (사용자 표시용)"), CodeHash = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false, comment: "SHA-256 hex (UNIQUE, 조회용)"), Status = table.Column(type: "int", nullable: false, comment: "상태 (1=Available, 2=Reserved, 3=Issued, 4=Used)"), IssuedToMemberID = table.Column(type: "int", nullable: true), IssuedAt = table.Column(type: "datetime2", nullable: true), UsedAt = table.Column(type: "datetime2", nullable: true), CreatedAt = table.Column(type: "datetime2", nullable: false), RowVersion = table.Column(type: "rowversion", rowVersion: true, nullable: false) }, constraints: table => { table.PrimaryKey("PK_CouponCode", x => x.ID); table.ForeignKey( name: "FK_CouponCode_Coupon_CouponID", column: x => x.CouponID, principalTable: "Coupon", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_CouponCode_Member_IssuedToMemberID", column: x => x.IssuedToMemberID, principalTable: "Member", principalColumn: "ID"); }, comment: "쿠폰 코드 풀 (Code 평문 + CodeHash SHA-256 hex)"); migrationBuilder.CreateTable( name: "OrderItem", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), OrderID = table.Column(type: "int", nullable: false), ProductID = table.Column(type: "int", nullable: false), Quantity = table.Column(type: "int", nullable: false), UnitPrice = table.Column(type: "int", nullable: false, comment: "주문 시점 상품 단가 스냅샷"), IssuedCouponCodeID = table.Column(type: "int", nullable: true, comment: "Digital 상품 발급 쿠폰 코드"), CreatedAt = table.Column(type: "datetime2", nullable: false) }, constraints: table => { table.PrimaryKey("PK_OrderItem", x => x.ID); table.ForeignKey( name: "FK_OrderItem_CouponCode_IssuedCouponCodeID", column: x => x.IssuedCouponCodeID, principalTable: "CouponCode", principalColumn: "ID"); table.ForeignKey( name: "FK_OrderItem_Order_OrderID", column: x => x.OrderID, principalTable: "Order", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_OrderItem_Product_ProductID", column: x => x.ProductID, principalTable: "Product", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }, comment: "주문 라인"); migrationBuilder.CreateTable( name: "MemberInventory", columns: table => new { ID = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), MemberID = table.Column(type: "int", nullable: false), OrderItemID = table.Column(type: "int", nullable: false), CouponCodeID = table.Column(type: "int", nullable: false), AcquiredAt = table.Column(type: "datetime2", nullable: false), UsedAt = table.Column(type: "datetime2", nullable: true), ExpiresAt = table.Column(type: "datetime2", nullable: true) }, constraints: table => { table.PrimaryKey("PK_MemberInventory", x => x.ID); table.ForeignKey( name: "FK_MemberInventory_CouponCode_CouponCodeID", column: x => x.CouponCodeID, principalTable: "CouponCode", principalColumn: "ID", onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_MemberInventory_Member_MemberID", column: x => x.MemberID, principalTable: "Member", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_MemberInventory_OrderItem_OrderItemID", column: x => x.OrderItemID, principalTable: "OrderItem", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }, comment: "회원 보관함 (Digital 상품)"); migrationBuilder.CreateIndex( name: "IX_Coupon_GameID", table: "Coupon", column: "GameID"); migrationBuilder.CreateIndex( name: "IX_Coupon_ProductID", table: "Coupon", column: "ProductID"); migrationBuilder.CreateIndex( name: "IX_CouponCode_CodeHash", table: "CouponCode", column: "CodeHash", unique: true); migrationBuilder.CreateIndex( name: "IX_CouponCode_CouponID_Status", table: "CouponCode", columns: new[] { "CouponID", "Status" }); migrationBuilder.CreateIndex( name: "IX_CouponCode_IssuedToMemberID", table: "CouponCode", column: "IssuedToMemberID"); migrationBuilder.CreateIndex( name: "IX_Game_IsActive_Order", table: "Game", columns: new[] { "IsActive", "Order" }); migrationBuilder.CreateIndex( name: "IX_Game_Name", table: "Game", column: "Name", unique: true); migrationBuilder.CreateIndex( name: "IX_GameSettlement_GameID_Year_Month", table: "GameSettlement", columns: new[] { "GameID", "Year", "Month" }, unique: true); migrationBuilder.CreateIndex( name: "IX_GameSettlement_SettledByAdminID", table: "GameSettlement", column: "SettledByAdminID"); migrationBuilder.CreateIndex( name: "IX_GameSettlement_Year_Month_Status", table: "GameSettlement", columns: new[] { "Year", "Month", "Status" }); migrationBuilder.CreateIndex( name: "IX_MemberAddress_MemberID_IsDefault", table: "MemberAddress", columns: new[] { "MemberID", "IsDefault" }); migrationBuilder.CreateIndex( name: "IX_MemberAddress_RecipientName_Hash", table: "MemberAddress", column: "RecipientName_Hash"); migrationBuilder.CreateIndex( name: "IX_MemberInventory_CouponCodeID", table: "MemberInventory", column: "CouponCodeID", unique: true); migrationBuilder.CreateIndex( name: "IX_MemberInventory_MemberID_UsedAt", table: "MemberInventory", columns: new[] { "MemberID", "UsedAt" }); migrationBuilder.CreateIndex( name: "IX_MemberInventory_OrderItemID", table: "MemberInventory", column: "OrderItemID"); migrationBuilder.CreateIndex( name: "IX_Order_ChannelID", table: "Order", column: "ChannelID"); migrationBuilder.CreateIndex( name: "IX_Order_MemberID_Status_CreatedAt", table: "Order", columns: new[] { "MemberID", "Status", "CreatedAt" }); migrationBuilder.CreateIndex( name: "IX_Order_OrderNumber", table: "Order", column: "OrderNumber", unique: true); migrationBuilder.CreateIndex( name: "IX_Order_Status_CreatedAt", table: "Order", columns: new[] { "Status", "CreatedAt" }); migrationBuilder.CreateIndex( name: "IX_OrderItem_IssuedCouponCodeID", table: "OrderItem", column: "IssuedCouponCodeID"); migrationBuilder.CreateIndex( name: "IX_OrderItem_OrderID", table: "OrderItem", column: "OrderID"); migrationBuilder.CreateIndex( name: "IX_OrderItem_ProductID", table: "OrderItem", column: "ProductID"); migrationBuilder.CreateIndex( name: "IX_OrderRefund_AdminID", table: "OrderRefund", column: "AdminID"); migrationBuilder.CreateIndex( name: "IX_OrderRefund_OrderID_Status", table: "OrderRefund", columns: new[] { "OrderID", "Status" }); migrationBuilder.CreateIndex( name: "IX_OrderRefund_Status", table: "OrderRefund", column: "Status"); migrationBuilder.CreateIndex( name: "IX_Product_GameID_IsActive_Order", table: "Product", columns: new[] { "GameID", "IsActive", "Order" }); migrationBuilder.CreateIndex( name: "IX_Product_IsActive_Type", table: "Product", columns: new[] { "IsActive", "Type" }); migrationBuilder.CreateIndex( name: "IX_Shipment_OrderID", table: "Shipment", column: "OrderID", unique: true); migrationBuilder.CreateIndex( name: "IX_Shipment_Status", table: "Shipment", column: "Status"); migrationBuilder.CreateIndex( name: "IX_Shipment_TrackingNumber", table: "Shipment", column: "TrackingNumber"); // 기존 WithdrawalRequest row 백필: 신규 분개 컬럼(DonationAmount/StoreRevenueAmount)이 0 으로 채워졌으나, // 기존 row 는 모두 후원 잔액(Donation) 단일 출금이었으므로 DonationAmount = RequestedAmount 로 백필. migrationBuilder.Sql("UPDATE WithdrawalRequest SET DonationAmount = RequestedAmount WHERE DonationAmount = 0 AND RequestedAmount > 0;"); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "GameSettlement"); migrationBuilder.DropTable( name: "MemberAddress"); migrationBuilder.DropTable( name: "MemberInventory"); migrationBuilder.DropTable( name: "OrderRefund"); migrationBuilder.DropTable( name: "Shipment"); migrationBuilder.DropTable( name: "OrderItem"); migrationBuilder.DropTable( name: "CouponCode"); migrationBuilder.DropTable( name: "Order"); migrationBuilder.DropTable( name: "Coupon"); migrationBuilder.DropTable( name: "Product"); migrationBuilder.DropTable( name: "Game"); migrationBuilder.DropColumn( name: "DonationAmount", table: "WithdrawalRequest"); migrationBuilder.DropColumn( name: "StoreRevenueAmount", table: "WithdrawalRequest"); } } }