Skip to main content
The Infrastructure Layer contains implementations of domain interfaces and all external dependencies. It handles persistence, external APIs, file systems, and framework-specific code.

Layer Overview

Location: ~/workspace/source/Chapi/Infrastructure/ Responsibilities:
  • Implement domain repository interfaces
  • Integrate with external services (Git, AI, OAuth)
  • Handle file system operations
  • Manage persistence (settings, cache)
  • Provide platform-specific implementations
Dependencies:
  • ✅ Depends on Domain Layer (implements interfaces)
  • ✅ Can depend on external libraries (LibGit2Sharp, etc.)
  • ❌ No dependencies on Presentation or Application

Repository Implementations

Git Repository Implementation

External Service Integrations

AI Chat Clients

Authentication Providers

Workspace Service

Code Generation (Roslyn)

Chapi uses Roslyn for code generation and manipulation.

Platform-Specific Services

Windows Credential Storage

public class WindowsCredentialStorageService : ICredentialStorageService
{
    public async Task StoreCredentialAsync(string key, string username, string token)
    {
        var credential = new PasswordCredential
        {
            Resource = $"ChapiAssistant_{key}",
            UserName = username,
            Password = token
        };

        // Use Windows Credential Manager
        credential.Save();
        await Task.CompletedTask;
    }

    public async Task<(string username, string token)?> GetCredentialAsync(string key)
    {
        try
        {
            var credential = PasswordVault.Retrieve($"ChapiAssistant_{key}");
            return (credential.UserName, credential.Password);
        }
        catch
        {
            return null;
        }
    }
}
Source: Infrastructure/Services/WindowsCredentialStorageService.cs

Infrastructure Components

Git Integration

  • LibGit2SharpRepository
  • GitChangeWatcher
  • GitChangesCache

AI Clients

  • GeminiChatClient
  • OpenAiChatClient
  • ClaudeChatClient

Authentication

  • GitHubOAuthProvider
  • GitLabOAuthProvider
  • GitAuthProviderFactory

Services

  • WorkspaceService
  • NotificationService
  • TemplateService

Performance Optimizations

public class GitChangesCache
{
    private readonly Dictionary<string, CachedChanges> _cache = new();

    public bool TryGetChanges(
        string projectPath, 
        out List<FileChange> changes,
        out int additions,
        out int deletions)
    {
        if (_cache.TryGetValue(projectPath, out var cached))
        {
            changes = cached.Changes;
            additions = cached.Additions;
            deletions = cached.Deletions;
            return true;
        }

        changes = null;
        additions = 0;
        deletions = 0;
        return false;
    }

    public void Invalidate(string projectPath)
    {
        _cache.Remove(projectPath);
    }
}
Instead of calculating diffs for all files upfront:
var change = new FileChange
{
    FilePath = item.FilePath,
    Status = status,
    Additions = 0,  // Calculated on-demand when file selected
    Deletions = 0   // Calculated on-demand when file selected
};
// Load metadata in parallel
_ = Task.Run(async () =>
{
    try { await LoadMetadataAsync(); } catch { }
}, token);

Testing Infrastructure

[Test]
public async Task LibGit2SharpRepository_CommitAsync_CreatesCommit()
{
    // Arrange
    var tempPath = CreateTemporaryRepository();
    var mockAuth = new Mock<IGitAuthProviderFactory>();
    var mockStorage = new Mock<ICredentialStorageService>();
    var repo = new LibGit2SharpRepository(mockAuth.Object, mockStorage.Object);

    // Act
    var result = await repo.CommitAsync(
        tempPath, 
        "Test commit", 
        new[] { "file.txt" });

    // Assert
    Assert.IsTrue(result.IsSuccess);
    Assert.AreEqual("Test commit", result.Data.Message);

    // Cleanup
    Directory.Delete(tempPath, true);
}

Domain Layer

Interfaces being implemented

Application Layer

Services consuming infrastructure

Dependency Injection

Service registration

Build docs developers (and LLMs) love