---
name: workflow
description: |
  Cree et configure des workflows automatises SmartStack.
  Utiliser ce skill quand:
  - L'utilisateur veut automatiser des actions (emails, webhooks)
  - L'utilisateur mentionne "workflow", "automatisation", "trigger"
  - Creation d'un processus metier avec etapes
  - Integration d'emails transactionnels
  Types: SendEmail, Wait, Condition, Webhook
---

# Skill Workflow SmartStack

> **Architecture:** Workflow = Trigger → Steps → Actions (Email/Wait/Condition/Webhook)
> Les workflows sont executes automatiquement lors d'evenements applicatifs.

## QUAND CE SKILL S'ACTIVE

Claude invoque automatiquement ce skill quand il detecte :

| Declencheur | Exemple |
|-------------|---------|
| Demande explicite | "Cree un workflow pour l'inscription" |
| Email automatique | "Envoie un email quand un ticket est cree" |
| Automatisation | "Automatise le processus d'onboarding" |
| Enchainement | "Apres 24h sans reponse, envoyer un rappel" |
| Mots-cles | "workflow", "trigger", "automatisation", "email template" |

---

## ARCHITECTURE WORKFLOW

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                         WORKFLOW ENGINE                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  [EVENT] ─────────────────────────────────────────────────────────────────┐  │
│     │                                                                     │  │
│     ▼                                                                     │  │
│  ┌─────────────────────────────┐                                         │  │
│  │     WorkflowTrigger         │                                         │  │
│  │  ex: "user.registered"      │                                         │  │
│  │      "ticket.created"       │                                         │  │
│  └─────────────┬───────────────┘                                         │  │
│                │                                                          │  │
│                ▼                                                          │  │
│  ┌─────────────────────────────┐                                         │  │
│  │   IWorkflowService          │                                         │  │
│  │   TriggerAsync(code, vars)  │                                         │  │
│  └─────────────┬───────────────┘                                         │  │
│                │                                                          │  │
│       ┌────────┴────────┐                                                │  │
│       ▼                 ▼                                                │  │
│  ┌─────────┐      ┌─────────────┐                                        │  │
│  │Workflow │      │  Workflow   │  (plusieurs workflows par trigger)     │  │
│  │  "A"    │      │    "B"      │                                        │  │
│  └────┬────┘      └──────┬──────┘                                        │  │
│       │                  │                                                │  │
│       ▼                  ▼                                                │  │
│  ┌─────────────────────────────────────────────────────────────────────┐ │  │
│  │                      WORKFLOW STEPS                                  │ │  │
│  │                                                                      │ │  │
│  │  Step 1: SendEmail     Step 2: Wait       Step 3: Condition         │ │  │
│  │  ┌───────────────┐    ┌─────────────┐    ┌────────────────┐         │ │  │
│  │  │ EmailTemplate │ →  │ Delay 24h   │ →  │ IF condition   │         │ │  │
│  │  │ + Variables   │    │             │    │ THEN Step 4    │         │ │  │
│  │  └───────────────┘    └─────────────┘    │ ELSE Step 5    │         │ │  │
│  │                                          └────────────────┘         │ │  │
│  │                                                                      │ │  │
│  │  Step 4: Webhook       Step 5: SendEmail                            │ │  │
│  │  ┌───────────────┐    ┌───────────────┐                              │ │  │
│  │  │ POST /api/... │    │ ReminderEmail │                              │ │  │
│  │  │ + Payload     │    │ + Variables   │                              │ │  │
│  │  └───────────────┘    └───────────────┘                              │ │  │
│  │                                                                      │ │  │
│  └─────────────────────────────────────────────────────────────────────┘ │  │
│                                                                          │  │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## TRIGGERS DISPONIBLES

### User Events

| Trigger Code | Declencheur | Variables Disponibles |
|--------------|-------------|----------------------|
| `user.registered` | Inscription | userId, email, displayName, confirmUrl |
| `user.email-confirmed` | Email confirme | userId, email, displayName |
| `user.password-reset-requested` | Reset demande | userId, email, resetUrl |
| `user.password-changed` | Password change | userId, email |
| `user.account-locked` | Compte bloque | userId, email, lockReason |
| `user.account-unlocked` | Compte debloque | userId, email |
| `user.onboarding-completed` | Onboarding termine | userId, email, displayName |
| `user.admin-password-reset` | Admin reset via lien | userId, email, resetUrl |
| `user.admin-password-reset-direct` | Admin reset direct | userId, email, tempPassword |

### Ticket Events (Support)

| Trigger Code | Declencheur | Variables Disponibles |
|--------------|-------------|----------------------|
| `ticket.created` | Ticket cree | ticketId, ticketNumber, title, creatorEmail, creatorName |
| `ticket.resolved` | Ticket resolu | ticketId, ticketNumber, title, resolverName |
| `ticket.assigned` | Ticket assigne | ticketId, ticketNumber, assigneeName, assigneeEmail |
| `ticket.commented` | Commentaire ajoute | ticketId, ticketNumber, commenterName, commentPreview |
| `ticket.sla-warning` | SLA proche expiration | ticketId, ticketNumber, deadline, remainingMinutes |
| `ticket.sla-breached` | SLA depasse | ticketId, ticketNumber, breachedAt |

### Ajouter un Nouveau Trigger

```csharp
// 1. Infrastructure/Persistence/Configurations/Communications/WorkflowTriggerConfiguration.cs
// Dans la methode GetSeedData(), ajouter:

new
{
    Id = Guid.Parse("NEW-GUID-HERE"),
    Code = "entity.event",
    Name = "Entity Event",
    Description = "Triggered when entity event occurs",
    TriggerType = "EntityEvent",
    AvailableVariablesJson = JsonSerializer.Serialize(new[]
    {
        new { Name = "entityId", Type = "Guid", Description = "Entity ID" },
        new { Name = "entityName", Type = "string", Description = "Entity name" },
        new { Name = "userEmail", Type = "string", Description = "User email" },
    }),
    IsActive = true,
    CreatedAt = seedDate
},

// 2. Declencher dans le service/controller
await _workflowService.TriggerAsync(
    "entity.event",
    new Dictionary<string, object>
    {
        ["entityId"] = entity.Id,
        ["entityName"] = entity.Name,
        ["userEmail"] = user.Email,
    },
    language: "fr");
```

---

## TYPES DE STEPS

### 1. SendEmail

Envoie un email en utilisant un template.

```csharp
// Creation via Factory Method
var step = WorkflowStep.CreateEmailStep(
    name: "Welcome Email",
    emailTemplateId: welcomeTemplateId,
    order: 1);

// Configuration JSON (si specifique)
{
    "templateId": "guid-template",
    "recipientVariable": "userEmail",    // Variable contenant l'email
    "ccEmails": ["admin@company.com"],   // CC optionnels
    "bccEmails": []
}
```

**Variables automatiques:**
- Toutes les variables du trigger sont injectees dans le template
- `{{userName}}`, `{{userEmail}}`, `{{ticketNumber}}`, etc.

### 2. Wait

Ajoute un delai avant le step suivant.

```csharp
// Creation
var step = WorkflowStep.CreateWaitStep(
    name: "Wait 24 hours",
    delayMinutes: 24 * 60,  // 1440 minutes
    order: 2);
```

**Cas d'usage:**
- Rappel apres X heures sans reponse
- Sequence d'onboarding espacee
- Delai avant escalade

### 3. Condition

Branche conditionnelle basee sur les variables.

```csharp
// Creation
var step = WorkflowStep.CreateConditionStep(
    name: "Check if premium user",
    configurationJson: JsonSerializer.Serialize(new
    {
        condition = "{{userType}} == 'Premium'",
        trueStepOrder = 3,   // Si vrai, aller au step 3
        falseStepOrder = 4   // Si faux, aller au step 4
    }),
    order: 2);
```

**Operateurs supportes:**
- `==`, `!=` (egalite)
- `>`, `<`, `>=`, `<=` (comparaison)
- `contains`, `startsWith`, `endsWith` (strings)
- `&&`, `||` (logique)

### 4. Webhook

Appelle une API externe.

```csharp
// Creation
var step = WorkflowStep.CreateWebhookStep(
    name: "Notify CRM",
    configurationJson: JsonSerializer.Serialize(new
    {
        url = "https://crm.example.com/api/events",
        method = "POST",
        headers = new Dictionary<string, string>
        {
            ["Authorization"] = "Bearer {{crmApiKey}}",
            ["Content-Type"] = "application/json"
        },
        body = new
        {
            eventType = "user.registered",
            userId = "{{userId}}",
            email = "{{userEmail}}"
        },
        retryCount = 3,
        timeoutSeconds = 30
    }),
    order: 3);
```

---

## WORKFLOW CREATION

### ETAPE 1: Definir le Trigger

```csharp
// Choisir un trigger existant ou en creer un nouveau
var triggerId = existingTriggerId; // ex: user.registered trigger ID
```

### ETAPE 2: Creer le Workflow

```csharp
// Domain/Communications/Workflow.cs via Factory Method
var workflow = Workflow.Create(
    code: "welcome-sequence",
    name: "Welcome Email Sequence",
    description: "Sends welcome emails after registration",
    triggerId: triggerId,
    applicationId: null,  // null = global
    isSystem: false,
    priority: 10);        // Plus haut = execute en premier
```

### ETAPE 3: Ajouter les Steps

```csharp
// Step 1: Email de bienvenue immediat
workflow.AddStep(WorkflowStep.CreateEmailStep(
    name: "Welcome Email",
    emailTemplateId: welcomeTemplateId,
    order: 1));

// Step 2: Attendre 24h
workflow.AddStep(WorkflowStep.CreateWaitStep(
    name: "Wait 24h",
    delayMinutes: 1440,
    order: 2));

// Step 3: Email de suivi
workflow.AddStep(WorkflowStep.CreateEmailStep(
    name: "Follow-up Email",
    emailTemplateId: followUpTemplateId,
    order: 3));
```

### ETAPE 4: Seed Data (Infrastructure)

```csharp
// Infrastructure/Persistence/Configurations/Communications/WorkflowConfiguration.cs

public void Configure(EntityTypeBuilder<Workflow> builder)
{
    // ... configuration ...

    builder.HasData(GetSeedData());
}

private static object[] GetSeedData()
{
    var seedDate = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    return new object[]
    {
        new
        {
            Id = Guid.Parse("WORKFLOW-GUID"),
            Code = "welcome-sequence",
            Name = "Welcome Email Sequence",
            Description = "Sends welcome emails after registration",
            TriggerId = Guid.Parse("TRIGGER-GUID"),
            ApplicationId = (Guid?)null,
            IsActive = true,
            IsSystem = true,
            Priority = 10,
            CreatedAt = seedDate
        }
    };
}
```

---

## DECLENCHEMENT WORKFLOW

### Dans un Service

```csharp
public class UserService : IUserService
{
    private readonly IWorkflowService _workflowService;

    public async Task<Result> RegisterAsync(RegisterCommand command, CancellationToken ct)
    {
        // ... creation utilisateur ...

        // Declencher le workflow
        await _workflowService.TriggerAsync(
            "user.registered",
            new Dictionary<string, object>
            {
                ["userId"] = user.Id,
                ["email"] = user.Email,
                ["displayName"] = user.DisplayName,
                ["confirmUrl"] = GenerateConfirmUrl(user.Id)
            },
            language: "fr",
            cancellationToken: ct);

        return Result.Success();
    }
}
```

### Dans un Controller

