# @candoa/workflows

Self-contained, type-safe workflow SDK for Candoa with Copilot-friendly syntax. Define chat workflows with triggers, actions, and full TypeScript support - no external dependencies required.

## 🚀 Features

- **Copilot-friendly syntax** - Optimized for GitHub Copilot autocompletion
- **Type-safe** - Full TypeScript support with parameter validation
- **Builder pattern** - Fluent API with method chaining
- **Template variables** - Dynamic value substitution with `{{variableName}}`
- **Pre-built actions** - Common workflow actions ready to use
- **Self-contained** - No external dependencies, all types included
- **Database integration** - Seamless integration with Candoa CRM
- **Sync command** - Deploy workflows to database with `pnpm run sync-workflows`

## 📦 Installation

```bash
npm install @candoa/workflows
# or
pnpm add @candoa/workflows
```

## 🔥 Quick Start

```typescript
import { workflow, collectFirstName, saveToContact } from '@candoa/workflows'

export default workflow('welcome-new-user', {
  description: "Collects the user's first name when they start a chat",
})
  .on('chat.started')
  .use(
    collectFirstName({ prompt: "Hi! What's your first name?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
  )
```

## 🧠 Core Concepts

### Workflow Definition

A workflow consists of:

1. **Name** - Unique identifier for the workflow
2. **Description** - Optional documentation
3. **Trigger** - Event that starts the workflow
4. **Actions** - Sequence of operations to execute

### Template Variables

Use template variables to pass data between actions:

```typescript
workflow('collect-contact-info')
  .on('chat.started')
  .use(
    collectFirstName({ prompt: "What's your first name?" }),
    collectEmail({ prompt: "What's your email address?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
    saveToContact({ field: 'email', value: '{{email}}' }),
    sendMessage({
      message: "Thanks {{firstName}}! I've saved your information.",
    }),
  )
```

## 🎯 Triggers

Available trigger types with full TypeScript autocompletion:

- `chat.started` - When a new chat session begins
- `chat.ended` - When a chat session ends
- `message.received` - When user sends a message
- `intent.detected` - When AI detects specific intent
- `sentiment.negative` - When negative sentiment is detected
- `payment.failed` - When a payment fails
- `user.signup` - When a user signs up
- `custom.event` - For custom events

## ⚡ Actions

### Data Collection

```typescript
// Collect user information
collectFirstName({ prompt: "What's your first name?" })
collectLastName({ prompt: "What's your last name?" })
collectEmail({ prompt: "What's your email address?" })

// Save to contact record
saveToContact({ field: 'firstName', value: '{{firstName}}' })
saveToContact({ field: 'email', value: '{{email}}' })
```

### Communication

```typescript
// Send messages
sendMessage({ message: 'Hello {{firstName}}!' })
sendMessage({ message: 'Please wait...', delay: 2000 })

// Send emails
sendEmail({
  to: '{{email}}',
  subject: 'Welcome to our platform!',
  body: 'Hi {{firstName}}, welcome aboard!',
})
```

### Workflow Control

```typescript
// Wait for a period
wait({ duration: 5, unit: 'seconds' })

// Conditional logic
conditional({
  condition: "{{sentiment}} == 'negative'",
  trueAction: handoffToHuman({ reason: 'Negative sentiment detected' }),
  falseAction: sendMessage({ message: 'How else can I help you?' }),
})

// Hand off to human agent
handoffToHuman({
  reason: 'Complex issue requiring human assistance',
})
```

### Task Management

```typescript
// Create tasks
createTask({
  title: 'Follow up with {{firstName}}',
  description: 'User expressed interest in premium features',
})

// Add tags
addTags({
  tags: ['new-user', 'interested'],
  target: 'contact',
})
```

## 🗄️ Database Integration

### Workflow Storage

Workflows are stored in your `workflows` table:

```sql
CREATE TABLE "workflow" (
  "id" text PRIMARY KEY,
  "projectId" text NOT NULL REFERENCES "project"("id"),
  "name" text NOT NULL,
  "workflowData" json NOT NULL,  -- SDK data stored here
  "createdAt" timestamp DEFAULT now(),
  "updatedAt" timestamp DEFAULT now()
);
```

### Manual Database Integration

