# Partner API Entegrasyon Planı — "subastro" ve Sonraki Astrolog Siteleri İçin

**Durum:** Taslak / Planlama
**Tarih:** 2026-07-22
**İlgili proje:** `../subastro` (PHP Laravel, wizard'lı astroloji danışmanlık scripti)

## 1. Amaç

`subastro`, bağımsız astrologlar için satılabilir/kurulabilir bir Laravel scripti. Her kurulum kendi
veritabanı ve kendi PayTR mağazasıyla çalışan **tek-kiracılı (single-tenant)** bir site. Bu siteler,
harita hesaplama, **harita çizimi (görsel)** ve AI yorum üretme işini kendileri yapmayacak — bizim asıl
astroloji motorumuz olan bu projeden (**astro-bilge-backend**) **sunucudan sunucuya (server-to-server)**
bir API üzerinden hizmet alacak. Yani subastro'nun tükettiği üç ayrı ürün var: (1) ham harita verisi,
(2) harita çizimi/görseli, (3) AI destekli yazılı yorum — bkz. §5.2-5.4.

Bugün `astro-bilge-backend`'in `routes/api.php` dosyasındaki API, **son kullanıcı hesabına** (Sanctum ile
giriş yapmış `User`) bağlı çalışıyor — mobil uygulama bunu kullanıyor. Bu API, `subastro` gibi dış
sitelerin kullanması için uygun değil çünkü:

- Kimlik doğrulama son kullanıcı login'i gerektiriyor (dış sitenin ziyaretçisi bizim `users` tablomuzda yok).
- Kredi/limit sistemi kullanıcı bazlı, partner/site bazlı değil.
- Rate limiting ve maliyet takibi partner ölçeğinde düşünülmemiş.

Bu doküman, mevcut hiçbir şeyi bozmadan **yeni, izole bir "Partner API" katmanı** eklemek için gereken
işleri tanımlar.

## 2. Mimari Yaklaşım

```
subastro (ve gelecekteki diğer astrolog siteleri)
        │  X-Partner-Key: pk_live_xxx  (HTTPS, sunucu→sunucu)
        ▼
astro-bilge-backend  /api/partner/v1/*
        │
        ├── PartnerAuth middleware  → partner_sites tablosundan doğrulama
        ├── Mevcut servisler yeniden kullanılır:
        │     ChartVisualizerService, AstroController mantığı,
        │     IndexController::generateNatalReport, AiService, OpenAIServiceRefactored
        ├── PartnerUsageLog → her istek loglanır, kredi düşülür
        └── JSON response: { success, data, error, meta: { credits_remaining } }
```

Önemli ilke: **Yeniden hesaplama motoru yazılmayacak.** Mevcut `ChartVisualizerService`,
`SwetestService`, `AiService`, `RelationshipChartService`, `FirdariaService` vb. servisler olduğu gibi
kullanılacak; Partner API sadece bunların üzerine ince bir "adapter/controller" katmanı ekleyecek.

## 3. Yeni Veritabanı Tabloları

### `partner_sites`
| Kolon | Tip | Açıklama |
|---|---|---|
| id | bigint | |
| name | string | Örn. "Elif Yıldız Astroloji (subastro)" |
| slug | string unique | |
| api_key_hash | string | `hash('sha256', $plainKey)` — plain key sadece oluşturulurken bir kez gösterilir |
| api_key_prefix | string | UI'de göstermek için `pk_live_a1b2...` gibi kısaltılmış hali |
| status | enum | active / suspended / trial |
| domain | string nullable | CORS/loglama için, opsiyonel doğrulama |
| credit_balance | integer | Ön ödemeli kredi bakiyesi (rapor türüne göre düşülür) |
| price_overrides | json nullable | Partnere özel rapor fiyatları (boşsa varsayılan fiyat tablosu kullanılır) |
| webhook_url | string nullable | İleride async rapor bildirimleri için |
| rate_limit_per_minute | integer default 30 | |
| notes | text nullable | |
| timestamps | | |

