# 02 — Ürün Modülü

## Ne İş Yapar?

Tenant kendi ürünlerini Flovy paneline girer. Bu ürünler RAG sistemine embed edilir ve AI'ın "search_products" tool'u ile aranır. Ziyaretçi "kırmızı tişört var mı?" dediğinde sistem bu tablodan arama yapar.

Panel.tekyerden.co'daki ürün modülünün sadeleştirilmiş versiyonudur — sadece Flovy'nin ihtiyacı olan alanlar alınmıştır.

---

## Veri Modeli

```
products
├── id (UUID)
├── tenant_id (FK → tenants)
├── title
├── description
├── bullet_points (JSON array)   ← "- %100 pamuk\n- Türkiye üretimi"
├── sku
├── barcode
├── price (DECIMAL 10,2)        ← TL
├── compare_at_price             ← İndirim öncesi fiyat (opsiyonel)
├── currency (default: TRY)
├── stock_quantity (INT)
├── stock_status (in_stock / low / out_of_stock)
├── low_stock_threshold (INT, default: 5)
├── is_active (BOOL)
├── images (JSON array of URLs)
├── category_id (FK → product_categories)
├── embedding_status (pending/indexed/failed)
├── embedding_updated_at
├── meta (JSON)                  ← Serbest alanlar (ağırlık, boyut vb.)
├── created_at
└── updated_at

product_categories
├── id
├── tenant_id
├── name
├── slug
└── parent_id (self-ref, opsiyonel)

product_variants
├── id
├── product_id
├── title                        ← "Kırmızı / L"
├── sku
├── price
├── stock_quantity
├── attributes (JSON)            ← {"renk": "kırmızı", "beden": "L"}
└── is_active
```

---

## API Endpoint'leri

### Panel (JWT gerekli)
```
GET    /api/products                ← Liste (cursor pagination)
POST   /api/products                ← Yeni ürün ekle
GET    /api/products/{id}           ← Detay
PUT    /api/products/{id}           ← Güncelle
DELETE /api/products/{id}           ← Soft delete
POST   /api/products/{id}/reindex   ← Manuel embedding yenile

GET    /api/products/categories     ← Kategori listesi
POST   /api/products/categories     ← Yeni kategori
PUT    /api/products/categories/{id}
DELETE /api/products/categories/{id}

POST   /api/products/import/csv     ← Toplu CSV yükleme
GET    /api/products/import/template ← CSV şablonu indir
```

### Widget (api_key gerekli, JWT yok)
```
GET  /api/widget/{api_key}/products/search?q=&category=&max_price=
```

---

## Embedding Akışı

Ürün eklendiğinde veya güncellendiğinde:

```
1. embedding_status = "pending" olarak kaydet
2. Celery task tetikle: IndexProductTask(product_id)
3. Task içinde:
   a. title + description + bullet_points birleştir
   b. Gemini text-embedding-004 ile embed et
   c. flovy_knowledge_chunks tablosuna yaz (source_type="product")
   d. embedding_status = "indexed"
```

Embedding bitmeden ürün aranabilir (DB LIKE sorgusu fallback), ama vektör aramasına girmez.

---

## Arama Mantığı (search_products tool)

```python
# 1. Metin araması (hızlı fallback)
products = db.query(Product).filter(
    Product.tenant_id == tenant_id,
    Product.is_active == True,
    or_(
        Product.title.ilike(f"%{query}%"),
        Product.description.ilike(f"%{query}%"),
    )
)

# 2. Embedding araması (varsa, üstteki ile birleştirilir)
query_vec = embed(query)
chunks = KnowledgeRetriever.top_k(tenant_id, query_vec, source_type="product", k=10)
```

Sonuçlar kullanıcıya `carousel` UI bloğu olarak dönür:
```json
{
  "ui_blocks": [{
    "type": "product_carousel",
    "products": [{
      "id": "...",
      "title": "Collagen Plus",
      "price": 299.00,
      "compare_at_price": 399.00,
      "stock_status": "low",
      "stock_quantity": 3,
      "image": "...",
      "has_variants": true,
      "variants": [...]
    }]
  }]
}
```

---

## İş Kuralları

- Tenant izolasyonu: Her sorgu `tenant_id` ile filtrelenir.
- `stock_status` otomatik güncellenir: `stock_quantity <= low_stock_threshold` → `low`, `== 0` → `out_of_stock`.
- Silinen ürün soft delete: `deleted_at` set edilir, embedding'i de chunk tablosundan kaldırılır.
- CSV import'ta aynı SKU varsa upsert yapılır.
- Ürün güncellendiğinde `embedding_status = "pending"` resetlenir, Celery reindex tetiklenir.
- Varyantlı ürünlerde `add_to_cart` tool'u `variant_id` olmadan çağrılamaz — AI bunu bilir (persona'da yazılı).
