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

# Composer LLM Cache Invalidation

> Phase 24 — Admin paneli 9. tab. Composer LLM narrative cache'ini scope bazlı invalidate edin. Platform admin yetkisi, Redis SCAN cursor pattern, audit log.

# Composer LLM Cache Invalidation

`v0.7.64` (Phase 24) ile gelen **Composer LLM cache invalidation** özelliği, hibrit rapor pipeline'ında üretilen LLM narrative cache'lerini scope bazlı temizlemeye olanak tanır. `platform_admin` rolündeki kullanıcılar **Admin paneli → 9. tab "LLM Önbellek"** sekmesinden 4 farklı scope'ta (all / locale / variant / run\_id) invalidation tetikleyebilir.

## Neden Cache Invalidation?

Hybrid Report composer her rapor için LLM çağrısı yapmamak adına narrative output'ları **Redis cache**'te tutar. Cache key formatı:

```
composer:llm:{locale}:{variant}:{run_id}:{section_hash}
```

**Cache'in temizlenmesi gerektiği durumlar:**

* **Prompt revizyonu** — LLM prompt template güncellendi, eski cache stale
* **Locale fix** — TR/EN translation hatası düzeltildi, yeni rendering gerekli
* **A/B test reset** — `LLM_AB_SPLIT` variant ratio değişti (örn: `v1.1:1.0` → `v1.2:1.0`)
* **Belirli bir run yeniden hesaplanıyor** — run\_id bazlı targeted invalidation
* **LLM model upgrade** — Claude Opus 4.7 → Opus 5.0 geçişi sonrası tüm cache stale

<Tip>
  Cache invalidation **destructive** bir işlemdir — sonraki rapor üretimi LLM çağrısı yapacaktır (latency + maliyet artar). Sadece gerçekten gerekli olduğunda kullanın.
</Tip>

## Yetki