### `partner_usage_logs`
| Kolon | Tip | Açıklama |
|---|---|---|
| id | bigint | |
| partner_site_id | FK | |
| endpoint | string | Örn. `interpretation.natal` |
| request_hash | string | İdempotency / tekrar isteklerini tespit etmek için |
| credits_charged | integer | |
| status | enum | success / failed / cached |
| duration_ms | integer | |
| meta | json nullable | İstek özet bilgisi (PII olmayan) |
| created_at | timestamp | |

### `partner_credit_transactions`
| Kolon | Tip | Açıklama |
|---|---|---|
| id | bigint | |
| partner_site_id | FK | |
| type | enum | topup / usage / refund / adjustment |
| amount | integer | Pozitif (topup) veya negatif (usage) |
| balance_after | integer | |
| reference | string nullable | Elle yüklemede admin notu, PayTR dekontu vb. |
| timestamps | | |

## 4. Kimlik Doğrulama & Güvenlik

- Header: `X-Partner-Key: pk_live_...` (Bearer token yerine özel header — Sanctum/son-kullanıcı auth
  akışıyla karışmasın diye bilinçli olarak ayrı tutulur).
- `App\Http\Middleware\PartnerApiAuth`:
  1. Header'ı al, boşsa 401.
  2. `hash('sha256', $key)` ile `partner_sites.api_key_hash` eşleşmesini bul.
  3. `status !== 'active'` ise 403.
  4. `$request->attributes->set('partner_site', $partnerSite)`.
  5. Rate limit: `RateLimiter::for('partner-api', ...)` — partner bazlı, `rate_limit_per_minute` alanına göre.
- Tüm partner route'ları `routes/partner_api.php` gibi ayrı bir dosyada, `api/partner/v1` prefix'i ve
  `partner.auth` middleware grubu altında toplanır — mevcut `routes/api.php`'ye dokunulmaz.
