> ## Documentation Index
> Fetch the complete documentation index at: https://docs.diyanet.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Event-Driven Akış

> Domain event vs integration event; Command Handler → SaveEntities → MediatR / Outbox → RabbitMQ tam akışı

## İki tür event

Sistemde iki farklı event türü vardır ve bunlar **bilinçli olarak** ayrı tutulur:

|           | Domain Event                                                               | Integration Event                                                             |
| --------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Kapsam    | Aynı process (in-memory)                                                   | Process/servis-arası                                                          |
| Transport | MediatR `Publish`                                                          | `IEventBus` → RabbitMQ                                                        |
| Zamanlama | `SaveChanges` ile **aynı transaction** mantığında, commit sonrası dispatch | Outbox ile aynı transaction'a yazılır, commit sonrası **asenkron** yayınlanır |
| Base      | `DomainEvent` (SharedKernel) — `INotification`                             | `IntegrationEvent` — `INotification`                                          |
| Örnek     | `UserOtpGeneratedDomainEvent`, `FaqCreatedDomainEvent`                     | `UserCreatedIntegrationEvent`, `CacheInvalidationIntegrationEvent`            |

## Tam akış

```mermaid theme={null}
flowchart TD
    CMD[Command Handler] --> AGG[aggregate.AddDomainEvent]
    AGG --> UOW[UnitOfWork.SaveEntitiesAsync]
    UOW --> SC[base.SaveChangesAsync]
    SC -->|result &gt; 0| DISP[MediatorExtension.DispatchDomainEventsAsync]

    DISP --> CHK{event IBusEvent mi?}
    CHK -->|Hayır: domain event| MED[mediator.Publish]
    MED --> NH[INotificationHandler'lar<br/>in-process]

    CHK -->|Evet: IntegrationEvent| BUS[IEventBus.PublishAsync]
    BUS --> OBX[(messaging.outbox_message<br/>aynı transaction)]
    OBX -.OutboxDeliveryService.-> MQ[RabbitMQ topic exchange<br/>integration_event_bus]
    MQ --> CON[IntegrationEventConsumer&lt;T&gt;]
    CON --> IEH[IIntegrationEventHandler&lt;T&gt;]
```

### Akış adım adım

1. **Command handler** aggregate metodunu çağırır; aggregate `AddDomainEvent(...)` ile event biriktirir.
2. **`UnitOfWork.SaveEntitiesAsync`** → `base.SaveChangesAsync` (audit + soft-delete interceptor burada devrede). `result > 0` ise dispatch tetiklenir.
3. **`MediatorExtension.DispatchDomainEventsAsync`** change-tracker'daki aggregate'lerin event'lerini toplar, temizler ve tek tek dispatch eder.
4. Event **`IBusEvent`'ten türüyorsa** (yani `IntegrationEvent` ise) → `IEventBus.PublishAsync` → Outbox tablosuna **aynı DbContext transaction'ında** yazılır; aksi halde `mediator.Publish` ile **in-process** `INotificationHandler`'lara gider.
5. Outbox'taki satırı `OutboxDeliveryService` arka planda RabbitMQ'ya publish eder.

```csharp theme={null}
// MediatorExtension.DispatchDomainEventsAsync (özet)
foreach (var domainEvent in domainEvents)
{
    try
    {
        if (domainEvent is IBusEvent busEvent)
        {
            if (busEvent is IntegrationEvent integrationEvent)
                await ctx._eventBus.PublishAsync(integrationEvent);   // Outbox
        }
        else
        {
            await mediator.Publish(domainEvent);                       // in-process
        }
    }
    catch (Exception ex)
    {
        // Akış kesilmesin — kalan event'ler dispatch edilmeye devam etsin; ama log'lansın.
        loggerFactory?.CreateLogger(typeof(MediatorExtension))
            .LogError(ex, "[DomainEventDispatch] Event işlenemedi: {EventType}", domainEvent.GetType().Name);
    }
}
```

<Note>
  **Kural:** Domain event commit'le birlikte aynı mantıksal işlemde dispatch edilir; integration event commit sonrası asenkron yayınlanır. Integration event'i Outbox'a yazmak, "DB commit oldu ama mesaj yayınlanamadı" (dual-write) riskini ortadan kaldırır — ayrıntı: [Outbox Pattern](/events/outbox-pattern).
</Note>

<Warning>
  `DispatchDomainEventsAsync` her event'i `try/catch` ile sarar ve hatayı log'layıp devam eder (silent failure değil). Yani bir handler patlasa bile diğer event'ler işlenir. Kritik tutarlılık gerektiren iş için handler'ı idempotent ve dayanıklı yaz.
</Warning>

## Hangisini ne zaman kullanmalı?

* **Domain event** — aynı process içinde yan etki: OTP SMS/e-posta gönder, cache tag düşür, admin bildirimi üret.
* **Integration event** — başka bir servisin (veya gelecekte ayrışacak bir bounded context'in) tüketeceği olay: welcome akışı, cross-service cache L1 senkron.

## Bu bölümde

<CardGroup cols={2}>
  <Card title="Domain Events" icon="bolt" href="/events/domain-events">
    `DomainEvent` base, `AddDomainEvent`, `INotificationHandler`.
  </Card>

  <Card title="Integration Events" icon="arrows-turn-to-dots" href="/events/integration-events">
    `IntegrationEvent`, `IBusEvent`, consumer kaydı.
  </Card>

  <Card title="Outbox Pattern" icon="inbox" href="/events/outbox-pattern">
    Transactional outbox, dual-write çözümü.
  </Card>

  <Card title="RabbitMQ Topology" icon="rabbit" href="/events/rabbitmq-topology">
    Exchange, routing key, retry, DLX.
  </Card>
</CardGroup>