| Rol                    | Yetki                                                     |
| ---------------------- | --------------------------------------------------------- |
| `CEO` / `CMO`          | ❌ Erişim yok                                              |
| `Analytics` / `Agency` | ❌ Erişim yok                                              |
| `platform_admin`       | ✅ Tam erişim (tüm org'lar için cache invalidate edebilir) |

<Warning>
  Cache invalidation **platform\_admin** yetkisi gerektirir. Org admin (`CEO`/`CMO`) bile bu endpoint'e erişemez. Endpoint-level guard: `Depends(require_platform_admin)`.
</Warning>

## 4 Scope

<CardGroup cols={2}>
  <Card title="all" icon="trash">
    **Tüm composer LLM cache** silinir. Org/locale/variant/run filtresi yok. Genelde major prompt revision sonrası kullanılır.
  </Card>

  <Card title="locale" icon="globe">
    Belirli locale(s)'lere ait cache silinir. Örn: `locales=["tr"]` → sadece Türkçe narrative cache'i temizler.
  </Card>

  <Card title="variant" icon="flask">
    Belirli variant(s)'lara ait cache silinir. Örn: `variant_ids=["v1.0"]` → eski variant cache'i temizler, A/B test reset için.
  </Card>

  <Card title="run_id" icon="bullseye">
    Tek bir run\_id'ye ait cache silinir. Targeted invalidation — diğer run'lar etkilenmez. Örn: `run_id="24774cd8-..."`.
  </Card>
</CardGroup>

## UI Flow

<Steps>
  <Step title="Admin paneli aç">
    Sol menüden **Admin** (yalnızca `platform_admin` için görünür) → 9. tab **"LLM Önbellek"** (`RefreshCw` icon).
  </Step>

  <Step title="Primary action — Invalidate All">
    Sayfa üstünde büyük **"Invalidate All"** butonu (destructive variant). Tıklandığında **ConfirmDialog** açılır:

    ```
    ⚠️ Tüm composer LLM cache'i silinecek
    Toplam: ~12,847 cache entry
    Bu işlem geri alınamaz. Sonraki rapor üretimi LLM çağrısı yapacaktır.
    [İptal]  [Onayla, Invalidate]
    ```
  </Step>

  <Step title="Advanced (collapsible)">
    **"Advanced"** chevron tıklandığında 3 scope açılır:

    * **By Locale**: multi-select dropdown (`tr`, `en`) + Invalidate butonu
    * **By Variant**: multi-select dropdown (mevcut variant\_id listesi) + Invalidate butonu
    * **By Run ID**: text input (UUID v4) + Invalidate butonu
  </Step>

  <Step title="Invalidation tetiklendi">
    Backend `POST /admin/cache/invalidate-composer-llm` çağrısı arka planda **Redis SCAN cursor** ile non-blocking iteration yapar. UI loading state'i gösterir, sonuçta toast notification: "✅ 8,243 cache entry invalidated (locale=tr)".
  </Step>

  <Step title="Audit log + Sentry tag">
    İşlem audit log'a yazılır: `cache_invalidated_composer_llm` (user\_id, scope, params, count). Sentry tag eklenir: `cache_invalidation_scope=locale`.
  </Step>
</Steps>

## Redis SCAN Cursor Pattern

Backend `llm.py.invalidate_cache_keys` fonksiyonu **`SCAN`** kullanır, **`KEYS`** **KULLANMAZ**:

```python theme={null}
async def invalidate_cache_keys(redis, scope, **params):
    pattern = build_pattern(scope, **params)  # composer:llm:tr:*
    cursor = 0
    deleted = 0
    while True:
        cursor, keys = await redis.scan(cursor, match=pattern, count=100)
        if keys:
            await redis.delete(*keys)
            deleted += len(keys)
        if cursor == 0:
            break
    return deleted
```

<Note>
  **Neden SCAN, KEYS değil?** `KEYS *` Redis'i **O(N)** blocking — production'da 100K+ key varsa Redis 5-10 saniye blok olur, tüm uygulama timeout alır. `SCAN` cursor-based iteration, **non-blocking** — production-safe.
</Note>

## API Endpoint

```bash theme={null}
curl -X POST https://api.mmmytics.com/api/v1/admin/cache/invalidate-composer-llm \
  -H "Authorization: Bearer $PLATFORM_ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "locale",
    "locales": ["tr"]
  }'
```

**Response:**

```json theme={null}
{
  "success": true,
  "data": {
    "scope": "locale",
    "deleted_count": 8243,
    "duration_ms": 1284
  }
}
```

## Audit Log Entry

```json theme={null}
{
  "event": "cache_invalidated_composer_llm",
  "user_id": "user-uuid-admin",
  "timestamp": "2026-05-28T14:23:47Z",
  "scope": "locale",
  "params": { "locales": ["tr"] },
  "deleted_count": 8243,
  "ip_address": "203.0.113.42"
}
```

## Sentry Tag

Sentry event'lerine cache invalidation context'i eklemek için tag set edilir:

```python theme={null}
sentry_sdk.set_tag("cache_invalidation_scope", scope)
sentry_sdk.set_tag("cache_invalidation_count", deleted_count)
```

Sentry dashboard'da bu tag'lerle filter yapılabilir; cache invalidation sonrası **artan LLM call rate** ve **latency p95 artışı** korelasyonu izlenir.

## Sorun Giderme

### `CACHE_INVALIDATE_SCOPE_INVALID`

**Sebep:** Scope + parametre uyumsuzluğu (örn: `scope=locale` ama `locales` boş, `scope=run_id` ama UUID format geçersiz).

**Çözüm:**

* `scope=all` → ek parametre gerekmez
* `scope=locale` → `locales: ["tr", "en"]` dolu liste
* `scope=variant` → `variant_ids: ["v1.0", "v1.1"]` dolu liste
* `scope=run_id` → geçerli UUID v4

Detay: [Sorun Giderme](/troubleshooting#cache_invalidate_scope_invalid).

### Invalidation sonrası rapor üretimi yavaş

**Sebep:** Cache miss — sonraki rapor LLM çağrısı yapıyor (\~10-30 saniye).

**Çözüm:** Normal davranış. Cache repopulate olduktan sonra (ilk birkaç rapor) latency normale döner.

### Deleted count = 0

**Sebep:** Belirtilen scope'ta cache entry yok (henüz hiç rapor üretilmemiş veya zaten temizlenmiş).

**Çözüm:** Pattern doğru mu kontrol et (locale code, variant\_id formatı). Redis'te aktif key sayısını `redis-cli DBSIZE` ile kontrol et.

## Sonraki Adım

<CardGroup cols={2}>
  <Card title="Per-Brand Benchmark Override" icon="sliders" href="/settings/benchmark-overrides">
    Marka-spesifik KPI eşik değerleri
  </Card>

  <Card title="L7 Reports" icon="file-pdf" href="/6-istasyon/l7-reports">
    Hibrit rapor üretimi + cache davranışı
  </Card>
</CardGroup>
