DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Design Workflow Engine with Claude Code: State Machine, Approval Flow, Timeout

Introduction

Complex workflows like 'order→review→payment→shipping' — implement persistent state machines with XState + DB for resumable approval flows with timeouts. Let Claude Code design this.

CLAUDE.md Rules

## Workflow Engine Rules
- State machine: XState (externally configurable)
- Persist all transitions to DB (resumable on crash)
- Event-driven (external triggers for transitions)
- Approval timeout: 48 hours → auto-escalate
- Step failures: 3 retries then manual review
Enter fullscreen mode Exit fullscreen mode

Generated Implementation

export const orderWorkflowMachine = createMachine({
  id: 'orderWorkflow',
  initial: 'submitted',
  states: {
    submitted: { on: { AUTO_APPROVE: 'payment_pending', NEEDS_REVIEW: 'pending_approval' } },

    pending_approval: {
      after: { 172_800_000: { target: 'escalated' } }, // 48h timeout
      on: { APPROVE: 'payment_pending', REJECT: 'rejected' },
    },

    payment_pending: {
      invoke: {
        src: 'processPaymentService',
        onDone: 'fulfillment',
        onError: [{ cond: 'canRetry', target: 'payment_pending' }, { target: 'payment_failed' }],
      },
    },

    fulfillment: {
      type: 'parallel', // inventory + shipping in parallel
      states: {
        inventory: { states: { reserving: {}, reserved: { type: 'final' } } },
        shipping:  { states: { creating_label: {}, label_created: { type: 'final' } } },
      },
      onDone: 'shipped',
    },

    shipped: { type: 'final' },
  },
});

// DB persistence
async function sendEvent(instanceId: string, event: WorkflowEvent) {
  const instance = await prisma.workflowInstance.findUniqueOrThrow({ where: { id: instanceId } });
  const nextState = service.send(event);

  await prisma.$transaction([
    prisma.workflowInstance.update({ where: { id: instanceId }, data: { state: nextState.value } }),
    prisma.workflowTransition.create({
      data: { instanceId, fromState: instance.state, toState: nextState.value, event: event.type },
    }),
  ]);
}
Enter fullscreen mode Exit fullscreen mode

Summary

  1. XState machine serialized to DB: survive crashes, resume from last state
  2. parallel state: inventory + shipping run concurrently
  3. 48h timeout → auto-escalation with notifications
  4. All transitions logged for audit trail

Review with **Code Review Pack (¥980)* at prompt-works.jp*

myouga (@myougatheaxo) — Axolotl VTuber.

Top comments (0)