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.
Veritabanı Modeli
Section titled “Veritabanı Modeli”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 lockingsubscriptionPlan/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.academyIdalanı, kursun hangi academy vitrinde görüneceğini belirler.
Tenant Çözümleme (Host → Academy)
Section titled “Tenant Çözümleme (Host → Academy)”Dosya: app/lib/tenant.ts → getTenantByRequest(db, request)
Çözümleme mantığı:
- Ana domain / localhost:
achidemy.net,www.achidemy.net,localhost,127.0.0.1→null(ana pazaryeri) - Subdomain:
*.achidemy.netve lokal*.localhost→academies.subdomainile eşleşme - Custom domain: diğer host’lar →
academies.customDomainile eşleşme - Subdomain veya custom domain eşleşmesi bulunursa tenant döner (MVP:
subscriptionStatusvitrin routing’ini şu an kapatmaz; yorum:tenant.tsiç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.
Storefront İzolasyonu (Kurs Kataloğu)
Section titled “Storefront İzolasyonu (Kurs Kataloğu)”Dosyalar:
app/routes/_index.tsx— academy host’unda kurslarıacademyIdile filtrelerapp/routes/courses.all.tsx— katalog/arama sorgularınaacademyIdfiltresi eklerapp/lib/db-queries.ts— helper sorgularda opsiyonelacademyIdfiltresi
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.
Open vs Closed (academyMode)
Section titled “Open vs Closed (academyMode)”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 Paneli: Academy Yönetimi
Section titled “Eğitmen Paneli: Academy Yönetimi”Eğitmen panelinde academy’yi yönetmek için temel sayfalar:
| Route | Dosya | Açıklama |
|---|---|---|
/:lang/instructor/academy | instructor.academy._index.tsx | Dashboard; kurulum rehberi, istatistikler |
/:lang/instructor/academy/settings | instructor.academy.settings.tsx | Domain/tema/mode ayarları |
/:lang/instructor/academy/students | instructor.academy.students.tsx | Öğrenci atama ve yönetimi |
/:lang/instructor/academy/builder | instructor.academy.builder.tsx | Vitrin tasarımı (CMS) |
/:lang/instructor/academy/pages | instructor.academy.pages._index.tsx | Dinamik sayfalar listesi (Page Manager) |
/:lang/instructor/academy/pages/:id | instructor.academy.pages.$id.tsx | Zengin metin sayfa editörü |
Academy Dashboard
Section titled “Academy Dashboard”Dosya: app/routes/instructor.academy._index.tsx
Dashboard sayfası şunları içerir:
- SetupGuide (Kurulum Rehberi): Adım adım academy kurulum süreci
- Academy Özeti: İsim, subdomain ve canlı URL
- İstatistikler: Toplam kurs ve öğrenci sayısı
- Hızlı Erişim: Ayarlar ve öğrenci yönetimi butonları
SetupGuide Bileşeni
Section titled “SetupGuide Bileşeni”Dosya: app/components/instructor/AcademySetupGuide.tsx
Eğitmenin academy kurulum sürecini takip etmesini sağlayan interaktif rehber:
| Adım | ID | Tamamlanma Koşulu |
|---|---|---|
| 1 | basicSettings | Academy adı ve subdomain dolu |
| 2 | branding | Logo veya tema rengi özelleştirilmiş |
| 3 | addCourse | En az bir kurs academy’ye bağlı |
| 4 | assignStudents | En 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ı
Academy Settings (Ayarlar)
Section titled “Academy Settings (Ayarlar)”Dosya: app/routes/instructor.academy.settings.tsx
İki ana bölüm:
-
Web sitesi ve domain:
- Academy adı
- Subdomain (
subdomain.achidemy.net) - Academy modu seçimi (open/closed)
-
Tasarım ve tema:
- Ana tema rengi (color picker)
- Hero başlık ve alt başlık
Academy Builder (CMS)
Section titled “Academy Builder (CMS)”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,TabsContentInput,Textarea,Button
Academy Students (Öğrenci Yönetimi)
Section titled “Academy Students (Öğrenci Yönetimi)”Dosya: app/routes/instructor.academy.students.tsx
Manuel öğrenci atama ve yönetimi:
-
Yeni öğrenci atama formu:
- Öğrenci e-posta adresi
- Kurs seçimi (academy’ye bağlı kurslar)
-
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
Academy Landing Page
Section titled “Academy Landing Page”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 Cases | Bağımsız eğitmenler, eğitim kurumları, kurumsal eğitim |
| Features | Subdomain, CMS, öğrenci yönetimi, ödeme, analitik |
| How It Works | 4 adımlı kurulum süreci |
| AI Highlight | Yapay zeka destekli kurs oluşturma |
| Final CTA | 14 gün ücretsiz deneme → kayıt sayfasına yönlendirme |
CTA Yönlendirmesi: /register?intent=academy
Sidebar Bileşeni
Section titled “Sidebar Bileşeni”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" },];Çoklu Dil Desteği
Section titled “Çoklu Dil Desteği”Academy modülü için tüm UI metinleri 6 dilde çevrilmiştir:
| Dil | Dosya |
|---|---|
| İngilizce | app/locales/en.json → academy.* |
| Türkçe | app/locales/tr.json → academy.* |
| Almanca | app/locales/de.json → academy.* |
| İspanyolca | app/locales/es.json → academy.* |
| Fransızca | app/locales/fr.json → academy.* |
| Japonca | app/locales/ja.json → academy.* |
Çeviri namespace’leri:
academy.sidebar.*— Sidebar metinleriacademy.dashboard.*— Dashboard metinleriacademy.builder.*— CMS/Builder metinleriacademy.settings.*— Ayarlar metinleriacademy.students.*— Öğrenci yönetimi metinleriacademy.setupGuide.*— Kurulum rehberi metinleri
| Konu | Açıklama |
|---|---|
| Tenant çözümleme | Host → subdomain/customDomain → academies tablosu |
| Tema enjeksiyonu | themeConfig.branding.primaryColor → CSS değişkeni |
| Kurs izolasyonu | courses.academyId filtresi ile sadece ilgili kurslar |
| Open vs Closed | academyMode ile fiyat/CTA gizleme veya gösterme |
| SetupGuide | 4 adımlı interaktif kurulum rehberi |
| CMS Builder | Görsel vitrin düzenleyicisi (hero, about, footer) |
| Page Manager | Dinamik sayfalar (slug) + zengin metin editörü |
| Öğrenci yönetimi | Manuel atama, enrollment takibi |
Lokal test akışı için Yerelde Subdomain/Tenant Geliştirme sayfasına bakın.
İlgili Dosyalar
Section titled “İlgili Dosyalar”app/lib/tenant.ts— Tenant çözümleme mantığıapp/routes/instructor.academy._index.tsx— Academy dashboardapp/routes/instructor.academy.settings.tsx— Academy ayarlarıapp/routes/instructor.academy.students.tsx— Öğrenci yönetimiapp/routes/instructor.academy.builder.tsx— Vitrin tasarımı (CMS)app/components/instructor/AcademySidebar.tsx— Academy sidebarapp/components/instructor/AcademySetupGuide.tsx— Kurulum rehberi bileşeniapp/components/ui/card.tsx— Card UI bileşenleriapp/components/ui/label.tsx— Label UI bileşeniapp/routes/$lang.my-achidemy.tsx— Academy landing page