```typescript
import {
  prepareWorkflowForDatabase,
  validateWorkflowCompatibility,
} from '@candoa/workflows'

// 1. Define your workflow
const welcomeWorkflow = workflow('welcome-new-user', {
  description: "Collects the user's first name when they start a chat",
})
  .on('chat.started')
  .use(
    collectFirstName({ prompt: "Hi! What's your first name?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
  )

// 2. Validate workflow
const validation = validateWorkflowCompatibility(welcomeWorkflow)
if (!validation.isValid) {
  console.error('Validation errors:', validation.errors)
  return
}

// 3. Prepare for database
const dbData = prepareWorkflowForDatabase(welcomeWorkflow, projectId)

// 4. Insert into database
await db.insert(workflows).values({
  id: crypto.randomUUID(),
  name: dbData.name,
  projectId: dbData.projectId,
  workflowData: dbData.workflowData,
})
```

## 🔄 Workflow Sync System

### Quick Sync

Create workflows in files and sync them to your database:

```bash
# Sync all workflows to your project
pnpm run sync-workflows --project-id=your-project-uuid

# Preview changes without applying them
pnpm run sync-workflows --project-id=your-project-uuid --dry-run

# Force overwrite existing workflows
pnpm run sync-workflows --project-id=your-project-uuid --force
```

### Directory Structure

The sync script discovers workflows in these locations:

```
packages/workflows/
├── examples/               # 📁 Example workflows (use as templates)
│   ├── welcome.ts
│   ├── candoa-integration.ts
│   └── advanced-workflows.ts
└── scripts/
    └── sync-workflows.ts   # 🔧 Sync script
```

### Workflow File Format

Export workflows from your files:

```typescript
// workflows/my-workflows.ts
import { workflow, sendMessage, collectFirstName } from '@candoa/workflows'

// ✅ Default export
export default workflow('welcome', {
  description: 'Welcome new users',
})
  .on('chat.started')
  .use(
    sendMessage({ message: 'Welcome!' }),
    collectFirstName({ prompt: "What's your name?" }),
  )

// ✅ Named exports
export const supportFlow = workflow('support-flow', {
  description: 'Handle support requests',
})
  .on('intent.detected')
  .use(sendMessage({ message: 'I can help with that!' }))
```

### Sync Output

```
🔄 Candoa Workflow Sync
========================
📁 Project ID: 0e8b8d5e-cade-4bf5-9e9f-c9e55a5d5ca0

📋 Found 1 workflow file:
   - /examples/welcome.ts

🔍 Processing: /examples/welcome.ts
   📝 Syncing workflow: new-user-onboarding
   ✅ Created: new-user-onboarding
   📝 Syncing workflow: frustration-escalation
   ✅ Created: frustration-escalation

📊 Sync Summary
===============
✅ Created: 2
🔄 Updated: 0
⏭️  Skipped: 1
❌ Errors: 0

🎉 Successfully synced 2 workflows!
```

## 🎨 Integration with Candoa Systems

### Contact Management

Works with your existing contact schema:

```typescript
const contactWorkflow = workflow('contact-creation', {
  description: 'Create comprehensive contact records',
})
  .on('chat.started')
  .use(
    collectFirstName({ prompt: "What's your first name?" }),
    collectEmail({ prompt: "What's your email?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
    saveToContact({ field: 'email', value: '{{email}}' }),
    addTags({ tags: ['new-contact'], target: 'contact' }),
  )
```

### Automated Handoff Integration

Enhances your existing handoff system:

```typescript
const smartHandoff = workflow('smart-handoff', {
  description: 'Intelligent handoff with data collection',
})
  .on('sentiment.negative')
  .use(
    sendMessage({
      message: 'Let me connect you with a human agent.',
    }),
    collectFirstName({ prompt: "What's your name?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
    handoffToHuman({
      reason: 'Negative sentiment with contact data',
    }),
  )
```

### Execution Context

Build context from your database:

```typescript
import { buildWorkflowContext } from '@candoa/workflows'

const context = buildWorkflowContext({
  conversationId: conversation.id,
  contactData: {
    id: contact.id,
    firstName: contact.name?.split(' ')[0],
    email: contact.email,
    phoneNumber: contact.phoneNumber,
  },
  messageHistory: messages.map((msg) => ({
    role: msg.role,
    content: msg.content,
    createdAt: msg.createdAt,
  })),
  triggerData: {
    sentiment: 'negative',
    intent: 'billing_question',
  },
})
```

## 📖 Advanced Examples

### Customer Onboarding Flow

