/ GUNRPG.Application / Operators / IOperatorEventStore.cs
IOperatorEventStore.cs
 1  using GUNRPG.Core.Operators;
 2  
 3  namespace GUNRPG.Application.Operators;
 4  
 5  /// <summary>
 6  /// Abstraction for storing and retrieving operator events.
 7  /// Events are append-only and must maintain hash chain integrity.
 8  /// Implementations must ensure atomic writes and proper ordering.
 9  /// </summary>
10  public interface IOperatorEventStore
11  {
12      /// <summary>
13      /// Appends a new event to an operator's event stream.
14      /// Events must be appended in sequence order with no gaps.
15      /// </summary>
16      /// <param name="evt">The event to append</param>
17      /// <exception cref="InvalidOperationException">If sequence number is invalid or hash chain is broken</exception>
18      Task AppendEventAsync(OperatorEvent evt);
19  
20      /// <summary>
21      /// Appends multiple events atomically to an operator's event stream.
22      /// All events must belong to the same operator and be in sequence order.
23      /// Either all events are appended or none are (transactional).
24      /// </summary>
25      /// <param name="events">The events to append in order</param>
26      /// <exception cref="InvalidOperationException">If events are invalid, out of order, or from different operators</exception>
27      Task AppendEventsAsync(IReadOnlyList<OperatorEvent> events);
28  
29      /// <summary>
30      /// Loads all events for a specific operator, ordered by sequence number.
31      /// Returns empty list if operator has no events.
32      /// Verifies hash chain integrity during load - fails fast if tampering detected.
33      /// </summary>
34      /// <param name="operatorId">The operator to load events for</param>
35      /// <returns>Ordered list of events</returns>
36      /// <exception cref="InvalidOperationException">If hash chain verification fails</exception>
37      Task<IReadOnlyList<OperatorEvent>> LoadEventsAsync(OperatorId operatorId);
38  
39      /// <summary>
40      /// Checks if an operator exists (has at least one event).
41      /// </summary>
42      Task<bool> OperatorExistsAsync(OperatorId operatorId);
43  
44      /// <summary>
45      /// Gets the current sequence number for an operator.
46      /// Returns -1 if operator doesn't exist.
47      /// </summary>
48      Task<long> GetCurrentSequenceAsync(OperatorId operatorId);
49  
50      /// <summary>
51      /// Lists all known operator IDs that have events.
52      /// For production use, consider adding pagination.
53      /// </summary>
54      Task<IReadOnlyList<OperatorId>> ListOperatorIdsAsync();
55  
56      /// <summary>
57      /// Lists operator IDs that belong to a specific account.
58      /// Only returns operators whose genesis event is associated with the given account.
59      /// </summary>
60      Task<IReadOnlyList<OperatorId>> ListOperatorIdsByAccountAsync(Guid accountId);
61  
62      /// <summary>
63      /// Returns the account ID associated with an operator, or null if no account is set.
64      /// </summary>
65      Task<Guid?> GetOperatorAccountIdAsync(OperatorId operatorId);
66  
67      /// <summary>
68      /// Associates an operator with an account by setting the AccountId on the genesis event document.
69      /// This must be called once after the operator is created.
70      /// </summary>
71      Task AssociateOperatorWithAccountAsync(OperatorId operatorId, Guid accountId);
72  }