Skill

business-logic-coder

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

From majestic-rails
Install
1
Run in your terminal
$
npx claudepluginhub majesticlabs-dev/majestic-marketplace --plugin majestic-rails
Tool Access

This skill uses the workspace's default tool permissions.

Supporting Assets
View in Repository
references/aasm-patterns.md
references/active-interaction.md
Skill Content

Business Logic Patterns

Orchestrator for structured business logic in Rails.

Skill Routing

NeedSkillUse When
Typed operationsactive-interaction-coderCreating business operations, refactoring service objects
State machinesaasm-coderImplementing 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-PatternProblemSolution
Long transactionsLock contentionSplit into smaller units
API calls insideTimeout blocks DBCall outside, then transact
User input insideIndefinite locksValidate first, transact last
Nested transactionsSavepoint confusionUse 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
Stats
Parent Repo Stars30
Parent Repo Forks6
Last CommitMar 15, 2026