```typescript
export const customerOnboarding = workflow('customer-onboarding', {
  description: 'Complete customer onboarding process',
})
  .on('user.signup')
  .use(
    sendMessage({
      message: "Welcome! Let's get you set up in just a few steps.",
    }),
    collectFirstName({ prompt: "First, what's your first name?" }),
    collectEmail({ prompt: "What's your email address?" }),
    saveToContact({ field: 'firstName', value: '{{firstName}}' }),
    saveToContact({ field: 'email', value: '{{email}}' }),
    sendMessage({ message: 'Perfect! Welcome aboard {{firstName}} 🎉' }),
    addTags({ tags: ['onboarded'], target: 'contact' }),
    createTask({
      title: 'Send welcome materials to {{firstName}}',
      assignee: 'onboarding-team',
    }),
  )
```

### Support Escalation

```typescript
export const supportEscalation = workflow('support-escalation', {
  description: 'Escalate negative sentiment to human agents',
})
  .on('sentiment.negative')
  .use(
    sendMessage({
      message:
        'I sense you might be frustrated. Let me get you connected with a human agent.',
    }),
    handoffToHuman({
      reason: 'Negative sentiment detected',
    }),
    createTask({
      title: 'Urgent: Frustrated customer needs assistance',
    }),
    addTags({ tags: ['escalated', 'urgent'], target: 'conversation' }),
  )
```

### Payment Recovery

```typescript
export const paymentRecovery = workflow('payment-recovery', {
  description: 'Handle failed payment with automated retry',
})
  .on('payment.failed')
  .use(
    sendMessage({
      message:
        'It looks like there was an issue with your payment. Let me help you resolve this.',
    }),
    wait({ duration: 1, unit: 'hours' }),
    sendEmail({
      to: '{{email}}',
      subject: 'Payment Issue - Action Required',
      body: 'Hi {{firstName}}, we had trouble processing your payment. Please update your payment method.',
    }),
    createTask({
      title: 'Follow up on failed payment for {{firstName}}',
      description: 'Payment failed, email sent, needs follow-up',
    }),
  )
```

## 📊 Analytics & Monitoring

### Workflow Performance Tracking

```typescript
import { extractWorkflowMetrics, updateWorkflowStats } from '@candoa/workflows'

// After workflow execution
const metrics = extractWorkflowMetrics(workflowDef, {
  success: true,
  executionTime: 1250, // milliseconds
  actionsCompleted: 5,
})

// Update workflow stats in database
const updatedWorkflowData = updateWorkflowStats(
  existingWorkflow.workflowData,
  true, // was successful
)

await db
  .update(workflows)
  .set({ workflowData: updatedWorkflowData })
  .where(eq(workflows.id, workflowId))
```

## 🛠️ Best Practices

### Organization

- Keep production workflows in `workflows/` directory
- Use `examples/` for testing and documentation
- Group related workflows in the same file
- Use descriptive workflow names and descriptions

### Naming Conventions

- Use kebab-case for workflow names: `new-user-onboarding`
- Include purpose in name: `support-ticket-creation`
- Avoid conflicts with existing workflows

### Development Workflow

1. **Develop** workflows locally using the SDK
2. **Test** with `--dry-run` flag first
3. **Sync** to staging environment
4. **Validate** in CRM interface
5. **Deploy** to production

### Version Control

- Commit workflow files to your repository
- Tag releases for workflow deployments
- Document changes in workflow descriptions
- Use branches for workflow development

## 🐛 Troubleshooting

### Common Sync Issues

**Project ID required:**

```bash
# ❌ Missing project ID
pnpm run sync-workflows

# ✅ Provide project ID
pnpm run sync-workflows --project-id=your-uuid
```

**Workflow already exists:**

```bash
# ❌ Workflow exists, won't overwrite
pnpm run sync-workflows --project-id=your-uuid

# ✅ Use force flag to overwrite
pnpm run sync-workflows --project-id=your-uuid --force
```

**Validation errors:**

- Check workflow structure matches SDK format
- Ensure all required fields are present
- Verify action parameters are valid
- Review error details in sync output

### Getting Help

- Review workflow examples in `examples/` directory
- Check sync output for detailed error messages
- Use `--dry-run` to preview changes without applying
- Validate workflows before syncing

## 🎨 IDE Support

This SDK is optimized for modern IDEs and GitHub Copilot:

- **Auto-completion** for trigger types, action parameters, and template variables
- **Type checking** for all parameters and return types
- **IntelliSense** documentation for all functions
- **Error highlighting** for invalid configurations

## 📄 License

MIT License - see LICENSE file for details
