Skip to content

Academy (Storefront) Tenant Mimarisi

Subdomain/custom domain tabanlı academy çözümleme, tema enjeksiyonu, open/closed LMS modu, vitrin izolasyonu ve eğitmen academy yönetim paneli.

Achidemy “Shopify benzeri” davranmak için her academy’yi bir tenant olarak ele alır ve tenant’ı host üzerinden çözer:

  • Lokal: http://ahmethoca.localhost:8787/en/...
  • Prod: https://ahmethoca.achidemy.net/en/... (örnek academy subdomain)
  • Custom domain: https://www.ahmethoca.com/en/...

Bu sayfada academy çözümleme, tema enjeksiyonu, kurs izolasyonu (sadece o academy’ye bağlı kurslar) ve eğitmen academy yönetim paneli anlatılır.

Academies (tenant):

  • Tablo: academies
  • Önemli alanlar:
    • ownerId: academy sahibi (eğitmen)
    • subdomain: tenant ana anahtarı (örn. ahmethoca)
    • customDomain: özel alan adı (opsiyonel)
    • academyMode: open (açık mağaza) / closed (kapalı LMS)
    • themeConfig / themeConfigDraft: tema + CMS (bloklar, siteTheme, adminTheme, authPages, siteSeo)
    • draftVersion / publishedVersion: optimistic locking
    • subscriptionPlan / subscriptionStatus: Stripe academy planı (Starter/Pro/Scale)
    • stripeSubscriptionId, stripeCustomerId

themeConfig yapısı (güncel):

type BlockData = {
id: string;
type: "navbar" | "hero" | "course-grid" | "features" | "footer";
variant: string;
settings: Record<string, unknown>;
};
type ThemeConfig = {
primaryColor?: string; // legacy
heroTitle?: string; // legacy
heroSubtitle?: string; // legacy
blocks?: BlockData[]; // ✅ anasayfa CMS blokları (published)
siteTheme?: { /* storefront renk, font, button */ };
adminTheme?: { /* eğitmen paneli */ };
authPages?: { login?: AuthPageConfig; register?: AuthPageConfig };
siteSeo?: { defaultMetaTitle?: string; noIndex?: boolean; /* ... */ };
};

Detay: Academy Visual Builder, Academy Auth Pages.

Courses → Academy bağlama:

  • courses.academyId alanı, kursun hangi academy vitrinde görüneceğini belirler.

Dosya: app/lib/tenant.tsgetTenantByRequest(db, request)

Çözümleme mantığı:

  1. Ana domain / localhost: achidemy.net, www.achidemy.net, localhost, 127.0.0.1null (ana pazaryeri)
  2. Subdomain: *.achidemy.net ve lokal *.localhostacademies.subdomain ile eşleşme
  3. Custom domain: diğer host’lar → academies.customDomain ile eşleşme
  4. Subdomain veya custom domain eşleşmesi bulunursa tenant döner (MVP: subscriptionStatus vitrin routing’ini şu an kapatmaz; yorum: tenant.ts içinde “KRİTİK MVP DÜZELTMESİ”)

Eğitmen paneli abonelik kontrolü ayrıdır: instructor.academy.tsx / hasActiveAcademySubscription — builder ve academy ayarları için aktif plan gerekebilir.

Root Injection (Tema Kılık Değiştirme)

Section titled “Root Injection (Tema Kılık Değiştirme)”

Dosya: app/root.tsx

Root loader, her request’te tenant’ı çözer ve layout <head> içine CSS değişkenini enjekte eder:

  • :root { --primary: <tenant.themeConfig.branding.primaryColor> }
  • Tenant yoksa default --primary (app/app.css) korunur.

Dosyalar:

  • app/routes/_index.tsx — academy host’unda kursları academyId ile filtreler
  • app/routes/courses.all.tsx — katalog/arama sorgularına academyId filtresi ekler
  • app/lib/db-queries.ts — helper sorgularda opsiyonel academyId filtresi

Blok tabanlı render (paylaşılan layout)

