Spensara Spensara Knowledge Base & Documentation Repository

Repository Docs & Knowledge Base

Consolidated Spensara documentation repository (722 Markdown & architecture documents in ../repository)
Built Word Documents (.docx): Spensara Overview (.docx) Capability Assessment (.docx) Brink POS Ingestion Analysis (.docx) The Borg Ingestion Architecture (.docx)

Implementation Specs (157)

Detailed engineering and feature implementation specifications.
implementation-specs/specs/AnomalyDetection/TASK3.1.md 4,975 bytes · Updated Oct 23, 2026 10:44 AM EDT
Raw File

TASK 3.1: Create IMonitorSpecRepository Interface

Summary

Define the repository interface for managing MonitorSpec entities in the Data project. This abstraction allows for different storage implementations and simplifies testing. Placing it in the Data project keeps repository contracts co-located with entities and the DbContext.

Dependencies

  • TASK 1.1 (MonitorSpec entity must exist)

Files to Create

1. backend/Kds.Ai.Data/Repositories/IMonitorSpecRepository.cs

csharp
using Kds.Ai.Data.Entities;
using Kds.Ai.Data.Enums;

namespace Kds.Ai.Data.Repositories;

/// <summary>
/// Repository for managing MonitorSpec entities
/// </summary>
public interface IMonitorSpecRepository
{
    /// <summary>
    /// Get a monitor spec by its ID
    /// </summary>
    Task<MonitorSpec?> GetByIdAsync(Guid id, CancellationToken ct = default);
    
    /// <summary>
    /// Get a monitor spec by name
    /// </summary>
    Task<MonitorSpec?> GetByNameAsync(string name, CancellationToken ct = default);
    
    /// <summary>
    /// Get all monitor specs in a given state
    /// </summary>
    Task<IReadOnlyList<MonitorSpec>> GetByStateAsync(
        MonitorState state, 
        CancellationToken ct = default);
    
    /// <summary>
    /// Get all active monitor specs (State == Active)
    /// </summary>
    Task<IReadOnlyList<MonitorSpec>> GetActiveAsync(CancellationToken ct = default);
    
    /// <summary>
    /// Get all monitor specs regardless of state
    /// </summary>
    Task<IReadOnlyList<MonitorSpec>> GetAllAsync(CancellationToken ct = default);
    
    /// <summary>
    /// Create a new monitor spec
    /// </summary>
    /// <param name="spec">The monitor spec to create</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>The created monitor spec with generated ID</returns>
    Task<MonitorSpec> CreateAsync(MonitorSpec spec, CancellationToken ct = default);
    
    /// <summary>
    /// Update an existing monitor spec
    /// </summary>
    /// <param name="spec">The monitor spec to update</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>The updated monitor spec</returns>
    Task<MonitorSpec> UpdateAsync(MonitorSpec spec, CancellationToken ct = default);
    
    /// <summary>
    /// Update the last run timestamp for a monitor spec
    /// </summary>
    Task UpdateLastRunAsync(Guid id, DateTimeOffset lastRunAt, CancellationToken ct = default);
    
    /// <summary>
    /// Transition a monitor spec to a new state
    /// </summary>
    Task SetStateAsync(Guid id, MonitorState state, CancellationToken ct = default);
    
    /// <summary>
    /// Delete a monitor spec
    /// </summary>
    /// <returns>True if deleted, false if not found</returns>
    Task<bool> DeleteAsync(Guid id, CancellationToken ct = default);
    
    /// <summary>
    /// Check if a monitor spec with the given name already exists
    /// </summary>
    Task<bool> ExistsByNameAsync(string name, CancellationToken ct = default);
}

Interface Design Rationale

Why Kds.Ai.Data?

The repository interface belongs in the Data project because:

  • It operates on MonitorSpec entities that are defined in the same project
  • It depends only on types from the Data project (MonitorSpec, MonitorState, KdsAiDbContext)
  • Any project that references Kds.Ai.Data can consume IMonitorSpecRepository without taking a dependency on Kds.Ai.AnomalyDetector
  • The EF Core implementation (TASK 3.2) naturally lives alongside the DbContext it uses

Query Methods

  • GetByIdAsync: Standard lookup by primary key
  • GetByNameAsync: Lookup by unique name (since MonitorSpec no longer has StoreGuid/MonitorType, name is the human identifier)
  • GetActiveAsync: For scheduler to find monitors to run
  • GetByStateAsync: For management/filtering by lifecycle state
  • GetAllAsync: For listing all monitors

Command Methods

  • CreateAsync: Returns entity with generated ID
  • UpdateAsync: Full entity update
  • UpdateLastRunAsync: Partial update for run tracking (common operation)
  • SetStateAsync: Transition between Draft/Active/Paused/Archived
  • DeleteAsync: Returns bool for existence check

Existence Check

  • ExistsByNameAsync: Prevent duplicate monitor names

Acceptance Criteria

  • [ ] IMonitorSpecRepository interface created in Kds.Ai.Data/Repositories/
  • [ ] Namespace is Kds.Ai.Data.Repositories
  • [ ] All CRUD methods defined
  • [ ] Query methods use MonitorState enum (not bool IsEnabled)
  • [ ] No references to StoreGuid or MonitorType properties
  • [ ] Async pattern with CancellationToken on all methods
  • [ ] XML documentation complete
  • [ ] Solution builds without errors

Notes

  • Implementation in TASK 3.2
  • Consider adding pagination for GetActiveAsync if many monitors expected
  • The interface doesn't include Runs navigation property loading - use explicit includes in implementation if needed