# Social Poster — Setup & Operations

Otomatik tahmin kartı üretip Twitter / Facebook / Instagram'a postlayan modül.
Cron her **10 dakikada bir** çalışır, **yaklaşan 10-60 dk içindeki maçları**
yakalar, AI Engine'den tahmin alır, 1080×1080 görsel üretir, caption üretir,
3 platforma post eder.

## 1) ENV değişkenleri

`.env`'ye ekle:

```bash
# Master switch — false ise cron çalışmaz, manual endpoint'ler de boş döner.
SOCIAL_POSTER_ENABLED=true

# Hangi sporlar (virgüllü liste). Varsayılan: football,basketball
SOCIAL_POSTER_SPORTS=football,basketball

# Yaklaşan maç penceresi (dakika). Varsayılan 10-60.
SOCIAL_POSTER_WINDOW_MIN=10
SOCIAL_POSTER_WINDOW_MAX=60

# Tek cron koşusunda kaç maç post edilir (rate-limit koruması). Varsayılan 5.
SOCIAL_POSTER_MAX_PER_RUN=5

# Public base URL — Instagram media upload için fotoğrafın HTTPS'ten erişilebilir
# olması ŞART. Localhost ile IG çalışmaz; production domain veya ngrok kullan.
APP_BASE_URL=https://api.iddaai.com

# AI Engine URL (orchestrator)
AI_ENGINE_URL=http://localhost:8000

# ─── Twitter / X ───
TWITTER_API_KEY=...
TWITTER_API_SECRET=...
TWITTER_ACCESS_TOKEN=...
TWITTER_ACCESS_SECRET=...

# ─── Meta (Facebook + Instagram) ───
META_PAGE_ACCESS_TOKEN=...   # FB Page'in long-lived access token'ı
META_PAGE_ID=...             # FB Page numeric ID
META_IG_USER_ID=...          # IG Business account numeric ID
META_GRAPH_API_VERSION=v25.0 # opsiyonel

# ─── Caption AI (opsiyonel — yoksa template caption kullanılır) ───
ENABLE_GEMINI=true
GEMINI_API_KEY=...
GEMINI_MODEL=gemini-1.5-flash

# Veya local Ollama:
OLLAMA_BASE_URL=http://localhost:11434
SOCIAL_POSTER_OLLAMA_MODEL=llama3.1
```

## 2) API anahtarlarını alma

### Twitter / X
1. https://developer.x.com → Project + App oluştur
2. App'ın "Keys and tokens" → "API Key", "API Secret" al
3. User authentication settings → "Read and write and Direct Message"
4. "Access Token and Secret" generate et (bu hesap adına post eder)
5. **Free tier**: 1500 tweet/ay, 50 post/24 saat — 10 dk'lık cron'la günde
   ~144 koşu × 5 post = 720 potansiyel post → free tier yetmez, **Basic plan
   ($200/ay)** lazım. Cron interval'i 30 dk'ya alıp 50/gün kalmak istersen
   `@Cron("*/30 * * * *")` olarak değiştir.

### Meta (Facebook + Instagram)
1. https://developers.facebook.com → App oluştur (type: Business)
2. Facebook Page bağla (mevcut sayfan yoksa oluştur)
3. Instagram Business hesabını Facebook Page'e bağla
4. Graph API Explorer'dan **page access token** al (User token değil!)
5. Long-lived token'a çevir (60 gün geçerli, refresh edilebilir)
6. **Page ID**: `https://graph.facebook.com/me/accounts?access_token=...`
7. **IG User ID**: `graph.facebook.com/{pageId}?fields=instagram_business_account&access_token=...`
8. Required permissions: `pages_show_list`, `pages_manage_posts`,
   `pages_read_engagement`, `instagram_basic`, `instagram_content_publish`

