# Domain Events (lightweight pub-sub)

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

SmartStack uses a minimal domain event pattern in `SmartStack.Domain.Support.Events`.

## Interface + base class

```csharp
public interface IDomainEvent
{
    DateTime OccurredAt { get; }
}

public abstract class DomainEvent : IDomainEvent
{
    public DateTime OccurredAt { get; } = DateTime.UtcNow;
}
```

## When to raise an event vs use a hook

| Use case | Mechanism |
|---|---|
| Cross-cutting side effect tied to entity lifecycle (Create/Update/Delete) | Entity hook (`IAfterCreate<T>`, …) — see [entity-hooks-pattern.md](entity-hooks-pattern.md) |
| Business event independent of CRUD (e.g. `WorkflowExecuted`, `LicenseRenewed`) | Domain event |
| Need to handle multiple unrelated reactions to the same business fact | Domain event |
| Reaction must be transactional with the entity write | Neither — code it inline in the handler |

## Convention

- One event class per business fact, named `{PastTense}Event` (e.g. `EmployeeOnboardedEvent`, `WorkflowExecutedEvent`).
- Place events in `Domain/{Aggregate}/Events/`.
- Inherit `DomainEvent` (gets `OccurredAt` for free).
- Dispatched by handlers (no automatic publication from `SaveChangesAsync` in v3.46) — keep dispatch explicit so the handler controls timing.

## Example dispatch (handler)

```csharp
await _mediator.Publish(new EmployeeOnboardedEvent(employee.Id, employee.TenantId), ct);
```

## Source

- `D:/01 - projets/SmartStack.app/features/IA-Workflow/src/SmartStack.Domain/Support/Events/IDomainEvent.cs`
