Agent Skills: Business Logic Patterns

Implement business logic with ActiveInteraction and AASM state machines. Routes to specialized skills for typed operations and state management.

UncategorizedID: majesticlabs-dev/majestic-marketplace/business-logic-coder

Install this agent skill to your local

pnpm dlx add-skill https://github.com/majesticlabs-dev/majestic-marketplace/tree/HEAD/plugins/majestic-rails/skills/business-logic-coder

Skill Files

Browse the full folder contents for business-logic-coder.

Download Skill

Loading file tree…

plugins/majestic-rails/skills/business-logic-coder/SKILL.md

Skill Metadata

Name
business-logic-coder
Description
Implement business logic with ActiveInteraction and AASM state machines. Routes to specialized skills for typed operations and state management.

Business Logic Patterns

Orchestrator for structured business logic in Rails.

Skill Routing

| Need | Skill | Use When | |------|-------|----------| | Typed operations | active-interaction-coder | Creating business operations, refactoring service objects | | State machines | aasm-coder | Implementing workflows, managing state transitions |

When to Use Each

ActiveInteraction

Use for operations - things that happen once:

  • User registration
  • Order placement
  • Payment processing
  • Data imports
  • Report generation
# Example: One-time operation with typed inputs
outcome = Users::Create.run(email: email, name: name)

AASM

Use for state management - things with lifecycle:

  • Order status (pending → paid → shipped)
  • Subscription state (trial → active → cancelled)
  • Document workflow (draft → review → published)
  • Task status (todo → in_progress → done)
# Example: Stateful entity with transitions
order.pay!  # pending → paid
order.ship! # paid → shipped

Combined Pattern

Often used together - interactions trigger state changes:

module Orders
  class Process < ActiveInteraction::Base
    object :order, class: Order

    def execute
      order.process!  # AASM transition
      fulfill_order(order)
      order
    end
  end
end

Setup

# Gemfile
gem "active_interaction", "~> 5.3"
gem "aasm", "~> 5.5"

Quick Reference

ActiveInteraction:

  • .run - Returns outcome (check .valid?)
  • .run! - Raises on failure
  • compose - Call nested interactions

AASM:

  • .event! - Transition or raise
  • .event - Transition or return false
  • .may_event? - Check if transition valid
  • .aasm.events - List available events

Transaction Boundaries

When business logic involves multi-step database operations, enforce proper transaction boundaries.

Atomic Operations

# PROBLEM: Partial failure leaves inconsistent state
def transfer_funds(from, to, amount)
  from.update!(balance: from.balance - amount)
  to.update!(balance: to.balance + amount)  # May fail!
end

# SOLUTION: Transaction wrapper with locking
def transfer_funds(from, to, amount)
  ActiveRecord::Base.transaction do
    from.lock!
    to.lock!
    from.update!(balance: from.balance - amount)
    to.update!(balance: to.balance + amount)
  end
end

Isolation Levels

# Default: READ COMMITTED (each query sees latest committed data)
# REPEATABLE READ: All reads see same snapshot
ActiveRecord::Base.transaction(isolation: :repeatable_read) do
  # Consistent reads for reports
end

# SERIALIZABLE: Full isolation (may cause serialization failures)
ActiveRecord::Base.transaction(isolation: :serializable) do
  # Strictest isolation, retry on failure
end

Deadlock Prevention

Rules:

  1. Lock records in consistent order (by ID ascending)
  2. Keep transactions short
  3. No user input inside transactions
  4. No external API calls inside transactions
# PROBLEM: Deadlock risk (inconsistent lock order)
def swap_owners(item_a, item_b)
  transaction do
    item_a.lock!  # Thread 1 locks A
    item_b.lock!  # Thread 2 locks B -> deadlock!
  end
end

# SOLUTION: Consistent lock order
def swap_owners(item_a, item_b)
  items = [item_a, item_b].sort_by(&:id)
  transaction do
    items.each(&:lock!)
    # Safe: always locks lower ID first
  end
end

Transaction Anti-Patterns

| Anti-Pattern | Problem | Solution | |--------------|---------|----------| | Long transactions | Lock contention | Split into smaller units | | API calls inside | Timeout blocks DB | Call outside, then transact | | User input inside | Indefinite locks | Validate first, transact last | | Nested transactions | Savepoint confusion | Use requires_new: true explicitly |

Nested Transactions

# PROBLEM: Inner rollback doesn't work as expected
transaction do
  create_order!
  transaction do  # This is a savepoint, not new transaction
    charge_card!  # Failure rolls back to savepoint only
  end
end

# SOLUTION: Explicit new transaction
transaction do
  create_order!
  transaction(requires_new: true) do
    charge_card!  # Failure rolls back only this block
  end
end

Related Skills

  • event-sourcing-coder - Record domain events from state transitions