### Gemini (caption AI — opsiyonel)
- https://aistudio.google.com → API key (free tier yeterli, günde ~1500 istek)
- `ENABLE_GEMINI=true` + `GEMINI_API_KEY=...`
- Gemini yoksa template caption kullanılır (yine SEO'lu, sadece daha statik)

## 3) Test komutları

```bash
# Servisi başlat
npm run start:dev

# Health endpoint — auth gerekmez
curl http://localhost:3005/social-poster/health | jq

# Manuel preview (görsel + JSON) — superadmin token gerekir
curl -H "Authorization: Bearer $TOKEN" \
     http://localhost:3005/social-poster/preview/<matchId>

# Görseli tarayıcıda direkt göster
open http://localhost:3005/social-poster/preview-png/<matchId>?token=$TOKEN

# Manuel post (tek maç, tüm platformlara) — superadmin token
curl -X POST -H "Authorization: Bearer $TOKEN" \
     http://localhost:3005/social-poster/post/<matchId>

# Cron'u beklemeden full sweep koş — superadmin token
curl -X POST -H "Authorization: Bearer $TOKEN" \
     http://localhost:3005/social-poster/run-now
```

## 4) SEO özellikleri

### Image dosya adı (SEO)
Eskiden: `prediction_basketball_xyz12345_1716595200000.jpg` (opaque)
Yeni: `sampiyonlar-ligi-unicaja-malaga-vs-aek-20260525.jpg` (Google indexable)

### Yan dosya: metadata sidecar
Her görsel için aynı dizinde `.json`:
- `title`, `description`, `og:*`, `schema.org SportsEvent`, `picks[]`
- Sayfada `<head>` Open Graph + Twitter Cards bu dosyadan beslenir
- Schema.org markup zengin sonuç (Google rich snippet) sağlar

### Caption (SEO + hashtags)
Her post 12'ye kadar küratör hashtag içerir:
- Marka: `#MaçTahmini #İddaa #BugünMaç`
- Spor: `#Futbol #Basketbol #FutbolTahmin`
- Lig: `#SüperLig #PremierLeague #ŞampiyonlarLigi #EuroLeague #NBA`
- Bölge: `#Türkiye #İngiltere #İspanya`
- Takım: `#Galatasaray #Fenerbahçe`
- Gün: `#PazarTahmini #CumartesiTahmini`
- Market: `#AltÜst #KGVar #ÇifteŞans #MaçSonucu #Handikap`

LLM (Gemini) caption üretiyorsa hashtag'leri çıkarır; sistem kendi
hashtag set'ini ekler. Tutarlı index için tek kaynak.

## 5) İzleme

```bash
# Health endpoint — periyodik monitor
curl http://localhost:3005/social-poster/health | jq

# Sample output:
{
  "enabled": true,
  "sports": ["football", "basketball"],
  "window_min_minutes": 10,
  "window_max_minutes": 60,
  "max_posts_per_run": 5,
  "top_leagues_loaded": 42,
  "posted_match_count": 137,
  "last_run_at": "2026-05-25T03:10:00.123Z",
  "last_run_result": { "posted": 4, "skipped": 1, "errors": 0 },
  "twitter_available": true,
  "meta_facebook_available": true,
  "meta_instagram_available": true,
  "ai_engine_url": "http://localhost:8000",
  "app_base_url": "https://api.iddaai.com"
}
```

`posted_match_count` `storage/social-poster-posted.json`'dan okunur, son 500
match ID hafızada — aynı maçı 2 kere post etmez.

## 6) Rate limit ipuçları

| Platform | Free limit | Tedbir |
|---|---|---|
| Twitter | 50 post/24 saat | `SOCIAL_POSTER_MAX_PER_RUN=2` + cron `*/30` → günde ~96 |
| Facebook | ~200 post/saat (Page) | Default config rahat |
| Instagram | 25 post/24 saat | `MAX_PER_RUN=1` + cron `*/60` → günde 24, sınırın hemen altında |

IG en sıkı sınır — production için **IG ayrı cron'da daha seyrek post**
yapılması önerilir (kod henüz tek cron, ileride ayrılabilir).

## 7) Hangi maçlar seçilir?

`top_leagues.json` dosyasındaki league_id'ler içinden:
- Şu anda 10-60 dakika sonra başlayacak
- Daha önce post edilmemiş
- `sport: football, basketball` filtresi geçen

`top_leagues.json` yoksa **tüm liglerden** maç seçer (hacmi yüksek tutar).
Sadece premium ligler postlamak istersen dosyayı doldur.

## 8) Görsel formatı

- **Boyut**: 1080×1080 (Instagram square — Twitter da kabul ediyor)
- **Format**: JPEG, quality 94
- **Tema**: Sport'a göre değişir — football yeşil, basketball turuncu
- **İçerik**: Lig logosu + ülke bayrağı, takım logoları + adları, HT skor,
  FT skor, top 3 tahmin (confidence ile), risk badge

Card layout `image-renderer.service.ts` içinde — value-pick yıldız ile
işaretli, scenario top 3 listelenir, footer alt'ta tarih + brand.

## 9) Sık sorular

**Q: Görseller nereye yazılıyor?**
`public/predictions/` (gitignored). ServeStatic ile `/predictions/<file>.jpg`
URL'inden erişilir.

**Q: Eski görseller temizleniyor mu?**
Hayır — manuel temizlik gerekir. Cron eklemek istersen `LimitResetterTask`
örneği var.

**Q: AI Engine çalışmıyorsa ne olur?**
Cron tahmin alamaz, log'a hata düşer, devam eder. Sonraki koşuda dener.

**Q: Bir maç 2 kere post ediliyor mu?**
Hayır — `postedMatchIds` set'i Match ID bazında dedup yapar, dosyaya yazılır
(restart-safe).

**Q: Caption Gemini olmadan ne kadar iyi?**
Template caption tüm bilgileri + 12 hashtag içerir. SEO açısından yeterli,
sadece anlatım daha statik. Gemini ile her post için özgün metin.
