# Maestro Pattern

## Overview

The Maestro Pattern is the core business logic orchestration pattern in this framework. It provides a structured approach to implementing complex business operations through sequential step execution with clear input/output contracts.

## Pattern Principles

### Single Responsibility
Each Mae (Maestro module) handles one specific business operation:
- `CreateGardenMae` - Creates a new garden
- `UpdateUserProfileMae` - Updates user profile information
- `ProcessOrderMae` - Handles order processing workflow

### Sequential Execution
Mae modules execute business logic in defined sequential steps:
1. **Validation** - Input validation and business rule checking
2. **Preparation** - Data transformation and preparation
3. **Persistence** - Database operations and state changes
4. **Post-Processing** - Notifications, logging, cleanup
5. **Response** - Result formatting and return

### Explicit Contracts
Mae modules define clear input and output contracts:
```go
type CreateGardenMaeInput struct {
    Form *forms.CreateGardenForm
    UserId string
}

type CreateGardenMaeOutput struct {
    Garden *mdl.Garden
    Success bool
}
```

## Mae Structure

### Basic Mae Template
```go
package mae

type CreateGardenMae struct {
    // Service dependencies
    GardenFetcher   *fetchers.GardenFetcher
    GardenHandler   *handlers.GardenHandler
    GardenMolder    *molders.CreateGardenFormMolder
    UserFetcher     *fetchers.UserFetcher

    // Utility dependencies
    Logger *logger.Logger
    Time   time.Time
}

func (this *CreateGardenMae) Execute(ctx context.Context, input *maes.CreateGardenMaeInput) (*maes.CreateGardenMaeOutput, error) {
    // Step 1: Validate input
    if err := this.validateInput(input); err != nil {
        return nil, err
    }

    // Step 2: Check business rules
    if err := this.checkBusinessRules(ctx, input); err != nil {
        return nil, err
    }

    // Step 3: Transform data
    garden := this.prepareGarden(input)

    // Step 4: Persist to database
    createdGarden, err := this.GardenHandler.Create(ctx, garden, nil)
    if err != nil {
        return nil, err
    }

    // Step 5: Post-processing
    this.Logger.Info("Garden created successfully", "garden_id", createdGarden.Id)

    return &maes.CreateGardenMaeOutput{
        Garden:  createdGarden,
        Success: true,
    }, nil
}
```

### Step Methods
Mae modules break down execution into focused step methods:

```go
func (this *CreateGardenMae) validateInput(input *maes.CreateGardenMaeInput) error {
    if input.Form == nil {
        return erro.N("Form is required")
    }

    if input.Form.Name == "" {
        return erro.N("Garden name is required")
    }

    if input.UserId == "" {
        return erro.N("User ID is required")
    }

    return nil
}

func (this *CreateGardenMae) checkBusinessRules(ctx context.Context, input *maes.CreateGardenMaeInput) error {
    // Check if user exists
    user, exists, err := this.UserFetcher.FindOneById(ctx, input.UserId, nil)
    if err != nil {
        return err
    }
    if !exists {
        return erro.N("User not found")
    }

    // Check user's garden limit
    mod := this.GardenFetcher.Mod()
    mod.ExactStringValueFilter("user_id", input.UserId)
    gardens, err := this.GardenFetcher.FindAll(ctx, mod)
    if err != nil {
        return err
    }

    if len(gardens) >= user.MaxGardens {
        return erro.N("User has reached maximum garden limit")
    }

    return nil
}

func (this *CreateGardenMae) prepareGarden(input *maes.CreateGardenMaeInput) *mdl.Garden {
    garden := &mdl.Garden{}
    garden, _ = this.GardenMolder.ToEntity(input.Form, garden)
    garden.UserId = input.UserId
    garden.CreatedAt = this.Time.Now()
    garden.UpdatedAt = this.Time.Now()
    return garden
}
```

## Mae Input/Output Structures

### Input Structure Pattern
```go
// src/dat/maes/create_garden_mae.go
package maes

type CreateGardenMaeInput struct {
    Form   *forms.CreateGardenForm  // User input
    UserId string                   // Context data
    Options *CreateGardenOptions    // Operation options (optional)
}

type CreateGardenOptions struct {
    SkipValidation bool
    SendEmail      bool
    CreateDefault  bool
}
```

