Files
ColaFlow/colaflow-api/src/Modules/Mcp/ColaFlow.Modules.Mcp.Domain/Repositories/IPendingChangeRepository.cs
Yaojia Wang 63d0e20371 feat(backend): Implement MCP Domain Layer - PendingChange, TaskLock, DiffPreview (Story 5.3)
Implemented comprehensive domain layer for MCP module following DDD principles:

Domain Entities & Aggregates:
- PendingChange aggregate root with approval workflow (Pending/Approved/Rejected/Expired/Applied)
- TaskLock aggregate root for concurrency control with 5-minute expiration
- Business rule enforcement at domain level

Value Objects:
- DiffPreview for CREATE/UPDATE/DELETE operations with validation
- DiffField for field-level change tracking
- PendingChangeStatus and TaskLockStatus enums

Domain Events (8 total):
- PendingChange: Created, Approved, Rejected, Expired, Applied
- TaskLock: Acquired, Released, Expired

Repository Interfaces:
- IPendingChangeRepository with query methods for status, entity, and expiration
- ITaskLockRepository with concurrency control queries

Domain Services:
- DiffPreviewService for generating diffs via reflection and JSON comparison
- TaskLockService for lock acquisition, release, and expiration management

Unit Tests (112 total, all passing):
- DiffFieldTests: 13 tests for value object behavior and equality
- DiffPreviewTests: 20 tests for operation validation and factory methods
- PendingChangeTests: 29 tests for aggregate lifecycle and business rules
- TaskLockTests: 26 tests for lock management and expiration
- Test coverage > 90% for domain layer

Technical Implementation:
- Follows DDD aggregate root pattern with encapsulation
- Uses factory methods for entity creation with validation
- Domain events for audit trail and loose coupling
- Immutable value objects with equality comparison
- Business rules enforced in domain entities (not services)
- 24-hour expiration for PendingChange, 5-minute for TaskLock
- Supports diff preview with before/after snapshots (JSON)

Story 5.3 completed - provides solid foundation for Phase 3 Diff Preview and approval workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:56:22 +01:00

82 lines
2.5 KiB
C#

using ColaFlow.Modules.Mcp.Domain.Entities;
using ColaFlow.Modules.Mcp.Domain.ValueObjects;
namespace ColaFlow.Modules.Mcp.Domain.Repositories;
/// <summary>
/// Repository interface for PendingChange aggregate root
/// </summary>
public interface IPendingChangeRepository
{
/// <summary>
/// Get a pending change by ID
/// </summary>
Task<PendingChange?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
/// <summary>
/// Get all pending changes for a tenant
/// </summary>
Task<IReadOnlyList<PendingChange>> GetByTenantAsync(
Guid tenantId,
CancellationToken cancellationToken = default);
/// <summary>
/// Get pending changes by status
/// </summary>
Task<IReadOnlyList<PendingChange>> GetByStatusAsync(
Guid tenantId,
PendingChangeStatus status,
CancellationToken cancellationToken = default);
/// <summary>
/// Get expired pending changes (still in PendingApproval status but past expiration time)
/// </summary>
Task<IReadOnlyList<PendingChange>> GetExpiredAsync(
CancellationToken cancellationToken = default);
/// <summary>
/// Get pending changes by API key
/// </summary>
Task<IReadOnlyList<PendingChange>> GetByApiKeyAsync(
Guid apiKeyId,
CancellationToken cancellationToken = default);
/// <summary>
/// Get pending changes for a specific entity
/// </summary>
Task<IReadOnlyList<PendingChange>> GetByEntityAsync(
Guid tenantId,
string entityType,
Guid entityId,
CancellationToken cancellationToken = default);
/// <summary>
/// Check if there are any pending changes for a specific entity
/// </summary>
Task<bool> HasPendingChangesForEntityAsync(
Guid tenantId,
string entityType,
Guid entityId,
CancellationToken cancellationToken = default);
/// <summary>
/// Add a new pending change
/// </summary>
Task AddAsync(PendingChange pendingChange, CancellationToken cancellationToken = default);
/// <summary>
/// Update an existing pending change
/// </summary>
Task UpdateAsync(PendingChange pendingChange, CancellationToken cancellationToken = default);
/// <summary>
/// Delete a pending change
/// </summary>
Task DeleteAsync(PendingChange pendingChange, CancellationToken cancellationToken = default);
/// <summary>
/// Save changes to the database
/// </summary>
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}