diff --git a/SVSim.Database/Models/ViewerPresent.cs b/SVSim.Database/Models/ViewerPresent.cs new file mode 100644 index 0000000..6527577 --- /dev/null +++ b/SVSim.Database/Models/ViewerPresent.cs @@ -0,0 +1,57 @@ +using System.ComponentModel.DataAnnotations; + +namespace SVSim.Database.Models; + +/// +/// One row per gift in a viewer's inbox. Replaces the tutorial-only +/// ViewerClaimedTutorialGift receipts model with a unified status-enum row that +/// serves both /gift/top + /gift/receive_gift (prod) and /tutorial/gift_top + +/// /tutorial/gift_receive (tutorial alias). +/// +public class ViewerPresent +{ + public long Id { get; set; } + + public long ViewerId { get; set; } + public Viewer Viewer { get; set; } = null!; + + /// Wire id ("71409625" in the prod capture). String to match the wire. + public string PresentId { get; set; } = string.Empty; + + public PresentStatus Status { get; set; } + + /// UserGoodsType-compatible int. Wire is stringified — see PresentMapper. + public int RewardType { get; set; } + public long RewardDetailId { get; set; } + public long RewardCount { get; set; } + public int ConditionNumber { get; set; } + public int PresentLimitType { get; set; } + public long RewardLimitTime { get; set; } + public int? ItemType { get; set; } + public string Message { get; set; } = string.Empty; + + public DateTime CreatedAt { get; set; } + public DateTime? ClaimedAt { get; set; } + + /// + /// Free-form provenance tag for future producers ("tutorial", "challenge_win", + /// "payment_refund:<txid>", "event:<id>"). Nothing in the receive handler reads + /// this today — the tutorial-step advance is route-gated, not Source-gated. + /// + public string? Source { get; set; } + + /// + /// EF Core optimistic concurrency for the claim path. Two concurrent claims of the + /// same PresentId: first wins, second's CommitAsync throws DbUpdateConcurrencyException. + /// + [Timestamp] + public byte[] RowVersion { get; set; } = Array.Empty(); +} + +public enum PresentStatus : byte +{ + Unclaimed = 0, + Claimed = 1, + Deleted = 2, + Expired = 3, +}