go

module
v0.0.0-...-6afd062 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: Apache-2.0

README

LibDomain

A Domain-Driven Design framework for Go enabling type-safe, event-sourced aggregates through declarative definitions and code generation.

Go Version License Status


What is LibDomain?

LibDomain is a complete framework for building complex business systems using Domain-Driven Design (DDD) principles in Go. It provides:

  • Declarative Domain Modeling - Define domain structure once, generate everything else
  • Event Sourcing - Complete audit trail and temporal queries built-in
  • Type Safety - Compile-time guarantees from definitions to code
  • Code Generation - Automatic boilerplate generation (~80% reduction)
  • Lazy Loading - Explicit property loading prevents N+1 queries
  • Multi-Tenancy - First-class tenant isolation support
Key Statistics
  • 6,000+ lines of core library code
  • 80,000+ lines of generated code (across all domains)
  • 20+ property types supported
  • 15 architecture decisions documented
  • 6 comprehensive guides for developers

Quick Start

1. Define Your Domain
// myapp/domain/theme/definitions.go
package theme

import (
    "libdomain"
    "libdomain/properties"
)

func init() {
    defs := &libdomain.Definitions{
        Package:    "myapp/domain/theme",
        Repository: "myapp/domains/theme",
    }

    defs.Register(&libdomain.AggregateDefinition{
        AggregateRoot: &libdomain.EntityDefinition{
            Name: "theme",
            Properties: []libdomain.PropertyDefinition{
                properties.Text("title", true),
                properties.Text("code", true),
                properties.Integer("sequence", true),
            },
        },
    })

    libdomain.Generate(defs)
}
2. Implement Domain Logic
// myapp/domain/theme/theme.go
package theme

func (t *Theme) UpdateTitle(ctx context.Context, newTitle string) error {
    if len(newTitle) < 3 {
        return errors.New("title too short")
    }

    event := &ThemeTitleUpdatedEvent{
        Title: newTitle,
    }

    t.Apply(event)
    return nil
}
3. Wire Application Layer
// myapp/application/theme/wire.go
package theme

import themegen "myapp/domain/theme/gen"

func init() {
    // Wire validation
    themegen.ThemeValidation = NewThemeValidator()

    // Wire authorization
    themegen.ThemeAuthPolicy = NewAuthorizationPolicy()

    // Wire event handlers
    themegen.ThemeEventHandler = NewEventHandler()
}
4. Use in Services
// myapp/application/theme/create_usecase.go
func (u *CreateThemeUseCase) Handle(ctx context.Context, cmd CreateThemeCommand) error {
    // Create aggregate
    theme, err := u.factory.NewTheme(ctx, cmd.TenantID, cmd.Title, cmd.Code, cmd.Sequence)
    if err != nil {
        return err
    }

    // Save to repository
    return u.repo.Save(ctx, theme)
}

Documentation

LibDomain includes comprehensive documentation for different audiences:

For Architects & Decision Makers
For Developers
For Contributors
Reading Order

New to LibDomain?

  1. ARCHITECTURE.md - Understand the system
  2. CONCEPTS.md - Learn terminology
  3. ERROR_HANDLING.md - Learn error philosophy

Ready to contribute? 4. CONTRIBUTING.md - Code standards and process 5. EXTENDING.md - Extension patterns

Deep dives:


Core Concepts

Aggregate

A cluster of domain objects (root entity, child entities, value objects) treated as a single unit.

Theme Aggregate:
├── Aggregate Root: Theme
│   ├── Properties: title, code, sequence
│   └── Methods: UpdateTitle, UpdateExternal
├── Child Entities: ThemeProjectItem[]
└── Value Objects: ThemeExternal{}
Event Sourcing

Store immutable domain events instead of current state. Rebuild state by replaying events.

User Action → Command → Event Created → Event Stored → Aggregate Replayed
Domain Events

Immutable facts about what happened in the domain.

type ThemeCreatedEvent struct {
    Title      string
    Code       string
    Sequence   int
    OccurredAt time.Time
    OccurredBy string
}
Lazy Loading

Properties must be explicitly loaded before access. Prevents N+1 queries.

if !theme.TitleIsLoaded() {
    theme, err = repo.FindByID(ctx, themeID)
}
title := theme.Title()  // Safe
Type-Safe Repository

Per-aggregate repository interface for data access.

type ThemeRepository interface {
    Save(ctx context.Context, theme *Theme) error
    FindByID(ctx context.Context, id ThemeID) (*Theme, error)
    FindByCode(ctx context.Context, code string) (*Theme, error)
}

Architecture Overview