Section titled “Blok tabanlı render (paylaşılan layout)”

Canlı vitrin render’ı StorefrontLayout üzerinden yapılır (app/components/storefront/StorefrontLayout.tsx):

  • Anasayfa: themeConfig.blocks
  • /p/:slug: academy_pages.publishedContent + global navbar/footer birleştirme

Detay: Storefront Runtime, Academy Visual Builder.

Academy academyMode === "closed" olduğunda vitrin davranışı değişir:

  • Fiyatlar ve satın alma CTA’ları gizlenir
  • Hero bölümünde “Öğrenci portalı girişi” CTA gösterilir
  • Sadece manuel atanmış öğrenciler kurs içeriklerine erişebilir

Eğitmen panelinde academy’yi yönetmek için temel sayfalar:

RouteDosyaAçıklama
/:lang/instructor/academyinstructor.academy._index.tsxDashboard; kurulum rehberi, istatistikler
/:lang/instructor/academy/settingsinstructor.academy.settings.tsxDomain/tema/mode ayarları
/:lang/instructor/academy/studentsinstructor.academy.students.tsxÖğrenci atama ve yönetimi
/:lang/instructor/academy/builderinstructor.academy.builder.tsxVitrin tasarımı (CMS)
/:lang/instructor/academy/pagesinstructor.academy.pages._index.tsxDinamik sayfalar listesi (Page Manager)
/:lang/instructor/academy/pages/:idinstructor.academy.pages.$id.tsxZengin metin sayfa editörü

Dosya: app/routes/instructor.academy._index.tsx

Dashboard sayfası şunları içerir:

  1. SetupGuide (Kurulum Rehberi): Adım adım academy kurulum süreci
  2. Academy Özeti: İsim, subdomain ve canlı URL
  3. İstatistikler: Toplam kurs ve öğrenci sayısı
  4. Hızlı Erişim: Ayarlar ve öğrenci yönetimi butonları

Dosya: app/components/instructor/AcademySetupGuide.tsx

Eğitmenin academy kurulum sürecini takip etmesini sağlayan interaktif rehber:

AdımIDTamamlanma Koşulu
1basicSettingsAcademy adı ve subdomain dolu
2brandingLogo veya tema rengi özelleştirilmiş
3addCourseEn az bir kurs academy’ye bağlı
4assignStudentsEn az bir öğrenci atanmış

Özellikler:

  • İlerleme çubuğu ve yüzde gösterimi
  • Tamamlanan adımlar yeşil ✓ ve soluk görünüm
  • Tamamlanmamış adımlarda “Başla” veya “Yapılandır” butonu
  • Bir sonraki adım vurgulanır (primary renk)
  • Tüm adımlar tamamlandığında kutlama mesajı

Dosya: app/routes/instructor.academy.settings.tsx

İki ana bölüm:

  1. Web sitesi ve domain:

    • Academy adı
    • Subdomain (subdomain.achidemy.net)
    • Academy modu seçimi (open/closed)
  2. Tasarım ve tema:

    • Ana tema rengi (color picker)
    • Hero başlık ve alt başlık

Dosya: app/routes/instructor.academy.builder.tsx

Görsel vitrin düzenleyicisi ile academy anasayfası tasarımı:

Builder sayfası artık blok tabanlı çalışır; sol panelde her blok ayarlanır, sağ panelde canlı önizleme yapılır.

Detay: Academy Visual Builder (Blok Tabanlı CMS).

Kullanılan UI Bileşenleri:

  • Card, CardHeader, CardTitle, CardContent (yeni eklendi)
  • Label (yeni eklendi)
  • Tabs, TabsList, TabsTrigger, TabsContent
  • Input, Textarea, Button

Dosya: app/routes/instructor.academy.students.tsx

Manuel öğrenci atama ve yönetimi:

  1. Yeni öğrenci atama formu:

    • Öğrenci e-posta adresi
    • Kurs seçimi (academy’ye bağlı kurslar)
  2. Aktif atamalar listesi:

    • Öğrenci adı ve e-postası
    • Atanan kurs
    • Atama tarihi

