Öğrenme Deneyimi (Student Experience)
Ders izleme paneli (learn.$slug), ilerleme takibi (api.update-progress), sertifika sistemi (PDF indirme).
Coursio’da öğrenciler kursa kayıt olduktan sonra ders izleme paneli ile içeriği takip eder, ilerleme anlık kaydedilir ve kurs bitiminde sertifika indirebilir. Bu sayfa Course Player (learn.$slug.tsx) yapısını, api.update-progress.ts ile ilerleme kaydını ve api.certificate.$id.download.ts ile dinamik PDF sertifika üretimini açıklar.
Ders İzleme Paneli (Course Player)
Section titled “Ders İzleme Paneli (Course Player)”Dosya: app/routes/learn.$slug.tsx
URL: /{lang}/learn/{courseSlug} (örn. /tr/learn/react-egitimi-abc12).
Loader Akışı
Section titled “Loader Akışı”- Auth: Oturum kontrolü; yoksa 401.
- Kurs:
getCourseBySlug(db, params.slug)ile kurs bulunur; yoksa 404. - Erişim:
checkEnrollment(db, userId, course.id)— kayıt yoksa 403. - Müfredat ve ilerleme (paralel):
getCourseCurriculumWithResources(db, course.id)→ bölümler, dersler, quiz’ler, kod egzersizleri, kaynaklar.getCompletedLessonIds(db, userId, course.id)→ tamamlanan ders ID’leri (user_lessons_progress.completed = true).getCompletedQuizIds,getCompletedExerciseIds→ tamamlanan quiz ve egzersiz ID’leri.
- Video URL’leri: Kayıtlı kullanıcı (veya önizleme dersi) için her video dersine
generateSignedVideoUrl(lesson.bunnyVideoId, libraryId, securityKey)ile imzalı URL eklenir (lesson.signedVideoUrl).
Loader çıktısı: course, curriculum, completedLessons, completedQuizzes, completedExercises, bunnyLibraryId.
Sayfa Yapısı
Section titled “Sayfa Yapısı”- Header: Geri (my-courses), kurs başlığı, müfredat menü toggle (mobil), “Sertifika kazan” metni.
- Ana alan:
- Video ders: Bunny embed iframe (
signedVideoUrlveya fallback embed URL), oynatma/duraklatma, süre takibi. Video bittiğinde otomatik tamamlama (toggleComplete) ve isteğe bağlı sonraki derse geçiş (geri sayım). - Quiz:
QuizPlayer— sorular, cevaplar, tamamlanıncarevalidateve sonraki içeriğe geçiş. - Kod egzersizi:
CodingWorkspace— dil, başlangıç kodu, test, tamamlanıncaonComplete→ revalidate.
- Video ders: Bunny embed iframe (
- Sekmeler (içerik / Q&A / notlar): İçerik kaynakları, Soru-Cevap (lazy
CourseQA), Notlar (lazyCourseNotes). - Yan panel (sidebar): Bölümler (Accordion), her bölümde ders / quiz / egzersiz listesi; tamamlananlar checkbox ile işaretli; tıklanınca
activeLesson/activeQuiz/activeExercisedeğişir. İlerleme özeti: “X / Y tamamlandı”.
Tamamlama ve İzlenme Raporu
Section titled “Tamamlama ve İzlenme Raporu”- Ders tamamlama: Kullanıcı checkbox ile “tamamladım” işaretleyebilir veya video sonuna gelince otomatik tamamlanır. Her iki durumda da
toggleLessonCompletion(lessonId, courseId, completed: true)GraphQL mutation’ı çağrılır;user_lessons_progress.completed = trueyapılır. Tamamlama sonrası izlenme süresi varsastopWatchingTracking(true)veyareportWatchedTime(0, true)ile son kez raporlanır. - İzlenme süresi (learn sayfası):
reportWatchedTime(minutes, lessonCompleted)→ GraphQLrecordLearningActivity(minutes, lessonCompleted, courseId)(streak ve abonelik izlenme logu). Periyodik (örn. 10 sn) veya ders bitişinde dakika bazlı gönderim.
İlerleme Takibi (Progress Tracking)
Section titled “İlerleme Takibi (Progress Tracking)”Anlık Kayıt: api.update-progress.ts
Section titled “Anlık Kayıt: api.update-progress.ts”Endpoint: POST /api/update-progress
Dosya: app/routes/api.update-progress.ts
Amaç: Video izlerken saniye bazında ilerlemenin anlık (heartbeat) kaydedilmesi.
Beklenen gövde (JSON):
userId,lessonId,courseId,instructorId(string)secondsWatched(number, > 0)isSubscription(boolean)
İşlemler (tek transaction):
- user_lessons_progress:
userId+lessonIdiçin kayıt yoksa insert (watchedSeconds: secondsWatched); varsawatchedSeconds = watchedSeconds + secondsWatched(onConflictDoUpdate). - daily_activities:
userId+ bugünün tarihi (YYYY-MM-DD) içintotalWatchedSecondsartırılır (streak/günlük aktivite). - subscription_watch_logs:
isSubscription === trueiseuserId,instructorId, tarih içindurationSecondsartırılır (abonelik havuzu payı).
Not: Ders “tamamlandı” bilgisi (completed: true) bu endpoint’te güncellenmez; tamamlama GraphQL toggleLessonCompletion ile yapılır. Bu API sadece izlenen süre birikimini günceller.
İstemci Tarafı
Section titled “İstemci Tarafı”- useLearningTracker (
app/hooks/useLearningTracker.ts): Oynatma durumu vecurrentTimeSecondsile periyodik heartbeat;fetch("/api/update-progress", { method: "POST", body: JSON.stringify({ courseId, lessonId, instructorId, secondsWatched, isSubscription }) }). (userId istemci tarafında eklenmeli veya API session’dan alınacak şekilde genişletilebilir.) - learn.$slug.tsx içinde izlenme raporu ağırlıklı olarak GraphQL
recordLearningActivity(dakika + lessonCompleted) ve ders bitişindetoggleLessonCompletionile yapılır.
Tamamlanan Ders Sorgusu
Section titled “Tamamlanan Ders Sorgusu”- getCompletedLessonIds (
app/lib/db-queries.ts):user_lessons_progresstablosundauserId,courseIdvecompleted = trueolan kayıtlarınlessonIdlistesini döner. Sidebar’daki tikler ve “X / Y tamamlandı” bu listeye göre hesaplanır.
Sertifika Sistemi
Section titled “Sertifika Sistemi”Koşul: Kurs Bitimi
Section titled “Koşul: Kurs Bitimi”Sertifika, tüm dersler tamamlandığında oluşturulur. GraphQL toggleLessonCompletion mutation’ında, bir ders completed: true yapıldıktan sonra:
- Kurstaki toplam ders sayısı (sadece lesson, quiz/egzersiz sayılmıyor) hesaplanır.
- Kullanıcının bu kursta
completed = trueolan ders sayısı hesaplanır. - Bu iki sayı eşitse ve o kullanıcı+kurs için
certificatestablosunda kayıt yoksa, yeni sertifika kaydı eklenir:userId,courseId,certificateCode(benzersiz),fullName,courseTitle,instructorName,issueDate.
Böylece kurs bitiminde sertifika otomatik oluşur.
İndirme: api.certificate.$id.download.ts
Section titled “İndirme: api.certificate.$id.download.ts”URL: GET /api/certificates/:id/download
Dosya: app/routes/api.certificate.$id.download.ts
Akış:
- Auth: Session kontrolü; giriş yoksa 401.
- Yetki: Sertifika
idveuserIdile sorgulanır; kayıt kullanıcıya ait değilse 404. - Kurs süresi: İlgili kurstaki tüm derslerin
lessons.durationtoplamı (saniye) alınır. - Doğrulama linki:
origin + "/verify/" + cert.certificateCode(örn.https://site.com/verify/CRT-xyz). - Referans no: Kategori kodu (categoryToCode) + sertifika kodunun son 6 karakteri (örn.
ABC-123456). - QR kod:
QRCode.toDataURL(verifyUrl)ile Base64 Data URL üretilir (PDF’e gömülecek). - PDF:
CertificateTemplateReact bileşeni (@react-pdf/renderer) ilerenderToStream(pdfElement)çağrılır;dataolarak sertifika alanları,durationSeconds,referenceNumber,qrDataUrlverilir. - Yanıt:
Content-Type: application/pdf,Content-Disposition: attachment; filename="certificate-{code}.pdf",Cache-Control: no-store.
Sertifika Şablonu (CertificateTemplate)
Section titled “Sertifika Şablonu (CertificateTemplate)”Dosya: app/components/CertificateTemplate.tsx
- @react-pdf/renderer kullanır:
Document,Page,Text,View,StyleSheet,Image. - Tek sayfa: arka plan, dekoratif çember/yıldız, başlık (“Sertifika” / “Certificate”),
fullName,courseTitle, “tamamladı” metni, süre (dakika/saat), referans numarası,issueDate, QR kod (Imagesrc={data.qrDataUrl}). - Görsel stil: Beyaz içerik alanı, mavi tonlarında arka plan; PDF çıktısı yazdırma ve paylaşım için uygundur.
Doğrulama (Verify)
Section titled “Doğrulama (Verify)”- Public URL:
/verify/:code— giriş gerekmez;certificateCodeile sertifika sorgulanır, varsa detay sayfası (veya doğrulama sonucu) gösterilir. Sertifika indirme ise yine/api/certificates/:id/downloadile kullanıcıya özeldir.
| Konu | Açıklama |
|---|---|
| Course Player | learn.$slug.tsx: loader (enrollment, curriculum, completed*, signedVideoUrl); header + ana alan (video/quiz/egzersiz) + sekmeler + sidebar (bölüm/ders listesi, ilerleme). |
| İlerleme | Dakika/tamamlama: GraphQL recordLearningActivity + toggleLessonCompletion. Saniye birikimi: POST /api/update-progress (userLessonsProgress.watchedSeconds, dailyActivities, subscriptionWatchLogs). |
| Tamamlama | user_lessons_progress.completed = true → getCompletedLessonIds; tüm dersler tamamlanınca sertifika kaydı oluşturulur. |
| Sertifika | Kurs bitince otomatik sertifika kaydı; indirme: GET /api/certificates/:id/download → CertificateTemplate ile PDF stream; QR + referans no ile doğrulama. |
İlgili mimari: Eğitmen ve Kurs Yönetimi (müfredat, video), Checkout & Webhooks (kayıt).
İlgili Dosyalar
Section titled “İlgili Dosyalar”app/routes/learn.$slug.tsx— Ders izleme paneli (Course Player); loader, müfredat, signedVideoUrl.app/routes/my-courses.learning.tsx— Kurslarım listesi.app/routes/api.update-progress.ts— Video izleme ilerlemesi (saniye) kaydı.app/routes/api.certificate.$id.download.ts— Sertifika PDF indirme.app/components/CertificateTemplate.tsx— Sertifika PDF şablonu (@react-pdf/renderer).app/hooks/useLearningTracker.ts— İzlenme süresi heartbeat.app/lib/streak.ts— recordLearningActivity, getStreakData, getWeeklyActivity.app/lib/db-queries.ts— getCompletedLessonIds, getCourseCurriculumWithResources.