┌─────────────────────────────────────────┐
│         Presentation Layer              │  HTTP/gRPC/WebSocket
│  (API Handlers, DTOs, Serialization)    │
├─────────────────────────────────────────┤
│       Application Layer                 │  Use Cases, Commands
│  (Services, Event Handlers, Commands)   │  Queries, Transactions
├─────────────────────────────────────────┤
│          Domain Layer (✓ LibDomain)     │  Aggregates, Events
│  (Entities, Value Objects, Events)      │  Repositories, Policies
├─────────────────────────────────────────┤
│      Infrastructure Layer               │  Persistence
│  (Repositories, Event Store, DB)        │  Event Publishing
└─────────────────────────────────────────┘

Error Handling Philosophy

LibDomain distinguishes between two types of errors:

Panic: Programmer Errors
// Invariant violation - programmer error
if !t.titleIsLoaded {
    panic("BUG: Title accessed before loading. Call AllPropertiesLoaded() first.")
}

// Initialization failure - programmer error
if ThemeEventHandler == nil {
    panic("BUG: ThemeEventHandler not initialized in init()")
}

Why? Returning errors for programmer errors leads to silent data corruption.

Error: Runtime/Operational Issues
// User input validation - operational
if len(title) < 3 {
    return NewValidationError("title", "must be at least 3 characters")
}

// Business rule violation - operational
if !hasRole(ctx, "admin") {
    return NewAuthorizationError("admin role required")
}

// External system failure - operational
db, err := sql.Open("postgres", connStr)
if err != nil {
    return fmt.Errorf("database connection failed: %w", err)
}

Why? Users can fix input errors, system can retry external calls, but programmer errors must be fixed in code.

See ERROR_HANDLING.md for complete philosophy.


Extension Points

LibDomain provides clean extension points for custom behavior:

Custom Property Types

Create new property types beyond the 20+ built-in types.

properties.CustomType("metadata", false, map[string]string{
    "description": "Custom metadata storage",
})
Custom Validation Rules

Implement domain-specific validation.

type ThemeValidator struct { /* ... */ }

func (v *ThemeValidator) ValidateTitle(title string) error {
    // Custom validation logic
}
Custom Authorization Policies

Control who can perform which actions.

type RoleBasedAuthPolicy struct { /* ... */ }

func (p *RoleBasedAuthPolicy) AuthorizeThemeCreate(ctx, event) (bool, error) {
    // Authorization logic
}
Custom Event Handlers

React to domain events with side effects.

type CustomEventHandler struct { /* ... */ }

func (h *CustomEventHandler) OnThemeCreated(setters, event) {
    // Event handling logic
}
Custom Repository Functions

Add custom query methods.

type ThemeRepository interface {
    // Generated
    FindByID(ctx context.Context, id ThemeID) (*Theme, error)
    // Custom
    FindByCode(ctx context.Context, code string) (*Theme, error)
}

See EXTENDING.md for complete extension guide.


Design Principles

1. Single Source of Truth

Domain structure defined once in definitions, generated everywhere.

2. Type Safety

Compile-time guarantees from definitions to code.

3. Explicit Dependencies

Properties must be explicitly loaded before access.

4. Invariant Protection

Business rules enforced at aggregate level.

5. Event-First

State changes recorded as events first, then applied.

6. Auditability

All changes recorded in event log.

7. Testability

Each component has clear interface, mockable for testing.


Supported Property Types

Category Types
Scalar Text, Integer, Boolean, Float
Temporal Date, DateTime
References ID, Entity, Slice
Complex ValueObject, OrderedMap, Selection
Special Binary, Translatable

Each property supports:

  • Required/optional constraints
  • Length constraints (min/max)
  • Pattern validation (regex)
  • Lazy loading
  • Custom validation

Project Status

Phase 1: Architecture Documentation ✅ COMPLETE
  • ARCHITECTURE.md - System design and components
  • DESIGN_DECISIONS.md - 15 ADRs explaining design
  • CONCEPTS.md - DDD terminology reference
  • ERROR_HANDLING.md - Error philosophy guide
  • EXTENDING.md - Extension guide
  • CONTRIBUTING.md - Contribution guidelines
Phase 2: Refactor Core Types (Planned)
  • Split definition.go (6,000+ lines) into 9 focused files
  • Add comprehensive godoc comments
  • Improve type organization
  • Create property helper functions
Phase 3-7: Code Quality & Release (Planned)
  • Generator refactoring
  • Interface-based injection
  • Comprehensive testing
  • Performance optimization
  • Open-source release preparation

See LIBDOMAIN_REFACTORING_PLAN.md for complete roadmap.


Building

# Download dependencies
go mod download

# Run tests
go test ./...

# Check code quality
go vet ./...
go fmt ./...

# Build examples
go build ./examples/...

Contributing

LibDomain welcomes contributions from the community!

