Tüm operasyon, tek bir domain-odaklı panelde
Kod tabanı işlevsel katmanlara değil, iş alanlarına (domain) göre organize edilmiştir. Her koleksiyon kümesi bir iş sürecine karşılık gelir — birbirine hook'larla bağlanır, iş mantığı src/lib/ altında paylaşılan çözücülerde toplanır.
Biletler & Rezervasyon
Günlük iş akışının kalbi: turlar, transfer biletleri, tedarikçi biletleri.
reservations/Transferler
Dinamik fiyat motoru: sabit, zone ve km bazlı; mesafe matrisi.
transfers/Turlar & Paketler
Çok dilli katalog; özellik & program seçenekleriyle.
tours/Tedarikçiler
Cari hesaplar, işlemler (debit/credit), faturalar & mutabakat.
suppliers/Lokasyonlar
Ülkeler, ilçeler, bölgeler, oteller, havalimanları.
locations/Entegrasyonlar
GetYourGuide & Tripadvisor siparişleri otomatik sisteme akar. Google Maps API ile enlem/boylam bazlı mesafe hesabı ve km fiyatlandırması.
integrations/Para Birimi
TCMB (Merkez Bankası) kur senkronu ve temizliği.
core/CurrencyRatesÇekirdek
Kullanıcılar, Medya, Siteler, Booking kaynakları, Seed kayıtları.
core/Tek panel, birden çok web sitesi
Aynı CMS, birden fazla web sitesinin turlarını profesyonelce yönetir. Her içerik bir siteye izoledir; her site kendi desteklediği dilleri tanımlar.
- Sites koleksiyonu:
name, benzersizdomain,isActive,supportedLocales(7 dile kadar),description. - Her Tour'da zorunlu
siteilişkisi → tur sadece ilgili sitede görünür. - TourPackage,
sitebilgisini bağlı tur'dan otomatik türetir. - BlogPost'ta zorunlu, Media'da opsiyonel
sitealanı. - Admin liste kolonlarında
sitegörünür → hızlı filtreleme.
Aktif siteler — tek panel
Her sitenin içeriği ve desteklediği diller birbirinden bağımsız — yönetim tek ekrandan.
Tur kataloğu ve satılabilir paketler
Her tur için önce içerik tanımlanır (açıklama, program, özellikler); ardından bu tura ait satılabilir paketler oluşturulur: dönem, fiyat ve araç/tedarikçi maliyeti. Aynı tura farklı dönemler veya fiyat seçenekleri için birden fazla paket açılabilir.
Tour — "Ne"
name,shortDescription,longDescription(çok dilli)district/region,slug,media[]- Özellik havuzları:
includedFeatures,excludedFeatures,highlightFeatures,safetyFeatures… → TourFeatureOptions - Tura özel
custom*Features(havuz dışı tek seferlik) programItems[]— itinerary: activity / pickup / meal / boat / visit …
TourPackage — "Ne zaman & kaça"
- Zorunlu
tourilişkisi;name/description periods[]— tarih aralığı, günler, saatler, buluşma/pickup noktalarıpricingModel:public(kişi başı) veyaprivate_group(grup)publicPrices[]— katılımcı tipi + fiyat + para birimisupplierPaxPrices[]— tedarikçi maliyeti (kişi/tip bazlı)
7 dil, tek tıkla yapay zeka çevirisi Aktif
İçerik 7 dilde tutulur (tr varsayılan, fallback açık). Bir dokümanı diğer dillere çevirmek için admin'de tek bir buton yeterli — arka planda TranslationService çalışır.
- Sağlayıcı: OpenRouter veya OpenAI uyumlu API (env ile yapılandırılır).
- Akıllı tarama: Koleksiyon şemasındaki tüm lokalize alanları (text, textarea, richText, array, group) özyinelemeli bulur.
- Batch: Çevrilecek metinleri ≤6000 karakterlik parçalara böler; URL, HTML etiketi ve
{{placeholder}}'ları korur. - Lexical desteği: Zengin metin (rich text) ağacını çözüp tekrar kurar.
- Endpoint'ler:
/api/<koleksiyon>/translate-single(tek dil) ve/translate(çoklu dil, varsayılanen,de,ru).
Yapay zeka ile blog yazımı Yol Haritası
Blog koleksiyonları ve AI içerik üretim akışı tasarlanmıştır. Editör "AI ile Oluştur" der, başlık + prompt girer; sistem yapılandırılmış içerik üretip mevcut taslağı doldurur.
Prompt gir
Başlık + tema/prompt + dil seçilir.
→AI üretir
generateBlogPostContent() → JSON: title, excerpt, sections (h2+paragraflar), SSS, meta.
Lexical'a dönüştür
buildBlogLexicalContent() editör formatına çevirir.
Taslak + çeviri
Kayıt taslak doldurulur; ardından AI ile çoklu dile çevrilir.
BlogPosts
title, excerpt, heroImage, content (Lexical), metaTitle/metaDescription, zorunlu site, categories, authors, publishedAt, slug, draft/published durumu.
BlogCategories
Siteye bağlı kategoriler: name, description (çok dilli), slug. Aynı çeviri altyapısı kategorilerde de kullanılır.
S3 tabanlı, siteye duyarlı medya kütüphanesi Aktif
Tüm görseller S3 / S3-uyumlu depolamada tutulur (yerelde RustFS/MinIO). Yükleme sırasında Sharp ile optimize edilir.
S3 Depolama
@payloadcms/storage-s3 ile bucket'a media/ önekiyle yazılır. Endpoint, bucket ve kimlik env'den gelir.
Alt & Site
Zorunlu alt (erişilebilirlik), opsiyonel site ile medya belirli bir siteye atanabilir.
Bağlamlı kullanım
Tours media[] (görsel + caption + sortOrder), Blog heroImage/metaImage. Public okuma, admin yükleme.
Tedarikçi hesapları, ödemeler ve otomatik bakiye takibi Aktif
Her tedarikçi için ayrı bir hesap tutulur. Yapılan her satış borç olarak, ödeme ise alacak olarak işlenir; bakiye otomatik güncellenir. Tüm tutarlar TCMB döviz kuruyla TL'ye çevrilerek raporlanır.
Tedarikçi & Hesap
Tedarikçi kaydı açılır; sistem otomatik olarak sıfır bakiyeli bir hesap oluşturur.
→Borç (debit)
Bilet/transfer satışı bir SupplierTransaction üretir → bakiyeye eklenir.
→Ödeme (credit)
manual-payment ile nakit/havale ödeme → bakiyeden düşülür.
Mutabakat
SupplierInvoice "paid" olunca otomatik mahsup işlemi oluşur, bakiye güncellenir.
| Koleksiyon | Rol | Önemli alanlar |
|---|---|---|
Suppliers | Tedarikçi kaydı | name, currency (EUR/USD/GBP/TRY/RUB), services[] |
SupplierAccounts | Cari bakiye | balance (otomatik), currency (senkron), /manual-payment |
SupplierTransactions | Borç/alacak defteri | type (debit/credit), amount, fxRateToTry, amountTry |
SupplierInvoices | Mutabakat belgesi | invoiceNumber, tarih aralığı, status (unpaid/paid/cancelled) |
🧾 AccountDetails
İşlem listesi, tarih filtresi, PDF export (jsPDF), manuel ödeme formu ve fatura oluşturma — hepsi tek panelde.
📑 SupplierInvoiceTools
Fatura sihirbazı: tarih/işlem otomatik prefill, PDF önizleme, mükerrer fatura kontrolü (çakışan dönem engellenir).
SMTP bağlantısı ve bilet üzerinden e-posta Aktif
Birden çok SMTP hesabı tanımlanır; her hesabın bir önceliği ve yönlendirme kuralları vardır. Bilet detayından müşteriye dil seçerek e-posta gönderilir; sistem ilk başarısız hesaptan sonrakine düşer (fallback) ve sonucu loglar.
⚙️ NotificationEmailAccounts
smtpgrubu:host,port,username,password,secure,ignoreTlspriority— düşük olan önce denenirroutingbayrakları:useForCustomerPrimary,useForSupplier*,useForGyg,useForSystemDefault
📤 Gönderim akışı
- Bilette CustomerNotificationActions → dil (tr/en/de/ru) + gönderici tercihi
- Backend HTML gövde + PDF eki (pdfmake/jspdf) üretir
getNotificationEmailCandidates()→ öncelikli hesap listesisendEmailUsingAccounts()sırayla dener (fallback)- Sonuç ReservationNotifications'a loglanır:
status,deliveryLog,sentAt
record-notification endpoint'i ise gönderimi yalnızca loglar.İki transfer fiyat modeli
Transfer rotaları iki şekilde fiyatlanır: Araç bazlı sabit fiyat veya KM-bazlı dinamik fiyat. Google Maps API üzerinden enlem/boylam ile gerçek yol mesafesi hesaplanır; gece zammı ve sezon çarpanları otomatik uygulanır.
Araç bazlı sabit fiyat
Her araç tipi için önceden tanımlanmış rota fiyatı. Hızlı teklif, öngörülebilir maliyet.
KM-bazlı dinamik fiyat
Google Maps ile gerçek mesafe × km tarifesi + gece zammı + sezon çarpanı. Rota eklendikçe otomatik hesaplanır.
| Bileşen | Açıklama |
|---|---|
KmPricingConfig (global) | km başı fiyat + minimum ücret, mesafe kademeleri, gece zammı (22:00–06:00), aylık seasonalMultipliers, round-trip indirimi |
VehicleTypes | pricingMode (private/shuttle), vehicleClass, maxCapacity, features |
TransferAddOns | pricingType (per_booking / per_person), rota bazlı override (etkin/fiyat/tip) |
DistanceMatrix | mesafe cache: google_maps / manual / haversine (yol faktörü ×1.3 fallback) |
TransferQuotes | 15 dk TTL, satır kalemleri, kur/fiyat snapshot, active/consumed/expired/cancelled |
Otomatik REST/GraphQL + public transfer API'leri Aktif
Payload her koleksiyon için otomatik REST (/api/<koleksiyon>) ve GraphQL (/api/graphql) sunar — hepsi access-control korumalı. Üstüne, dış istemciler için özel public transfer API'leri vardır (30 istek/dk IP limiti).
| Endpoint | Amaç |
|---|---|
POST /api/transfers/price | Fiyat teklifi (fixed / dynamic) |
POST /api/transfers/available-routes | Origin/destination'a uyan rotalar |
GET /api/transfers/locations | Lokasyon arama (ad/kod) |
GET /api/transfers/vehicle-types | Araç tipi kataloğu |
POST /api/transfers/book | Teklifi bilete çevir (quote → ticket) |
POST /api/gyg/1/* | GetYourGuide entegrasyonu (Basic Auth) |
Kimlik doğrulama yöntemleri: admin cookie · x-jobs-secret / Bearer / ?token= (automation) · tenant API key (Authorization: Bearer veya x-api-key) · GYG için Basic Auth.
# Sabit rotada 2 yolcu için EUR teklif curl -X POST "http://localhost:3000/api/transfers/price" \ -H "Authorization: Bearer <tenant-api-key>" \ -H "Content-Type: application/json" \ -d '{ "mode": "fixed", "routeID": "12", "vehicleTypeID": "3", "transferDate": "2026-07-15", "passengerCount": 2, "isRoundTrip": false, "requestedCurrency": "EUR" }'
Tarayıcıdan API çağrısı Yol Haritası
Admin panelinin içinde, tarayıcıda çalışan bir API konsolu (/admin/curl-console). Seed endpoint'lerini ve Payload REST API'sini terminal açmadan tetikler. API anahtarı yalnızca localStorage'da tutulur; istek/yanıt sunucuda loglanmaz.
Hedef seçici
Same-origin / local dev / staging / prod. /api/curl-proxy sunucu-sunucu iletir (CORS/CSRF derdi yok).
Güvenli proxy
Admin-only, origin whitelist (SSRF koruması), 5MB body, 30sn timeout, 30 istek/dk.
Geçmiş & preset
Method, query builder, header editörü, JSON body; son 20 istek geçmişi ve kayıtlı preset'ler.
.kilo/plans/curl-console.md. Districts/Regions için hazır REST sorgu örnekleri plan dosyasında mevcut.Tek komutla, prod-dostu veri yükleme Aktif
Seed işlemleri hem CLI script'leri hem de HTTP endpoint'leri olarak sunulur. Docker runtime'da pnpm bulunmadığı için, prod'da seed/cleanup tamamen curl ile yapılabilir. Çoğu işlem dryRun ile önce simüle edilir.
| Endpoint | İş |
|---|---|
/api/seed-registries/transfer-demo/seed | 13 demo transfer rotası + fiyat |
/api/seed-registries/transfer-routes/seed | Fiyat listesinden rotalar (kapasite bazlı) |
/api/seed-registries/pricing-zones/seed | Varsayılan zone tarifeleri |
/api/seed-registries/tour-detail-defaults/seed | Tur özellik/program varsayılanları |
/api/seed-registries/vehicle-types/sync-codes | Araç tipi kodlarını senkronla |
Yetki: x-jobs-secret header'ı (→ PAYLOAD_JOBS_SECRET / PAYLOAD_SECRET) veya admin oturumu. SeedRegistries koleksiyonu ne yapıldığını namespace bazlı kaydeder (entries, lastSeededAt).
# 1) Ne olacağını gör (DB'ye yazmaz) curl -X POST "http://localhost:3000/api/seed-registries/transfer-demo/seed" \ -H "x-jobs-secret: $PAYLOAD_JOBS_SECRET" \ -H "Content-Type: application/json" \ -d '{"dryRun": true}' # 2) Çıktıyı onayladıktan sonra gerçekten yaz curl -X POST "http://localhost:3000/api/seed-registries/transfer-demo/seed" \ -H "x-jobs-secret: $PAYLOAD_JOBS_SECRET" \ -H "Content-Type: application/json" \ -d '{"dryRun": false}'
pnpm run import:payload-data REST üzerinden toplu kayıt yükler; datas/ klasöründe hazır referans veri setleri (ör. tur paketi import şablonu) bulunur.Gözden kaçabilecek ama önemli parçalar
Zamanlanmış işler
sync-tcmb-rates (her gün 15:35) ve cleanup-old-currency-rates (aylık, 90 gün saklama). payload.config.ts cron ile.
Entegrasyonlar
GetYourGuide & Tripadvisor siparişleri otomatik sisteme akar. Google Maps API ile enlem/boylam bazlı mesafe ve km fiyatlandırması.
Docker
Standalone Next.js, Postgres 18, RustFS. Runtime image'da pnpm yok → seed/cleanup HTTP endpoint'leriyle yapılır.
Otomasyon yetkisi
canAccessJobs → canAccessAutomation: admin kullanıcı veya secret header/token.
Güvenli migration
Drizzle, push:false. Sadece açık migration (pnpm payload migrate); fresh/reset açık onay ister.
TCMB kurları
Merkez Bankası kurları senkronlanır; tedarikçi işlemleri ve transfer teklifleri bu kurlarla TRY'ye sabitlenir.