```csharp
[HttpPost("tickets")]
public async Task<ActionResult> CreateTicket(CreateTicketRequest request, CancellationToken ct)
{
    var ticket = await _ticketService.CreateAsync(request, ct);

    // Declencher workflow
    await _workflowService.TriggerAsync(
        "ticket.created",
        new Dictionary<string, object>
        {
            ["ticketId"] = ticket.Id,
            ["ticketNumber"] = ticket.Number,
            ["title"] = ticket.Title,
            ["creatorEmail"] = _currentUser.Email,
            ["creatorName"] = _currentUser.DisplayName
        });

    return CreatedAtAction(nameof(GetById), new { id = ticket.Id }, ticket);
}
```

---

## EMAIL TEMPLATES

### Structure Template

```csharp
// Domain/Communications/EmailTemplate.cs
public class EmailTemplate : BaseEntity
{
    public string Code { get; private set; }           // "welcome-email"
    public string Name { get; private set; }           // "Welcome Email"
    public string Category { get; private set; }       // "Transactional"
    public bool IsActive { get; private set; }
    public bool IsSystem { get; private set; }

    // Translations (multi-langue)
    public ICollection<EmailTemplateTranslation> Translations { get; }
}

public class EmailTemplateTranslation
{
    public string LanguageCode { get; set; }  // "fr", "en"
    public string Subject { get; set; }        // "Bienvenue {{userName}}"
    public string HtmlBody { get; set; }       // HTML avec variables
    public string TextBody { get; set; }       // Version texte
}
```

### Variables dans Templates

```html
<!-- HtmlBody avec Handlebars-like syntax -->
<h1>Bienvenue {{userName}}!</h1>
<p>Votre compte a ete cree avec succes.</p>
<p>Email: {{userEmail}}</p>
<a href="{{confirmUrl}}">Confirmer votre email</a>

<!-- Conditions -->
{{#if isPremium}}
  <p>Merci pour votre abonnement Premium!</p>
{{else}}
  <p>Decouvrez nos offres Premium.</p>
{{/if}}

<!-- Boucles -->
{{#each items}}
  <li>{{this.name}} - {{this.price}}</li>
{{/each}}
```

---

## FRONTEND WORKFLOW EDITOR

### API Workflows

```typescript
// services/api/workflowsApi.ts
export const workflowsApi = {
  // CRUD Workflows
  getAll: () => apiClient.get<WorkflowDto[]>('/admin/workflows'),
  getById: (id: string) => apiClient.get<WorkflowDto>(`/admin/workflows/${id}`),
  create: (data: CreateWorkflowRequest) => apiClient.post('/admin/workflows', data),
  update: (id: string, data: UpdateWorkflowRequest) => apiClient.put(`/admin/workflows/${id}`, data),
  delete: (id: string) => apiClient.delete(`/admin/workflows/${id}`),

  // Triggers
  getTriggers: () => apiClient.get<WorkflowTriggerDto[]>('/admin/workflows/triggers'),

  // Steps
  addStep: (workflowId: string, step: CreateStepRequest) =>
    apiClient.post(`/admin/workflows/${workflowId}/steps`, step),
  updateStep: (workflowId: string, stepId: string, step: UpdateStepRequest) =>
    apiClient.put(`/admin/workflows/${workflowId}/steps/${stepId}`, step),
  deleteStep: (workflowId: string, stepId: string) =>
    apiClient.delete(`/admin/workflows/${workflowId}/steps/${stepId}`),
  reorderSteps: (workflowId: string, stepIds: string[]) =>
    apiClient.post(`/admin/workflows/${workflowId}/steps/reorder`, { stepIds }),

  // Execution
  execute: (workflowId: string, variables: Record<string, unknown>) =>
    apiClient.post(`/admin/workflows/${workflowId}/execute`, { variables }),
};
```

### Composant WorkflowStepsEditor