Before contributing, please read:

  1. CONTRIBUTING.md - Contribution guidelines
  2. ARCHITECTURE.md - System design
  3. CONCEPTS.md - DDD terminology

Contribution Process:

  1. Fork the repository
  2. Create a feature branch
  3. Follow coding standards and testing requirements
  4. Submit pull request with clear description
  5. Address review feedback
  6. Merge when approved

See CONTRIBUTING.md for detailed guidelines.


Architecture Decisions

LibDomain is built on well-reasoned architectural decisions documented in DESIGN_DECISIONS.md.

Key decisions include:

  • ADR-003: Panic for programmer errors, error return for runtime issues
  • ADR-002: Event sourcing as core pattern
  • ADR-004: Lazy loading of properties
  • ADR-008: Interfaces for all major components

See DESIGN_DECISIONS.md for all 15 ADRs.


Examples

See examples/ directory for complete working examples:

examples/
└── theme/                    # Complete theme domain example
    ├── definitions.go        # Domain definitions
    ├── domain/              # Domain logic
    ├── application/         # Application services
    └── tests/               # Example tests

License

LibDomain is proprietary software. See LICENSE file for details.


Support

For questions or issues:

  1. Check ARCHITECTURE.md for system design
  2. Check CONCEPTS.md for terminology
  3. Check ERROR_HANDLING.md for error guidance
  4. See EXTENDING.md for extension patterns
  5. Read CONTRIBUTING.md for code standards

For bug reports and feature requests, please use the issue tracker.


Roadmap

Phase 1: Architecture Documentation ✅ COMPLETE

  • Professional documentation for open-source quality

Phase 2: Core Library Refactoring (Next)

  • Split monolithic definitions into focused modules
  • Improve type organization

Phase 3-7: Quality & Release

  • Generator improvements
  • Comprehensive testing
  • Performance optimization
  • Open-source release

See PHASE_1_SUMMARY.md for detailed timeline.


Architecture at a Glance

Definitions (DSL)
    ↓
Generator (Templates)
    ↓
Generated Code (Types, Events, Handlers)
    ↓
Domain Logic (Aggregates, Services)
    ↓
Application Services (Use Cases, Commands)
    ↓
Presentation (APIs, DTOs)
    ↓
Infrastructure (Repositories, Event Store)

Data Flow:

User Action
    ↓
Command
    ↓
Event Created
    ↓
Event Stored
    ↓
Aggregate Replayed
    ↓
State Consistent

Key Statistics

Metric Value
Go Version 1.21+
Core Library ~6,000 lines
Generated Code 80,000+ lines
Documentation 12,000+ words
Code Examples 150+
Architecture Decisions 15
Property Types 20+
Extension Points 5+

Next Steps

For Users:

  1. Read ARCHITECTURE.md
  2. Review examples in examples/
  3. Check CONCEPTS.md for terminology
  4. See EXTENDING.md for customization

For Contributors:

  1. Read CONTRIBUTING.md
  2. Review DESIGN_DECISIONS.md
  3. Check coding standards in CONTRIBUTING.md
  4. See EXTENDING.md for patterns

For Architects:

  1. Review ARCHITECTURE.md
  2. Study DESIGN_DECISIONS.md
  3. Check PHASE_1_SUMMARY.md for roadmap

LibDomain: Domain-Driven Design for Go 🚀

Built with principles of event sourcing, type safety, and maintainability.

Directories

Path Synopsis
batch
Package batch provides a runtime primitive for executing multiple aggregate commands atomically within a single ApplicationContext / database transaction.
Package batch provides a runtime primitive for executing multiple aggregate commands atomically within a single ApplicationContext / database transaction.
importer/natsworker
Package natsworker provides NATS-based publishing and worker wiring for async imports.
Package natsworker provides NATS-based publishing and worker wiring for async imports.
importer/pgjobstore
Package pgjobstore is a PostgreSQL-backed implementation of importer.JobStore that integrates with the stack framework's DatasourceClient.
Package pgjobstore is a PostgreSQL-backed implementation of importer.JobStore that integrates with the stack framework's DatasourceClient.
cmd
applicationgen command
applicationgen is a CLI tool for generating application layer code from service definitions
applicationgen is a CLI tool for generating application layer code from service definitions
diagramgen command
domaingen command
domaingen is a CLI tool for generating domain code from BoundedContext definitions
domaingen is a CLI tool for generating domain code from BoundedContext definitions
filter
Package filter provides shared filter and sort primitives for domain list queries.
Package filter provides shared filter and sort primitives for domain list queries.
drivers
api
infrastructure
deletion_guard
Package deletion_guard provides the gRPC-based pre-deletion guard mechanism.
Package deletion_guard provides the gRPC-based pre-deletion guard mechanism.
pkg
presentation

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL