Architecture
coverctl is built with Domain-Driven Design (DDD) principles and follows clean architecture patterns. This document describes the project structure and design decisions.
Project Structure
Section titled “Project Structure”coverctl/├── cmd/coverctl/ # CLI entry point├── internal/│ ├── domain/ # Core business logic│ ├── application/ # Application services│ ├── infrastructure/ # External adapters│ └── cli/ # CLI parsing and output├── docs/ # Documentation (this site)├── schemas/ # JSON schemas└── templates/ # Config templatesLayer Responsibilities
Section titled “Layer Responsibilities”Domain Layer (internal/domain/)
Section titled “Domain Layer (internal/domain/)”The domain layer contains the core business logic with no external dependencies.
Key components:
CoverageStat: Coverage statistics for a filePolicy: Coverage policy definitionsDomain: Domain configurationResult: Coverage evaluation resultsEvaluate(): Policy evaluation logic
type Policy struct { Default DefaultPolicy Domains []Domain}
func Evaluate(policy Policy, coverage map[string]CoverageStat) Result { // Pure business logic, no I/O}Application Layer (internal/application/)
Section titled “Application Layer (internal/application/)”The application layer orchestrates use cases by coordinating domain logic and infrastructure.
Key services:
Check(): Run tests, evaluate coverage, enforce policyRunOnly(): Generate coverage profileReport(): Analyze existing profileWatch(): Continuous coverage monitoring
Interfaces defined here:
CoverageRunner: Run tests with coverageProfileParser: Parse coverage profilesConfigLoader: Load configurationReporter: Format and output results
type Service struct { CoverageRunner CoverageRunner ProfileParser ProfileParser ConfigLoader ConfigLoader Reporter Reporter // ...}
func (s *Service) Check(ctx context.Context, opts CheckOptions) error { // Orchestrate domain + infrastructure}Infrastructure Layer (internal/infrastructure/)
Section titled “Infrastructure Layer (internal/infrastructure/)”Adapters for external systems and I/O operations.
Adapters:
gotool/: Go toolchain integration (go test)config/: YAML configuration loadingcoverprofile/: Coverage profile parsingreport/: Text/JSON/HTML outputdiff/: Git diff integrationwatcher/: File system watching
type Runner struct { Module ModuleResolver Exec func(ctx, dir, args) error}
func (r Runner) Run(ctx context.Context, opts RunOptions) (string, error) { // Execute go test with coverage}CLI Layer (internal/cli/)
Section titled “CLI Layer (internal/cli/)”Command-line interface parsing and user interaction.
Responsibilities:
- Parse command-line arguments
- Validate inputs
- Call application services
- Format output for terminal
func Run(args []string, stdout, stderr io.Writer, svc Service) int { // Parse args, dispatch to service methods}Design Principles
Section titled “Design Principles”Dependency Inversion
Section titled “Dependency Inversion”All dependencies point inward toward the domain layer:
CLI → Application → Domain ↓ InfrastructureApplication layer defines interfaces; infrastructure implements them.
Hexagonal Architecture
Section titled “Hexagonal Architecture”The application core is isolated from external concerns:
┌─────────────────┐ │ CLI Port │ └────────┬────────┘ │ ┌─────────────▼─────────────┐ │ Application Core │ │ ┌─────────────────────┐ │ │ │ Domain │ │ │ └─────────────────────┘ │ └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ Infrastructure Ports │ │ ┌──────┐ ┌──────┐ ┌────┐ │ │ │ Git │ │ File │ │ Go │ │ │ └──────┘ └──────┘ └────┘ │ └───────────────────────────┘Pure Domain Logic
Section titled “Pure Domain Logic”The domain layer has no side effects:
// Pure function - easy to testfunc Evaluate(policy Policy, coverage Coverage) Result { // No I/O, no state mutation return result}Interface Segregation
Section titled “Interface Segregation”Small, focused interfaces:
// Single responsibilitytype CoverageRunner interface { Run(ctx context.Context, opts RunOptions) (string, error)}
type ProfileParser interface { Parse(path string) (map[string]CoverageStat, error)}Testing Strategy
Section titled “Testing Strategy”Unit Tests
Section titled “Unit Tests”Each layer is tested in isolation:
- Domain: Pure function tests
- Application: Mock infrastructure interfaces
- Infrastructure: Integration tests with real I/O
- CLI: End-to-end argument parsing tests
Test Coverage
Section titled “Test Coverage”coverctl uses itself for coverage enforcement:
policy: default: min: 75 domains: - name: domain match: ["./internal/domain/..."] min: 85 - name: application match: ["./internal/application/..."] min: 80Key Decisions
Section titled “Key Decisions”Go Standard Library
Section titled “Go Standard Library”Minimal external dependencies:
charmbracelet/bubbletea: TUI wizardcharmbracelet/lipgloss: Terminal stylingfsnotify/fsnotify: File watchinggopkg.in/yaml.v3: YAML parsing
Coverage Mode
Section titled “Coverage Mode”Uses covermode=atomic for accurate concurrent coverage.
Profile Format
Section titled “Profile Format”Standard Go coverage profile format for compatibility with go tool cover.
See Also
Section titled “See Also”- Contributing - How to contribute
- GitHub Repository