Skip to main content
Preview
Preview Feature — This feature is currently in preview and under active development. APIs and functionality may change. We recommend testing thoroughly before using in production.

Examples

Real-world feature patterns using the code-first API. For new conditional and iteration code, follow Building Features - Portable control flow.

Legacy examples

Some longer examples on this page demonstrate branchOverrides or native JavaScript control flow from the earlier recording API. Treat those examples as migration references. New Features must use ctx.branch/ctx.when, ctx.each(ctx.sampleInput...), portable Functions for runtime-sized algorithms, and ctx.transform for runtime-generated values.

E-Commerce Order Fulfillment

A complete order processing feature with payment, inventory, and notifications. Because the handler returns early when validation fails, use branchOverrides so the compiler records the payment and later steps; at runtime those steps run only when the condition holds.

await ductape.features.define({
tag: 'order-fulfillment',
name: 'Order Fulfillment',
description: 'Process customer orders from payment to delivery',
controlFlowMode: 'legacy',

options: {
timeout: 600000, // 10 minutes
rollback_strategy: 'reverse_all',
},

signals: {
'cancel-order': { input: { reason: 'string' } },
},

branchOverrides: { 'validate-order': { available: true } },

handler: async (ctx) => {
ctx.log.info('Starting order fulfillment', { orderId: ctx.input.orderId });

// Step 1: Validate order and check inventory
const validation = await ctx.step('validate-order', async () => {
const inventory = await ctx.api.run({
app: 'inventory-api',
event: 'check-availability',
input: { body: { items: ctx.input.items } },
});

return {
available: inventory.allAvailable,
unavailableItems: inventory.unavailableItems || [],
};
});

if (!validation.available) {
return {
success: false,
reason: 'items_unavailable',
unavailableItems: validation.unavailableItems,
};
}

// Step 2: Calculate totals and apply discounts
const pricing = await ctx.step('calculate-pricing', async () => {
const subtotal = ctx.input.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);

let discount = 0;
if (ctx.input.couponCode) {
const coupon = await ctx.api.run({
app: 'promotions-api',
event: 'validate-coupon',
input: { body: { code: ctx.input.couponCode } },
});
if (coupon.valid) {
discount = coupon.discountAmount;
}
}

const tax = (subtotal - discount) * 0.08; // 8% tax
const total = subtotal - discount + tax;

return { subtotal, discount, tax, total };
});

// Step 3: Process payment (with rollback)
const payment = await ctx.step(
'process-payment',
async () => {
return ctx.api.run({
app: 'stripe',
event: 'create-charge',
input: {
body: {
amount: Math.round(pricing.total * 100), // cents
currency: 'usd',
customer: ctx.input.customerId,
metadata: { orderId: ctx.input.orderId },
},
headers: {
'Idempotency-Key': `order-${ctx.input.orderId}-payment`,
},
},
retries: 3,
timeout: 30000,
});
},
async (result) => {
// Rollback: Refund the charge
await ctx.api.run({
app: 'stripe',
event: 'create-refund',
input: {
body: { charge: result.id, reason: 'order_cancelled' },
},
});
ctx.log.info('Payment refunded', { chargeId: result.id });
}
);

// Checkpoint after payment
await ctx.checkpoint('payment-complete', {
chargeId: payment.id,
amount: pricing.total,
});

// Step 4: Reserve inventory (with rollback)
await ctx.step(
'reserve-inventory',
async () => {
return ctx.api.run({
app: 'inventory-api',
event: 'reserve-items',
input: {
body: {
orderId: ctx.input.orderId,
items: ctx.input.items,
},
},
});
},
async () => {
// Rollback: Release reserved items
await ctx.api.run({
app: 'inventory-api',
event: 'release-items',
input: { body: { orderId: ctx.input.orderId } },
});
}
);

// Step 5: Create order record
const order = await ctx.step('create-order-record', async () => {
return ctx.database.insert({
database: 'orders-db',
event: 'create-order',
data: {
order_id: ctx.input.orderId,
customer_id: ctx.input.customerId,
items: ctx.input.items,
subtotal: pricing.subtotal,
discount: pricing.discount,
tax: pricing.tax,
total: pricing.total,
payment_id: payment.id,
status: 'confirmed',
created_at: new Date().toISOString(),
},
});
});

// Step 6: Send confirmation email (non-critical)
await ctx.step(
'send-confirmation-email',
async () => {
await ctx.notification.email({
notification: 'transactional',
event: 'order-confirmed',
recipients: [ctx.input.email],
subject: { orderId: ctx.input.orderId },
template: {
orderId: ctx.input.orderId,
items: ctx.input.items,
total: pricing.total,
estimatedDelivery: '3-5 business days',
},
});
},
null,
{ allow_fail: true }
);

// Step 7: Queue for warehouse fulfillment
await ctx.step('queue-fulfillment', async () => {
await ctx.messaging.produce({
event: 'warehouse-events:new-order',
message: {
orderId: ctx.input.orderId,
items: ctx.input.items,
shippingAddress: ctx.input.shippingAddress,
priority: ctx.input.isPrime ? 'high' : 'normal',
},
});
});

ctx.log.info('Order fulfilled successfully', {
orderId: ctx.input.orderId,
chargeId: payment.id,
});

return {
success: true,
orderId: ctx.input.orderId,
orderRecordId: order.id,
chargeId: payment.id,
total: pricing.total,
};
},
});