Atama mantığı:

  • Öğrenci sistemde kayıtlı olmalı (e-posta ile arama)
  • Kurs bu academy’ye bağlı olmalı
  • Aynı öğrenci-kurs kombinasyonu tekrar atanamaz

Dosya: app/routes/$lang.my-achidemy.tsx

Eğitmenler ve kurumlar için academy tanıtım sayfası:

Bölümİçerik
Hero”Kendi Online Akademinizi Kurun” vurgusu, 3 temel avantaj
Use CasesBağımsız eğitmenler, eğitim kurumları, kurumsal eğitim
FeaturesSubdomain, CMS, öğrenci yönetimi, ödeme, analitik
How It Works4 adımlı kurulum süreci
AI HighlightYapay zeka destekli kurs oluşturma
Final CTA14 gün ücretsiz deneme → kayıt sayfasına yönlendirme

CTA Yönlendirmesi: /register?intent=academy


Dosya: app/components/instructor/AcademySidebar.tsx

Academy sayfaları için özel sidebar:

const ACADEMY_MENU_ITEMS = [
{ icon: Store, labelKey: "academy.sidebar.overview", path: "/instructor/academy" },
{ icon: Settings, labelKey: "academy.sidebar.settings", path: "/instructor/academy/settings" },
{ icon: Users, labelKey: "academy.sidebar.students", path: "/instructor/academy/students" },
{ icon: LayoutTemplate, labelKey: "academy.sidebar.builder", path: "/instructor/academy/builder" },
{ icon: FileText, labelKey: "academy.sidebar.pages", path: "/instructor/academy/pages" },
];

Academy modülü için tüm UI metinleri 6 dilde çevrilmiştir:

DilDosya
İngilizceapp/locales/en.jsonacademy.*
Türkçeapp/locales/tr.jsonacademy.*
Almancaapp/locales/de.jsonacademy.*
İspanyolcaapp/locales/es.jsonacademy.*
Fransızcaapp/locales/fr.jsonacademy.*
Japoncaapp/locales/ja.jsonacademy.*

Çeviri namespace’leri:

  • academy.sidebar.* — Sidebar metinleri
  • academy.dashboard.* — Dashboard metinleri
  • academy.builder.* — CMS/Builder metinleri
  • academy.settings.* — Ayarlar metinleri
  • academy.students.* — Öğrenci yönetimi metinleri
  • academy.setupGuide.* — Kurulum rehberi metinleri

KonuAçıklama
Tenant çözümlemeHost → subdomain/customDomain → academies tablosu
Tema enjeksiyonuthemeConfig.branding.primaryColor → CSS değişkeni
Kurs izolasyonucourses.academyId filtresi ile sadece ilgili kurslar
Open vs ClosedacademyMode ile fiyat/CTA gizleme veya gösterme
SetupGuide4 adımlı interaktif kurulum rehberi
CMS BuilderGörsel vitrin düzenleyicisi (hero, about, footer)
Page ManagerDinamik sayfalar (slug) + zengin metin editörü
Öğrenci yönetimiManuel atama, enrollment takibi

Lokal test akışı için Yerelde Subdomain/Tenant Geliştirme sayfasına bakın.

  • app/lib/tenant.ts — Tenant çözümleme mantığı
  • app/routes/instructor.academy._index.tsx — Academy dashboard
  • app/routes/instructor.academy.settings.tsx — Academy ayarları
  • app/routes/instructor.academy.students.tsx — Öğrenci yönetimi
  • app/routes/instructor.academy.builder.tsx — Vitrin tasarımı (CMS)
  • app/components/instructor/AcademySidebar.tsx — Academy sidebar
  • app/components/instructor/AcademySetupGuide.tsx — Kurulum rehberi bileşeni
  • app/components/ui/card.tsx — Card UI bileşenleri
  • app/components/ui/label.tsx — Label UI bileşeni
  • app/routes/$lang.my-achidemy.tsx — Academy landing page