### Output Structure Pattern
```go
type CreateGardenMaeOutput struct {
    Garden    *mdl.Garden           // Primary result
    Success   bool                  // Operation success flag
    Messages  []string              // User messages
    Metadata  map[string]interface{} // Additional data
}
```

## Advanced Mae Patterns

### Transaction Management
```go
func (this *CreateGardenWithPlantsMae) Execute(ctx context.Context, input *maes.CreateGardenWithPlantsMaeInput) (*maes.CreateGardenWithPlantsMaeOutput, error) {
    // Begin transaction
    tx, err := this.SqlDb.Begin(ctx)
    if err != nil {
        return nil, err
    }
    defer tx.Rollback() // Will be no-op if committed

    // Step 1: Create garden
    handlerMod := &handler.HandlerMod{Tx: tx}
    garden, err := this.GardenHandler.Create(ctx, input.Garden, handlerMod)
    if err != nil {
        return nil, err
    }

    // Step 2: Create plants
    for _, plantForm := range input.PlantForms {
        plant := this.preparePlant(plantForm, garden.Id)
        _, err := this.PlantHandler.Create(ctx, plant, handlerMod)
        if err != nil {
            return nil, err
        }
    }

    // Commit transaction
    if err := tx.Commit(); err != nil {
        return nil, err
    }

    return &maes.CreateGardenWithPlantsMaeOutput{
        Garden:  garden,
        Success: true,
    }, nil
}
```

### Cross-Entity Operations
```go
func (this *TransferGardenOwnershipMae) Execute(ctx context.Context, input *maes.TransferGardenOwnershipMaeInput) (*maes.TransferGardenOwnershipMaeOutput, error) {
    // Step 1: Validate both users exist
    currentOwner, err := this.validateUser(ctx, input.CurrentOwnerId)
    if err != nil {
        return nil, err
    }

    newOwner, err := this.validateUser(ctx, input.NewOwnerId)
    if err != nil {
        return nil, err
    }

    // Step 2: Validate garden ownership
    garden, err := this.validateGardenOwnership(ctx, input.GardenId, input.CurrentOwnerId)
    if err != nil {
        return nil, err
    }

    // Step 3: Check new owner capacity
    if err := this.checkOwnerCapacity(ctx, input.NewOwnerId); err != nil {
        return nil, err
    }

    // Step 4: Transfer ownership
    garden.UserId = input.NewOwnerId
    updatedGarden, err := this.GardenHandler.Update(ctx, garden, nil)
    if err != nil {
        return nil, err
    }

    // Step 5: Update related entities
    if err := this.updateRelatedEntities(ctx, garden.Id, input.NewOwnerId); err != nil {
        return nil, err
    }

    // Step 6: Send notifications
    this.sendTransferNotifications(ctx, currentOwner, newOwner, garden)

    return &maes.TransferGardenOwnershipMaeOutput{
        Garden:      updatedGarden,
        PreviousOwner: currentOwner,
        NewOwner:    newOwner,
        Success:     true,
    }, nil
}
```

### Mae Composition
```go
func (this *CompleteGardenSetupMae) Execute(ctx context.Context, input *maes.CompleteGardenSetupMaeInput) (*maes.CompleteGardenSetupMaeOutput, error) {
    // Step 1: Create garden
    createGardenOutput, err := this.CreateGardenMae.Execute(ctx, &maes.CreateGardenMaeInput{
        Form:   input.GardenForm,
        UserId: input.UserId,
    })
    if err != nil {
        return nil, err
    }

    // Step 2: Add default plants
    for _, plantForm := range input.DefaultPlants {
        plantForm.GardenId = createGardenOutput.Garden.Id
        _, err := this.CreatePlantMae.Execute(ctx, &maes.CreatePlantMaeInput{
            Form: plantForm,
        })
        if err != nil {
            // Log error but continue
            this.Logger.Error("Failed to create default plant", "error", err)
        }
    }

    // Step 3: Setup garden tasks
    if err := this.setupDefaultTasks(ctx, createGardenOutput.Garden.Id); err != nil {
        this.Logger.Error("Failed to setup default tasks", "error", err)
    }

    return &maes.CompleteGardenSetupMaeOutput{
        Garden:  createGardenOutput.Garden,
        Success: true,
    }, nil
}
```