```tsx
// components/admin/workflows/WorkflowStepsEditor.tsx
import { Mail, Clock, GitBranch, Webhook, Plus, GripVertical, Trash2 } from 'lucide-react';

const stepTypeConfig = {
  SendEmail: { icon: Mail, color: 'blue', label: 'Email' },
  Wait: { icon: Clock, color: 'amber', label: 'Delai' },
  Condition: { icon: GitBranch, color: 'purple', label: 'Condition' },
  Webhook: { icon: Webhook, color: 'green', label: 'Webhook' },
};

export function WorkflowStepsEditor({ workflowId, steps, onUpdate }) {
  // Drag and drop pour reordonner
  // Modal pour editer chaque step
  // Bouton pour ajouter un step

  return (
    <div className="space-y-4">
      {steps.map((step, index) => (
        <WorkflowStepCard
          key={step.id}
          step={step}
          index={index}
          onEdit={() => openEditModal(step)}
          onDelete={() => handleDelete(step.id)}
        />
      ))}

      <button
        onClick={() => openAddModal()}
        className="w-full p-4 border-2 border-dashed rounded-lg"
      >
        <Plus className="w-5 h-5 mr-2" />
        Ajouter une etape
      </button>
    </div>
  );
}
```

---

## WORKFLOWS SYSTEME (SEED)

| Code | Trigger | Description |
|------|---------|-------------|
| `email-confirmation` | `user.registered` | Email de confirmation apres inscription |
| `welcome-email` | `user.email-confirmed` | Email de bienvenue apres confirmation |
| `password-reset` | `user.password-reset-requested` | Email avec lien de reset |
| `account-unlocked-notification` | `user.account-unlocked` | Notification compte debloque |
| `user-onboarding` | `user.onboarding-completed` | Email fin d'onboarding |
| `admin-password-reset` | `user.admin-password-reset` | Reset admin via lien |
| `admin-password-reset-direct` | `user.admin-password-reset-direct` | Reset admin direct |

---

## CHECKLIST CREATION WORKFLOW

```
□ Trigger identifie (existant ou nouveau)
□ Si nouveau trigger:
  □ Ajoute dans WorkflowTriggerConfiguration.cs seed
  □ Variables definies (AvailableVariablesJson)
  □ Migration EF Core creee
□ Workflow cree avec:
  □ Code unique (kebab-case)
  □ Nom descriptif
  □ Trigger lie
  □ Priority definie
□ Steps configures:
  □ SendEmail avec templateId valide
  □ Wait avec delayMinutes
  □ Condition avec expression valide
  □ Webhook avec URL et payload
□ Email templates crees (si SendEmail steps)
□ Declenchement ajoute dans le code source
□ Tests:
  □ Trigger declenche le workflow
  □ Emails envoyes correctement
  □ Variables substituees
□ Migration EF Core si seed data modifie
```

---

## REGLES ABSOLUES

1. **TOUJOURS** utiliser IWorkflowService.TriggerAsync (jamais execution directe)
2. **TOUJOURS** fournir toutes les variables attendues par le trigger
3. **TOUJOURS** specifier la langue pour les emails
4. **TOUJOURS** utiliser des codes kebab-case uniques
5. **TOUJOURS** definir une priority (10 = standard, 20+ = prioritaire)
6. **TOUJOURS** logger les executions de workflow
7. **JAMAIS** hardcoder les URLs dans les templates
8. **JAMAIS** exposer des secrets dans les variables
9. **JAMAIS** creer des boucles infinies (workflow A → trigger B → workflow A)
10. **JAMAIS** oublier les email templates pour les steps SendEmail

---

## FICHIERS CLES

| Fichier | Role |
|---------|------|
| `Domain/Communications/Workflow.cs` | Entite workflow |
| `Domain/Communications/WorkflowStep.cs` | Entite step |
| `Domain/Communications/WorkflowTrigger.cs` | Entite trigger |
| `Domain/Communications/Enums/WorkflowStepType.cs` | Types de steps |
| `Application/Common/Interfaces/IWorkflowService.cs` | Interface service |
| `Infrastructure/Services/Workflow/WorkflowExecutionService.cs` | Implementation |
| `Infrastructure/Persistence/Configurations/Communications/WorkflowConfiguration.cs` | EF Config + Seed |
| `web/src/components/admin/workflows/WorkflowStepsEditor.tsx` | UI Editor |
