# Entity Lifecycle Hooks (v3.46+)

> Extracted from `smartstack-api.md` for clarity. Loaded only when generating code that needs hooks.

SmartStack exposes 6 typed hook interfaces + 1 executor in `SmartStack.Application.Common.Interfaces.Hooks`.

## Interfaces

```csharp
public interface IBeforeCreate<in T>  where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }
public interface IAfterCreate<in T>   where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }
public interface IBeforeUpdate<in T>  where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }
public interface IAfterUpdate<in T>   where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }
public interface IBeforeDelete<in T>  where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }
public interface IAfterDelete<in T>   where T : class { int Order => 0; Task ExecuteAsync(T entity, CancellationToken ct = default); }

public interface IHookExecutor
{
    Task ExecuteBeforeCreateAsync<T>(T entity, CancellationToken ct = default) where T : class;
    Task ExecuteAfterCreateAsync<T>(T entity,  CancellationToken ct = default) where T : class;
    Task ExecuteBeforeUpdateAsync<T>(T entity, CancellationToken ct = default) where T : class;
    Task ExecuteAfterUpdateAsync<T>(T entity,  CancellationToken ct = default) where T : class;
    Task ExecuteBeforeDeleteAsync<T>(T entity, CancellationToken ct = default) where T : class;
    Task ExecuteAfterDeleteAsync<T>(T entity,  CancellationToken ct = default) where T : class;
}
```

## Semantics

- **`IBefore*`** runs **before** the entity is persisted. May transform the entity. May `throw` to cancel the operation (the calling handler does NOT call `SaveChangesAsync`).
- **`IAfter*`** runs **after** `SaveChangesAsync` completes. Side-effects only (notifications, indexing, caches, integrations). Throwing here does NOT roll back the DB write — wrap risky calls.
- **`Order`** (default 0) — lower runs earlier. Use `Order = -100` to pre-empt validation, `Order = 100` to run last.

## DI registration (Infrastructure DependencyInjection.cs)

```csharp
services.AddScoped<IHookExecutor, HookExecutor>();
services.AddScoped<IBeforeCreate<Employee>,  EmployeeValidationHook>();
services.AddScoped<IAfterCreate<Employee>,   EmployeeWelcomeNotificationHook>();
services.AddScoped<IAfterUpdate<Employee>,   EmployeeUpdatedAuditHook>();
```

## Usage in service / handler

```csharp
public async Task<EmployeeDto> CreateAsync(CreateEmployeeDto dto, CancellationToken ct)
{
    var entity = Employee.Create(dto.TenantId, dto.Code, dto.Name);
    await _hooks.ExecuteBeforeCreateAsync(entity, ct);   // may throw → cancel
    _db.Employees.Add(entity);
    await _db.SaveChangesAsync(ct);
    await _hooks.ExecuteAfterCreateAsync(entity, ct);    // post-commit side effects
    return _mapper.Map<EmployeeDto>(entity);
}
```

## DO / DON'T

- DO use hooks for cross-cutting concerns (notifications, audit beyond `IAuditableEntity`, cache invalidation)
- DO keep hooks small and idempotent — `IAfter*` runs without DB transaction
- DON'T use hooks for business validation that varies per command — keep that in the handler / FluentValidation
- DON'T register the same hook twice — DI picks all of them, and they all execute

## Sources

- `D:/01 - projets/SmartStack.app/features/IA-Workflow/src/SmartStack.Application/Common/Interfaces/Hooks/IBeforeCreate.cs`
- `D:/01 - projets/SmartStack.app/features/IA-Workflow/src/SmartStack.Application/Common/Interfaces/Hooks/IAfterCreate.cs`
- `D:/01 - projets/SmartStack.app/features/IA-Workflow/src/SmartStack.Application/Common/Interfaces/Hooks/IHookExecutor.cs` (and 4 more)
