> ## 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.

# Cache Mimarisi

> HybridCache (L1 memory + L2 Redis), spec tabanlı opt-in cache, tag invalidation ve multi-instance broadcast

## İki katman, tek API

Sistem **L1 (in-process memory)** + **L2 (Redis)** birleşik cache kullanır. Alt katman .NET `HybridCache` (`Microsoft.Extensions.Caching.Hybrid`) infrastructure'ı; uygulama kodu bunu doğrudan değil, `BuildingBlocks.Caching.IHybridRequestCache` arayüzü üzerinden görür.

`IHybridRequestCache`, `HybridCache`'in üzerine ince bir wrapper'dır (`HybridRequestCache`). Tek başına `HybridCache` zaten L1 + L2 + stampede protection + tag-based invalidation veriyor; wrapper yalnızca iki şey ekler:

1. **Test edilebilir abstraction** — `HybridCache`'i doğrudan inject etmek yerine interface üzerinden.
2. **Multi-instance broadcast hook'u** — tag invalidate edilince diğer node'ların L1'ini de düşürmek için (`IRemoteTagBroadcaster`).

```mermaid theme={null}
flowchart LR
    REQ[Query / Repository] --> H[IHybridRequestCache]
    H -->|1) check| L1[(L1: Memory<br/>Cache:L1:Ttl = 1 dk)]
    L1 -.miss.-> H
    H -->|2) check| L2[(L2: Redis<br/>Cache:L2:Ttl = 5 dk)]
    L2 -.miss.-> H
    H -->|3) factory| DB[(PostgreSQL)]
    DB --> L2
    L2 --> L1
    L1 --> RES[Sonuç]
```

## Cache opt-in: spec tabanlı

Cache her query'de otomatik açık **değildir**. `CachedRepository<T>` decorator yalnızca spec üzerinde `EnableCache(...)` zinciri kurulmuşsa cache'ler. Komut/handler tarafı cache hakkında hiçbir şey bilmez — kararı spec verir:

```csharp theme={null}
Query
  .Where(f => f.IsActive)
  .EnableCache(nameof(PublicFaqsPagedSpecification), filter.Page, filter.PageSize, filter.SearchTerm)
  .WithCacheTtl(TimeSpan.FromMinutes(5))
  .WithTags(CacheTag);   // "faqs"
```

Public liste spec'leri cache'i açar (sık çağrılır, invalidate kuralı net), admin spec'leri açmaz (anlık değişiklik görünsün). Ayrıntı: [Hybrid Cache](/caching/hybrid-cache).

<Note>
  `Cache:Enabled` bayrağı yalnızca **spec/DB query cache**'ini (`CachedRepository`) etkiler. `UserContextCache`, JWKS, Keycloak PKCE state gibi auth/token cache'leri `HybridCache`'i doğrudan kullanır ve bu bayraktan etkilenmez (auth cache'siz çalışamayacağı için kasten ayrı tutulur).
</Note>

## Invalidation — event-driven, tag-bazlı

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant API1 as API Node #1
    participant DB as PostgreSQL
    participant L2 as Redis
    participant MQ as RabbitMQ
    participant API2 as API Node #2

    Note over API1: Admin: FAQ güncelle
    API1->>DB: UPDATE faq ...
    Note over API1: FaqUpdatedDomainEvent → handler
    API1->>L2: RemoveByTagAsync("faqs")
    API1->>API1: L1 "faqs" düşür
    API1->>MQ: Publish CacheInvalidationIntegrationEvent { tag: "faqs", node: API1 }
    MQ-->>API2: Consume (echo guard: kendi node'unu atlar)
    API2->>API2: RemoveByTagLocallyAsync("faqs") → sadece L1
    Note over API1,API2: Sonraki read → factory → cache repopulate
```

1. **DB güncellenir** — komut handler içinde.
2. **Tag-bazlı eviction** — domain event handler `RemoveByTagAsync("faqs")` çağırır; L2'de tag işaretlenir (lazy invalidation), local L1 düşer.
3. **Diğer node'lar bilgilendirilir** — `Cache:BroadcastTagInvalidation` açıksa `CacheInvalidationIntegrationEvent` RabbitMQ üzerinden yayınlanır; her node kendi L1'ini düşürür.

Ayrıntı: [Invalidation](/caching/invalidation) ve [Multi-Instance Senkron](/caching/multi-instance).

## Konfigürasyon

```json theme={null}
{
  "Cache": {
    "Enabled": true,
    "L1": { "Ttl": "00:01:00" },
    "L2": { "Ttl": "00:05:00" },
    "BroadcastTagInvalidation": false
  }
}
```

| Anahtar                          | Varsayılan        | Anlamı                                                                                        |
| -------------------------------- | ----------------- | --------------------------------------------------------------------------------------------- |
| `Cache:Enabled`                  | —                 | Spec/DB query cache kill-switch. `false` ise `CachedRepository` raw EF Core'a düşer.          |
| `Cache:L1:Ttl`                   | `00:01:00` (1 dk) | L1 (memory) varsayılan TTL. Multi-instance'da L2'den kısa olmalı.                             |
| `Cache:L2:Ttl`                   | `00:05:00` (5 dk) | L2 (Redis) varsayılan TTL. Spec `WithCacheTtl(...)` ile per-entry override edebilir.          |
| `Cache:BroadcastTagInvalidation` | `false`           | Multi-instance L1 senkronizasyonu için tag invalidation broadcast'i. Single-node'da gereksiz. |

<Warning>
  Kayıt sırası kritiktir: `AddRedisCache` → `AddCache` → `AddHybridCache`. Sıra bozulursa `HybridCache` L1-only mode'a düşer. Ayrıntı: [Hybrid Cache](/caching/hybrid-cache).
</Warning>

## Bu bölümde

<CardGroup cols={2}>
  <Card title="Hybrid Cache" icon="layer-group" href="/caching/hybrid-cache">
    `IHybridRequestCache` API, kayıt sırası, stampede protection, spec cache.
  </Card>

  <Card title="Invalidation" icon="trash" href="/caching/invalidation">
    `CacheTags`, domain event handler'da `RemoveByTagAsync`.
  </Card>

  <Card title="Multi-Instance Senkron" icon="network-wired" href="/caching/multi-instance">
    `EventBusRemoteTagBroadcaster` + echo guard ile L1 broadcast.
  </Card>

  <Card title="Event Akışı" icon="bolt" href="/events/overview">
    Domain event ve integration event'lerin tam akışı.
  </Card>
</CardGroup>