## Error Handling in Maes

### Structured Error Response
```go
type MaeError struct {
    Code     string                 `json:"code"`
    Message  string                 `json:"message"`
    Field    string                 `json:"field,omitempty"`
    Context  map[string]interface{} `json:"context,omitempty"`
}

func (this *CreateGardenMae) validateBusinessRules(ctx context.Context, input *maes.CreateGardenMaeInput) error {
    // Check garden name uniqueness
    existing, _, err := this.GardenFetcher.FindByName(ctx, input.Form.Name, nil)
    if err != nil {
        return &MaeError{
            Code:    "database_error",
            Message: "Failed to check garden name uniqueness",
            Context: map[string]interface{}{
                "operation": "find_by_name",
                "name":      input.Form.Name,
            },
        }
    }

    if existing != nil {
        return &MaeError{
            Code:    "validation_error",
            Message: "Garden name already exists",
            Field:   "name",
            Context: map[string]interface{}{
                "existing_id": existing.Id,
            },
        }
    }

    return nil
}
```

## Mae Testing Patterns

### Unit Testing Structure
```go
func TestCreateGardenMae_Success(t *testing.T) {
    // Arrange
    ctx := context.Background()
    mae := setupCreateGardenMae(t)

    input := &maes.CreateGardenMaeInput{
        Form: &forms.CreateGardenForm{
            Name:        "Test Garden",
            Description: "A test garden",
        },
        UserId: "user123",
    }

    // Act
    output, err := mae.Execute(ctx, input)

    // Assert
    require.NoError(t, err)
    assert.True(t, output.Success)
    assert.Equal(t, "Test Garden", output.Garden.Name)
    assert.NotEmpty(t, output.Garden.Id)
}

func TestCreateGardenMae_ValidationError(t *testing.T) {
    // Arrange
    mae := setupCreateGardenMae(t)
    input := &maes.CreateGardenMaeInput{
        Form: &forms.CreateGardenForm{
            Name: "", // Invalid: empty name
        },
        UserId: "user123",
    }

    // Act
    output, err := mae.Execute(context.Background(), input)

    // Assert
    assert.Error(t, err)
    assert.Nil(t, output)
    assert.Contains(t, err.Error(), "name is required")
}
```

### Integration Testing
```go
func TestCreateGardenMae_Integration(t *testing.T) {
    // Setup real database and services
    db := setupTestDatabase(t)
    container := setupTestContainer(t, db)
    mae := container.CreateGardenMae

    // Test complete flow
    input := createValidInput()
    output, err := mae.Execute(context.Background(), input)

    // Verify database state
    garden := mustFindGardenInDb(t, db, output.Garden.Id)
    assert.Equal(t, input.Form.Name, garden.Name)
}
```

## Mae Best Practices

### Design Guidelines
1. **Single Business Operation** - Each Mae handles one coherent business operation
2. **Clear Steps** - Break complex operations into focused step methods
3. **Input Validation** - Always validate input early and comprehensively
4. **Error Context** - Provide detailed error context for debugging
5. **Transaction Boundaries** - Use transactions for multi-entity operations

### Implementation Guidelines
1. **Dependency Injection** - Inject all required services through constructor
2. **Context Propagation** - Pass context through all service calls
3. **Logging** - Log significant operations and errors
4. **Testing** - Write both unit and integration tests
5. **Documentation** - Document business rules and edge cases

### Performance Considerations
1. **Batch Operations** - Use batch operations when processing multiple entities
2. **Lazy Loading** - Only load data that's actually needed
3. **Connection Management** - Proper database connection handling
4. **Memory Management** - Avoid holding large datasets in memory

## LLM Mae Development Notes

When implementing Mae modules:
- Start with input/output structure definition
- Break complex operations into sequential steps
- Always validate input and business rules
- Use explicit error types with context
- Test both success and failure scenarios
- Follow transaction patterns for data consistency
- Compose Maes for complex workflows