- IP kısıtlaması opsiyonel (partner `domain`/sunucu IP'si sabitse `allowed_ips` json alanı eklenebilir —
  MVP'de gerekli değil, HTTPS + gizli key yeterli).
- Loglarda asla `api_key` plain text yazılmaz, sadece `api_key_prefix`.

## 5. Endpoint Listesi (v1)

Ortak response zarfı:
```json
{
  "success": true,
  "data": { ... },
  "meta": { "credits_remaining": 4820, "credits_charged": 20 }
}
```
Hata durumunda:
```json
{ "success": false, "error": { "code": "INSUFFICIENT_CREDITS", "message": "Kredi bakiyesi yetersiz." } }
```

### 5.1 Referans / Ücretsiz Uçlar
- `GET /api/partner/v1/reference/cities?q=istanbul` — `MainController::search` proxy'si, ücretsiz.
- `GET /api/partner/v1/reference/extra-points-catalog` — `AstroController::getExtraPointsCatalog` proxy'si, ücretsiz.
- `GET /api/partner/v1/ping` — anahtar geçerliliği + kalan kredi kontrolü (sağlık kontrolü).

### 5.2 Ham Harita Hesaplama — Sayısal Veri (yorumsuz, düşük maliyetli)
- `POST /api/partner/v1/chart/natal`
  - Body: `{ "date": "1994-02-18", "time": "07:40", "place": {"lat":..,"lng":..,"tz":"Europe/Istanbul"} }`
  - `ChartVisualizerService` / mevcut `AstroController::getFullChartData` mantığını sarmalar.
  - Gezegen konumları, evler, açılar **JSON** olarak döner — **AI yorum içermez**, düşük kredi maliyeti.
- `POST /api/partner/v1/chart/synastry` — iki doğum verisiyle sinastri haritası (mevcut `getSynastryChartData` mantığı).
- `POST /api/partner/v1/chart/composite` — `DualChartService` üzerinden.

### 5.3 Harita Çizimi — Görsel (subastro'nun "Astro Bilge'den Yorum Al" sayfasındaki harita görselleri buradan gelir)
- `POST /api/partner/v1/chart/natal/drawing`
  - Aynı body (`date`, `time`, `place`) + opsiyonel `format` (`svg` | `png`, varsayılan `svg`).
  - `ChartVisualizerService::generateSvg()` **birebir** kullanılır — yeni bir çizim motoru yazılmaz.
  - Response: `{ "svg_data_uri": "data:image/svg+xml;base64,...", "png_url": null }` — `format=png` istenirse
    sunucu tarafında (ör. `Imagick`/`resvg`) SVG'den PNG'ye dönüştürülüp geçici bir imzalı URL olarak da
    sunulabilir (ikinci faz, MVP'de SVG yeterli — tarayıcıda ve PDF'te doğrudan gösterilebiliyor).
  - Ham veri (§5.2) ile aynı maliyet sınıfında, **AI/OpenAI çağrısı içermez** — bu yüzden metin
    yorumundan çok daha ucuza fiyatlandırılmalı (öneri: harita çizimi tek başına ~1-2 kredi, yorumla
    birlikte paket halinde satılabilir).
- `POST /api/partner/v1/chart/synastry/drawing` — iki kişilik sinastri haritası çizimi (varsa `renderSvgForChartKey('synastry', ...)` karşılığı).

### 5.4 AI Yorum Üretimi (yüksek maliyetli — subastro'nun "Astro Bilge'den Yorum Al" akışında harita çizimiyle birlikte sunulur)
- `POST /api/partner/v1/interpretation/natal` — `IndexController::generateNatalReport` + `AiService` yeniden kullanılır. Response: `{ title, content_html, content_text, word_count, chart_svg_data_uri, pdf_url }` — **metin yorumuyla birlikte harita çizimi de aynı yanıtta döner**, subastro tarafında ayrı bir istek atmaya gerek kalmaz.
- `POST /api/partner/v1/interpretation/relationship` — `RelationshipChartService` + AI, aynı şekilde çizim dahil.
- `POST /api/partner/v1/interpretation/yearly` — Solar Return / `FirdariaService` + AI.
- `POST /api/partner/v1/interpretation/pdf` — Var olan bir `report_id`'yi PDF olarak alma (dompdf, mevcut `AIAssistantController::generatePdf` deseni) — harita çizimi PDF'in içine gömülür.

Her AI endpoint isteği **eşzamanlı (senkron)** yanıtlanabilir (mevcut sistemde natal rapor birkaç
saniyede üretiliyor); ileride uzun sürecek rapor türleri için `202 Accepted` + `webhook_url` / polling
endpoint'i (`GET /interpretation/{id}`) eklenecek şekilde tasarlanmalı.

> **Not:** subastro tarafı yalnızca metin yorumunu değil, **harita çizimini de** ayrı bir ürün olarak
> sunabilmeli — bu yüzden §5.3 ve §5.4'ü ayrı endpoint'ler olarak tuttuk: bir danışan sadece "haritamı
> görmek istiyorum" diyebilir (ucuz, §5.3), bir başkası "detaylı yorum + harita" paketini alabilir (§5.4).

### 5.5 Kredi & Kullanım
- `GET /api/partner/v1/account` — partner adı, bakiye, bu ayki kullanım özeti.
- `GET /api/partner/v1/usage?from=&to=` — `partner_usage_logs` özeti (subastro admin panelinde "Astro Bilge kullanım raporu" göstermek için).

## 6. Kredi / Faturalama Modeli

**Önerilen:** Ön ödemeli kredi bakiyesi (mevcut `UserAiUsageLog` / kredi mantığına paralel).

- Her rapor türünün sabit bir kredi maliyeti vardır (örn. Natal AI yorum = 20 kredi, ham harita = 1 kredi).
- `partner_sites.price_overrides` ile partnere özel maliyet tanımlanabilir (ör. lansmanda subastro'ya indirimli).
- Kredi tükenince `403 INSUFFICIENT_CREDITS` döner; subastro tarafı bunu kullanıcıya "şu an AI yorum
  hizmeti geçici olarak kapalı" gibi zarif bir mesaja çevirmeli, **asla ham hata göstermemeli.**
- Kredi yükleme: MVP'de bizim (agency) tarafımızdan admin panelinden elle yüklenir
  (`partner_credit_transactions` type=topup). İleride partner'ın kendi PayTR'ı üzerinden bize ödeme yapıp
  otomatik kredi yüklemesi ayrı bir faz (bkz. §9 Faz 4).

## 7. Admin Paneli Eklentileri (astro-bilge-backend tarafında)

`app/Http/Controllers/Admin/` altına yeni bir `PartnerSiteController` eklenmeli:

- Partner site listesi + oluşturma (API key üretimi — oluşturulduğu anda tek seferlik gösterilir).
- Kredi yükleme formu.
- Kullanım grafiği (günlük/aylık istek sayısı, en çok kullanılan endpoint).
- Fiyat override formu (rapor türü → partnere özel kredi maliyeti).
- Durdurma / yeniden aktifleştirme (status).

Bu, mevcut `Admin/UserController`, `Admin/OrderController` desenleriyle aynı stilde yazılmalı (Blade +
mevcut admin layout).

## 8. subastro Tarafında Kullanım (referans — orada implemente edilecek)

`subastro` içinde `App\Services\AstroBilge\AstroBilgeApiClient` gibi bir servis:

```php
class AstroBilgeApiClient
{
    public function __construct(
        private string $baseUrl,   // site_settings.astrobilge_api_base_url
        private string $apiKey,    // site_settings.astrobilge_api_key
    ) {}

    public function natalInterpretation(array $birthData): array
    {
        $response = Http::withHeaders(['X-Partner-Key' => $this->apiKey])
            ->timeout(30)
            ->post("{$this->baseUrl}/api/partner/v1/interpretation/natal", $birthData);

        if ($response->failed()) {
            throw new AstroBilgeApiException($response);
        }

        return $response->json('data');
    }
}
```

subastro tarafında bu servis, AI rapor satın alma akışında (ödeme başarılı → API çağrısı → PDF/HTML
teslimatı) kullanılacak. Hata durumunda (kredi bitti, timeout, 5xx) kullanıcıya "raporun birkaç dakika
içinde e-posta ile gönderilecek" gibi bir yedek akış sunulmalı ve arka planda queue job ile retry edilmeli
— senkron HTTP çağrısını kullanıcıyı bekletmeden queue'ya almak (`ShouldQueue`) önerilir.

## 9. Uygulama Fazları

| Faz | Kapsam |
|---|---|
| **Faz 0** | `partner_sites`, `partner_usage_logs`, `partner_credit_transactions` migration'ları + modeller |
| **Faz 1** | `PartnerApiAuth` middleware, `routes/partner_api.php`, `/ping`, `/reference/*` (ücretsiz uçlar) |
| **Faz 2** | `/chart/natal`, `/chart/synastry` — mevcut servislerin adapter'ı, kredi düşme mantığı |
| **Faz 3** | `/interpretation/natal`, `/interpretation/relationship`, `/interpretation/yearly`, PDF üretimi |
| **Faz 4** | Admin panelde Partner Site yönetimi (CRUD, kredi yükleme, kullanım raporu) |
| **Faz 5** | subastro ilk canlı entegrasyonu, uçtan uca test (gerçek kredi düşümü, hata senaryoları) |
| **Faz 6** (opsiyonel, ileride) | Partner'ın kendi ödemesiyle otomatik kredi yüklemesi, webhook/async rapor teslimatı, partner başına özel prompt/marka sesi ayarları |

## 10. Geriye Dönük Uyumluluk

- Mevcut `routes/api.php`, mobil uygulama, panel — **hiçbiri değişmeyecek.**
- Yeni tablolar mevcut `users`, `packages`, `subscriptions` şemasına dokunmaz, tamamen ek (additive).
- `AiService` / `OpenAIServiceRefactored` içinde partner-özel prompt ihtiyacı çıkarsa, mevcut
  `PromptSelectorService` deseni genişletilir (partner_id parametresi eklenir) — kırılma riski düşük.

## 11. Açık Sorular (karar bekliyor)

1. Partner API için ayrı bir subdomain mi (`partner-api.astrobilge.com`) yoksa aynı domain altında
   `/api/partner/v1` mi? (Öneri: aynı domain, ayrı prefix — DNS/SSL karmaşıklığı yaratmaz.)
2. Kredi fiyatlandırması TL bazlı mı, soyut "kredi" birimi mi? (Öneri: soyut kredi — döviz/KDV
   değişikliklerinde iki tarafı da güncellemek zorunda kalmayız.)
3. subastro dışındaki gelecekteki astrolog siteleri için partner başına marka/prompt özelleştirmesi ne
   kadar derin olmalı? (MVP'de gerek yok, Faz 6'da değerlendirilir.)
