diff --git a/SVSim.Database/Repositories/Card/ICardInventoryRepository.cs b/SVSim.Database/Repositories/Card/ICardInventoryRepository.cs index 4dc66f2..90bb475 100644 --- a/SVSim.Database/Repositories/Card/ICardInventoryRepository.cs +++ b/SVSim.Database/Repositories/Card/ICardInventoryRepository.cs @@ -18,6 +18,14 @@ public interface ICardInventoryRepository /// when validation fails. On error nothing is written. /// Task DestructCards(long viewerId, IReadOnlyDictionary destructCounts); + + /// + /// Validate-then-mutate craft of cards from RedEther. Atomic in a transaction; on validation + /// failure nothing is written. Routes Card grants through + /// so the CardCosmeticReward cascade fires for first-time owners. + /// + /// cardId → num_to_create. Empty dict is rejected by the caller. + Task CreateCards(long viewerId, IReadOnlyDictionary createCounts); } /// @@ -42,3 +50,28 @@ public enum DestructError CardProtected, InsufficientCards, } + +public sealed record CreateOutcome(CreateResult? Result, CreateError? Error) +{ + public bool IsSuccess => Result is not null; + + public static CreateOutcome Ok(CreateResult r) => new(r, null); + public static CreateOutcome Fail(CreateError e) => new(null, e); +} + +/// +/// Outcome of a successful create. is the flattened +/// list returned by +/// — one Card entry per crafted cardId plus any cosmetic-cascade entries. +/// +public sealed record CreateResult( + ulong NewRedEtherTotal, + IReadOnlyList Grants); + +public enum CreateError +{ + UnknownCard, + NotCraftable, + WouldExceedMaxCopies, + InsufficientVials, +}