Skip to main content

Domain Model

Domain model lengkap dengan entities, value objects, aggregates, dan business rules.

🏗️ Domain-Driven Design

Aplikasi ini menggunakan prinsip Domain-Driven Design (DDD) untuk memisahkan business logic dari infrastructure.

📦 Core Entities

User Aggregate

// Domain Entity
type User struct {
    ID            uuid.UUID
    Email         Email         // Value Object
    Password      Password      // Value Object
    Name          string
    Phone         Phone         // Value Object
    Role          Role          // Value Object
    EmailVerified bool
    CreatedAt     time.Time
    UpdatedAt     time.Time
}

// Value Objects
type Email struct {
    value string
}

func NewEmail(email string) (Email, error) {
    if !isValidEmail(email) {
        return Email{}, errors.New("invalid email format")
    }
    return Email{value: strings.ToLower(email)}, nil
}

type Role struct {
    name string
}

const (
    RoleAdmin Role = Role{"admin"}
    RoleUser  Role = Role{"user"}
    RoleGuest Role = Role{"guest"}
)

Product Aggregate

type Product struct {
    ID          uuid.UUID
    SKU         SKU           // Value Object
    Name        string
    Description string
    Price       Money         // Value Object
    Stock       Stock         // Value Object
    Category    *Category
    Active      bool
    CreatedAt   time.Time
}

type Money struct {
    Amount   decimal.Decimal
    Currency string
}

type Stock struct {
    Available int
    Reserved  int
}

func (s *Stock) Reserve(quantity int) error {
    if s.Available < quantity {
        return errors.New("insufficient stock")
    }
    s.Available -= quantity
    s.Reserved += quantity
    return nil
}

Order Aggregate

type Order struct {
    ID            uuid.UUID
    OrderNumber   OrderNumber    // Value Object
    UserID        uuid.UUID
    Items         []OrderItem
    Status        OrderStatus    // Value Object
    TotalAmount   Money
    CreatedAt     time.Time
}

type OrderItem struct {
    ProductID  uuid.UUID
    Quantity   int
    UnitPrice  Money
    Subtotal   Money
}

type OrderStatus string

const (
    OrderStatusPending   OrderStatus = "pending"
    OrderStatusPaid      OrderStatus = "paid"
    OrderStatusShipped   OrderStatus = "shipped"
    OrderStatusCompleted OrderStatus = "completed"
    OrderStatusCancelled OrderStatus = "cancelled"
)

// Domain Methods
func (o *Order) CalculateTotal() {
    total := decimal.Zero
    for _, item := range o.Items {
        total = total.Add(item.Subtotal.Amount)
    }
    o.TotalAmount = Money{Amount: total, Currency: "IDR"}
}

func (o *Order) CanBeCancelled() bool {
    return o.Status == OrderStatusPending || o.Status == OrderStatusPaid
}

🎯 Aggregates & Boundaries


📚 Repository Interfaces

// Domain Repository Interface
type UserRepository interface {
    FindByID(ctx context.Context, id uuid.UUID) (*User, error)
    FindByEmail(ctx context.Context, email Email) (*User, error)
    Save(ctx context.Context, user *User) error
    Delete(ctx context.Context, id uuid.UUID) error
}

type ProductRepository interface {
    FindByID(ctx context.Context, id uuid.UUID) (*Product, error)
    FindBySKU(ctx context.Context, sku SKU) (*Product, error)
    List(ctx context.Context, filter ProductFilter) ([]*Product, error)
    Save(ctx context.Context, product *Product) error
}

type OrderRepository interface {
    FindByID(ctx context.Context, id uuid.UUID) (*Order, error)
    FindByUserID(ctx context.Context, userID uuid.UUID) ([]*Order, error)
    Save(ctx context.Context, order *Order) error
}

🔄 Domain Events

// Domain Events
type DomainEvent interface {
    OccurredAt() time.Time
    EventType() string
}

type UserRegisteredEvent struct {
    UserID      uuid.UUID
    Email       string
    OccurredOn  time.Time
}

type OrderCreatedEvent struct {
    OrderID     uuid.UUID
    UserID      uuid.UUID
    TotalAmount decimal.Decimal
    OccurredOn  time.Time
}

type PaymentCompletedEvent struct {
    OrderID     uuid.UUID
    Amount      decimal.Decimal
    Method      string
    OccurredOn  time.Time
}

📋 Complete Domain Model

Lihat dokumentasi lengkap di Technical Specs.