User Onboarding

Multi-step user registration with email verification:

await ductape.features.define({
tag: 'user-onboarding',
name: 'User Onboarding',

signals: {
'email-verified': { input: { code: 'string' } },
},

handler: async (ctx) => {
// Step 1: Create user account
const user = await ctx.step(
'create-user',
async () => {
return ctx.database.insert({
database: 'users-db',
event: 'create-user',
data: {
email: ctx.input.email,
name: ctx.input.name,
password_hash: ctx.input.passwordHash,
status: 'pending_verification',
created_at: new Date().toISOString(),
},
});
},
async (result) => {
// Rollback: Delete user if onboarding fails
await ctx.database.delete({
database: 'users-db',
event: 'delete-user',
where: { id: result.id },
});
}
);

// Step 2: Generate verification code
const verificationCode = ctx.transform.uuid();
ctx.setState('verificationCode', verificationCode);

// Step 3: Send verification email
await ctx.step('send-verification', async () => {
await ctx.notification.email({
notification: 'transactional',
event: 'email-verification',
recipients: [ctx.input.email],
subject: { appName: 'MyApp' },
template: {
name: ctx.input.name,
code: verificationCode,
expiresIn: '24 hours',
},
});
});

// Step 4: Wait for email verification
const verification = await ctx.waitForSignal('email-verified', {
timeout: '24h',
});

// Validate the code
if (verification.code !== ctx.getState('verificationCode')) {
await ctx.triggerRollback('Invalid verification code');
return { success: false, reason: 'invalid_code' };
}

// Step 5: Activate user account
await ctx.step('activate-user', async () => {
await ctx.database.update({
database: 'users-db',
event: 'update-user',
where: { id: user.id },
data: {
status: 'active',
verified_at: new Date().toISOString(),
},
});
});

// Step 6: Create user profile
await ctx.step('create-profile', async () => {
await ctx.database.insert({
database: 'profiles-db',
event: 'create-profile',
data: {
user_id: user.id,
display_name: ctx.input.name,
avatar_url: null,
bio: null,
},
});
});

// Step 7: Send welcome email (non-critical)
await ctx.step(
'send-welcome',
async () => {
await ctx.notification.email({
notification: 'transactional',
event: 'welcome',
recipients: [ctx.input.email],
template: {
name: ctx.input.name,
loginUrl: 'https://myapp.com/login',
},
});
},
null,
{ allow_fail: true }
);

return {
success: true,
userId: user.id,
email: ctx.input.email,
};
},
});

Document Processing Pipeline

Process uploaded documents with OCR and classification:

await ductape.features.define({
tag: 'document-pipeline',
name: 'Document Processing Pipeline',

options: {
timeout: 300000, // 5 minutes for large documents
},

handler: async (ctx) => {
ctx.log.info('Processing document', {
documentId: ctx.input.documentId,
fileName: ctx.input.fileName,
});

// Step 1: Download the document
const document = await ctx.step('download-document', async () => {
return ctx.storage.download({
storage: 'uploads',
event: 'get-document',
input: { file_key: ctx.input.fileKey },
});
});

// Step 2: Run OCR extraction
const ocrResult = await ctx.step(
'extract-text',
async () => {
return ctx.api.run({
app: 'ocr-service',
event: 'extract',
input: {
body: {
content: document.content,
contentType: document.content_type,
options: { language: 'en', detectLayout: true },
},
},
timeout: 60000,
});
},
null,
{ retries: 2 }
);

// Step 3: Classify document type
const classification = await ctx.step('classify-document', async () => {
return ctx.api.run({
app: 'ml-classifier',
event: 'classify',
input: {
body: {
text: ocrResult.text,
categories: ['invoice', 'receipt', 'contract', 'report', 'other'],
},
},
});
});

// Step 4: Extract structured data based on document type
const extractedData = await ctx.step('extract-data', async () => {
const extractionConfig = {
invoice: { fields: ['vendor', 'total', 'date', 'items'] },
receipt: { fields: ['store', 'total', 'date', 'items'] },
contract: { fields: ['parties', 'terms', 'date', 'signatures'] },
report: { fields: ['title', 'author', 'date', 'summary'] },
other: { fields: ['title', 'content'] },
};

return ctx.api.run({
app: 'data-extractor',
event: 'extract',
input: {
body: {
text: ocrResult.text,
documentType: classification.category,
fields: extractionConfig[classification.category],
},
},
});
});

// Step 5: Store processed document
const processedDoc = await ctx.step('store-result', async () => {
return ctx.database.insert({
database: 'documents-db',
event: 'store-processed',
data: {
original_file_key: ctx.input.fileKey,
file_name: ctx.input.fileName,
document_type: classification.category,
confidence: classification.confidence,
extracted_text: ocrResult.text,
extracted_data: extractedData,
processed_at: new Date().toISOString(),
},
});
});

// Step 6: Index for search
await ctx.step(
'index-document',
async () => {
await ctx.api.run({
app: 'search-api',
event: 'index',
input: {
body: {
id: processedDoc.id,
content: ocrResult.text,
metadata: {
type: classification.category,
fileName: ctx.input.fileName,
...extractedData,
},
},
},
});
},
null,
{ allow_fail: true }
);

// Step 7: Notify user
await ctx.step(
'notify-completion',
async () => {
await ctx.notification.push({
notification: 'app-notifications',
event: 'document-processed',
tokens: [ctx.input.deviceToken],
title: { fileName: ctx.input.fileName },
body: { documentType: classification.category },
data: { documentId: processedDoc.id },
});
},
null,
{ allow_fail: true }
);

return {
success: true,
documentId: processedDoc.id,
documentType: classification.category,
confidence: classification.confidence,
};
},
});

Subscription Billing

Recurring subscription billing with retry logic:

await ductape.features.define({
tag: 'subscription-billing',
name: 'Subscription Billing',

options: {
rollback_strategy: 'critical_only',
},

handler: async (ctx) => {
const { subscriptionId, customerId, amount } = ctx.input;

ctx.log.info('Processing subscription billing', { subscriptionId });

// Step 1: Get subscription details
const subscription = await ctx.step('get-subscription', async () => {
return ctx.database.query({
database: 'subscriptions-db',
event: 'get-subscription',
params: { id: subscriptionId },
});
});

if (!subscription || subscription.status !== 'active') {
return { success: false, reason: 'subscription_inactive' };
}

// Step 2: Get payment method
const paymentMethod = await ctx.step('get-payment-method', async () => {
return ctx.api.run({
app: 'stripe',
event: 'get-payment-method',
input: { params: { customerId } },
});
});

if (!paymentMethod.valid) {
// Notify about payment method issue
await ctx.step(
'notify-payment-issue',
async () => {
await ctx.notification.email({
notification: 'billing',
event: 'payment-method-invalid',
recipients: [subscription.email],
template: { updateUrl: 'https://app.com/billing' },
});
},
null,
{ allow_fail: true }
);

return { success: false, reason: 'invalid_payment_method' };
}

// Step 3: Attempt payment (with retries)
let paymentAttempt = 0;
let paymentResult = null;
let lastError = null;

while (paymentAttempt < 3 && !paymentResult) {
paymentAttempt++;
ctx.setState('paymentAttempt', paymentAttempt);

try {
paymentResult = await ctx.step(`payment-attempt-${paymentAttempt}`, async () => {
return ctx.api.run({
app: 'stripe',
event: 'create-charge',
input: {
body: {
amount: amount * 100,
currency: 'usd',
customer: customerId,
payment_method: paymentMethod.id,
metadata: {
subscriptionId,
attempt: paymentAttempt,
},
},
headers: {
'Idempotency-Key': `sub-${subscriptionId}-${ctx.feature_id}-${paymentAttempt}`,
},
},
});
});
} catch (error) {
lastError = error;
ctx.log.warn('Payment attempt failed', {
attempt: paymentAttempt,
error: error.message,
});

if (paymentAttempt < 3) {
// Wait before retry (exponential backoff)
await ctx.sleep(paymentAttempt * 2000);
}
}
}

if (!paymentResult) {
// All payment attempts failed
await ctx.step('mark-payment-failed', async () => {
await ctx.database.update({
database: 'subscriptions-db',
event: 'update-subscription',
where: { id: subscriptionId },
data: {
status: 'past_due',
failed_payments: (subscription.failed_payments || 0) + 1,
last_payment_error: lastError?.message,
},
});
});

await ctx.step(
'notify-payment-failed',
async () => {
await ctx.notification.email({
notification: 'billing',
event: 'payment-failed',
recipients: [subscription.email],
template: {
amount,
attempts: paymentAttempt,
updateUrl: 'https://app.com/billing',
},
});
},
null,
{ allow_fail: true }
);

return {
success: false,
reason: 'payment_failed',
attempts: paymentAttempt,
};
}

// Step 4: Record successful payment (critical)
await ctx.step(
'record-payment',
async () => {
return ctx.database.insert({
database: 'payments-db',
event: 'create-payment',
data: {
subscription_id: subscriptionId,
customer_id: customerId,
charge_id: paymentResult.id,
amount,
status: 'succeeded',
created_at: new Date().toISOString(),
},
});
},
null,
{ critical: true }
);

// Step 5: Update subscription
await ctx.step('update-subscription', async () => {
await ctx.database.update({
database: 'subscriptions-db',
event: 'update-subscription',
where: { id: subscriptionId },
data: {
last_payment_at: new Date().toISOString(),
next_billing_date: new Date(
Date.now() + 30 * 24 * 60 * 60 * 1000
).toISOString(),
failed_payments: 0,
},
});
});

// Step 6: Generate invoice
await ctx.step('generate-invoice', async () => {
const invoice = await ctx.api.run({
app: 'invoice-service',
event: 'generate',
input: {
body: {
subscriptionId,
chargeId: paymentResult.id,
amount,
},
},
});

return invoice;
});

// Step 7: Send receipt (non-critical)
await ctx.step(
'send-receipt',
async () => {
await ctx.notification.email({
notification: 'billing',
event: 'payment-receipt',
recipients: [subscription.email],
template: {
amount,
chargeId: paymentResult.id,
date: new Date().toLocaleDateString(),
},
});
},
null,
{ allow_fail: true }
);

return {
success: true,
chargeId: paymentResult.id,
amount,
nextBillingDate: new Date(
Date.now() + 30 * 24 * 60 * 60 * 1000
).toISOString(),
};
},
});

Approval Feature

Multi-level approval process with escalation:

await ductape.features.define({
tag: 'expense-approval',
name: 'Expense Approval',

signals: {
'manager-decision': { input: { approved: 'boolean', comments: 'string' } },
'director-decision': { input: { approved: 'boolean', comments: 'string' } },
'finance-decision': { input: { approved: 'boolean', comments: 'string' } },
},

queries: {
'getStatus': {
handler: (ctx) => ({
requestId: ctx.input.requestId,
amount: ctx.input.amount,
status: ctx.getState('status') || 'pending',
currentApprover: ctx.getState('currentApprover'),
approvals: ctx.getState('approvals') || [],
}),
},
},

handler: async (ctx) => {
const { requestId, employeeId, amount, description } = ctx.input;

ctx.setState('status', 'pending');
ctx.setState('approvals', []);

// Step 1: Create expense request
const request = await ctx.step('create-request', async () => {
return ctx.database.insert({
database: 'expenses-db',
event: 'create-request',
data: {
request_id: requestId,
employee_id: employeeId,
amount,
description,
status: 'pending_approval',
created_at: new Date().toISOString(),
},
});
});

// Step 2: Get approval chain
const approvalChain = await ctx.step('get-approval-chain', async () => {
// Determine required approvers based on amount
const chain = [];

chain.push({ level: 'manager', required: true });

if (amount > 1000) {
chain.push({ level: 'director', required: true });
}

if (amount > 5000) {
chain.push({ level: 'finance', required: true });
}

return chain;
});

ctx.setState('approvalChain', approvalChain);

// Step 3: Manager approval
ctx.setState('currentApprover', 'manager');

await ctx.step('notify-manager', async () => {
await ctx.notification.email({
notification: 'approvals',
event: 'approval-request',
recipients: [ctx.input.managerEmail],
template: {
employeeName: ctx.input.employeeName,
amount,
description,
approveUrl: `https://app.com/approve/${requestId}`,
},
});
});

const managerDecision = await ctx.waitForSignal('manager-decision', {
timeout: '48h',
});

ctx.setState('approvals', [
...ctx.getState('approvals'),
{
level: 'manager',
approved: managerDecision.approved,
comments: managerDecision.comments,
timestamp: Date.now(),
},
]);

if (!managerDecision.approved) {
await ctx.step('mark-rejected', async () => {
await ctx.database.update({
database: 'expenses-db',
event: 'update-request',
where: { request_id: requestId },
data: {
status: 'rejected',
rejected_by: 'manager',
rejection_reason: managerDecision.comments,
},
});
});

await ctx.step('notify-rejection', async () => {
await ctx.notification.email({
notification: 'approvals',
event: 'request-rejected',
recipients: [ctx.input.employeeEmail],
template: {
amount,
rejectedBy: 'Manager',
reason: managerDecision.comments,
},
});
});

return {
success: false,
status: 'rejected',
rejectedBy: 'manager',
reason: managerDecision.comments,
};
}

// Step 4: Director approval (if needed)
if (amount > 1000) {
ctx.setState('currentApprover', 'director');

await ctx.step('notify-director', async () => {
await ctx.notification.email({
notification: 'approvals',
event: 'approval-request',
recipients: [ctx.input.directorEmail],
template: {
employeeName: ctx.input.employeeName,
amount,
description,
managerApproved: true,
approveUrl: `https://app.com/approve/${requestId}`,
},
});
});

const directorDecision = await ctx.waitForSignal('director-decision', {
timeout: '48h',
});

ctx.setState('approvals', [
...ctx.getState('approvals'),
{
level: 'director',
approved: directorDecision.approved,
comments: directorDecision.comments,
timestamp: Date.now(),
},
]);

if (!directorDecision.approved) {
// Similar rejection handling...
return { success: false, status: 'rejected', rejectedBy: 'director' };
}
}

// Step 5: Finance approval (if needed)
if (amount > 5000) {
ctx.setState('currentApprover', 'finance');

await ctx.step('notify-finance', async () => {
await ctx.notification.email({
notification: 'approvals',
event: 'approval-request',
recipients: [ctx.input.financeEmail],
template: {
employeeName: ctx.input.employeeName,
amount,
description,
previousApprovals: ctx.getState('approvals'),
approveUrl: `https://app.com/approve/${requestId}`,
},
});
});

const financeDecision = await ctx.waitForSignal('finance-decision', {
timeout: '72h',
});

ctx.setState('approvals', [
...ctx.getState('approvals'),
{
level: 'finance',
approved: financeDecision.approved,
comments: financeDecision.comments,
timestamp: Date.now(),
},
]);

if (!financeDecision.approved) {
return { success: false, status: 'rejected', rejectedBy: 'finance' };
}
}

// Step 6: Mark as approved
ctx.setState('status', 'approved');

await ctx.step('mark-approved', async () => {
await ctx.database.update({
database: 'expenses-db',
event: 'update-request',
where: { request_id: requestId },
data: {
status: 'approved',
approved_at: new Date().toISOString(),
approvals: ctx.getState('approvals'),
},
});
});

// Step 7: Initiate reimbursement
await ctx.step('initiate-reimbursement', async () => {
await ctx.messaging.produce({
event: 'payroll-events:process-reimbursement',
message: {
requestId,
employeeId,
amount,
approvals: ctx.getState('approvals'),
},
});
});

// Step 8: Notify employee
await ctx.step('notify-approval', async () => {
await ctx.notification.email({
notification: 'approvals',
event: 'request-approved',
recipients: [ctx.input.employeeEmail],
template: {
amount,
description,
expectedPayment: 'Next payroll cycle',
},
});
});

return {
success: true,
status: 'approved',
approvals: ctx.getState('approvals'),
};
},
});

Data Sync Feature

Synchronize data between systems with conflict resolution:

await ductape.features.define({
tag: 'data-sync',
name: 'Data Synchronization',

options: {
timeout: 600000,
rollback_strategy: 'to_checkpoint',
},

handler: async (ctx) => {
const { sourceSystem, targetSystem, entityType, batchSize = 100 } = ctx.input;

ctx.log.info('Starting data sync', { sourceSystem, targetSystem, entityType });

// Step 1: Get last sync checkpoint
const lastSync = await ctx.step('get-last-sync', async () => {
const result = await ctx.database.query({
database: 'sync-db',
event: 'get-sync-state',
params: { source: sourceSystem, target: targetSystem, entity: entityType },
});
return result[0] || { lastSyncedAt: null, lastSyncedId: null };
});

// Step 2: Fetch changed records from source
const sourceRecords = await ctx.step('fetch-source-records', async () => {
return ctx.api.run({
app: sourceSystem,
event: 'get-records',
input: {
body: {
entityType,
modifiedAfter: lastSync.lastSyncedAt,
limit: batchSize,
},
},
});
});

if (sourceRecords.records.length === 0) {
ctx.log.info('No records to sync');
return { success: true, synced: 0, conflicts: 0 };
}

ctx.setState('totalRecords', sourceRecords.records.length);
ctx.setState('syncedRecords', 0);
ctx.setState('conflicts', []);

await ctx.checkpoint('records-fetched', {
count: sourceRecords.records.length,
});

// Step 3: Process each record
for (const record of sourceRecords.records) {
await ctx.step(`sync-record-${record.id}`, async () => {
// Check for existing record in target
const existing = await ctx.api.run({
app: targetSystem,
event: 'get-record',
input: { params: { id: record.id } },
});

if (existing && existing.modifiedAt > record.modifiedAt) {
// Conflict: target is newer
const conflicts = ctx.getState('conflicts') || [];
conflicts.push({
recordId: record.id,
sourceModified: record.modifiedAt,
targetModified: existing.modifiedAt,
});
ctx.setState('conflicts', conflicts);
ctx.log.warn('Sync conflict detected', { recordId: record.id });
return { skipped: true, reason: 'conflict' };
}

// Sync the record
if (existing) {
await ctx.api.run({
app: targetSystem,
event: 'update-record',
input: { body: record },
});
} else {
await ctx.api.run({
app: targetSystem,
event: 'create-record',
input: { body: record },
});
}

const synced = (ctx.getState('syncedRecords') || 0) + 1;
ctx.setState('syncedRecords', synced);

return { synced: true };
});
}

// Step 4: Update sync state
const lastRecord = sourceRecords.records[sourceRecords.records.length - 1];
await ctx.step('update-sync-state', async () => {
await ctx.database.update({
database: 'sync-db',
event: 'update-sync-state',
where: { source: sourceSystem, target: targetSystem, entity: entityType },
data: {
lastSyncedAt: new Date().toISOString(),
lastSyncedId: lastRecord.id,
recordsSynced: ctx.getState('syncedRecords'),
conflictsFound: ctx.getState('conflicts')?.length || 0,
},
});
});

// Step 5: Report conflicts if any
const conflicts = ctx.getState('conflicts') || [];
if (conflicts.length > 0) {
await ctx.step(
'report-conflicts',
async () => {
await ctx.notification.email({
notification: 'system-alerts',
event: 'sync-conflicts',
recipients: [ctx.input.adminEmail],
template: {
sourceSystem,
targetSystem,
entityType,
conflictCount: conflicts.length,
conflicts,
},
});
},
null,
{ allow_fail: true }
);
}

return {
success: true,
synced: ctx.getState('syncedRecords'),
conflicts: conflicts.length,
hasMore: sourceRecords.hasMore,
};
},
});

Tips for Building Features

1. Design for Failure

Always assume steps can fail. Define rollback handlers for critical operations:

await ctx.step('critical-op', doWork, undoWork, { critical: true });

2. Use Checkpoints for Long Features

Break long features into phases:

await ctx.checkpoint('phase-1-complete');

3. Keep Steps Atomic

Each step should do one thing well:

// Good: Single responsibility
await ctx.step('charge-card', chargeCard);
await ctx.step('send-receipt', sendReceipt);

// Bad: Multiple responsibilities
await ctx.step('process-payment', async () => {
await chargeCard();
await sendReceipt();
await updateInventory();
});

4. Use allow_fail for Non-Critical Steps

await ctx.step('analytics', trackEvent, null, { allow_fail: true });

5. Implement Idempotency

Use idempotency keys for external operations:

await ctx.api.run({
app: 'stripe',
event: 'charge',
input: {
headers: { 'Idempotency-Key': `${ctx.feature_id}-payment` },
},
});