Admin Yönetim Paneli (Admin Console)
Kurs moderasyonu, finansal yönetim, ödeme/iade, fiyat katmanları (admin.price-tiers).
Coursio’da Admin rolüne sahip kullanıcılar, Admin Console üzerinden kurs onaylama/reddetme, platform geliri ve bekleyen ödemeleri yönetme, iade (refund) takibi ve fiyat katmanları (tier) güncellemesi yapar. Bu sayfa kullanıcı ve kurs moderasyonu, finansal yönetim (toplam gelir, bekleyen ödemeler, iade) ve admin.price-tiers.tsx ile global fiyat güncellemelerini açıklar.
Genel Erişim
Section titled “Genel Erişim”- Yetki: Tüm admin route’larında
session.user.role === "admin"kontrolü yapılır; değilse 401 veya 404. - Layout:
app/routes/admin.tsx— sidebar (Kurslar, Kullanıcılar, Finans, Ödemeler, İadeler, Fiyat Katmanları, Abonelik vb.) ve bildirim kutusu (Son Hareketler / Tüm Bildirimler). - Dashboard:
admin._index.tsx—getAdminStats(db)ile özet metrikler (kullanıcı sayıları, onay bekleyen kurs, gelir özeti).
Kullanıcı ve Kurs Moderasyonu
Section titled “Kullanıcı ve Kurs Moderasyonu”Kurs Onaylama / Reddetme Süreçleri
Section titled “Kurs Onaylama / Reddetme Süreçleri”Dosya: app/routes/admin.courses.tsx
Loader:
- Tüm kurslar eğitmen bilgisiyle sayfalanır (
courses+usersjoin); alanlar:id,title,status,slug,price,thumbnailUrl,instructor.name,instructor.email. statusdeğerleri:draft,pending_review,published,archived.
Liste:
- Her satırda kurs başlığı, eğitmen adı/e-posta, durum badge’i (İnceleme Bekliyor / Yayında / Taslak), fiyat, thumbnail.
- İnceleme Bekliyor (
pending_review): “İncele” ve “Onayla” / “Reddet” aksiyonları.
Karar mekanizması:
- Onayla: GraphQL
updateCourse(id, status: "published")→ kurs yayına alınır. - Reddet: GraphQL
updateCourse(id, status: "draft")→ kurs taslağa çekilir. - İşlem sonrası toast ve
revalidate()ile liste güncellenir.
Önizleme: “İncele” ile admin.course.$slug.preview sayfasına gidilir.
Kurs Önizleme (İnceleme Öncesi)
Section titled “Kurs Önizleme (İnceleme Öncesi)”Dosya: app/routes/admin.course.$slug.preview.tsx
URL: /admin/course/:slug/preview
Loader:
- Admin oturumu kontrolü;
getCourseBySlug(db, params.slug)ile kurs;getCourseCurriculum(db, course.id)ile müfredat. - Toplam süre ve ders sayısı müfredattan hesaplanır; bölgesel fiyat
getRegionalPrice(db, course.priceTierId, country)ile alınır.
Sayfa: Kurs başlığı, açıklama, öğrenme çıktıları, müfredat (bölüm/ders listesi, video hazır bilgisi), fiyat. “Denetim Listesine Dön” ile /admin/courses’a dönülür; onay/red işlemi kurs listesi sayfasındaki butonlarla yapılır.
Finansal Yönetim
Section titled “Finansal Yönetim”Toplam Platform Geliri ve Metrikler
Section titled “Toplam Platform Geliri ve Metrikler”Dosya: app/routes/admin.finances.tsx
Loader: getAdminStats(db) ve getAdminSystemStats(db) (app/lib/db-queries.ts).
getAdminStats: earnings tablosundan (status ≠ refunded) satış türüne göre ayrıştırma:
- Brüt satış geliri, organik/direkt/affiliate satış sayıları ve payları.
- Abonelik: brüt abonelik geliri, platform payı (%60), eğitmen havuzu (%40).
- Toplam iade tutarı, net platform karı (totalRevenue) vb.
getAdminSystemStats:
- Tamamlanan öğretmen ödemeleri toplamı (
payout_requests.status = 'completed'). - Bekleyen ödemeler toplamı (
payout_requests.status = 'pending').
Sayfa kartları (örnek):
- Net Platform Karı (totalRevenue).
- Organik Satış Payı (purchaseRevenue, %55 komisyon).
- Bekleyen Ödemeler (system.pendingPayoutAmount).
- Toplam İade Tutarı (totalRefundedAmount).
- Affiliate satış payı ve affiliate komisyonu.
- Abonelik ekonomisi: brüt gelir, platform %60, eğitmen havuzu %40.
- “Gelir Havuzunu Dağıt” butonu →
adminDistributeSubscriptionEarnings(totalPool)mutation (abonelik havuzunu eğitmenlere dağıtım).
Bekleyen Ödemeler ve Ödeme Onayı
Section titled “Bekleyen Ödemeler ve Ödeme Onayı”Dosya: app/routes/admin.payouts.tsx
Loader: payout_requests (pending/processing/completed/rejected) listesi; her talep için eğitmen bilgisi (ad, e-posta, ülke, manualPayoutDetails — TR için IBAN/Payoneer).
Action (Form POST):
intent:approve|reject,payoutId: talep ID.- Onay (approve):
- Eğitmen TR değilse ve
stripeConnectIdvarsa: Stripetransfers.createile platform bakiyesinden eğitmen Connect hesabına transfer;stripeTransferIdkaydedilir. - TR ise: manuel ödeme (admin bankadan gönderir); sadece durum güncellenir.
payout_requests: status =completed,processedAt,stripeTransferId(varsa).- İlgili
earnings: status =withdrawn.
- Eğitmen TR değilse ve
- Red (reject):
payout_requests.status = 'rejected'; ilgili earnings status =completed(tekrar talep edilebilir).
İade (Refund) Yönetimi
Section titled “İade (Refund) Yönetimi”Dosya: app/routes/admin.refunds.tsx
Loader:
- İade edilmiş kayıtlar:
enrollments+coursesjoin;refundedAt IS NOT NULLverefundStatus = 'completed'. - Öğrenci ve eğitmen adı/e-posta ayrı sorgularla eklenir.
- Toplam iade tutarı (course price toplamı) hesaplanır.
Sayfa: Tablo — öğrenci, kurs, eğitmen, kayıt tarihi, iade tarihi, iade sebebi (not_satisfied, wrong_course, technical_issues, other), kurs fiyatı. Arama ve filtre (örn. sebep). İade işleminin kendisi (Stripe refund vb.) genelde webhook veya ayrı refund aksiyonu ile yapılır; bu sayfa geçmiş iadeleri listeler ve raporlar.
Fiyat Katmanları (Tier Management)
Section titled “Fiyat Katmanları (Tier Management)”Dosya: app/routes/admin.price-tiers.tsx
URL: /admin/price-tiers (admin layout altında).
Amaç: Bölgesel fiyatlandırmada kullanılan price_tiers ve tier_prices tablolarını yönetmek; eğitmenler kurslarına bir tier atar, bu sayfadan global fiyat güncellenir.
Loader
Section titled “Loader”- Admin kontrolü;
priceTierstablosuorderartan sırada; her tier içintierPrices(currency, amount) çekilir. - Dönüş:
tiers— her biriid,name,order,prices: [{ id, tierId, currency, amount }].
Action (Form intent’lere göre)
Section titled “Action (Form intent’lere göre)”| intent | Açıklama |
|---|---|
createTier | Yeni katman: name, order → price_tiers insert. |
updateTier | Katman güncelle: tierId, name, order → price_tiers update. |
deleteTier | Katman sil: tierId → price_tiers delete (cascade ile tier_prices da silinir). |
addPrice | Tier’a fiyat ekle: tierId, currency, amount → tier_prices insert. |
updatePrice | Fiyat güncelle: priceId, amount → tier_prices update. |
deletePrice | Fiyat sil: priceId → tier_prices delete. |
Para birimleri: USD, EUR, TRY, GBP (CURRENCIES sabiti). Her tier için bu para birimlerinde ayrı satır; eksik currency’ler için “Fiyat ekle” formu.
Sayfa Yapısı
Section titled “Sayfa Yapısı”- Başlık: “Fiyat Katmanları” — “Eğitmenlerin kurslarına atayabileceği katmanları ve bölgesel fiyatları buradan yönetin.”
- Yeni katman ekle: Form — name, order; submit → createTier.
- Mevcut katmanlar: Accordion/liste — her tier için ad, sıra, fiyat sayısı; genişletilince:
- Tier ad/sıra güncelleme formu (updateTier).
- Fiyat listesi: currency + amount + “Kaydet” (updatePrice) + “Sil” (deletePrice).
- Eksik currency için “Fiyat ekle” (addPrice) — currency select + amount.
- “Katmanı sil” (deleteTier).
Böylece global fiyat güncellemeleri tek yerden yapılır; kurslar price_tier_id ile bu katmanlara bağlı olduğu için bölgesel fiyatlar (pricing-engine, tier_prices) otomatik güncellenir.
| Konu | Açıklama |
|---|---|
| Kurs moderasyonu | admin.courses: liste (status badge); Onayla → updateCourse(…, published); Reddet → draft. Önizleme: admin.course.$slug.preview. |
| Finansal yönetim | admin.finances: getAdminStats (gelir, organik/affiliate/abonelik, iade); getAdminSystemStats (bekleyen ödemeler); abonelik havuzu dağıtımı. |
| Bekleyen ödemeler | admin.payouts: liste; approve → Stripe transfer (TR değilse) veya manuel (TR); reject → status güncelleme. |
| İade yönetimi | admin.refunds: iade edilmiş enrollment listesi, toplam iade tutarı, arama/filtre. |
| Fiyat katmanları | admin.price-tiers: tier CRUD + tier_prices CRUD (currency/amount); global fiyat güncellemeleri. |
İlgili mimari: Bölgesel Fiyatlandırma (tier_prices kullanımı), Stripe Connect ve TR Payout (ödeme onayı).
İlgili Dosyalar
Section titled “İlgili Dosyalar”app/routes/admin.tsx— Admin layout; session ve role kontrolü; Son hareketler / Tüm bildirimler.app/routes/admin._index.tsx— Admin dashboard.app/routes/admin.courses.tsx— Kurs listesi, onay/red.app/routes/admin.course.$slug.preview.tsx— Kurs önizleme.app/routes/admin.users.tsx,admin.finances.tsx,admin.payouts.tsx,admin.refunds.tsx,admin.messages.tsx,admin.price-tiers.tsx,admin.subscription.tsx— Alt sayfalar.app/routes/api.admin.activities.ts— GET /api/admin/activities.app/lib/db-queries.ts— getAdminStats, getAdminNotificationCounts, getAdminRecentActivities, getAdminAllActivities.app/lib/stripe-connect-payout.ts— processPayoutTransfer (admin onayı sonrası).