< Summary

Information
Class: FirebaseAdapter.Models.FirestoreMatchOutcome
Assembly: FirebaseAdapter
File(s): /home/runner/work/KicktippAi/KicktippAi/src/FirebaseAdapter/Models/FirestoreModels.cs
Line coverage
100%
Covered lines: 5
Uncovered lines: 0
Coverable lines: 5
Total lines: 434
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/FirebaseAdapter/Models/FirestoreModels.cs

#LineLine coverage
 1using Google.Cloud.Firestore;
 2using NodaTime;
 3using EHonda.KicktippAi.Core;
 4
 5namespace FirebaseAdapter.Models;
 6
 7/// <summary>
 8/// Firestore document model for storing match predictions.
 9/// </summary>
 10[FirestoreData]
 11public class FirestoreMatchPrediction
 12{
 13    /// <summary>
 14    /// Document ID constructed from match details for uniqueness.
 15    /// Format: "{homeTeam}_{awayTeam}_{startsAtTicks}_{matchday}"
 16    /// </summary>
 17    [FirestoreDocumentId]
 18    public string? Id { get; set; }
 19
 20    /// <summary>
 21    /// Home team name.
 22    /// </summary>
 23    [FirestoreProperty("homeTeam")]
 24    public string HomeTeam { get; set; } = string.Empty;
 25
 26    /// <summary>
 27    /// Away team name.
 28    /// </summary>
 29    [FirestoreProperty("awayTeam")]
 30    public string AwayTeam { get; set; } = string.Empty;
 31
 32    /// <summary>
 33    /// Match start time as UTC timestamp.
 34    /// </summary>
 35    [FirestoreProperty("startsAt")]
 36    public Timestamp StartsAt { get; set; }
 37
 38    /// <summary>
 39    /// Match day number (1-34 for Bundesliga).
 40    /// </summary>
 41    [FirestoreProperty("matchday")]
 42    public int Matchday { get; set; }
 43
 44    /// <summary>
 45    /// Predicted home team goals.
 46    /// </summary>
 47    [FirestoreProperty("homeGoals")]
 48    public int HomeGoals { get; set; }
 49
 50    /// <summary>
 51    /// Predicted away team goals.
 52    /// </summary>
 53    [FirestoreProperty("awayGoals")]
 54    public int AwayGoals { get; set; }
 55
 56    /// <summary>
 57    /// Optional structured justification payload (stored as JSON string) explaining the predicted outcome.
 58    /// </summary>
 59    [FirestoreProperty("justification")]
 60    public string? Justification { get; set; }
 61
 62    /// <summary>
 63    /// When the prediction was created (UTC timestamp).
 64    /// </summary>
 65    [FirestoreProperty("createdAt")]
 66    public Timestamp CreatedAt { get; set; }
 67
 68    /// <summary>
 69    /// When the prediction was last updated (UTC timestamp).
 70    /// </summary>
 71    [FirestoreProperty("updatedAt")]
 72    public Timestamp UpdatedAt { get; set; }
 73
 74    /// <summary>
 75    /// Competition/season identifier (e.g., "bundesliga-2025-26").
 76    /// </summary>
 77    [FirestoreProperty("competition")]
 78    public string Competition { get; set; } = "bundesliga-2025-26";
 79
 80    /// <summary>
 81    /// The AI model used to generate this prediction (e.g., "gpt-4o", "o1-mini").
 82    /// </summary>
 83    [FirestoreProperty("model")]
 84    public string Model { get; set; } = string.Empty;
 85
 86    /// <summary>
 87    /// Stable identity key for the model configuration used to generate this prediction.
 88    /// </summary>
 89    [FirestoreProperty("modelConfigKey")]
 90    public string? ModelConfigKey { get; set; }
 91
 92    /// <summary>
 93    /// Optional OpenAI reasoning effort used to generate this prediction.
 94    /// </summary>
 95    [FirestoreProperty("reasoningEffort")]
 96    public string? ReasoningEffort { get; set; }
 97
 98    /// <summary>
 99    /// JSON string containing the token usage object from the API (e.g., completion_tokens, prompt_tokens, total_tokens
 100    /// </summary>
 101    [FirestoreProperty("tokenUsage")]
 102    public string TokenUsage { get; set; } = string.Empty;
 103
 104    /// <summary>
 105    /// Cost in USD to generate this prediction.
 106    /// </summary>
 107    [FirestoreProperty("cost")]
 108    public double Cost { get; set; }
 109
 110    /// <summary>
 111    /// The community context (community rules) used to generate this prediction.
 112    /// </summary>
 113    [FirestoreProperty("communityContext")]
 114    public string CommunityContext { get; set; } = string.Empty;
 115
 116    /// <summary>
 117    /// Names of context documents that were used as input for generating this prediction.
 118    /// Used to check if prediction is outdated compared to context changes.
 119    /// </summary>
 120    [FirestoreProperty("contextDocumentNames")]
 121    public string[] ContextDocumentNames { get; set; } = [];
 122
 123    /// <summary>
 124    /// Reprediction index for tracking prediction versions.
 125    /// Starts at 0 for the first prediction, increments for each reprediction.
 126    /// </summary>
 127    [FirestoreProperty("repredictionIndex")]
 128    public int RepredictionIndex { get; set; } = 0;
 129}
 130
 131/// <summary>
 132/// Firestore document model for storing match information without predictions.
 133/// Used for managing match days and match schedules.
 134/// </summary>
 135[FirestoreData]
 136public class FirestoreMatch
 137{
 138    /// <summary>
 139    /// Document ID constructed from match details.
 140    /// </summary>
 141    [FirestoreDocumentId]
 142    public string? Id { get; set; }
 143
 144    /// <summary>
 145    /// Home team name.
 146    /// </summary>
 147    [FirestoreProperty("homeTeam")]
 148    public string HomeTeam { get; set; } = string.Empty;
 149
 150    /// <summary>
 151    /// Away team name.
 152    /// </summary>
 153    [FirestoreProperty("awayTeam")]
 154    public string AwayTeam { get; set; } = string.Empty;
 155
 156    /// <summary>
 157    /// Match start time as UTC timestamp.
 158    /// </summary>
 159    [FirestoreProperty("startsAt")]
 160    public Timestamp StartsAt { get; set; }
 161
 162    /// <summary>
 163    /// Match day number (1-34 for Bundesliga).
 164    /// </summary>
 165    [FirestoreProperty("matchday")]
 166    public int Matchday { get; set; }
 167
 168    /// <summary>
 169    /// Competition/season identifier.
 170    /// </summary>
 171    [FirestoreProperty("competition")]
 172    public string Competition { get; set; } = "bundesliga-2025-26";
 173
 174    /// <summary>
 175    /// Indicates whether the match has been cancelled.
 176    /// Cancelled matches show "Abgesagt" on Kicktipp instead of a scheduled time.
 177    /// See docs/features/cancelled-matches.md for design rationale.
 178    /// </summary>
 179    [FirestoreProperty("isCancelled")]
 180    public bool IsCancelled { get; set; } = false;
 181}
 182
 183/// <summary>
 184/// Firestore document model for storing bonus predictions.
 185/// </summary>
 186[FirestoreData]
 187public class FirestoreBonusPrediction
 188{
 189    /// <summary>
 190    /// Document ID - unique identifier for the prediction.
 191    /// </summary>
 192    [FirestoreDocumentId]
 193    public string? Id { get; set; }
 194
 195    /// <summary>
 196    /// The bonus question text (for observability).
 197    /// </summary>
 198    [FirestoreProperty("questionText")]
 199    public string QuestionText { get; set; } = string.Empty;
 200
 201    /// <summary>
 202    /// Selected option IDs for the bonus question.
 203    /// </summary>
 204    [FirestoreProperty("selectedOptionIds")]
 205    public string[] SelectedOptionIds { get; set; } = [];
 206
 207    /// <summary>
 208    /// Selected option texts (for observability).
 209    /// </summary>
 210    [FirestoreProperty("selectedOptionTexts")]
 211    public string[] SelectedOptionTexts { get; set; } = [];
 212
 213    /// <summary>
 214    /// When the bonus prediction was created (UTC timestamp).
 215    /// </summary>
 216    [FirestoreProperty("createdAt")]
 217    public Timestamp CreatedAt { get; set; }
 218
 219    /// <summary>
 220    /// When the bonus prediction was last updated (UTC timestamp).
 221    /// </summary>
 222    [FirestoreProperty("updatedAt")]
 223    public Timestamp UpdatedAt { get; set; }
 224
 225    /// <summary>
 226    /// Competition/season identifier (e.g., "bundesliga-2025-26").
 227    /// </summary>
 228    [FirestoreProperty("competition")]
 229    public string Competition { get; set; } = "bundesliga-2025-26";
 230
 231    /// <summary>
 232    /// The AI model used to generate this prediction (e.g., "gpt-4o", "o1-mini").
 233    /// </summary>
 234    [FirestoreProperty("model")]
 235    public string Model { get; set; } = string.Empty;
 236
 237    /// <summary>
 238    /// Stable identity key for the model configuration used to generate this prediction.
 239    /// </summary>
 240    [FirestoreProperty("modelConfigKey")]
 241    public string? ModelConfigKey { get; set; }
 242
 243    /// <summary>
 244    /// Optional OpenAI reasoning effort used to generate this prediction.
 245    /// </summary>
 246    [FirestoreProperty("reasoningEffort")]
 247    public string? ReasoningEffort { get; set; }
 248
 249    /// <summary>
 250    /// JSON string containing the token usage object from the API (e.g., completion_tokens, prompt_tokens, total_tokens
 251    /// </summary>
 252    [FirestoreProperty("tokenUsage")]
 253    public string TokenUsage { get; set; } = string.Empty;
 254
 255    /// <summary>
 256    /// Cost in USD to generate this prediction.
 257    /// </summary>
 258    [FirestoreProperty("cost")]
 259    public double Cost { get; set; }
 260
 261    /// <summary>
 262    /// The community context (community rules) used to generate this prediction.
 263    /// </summary>
 264    [FirestoreProperty("communityContext")]
 265    public string CommunityContext { get; set; } = string.Empty;
 266
 267    /// <summary>
 268    /// Names of context documents that were used as input for generating this prediction.
 269    /// Used to check if prediction is outdated compared to context changes.
 270    /// </summary>
 271    [FirestoreProperty("contextDocumentNames")]
 272    public string[] ContextDocumentNames { get; set; } = [];
 273
 274    /// <summary>
 275    /// Reprediction index for tracking prediction versions.
 276    /// Starts at 0 for the first prediction, increments for each reprediction.
 277    /// </summary>
 278    [FirestoreProperty("repredictionIndex")]
 279    public int RepredictionIndex { get; set; } = 0;
 280}
 281
 282/// <summary>
 283/// Firestore document model for storing KPI context documents.
 284/// Used for storing contextual data for bonus predictions.
 285/// </summary>
 286[FirestoreData]
 287public class FirestoreKpiDocument
 288{
 289    /// <summary>
 290    /// Document ID - constructed from document name, community context, and version.
 291    /// Format: "{documentName}_{communityContext}_{version}"
 292    /// </summary>
 293    [FirestoreDocumentId]
 294    public string? Id { get; set; }
 295
 296    /// <summary>
 297    /// The document name (for observability and context lookup consistency).
 298    /// </summary>
 299    [FirestoreProperty("documentName")]
 300    public string DocumentName { get; set; } = string.Empty;
 301
 302    /// <summary>
 303    /// The document content (TSV format).
 304    /// </summary>
 305    [FirestoreProperty("content")]
 306    public string Content { get; set; } = string.Empty;
 307
 308    /// <summary>
 309    /// Document description.
 310    /// </summary>
 311    [FirestoreProperty("description")]
 312    public string Description { get; set; } = string.Empty;
 313
 314    /// <summary>
 315    /// Version number for this document (starts at 0).
 316    /// </summary>
 317    [FirestoreProperty("version")]
 318    public int Version { get; set; }
 319
 320    /// <summary>
 321    /// When the document was created (UTC timestamp).
 322    /// </summary>
 323    [FirestoreProperty("createdAt")]
 324    public Timestamp CreatedAt { get; set; }
 325
 326    /// <summary>
 327    /// Competition/season identifier (e.g., "bundesliga-2025-26").
 328    /// </summary>
 329    [FirestoreProperty("competition")]
 330    public string Competition { get; set; } = "bundesliga-2025-26";
 331
 332    /// <summary>
 333    /// Community context for filtering KPI documents.
 334    /// </summary>
 335    [FirestoreProperty("communityContext")]
 336    public string CommunityContext { get; set; } = string.Empty;
 337}
 338
 339/// <summary>
 340/// Firestore document model for storing versioned context documents.
 341/// Used for storing contextual data retrieved from Kicktipp for matchday predictions.
 342/// </summary>
 343[FirestoreData]
 344public class FirestoreContextDocument
 345{
 346    /// <summary>
 347    /// Document ID - constructed from document name, community context, and version.
 348    /// Format: "{documentName}_{communityContext}_{version}"
 349    /// </summary>
 350    [FirestoreDocumentId]
 351    public string? Id { get; set; }
 352
 353    /// <summary>
 354    /// The context document name (e.g., "bundesliga-standings.csv", "recent-history-fcb.csv").
 355    /// </summary>
 356    [FirestoreProperty("documentName")]
 357    public string DocumentName { get; set; } = string.Empty;
 358
 359    /// <summary>
 360    /// The document content (CSV format).
 361    /// </summary>
 362    [FirestoreProperty("content")]
 363    public string Content { get; set; } = string.Empty;
 364
 365    /// <summary>
 366    /// Version number for this document (starts at 0).
 367    /// </summary>
 368    [FirestoreProperty("version")]
 369    public int Version { get; set; }
 370
 371    /// <summary>
 372    /// When the document was created (UTC timestamp).
 373    /// </summary>
 374    [FirestoreProperty("createdAt")]
 375    public Timestamp CreatedAt { get; set; }
 376
 377    /// <summary>
 378    /// Competition/season identifier (e.g., "bundesliga-2025-26").
 379    /// </summary>
 380    [FirestoreProperty("competition")]
 381    public string Competition { get; set; } = "bundesliga-2025-26";
 382
 383    /// <summary>
 384    /// Community context for filtering context documents.
 385    /// </summary>
 386    [FirestoreProperty("communityContext")]
 387    public string CommunityContext { get; set; } = string.Empty;
 388}
 389
 390/// <summary>
 391/// Firestore document model for storing persisted match outcomes collected from Kicktipp.
 392/// </summary>
 393[FirestoreData]
 394public class FirestoreMatchOutcome
 395{
 396    [FirestoreDocumentId]
 397    public string? Id { get; set; }
 398
 399    [FirestoreProperty("homeTeam")]
 1400    public string HomeTeam { get; set; } = string.Empty;
 401
 402    [FirestoreProperty("awayTeam")]
 1403    public string AwayTeam { get; set; } = string.Empty;
 404
 405    [FirestoreProperty("startsAt")]
 406    public Timestamp StartsAt { get; set; }
 407
 408    [FirestoreProperty("matchday")]
 409    public int Matchday { get; set; }
 410
 411    [FirestoreProperty("homeGoals")]
 412    public int? HomeGoals { get; set; }
 413
 414    [FirestoreProperty("awayGoals")]
 415    public int? AwayGoals { get; set; }
 416
 417    [FirestoreProperty("availability")]
 1418    public string Availability { get; set; } = nameof(MatchOutcomeAvailability.Pending);
 419
 420    [FirestoreProperty("tippspielId")]
 421    public string? TippSpielId { get; set; }
 422
 423    [FirestoreProperty("createdAt")]
 424    public Timestamp CreatedAt { get; set; }
 425
 426    [FirestoreProperty("updatedAt")]
 427    public Timestamp UpdatedAt { get; set; }
 428
 429    [FirestoreProperty("competition")]
 1430    public string Competition { get; set; } = "bundesliga-2025-26";
 431
 432    [FirestoreProperty("communityContext")]
 1433    public string CommunityContext { get; set; } = string.Empty;
 434}

Methods/Properties

.ctor()