StudentsPageQuery → organization(slug).students(first,after,filters) connection (dataTableOrganizationStudents fragment; OrganizationStudentsTablePaginationQuery ile artımlı). Erişim: ORG_STUDENTS_VIEW (detay + yazma ADMIN/OWNER). Araç çubuğu iki satır: arama + Özel Alanlar / Öğrenci Ekle, altında Filtreler + aktif filtre çipleri + Filtreleri sıfırla.| Öğrenci | Etiketler | Toplam Harcama | Kaydolma Tarihi | Son Giriş | Son Aktivite | |||
|---|---|---|---|---|---|---|---|---|
| elif.yilmaz@ornek.com | VIP Mezun | ₺12.480,00 | 14 Şub 2025 | 2 gün önce | 3 saat önce | |||
| mertkaya@ornek.com | Aktif | ₺6.320,00 | 28 Mar 2025 | 5 saat önce | 1 saat önce | |||
| ayse.demir@ornek.com | Deneme | ₺1.320,00 | 2 May 2025 | 1 hafta önce | 4 gün önce | |||
| canozturk@ornek.com | - | — | 19 May 2025 | - | - | |||
| zeynep.sahin@ornek.com | VIP | ₺9.870,50 | 3 Haz 2025 | Dün | 2 saat önce | |||
BA boran.aksoy@ornek.com (isim girilmemiş) | boran.aksoy@ornek.com | - | — | 28 Haz 2025 | - | - |
OrganizationStudentSortField: GIVEN_NAME/EMAIL/CREATED_AT/LAST_ACTIVITY_AT/LIFETIME_VALUE), etiketler sıralanamaz.AdminContentSkeleton görünür.ORG_STUDENTS_VIEW yok)NoAccessMessage section="Öğrenciler" (AccessGate.section) render edilir. Tablo/refetch hataları küçük yıkıcı-tonlu bandlarla degrade olur; facet hatası tabloyu düşürmeden ayrı bir bandda gösterilir.useStudentsFilterFacets (accessOptions/coachingOptions/tierOptions/bundleOptions), useOrganizationTags, addOrganizationStudents, inviteCourseAcademicTermStudent, bulkAddTagsToStudents. Yazma işlemleri ADMIN/OWNER gerektirir.useStudentsExport) mevcut filtre setini kapsar; durum göstergesi Başlatılıyor… → {n}/{total} → Dışa aktarıldı / Uyarı ile dışa aktarıldı / Dışa aktarma başarısız. Kimlik/E-posta/Ad/Soyad/Kayıt/Son Giriş/Son Etkinlik/Dil/Saat Dilimi/Etiketler/Harcama/Para Birimi sütunları seçilebilir.addOrganizationStudents → başarılı/yeni-oluşturulan/başarısız sayısı; yeni satırlar @appendNode ile connection'a eklenir, totalCount artar. Kısmi başarı görünümü: yeşil banner + yıkıcı-tonlu “Aşağıdaki e-postalar eklenemedi:” çip listesi. Görünür çip 50 ile sınırlı (“+N e-posta daha”).bulkInviteCourseAcademicTermStudents) sayı bazlı başlık + kısmi-başarı özeti gösterir.useStudentTagMutations); toast'lar “{name} etiketi başarıyla eklendi/silindi”. Etiket kalmayınca “Etiket yok”, hepsi eklendiyse buton “Tüm etiketler eklenmiş”. Toplu varyant Etiket Ekle / Etiket Kaldır sekmeleri + sahnelenen rozet alanı taşır./admin/students/[studentId]). Kaynak: StudentDetailPageQuery → node …on OrganizationStudent (email, ad/soyad, image, createdAt, lastSignInAt, lastActivityAt, lifetimeValue, tags, enrollments, subscriptions, customFields, latestLoginOtp, orders.totalCount). Erişim yalnızca ADMIN/OWNER — aksi halde Next.js notFound(). Sekmeler: Genel Bakış · Kayıtlar · Abonelikler · Satın Alımlar (sayım rozeti yalnızca >0 iken). Not: mevcut kodda zaman tüneli/destek/e-posta/notlar sekmesi yoktur (src/crm boş); Özel Alanlar Genel Bakış'ta bir karttır.483 921
E-posta
Geçerli
updateOrganizationStudent; toast “İsim güncellendi”). OTP çipi latestLoginOtp varsa görünür: kod + kanal rozeti (E-posta/SMS/WhatsApp) + Geçerli/Süresi Dolmuş + geçerlilik zamanı. Etiketler kalemi Etiketleri Yönet diyaloğunu açar; etiket yoksa “Etiket yok”.EditCustomFieldsCardMutation → updateOrganizationStudent(customFields[]). Sahibi-öğrenci (OWNER) düzenleyebilir alanlar yöneticiye salt-okunur. Kayıt toast'ı “Özel alanlar güncellendi”, değişiklik yoksa “Değişiklik yapılmadı”. Kaydedilmemiş düzenleme beforeunload + iptal onay diyaloğu ile korunur.StudentDetailPageQuery (enrollments, subscriptions) + Satın Alımlar sekmesi kendi kendine yüklenen StudentPurchasesTabQuery → orders(first:50) (backend query-complexity bütçesi için ayrı sorgu, ErrorBoundary + Suspense ile izole). Yalnızca ADMIN/OWNER görür.| Kurs | Dönem | İlerleme | Erişim Bitiş |
|---|---|---|---|
| Sosyolojiye Giriş | 2025 Güz Dönemi | - | |
| Psikolojiye Giriş | 2025 Bahar Dönemi | 31 Ara 2026 | |
| Mitoloji Serisi | Tek Dönem | - |
progress.overallProgress (yuvarlanmış %), Erişim Bitiş accessExpiresAt yoksa “-”. Boş: “Henüz kayıtlı kurs bulunmuyor.” Kurs’u silinmiş kayıtlar tablodan filtrelenir.cancelAtPeriodEnd ile. Boş: “Aktif abonelik bulunmuyor.” Ödemeleri Görüntüle yan sheet açar (aşağıda).StudentSubscriptionPaymentsSheet_subscription. Her satır Tutar / Ödenen Tutar / Ödeme Tarihi + fatura başına “Faturayı İndir”. Boş: “Bu abonelik için ödeme bulunamadı.”| Tarih | Ürünler | Tutar | Durum | |
|---|---|---|---|---|
| 8 Tem 2026 | Sosyolojiye Giriş | ₺1.385,83 | Tamamlandı | |
| 2 May 2026 | Psikolojiye Giriş +1 | ₺2.640,00 | Tamamlandı | |
| 18 Mar 2026 | Mitoloji Serisi | ₺2.640,00 | Kısmen İade Edildi | |
| 4 Şub 2026 | Birebir Koçluk · 4 Seans | ₺3.200,00 | Ödeme Bekleniyor | |
| 14 Şub 2025 | Flu Akademi 1. Dönem Paketi | ₺3.517,50 | İade Edildi |
/admin/orders/{slug}'e gider. Sipariş durum rozetleri: Ödeme Bekleniyor / Tamamlandı / Kısmen İade Edildi / İade Edildi / Başarısız vb. (renk-kodlu). Ürünler lineItems.orderable (CourseAcademicTerm / CoachingSessionPlan / Bundle). Yükleniyor: 4 satırlık skeleton kartı; hata: ortalanmış “Satın almalar yüklenemedi. Lütfen sayfayı yenileyin.” Boş: “Henüz satın alma bulunmuyor.”CustomFieldDefinitionsListQuery → Organization.customStudentFieldDefinitions{id,type,title,editability,validationSchema,visibility} + reorder/create/update/delete OrganizationStudentCustomFieldDefinition mutasyonları. Büyük modal (85vh), sekmeler Mevcut Alanlar (N) ve Alan Ekle; kaydedilmemiş düzenleme onay diyaloğu ile korunur.deleteOrganizationStudentCustomFieldDefinition — tanımı ve tüm öğrencilerdeki verisini kalıcı siler; buton silme sırasında “Siliniyor...”. Kaydedilmemiş düzenleme varken sekme/alan değiştirmek de bir kaydedilmemiş-değişiklik onay diyaloğu tetikler.addOrganizationStudents) ancak henüz hiç giriş yapmamış / adı girilmemiş bir OrganizationStudent'tır: ad yok → listede (isim girilmemiş), detay başlığında düz -; Son Giriş / Son Aktivite boş (-), Toplam Harcama ₺0,00 (tamamlanmış ödeme yok), boş kayıt/abonelik/satın alma. Aynı Contact-360 şablonu bu minimal veriyle nasıl göründüğünü aşağıda yakalar. Kaynak: StudentDetailPageQuery; latestLoginOtp null → OTP satırı hiç render edilmez.studentName = [givenName,lastName].join(' ') || '-') ve avatar fallback'i kişi ikonuna döner. OTP satırı latestLoginOtp yokken hiç çizilmez. Detay sayfasında Toplam Harcama her zaman formatMoney ile basılır; tamamlanmış ödeme yoksa ₺0,00 görünür (roster'daki em-dash kısayolu burada yoktur). Kod özel bir lead banner'ı barındırmaz — bu ekran, boş verinin doğal görünümüdür.grantProductAccess(orderableId, studentId | email, message?) — orderableId bir Kurs(Dönem)/DijitalÜrün/CanlıEtkinlik/Paket GlobalId'sidir, alıcı studentId ya da email ile belirtilir, message alıcının kayıt e-postasına eklenen opsiyonel nottur; yetki organizasyon Yönetici/Sahip veya ürünün eğitmeni (COURSE_EDIT / hasTermPermission). Bugün bu ekran yok — mutation yalnızca GraphQL API'de var; roster ve profildeki giriş noktaları, diyalog ve verilen-erişim rozeti henüz kurulmadı. Diyalogdaki sebep ve süre alanları planlanan FE eklentileridir — mutation bugün bu iki alanı taşımaz.CourseAcademicTerm); Dijital → tek DigitalProduct seçimi; Etkinlik → LiveEvent; Paket → Bundle (dört ayrı tür, takma-ad değil). Başarı toast'ı “{ürün} erişimi verildi” + Kayıtlar listesine @appendNode. grantProductAccess bugün yalnızca GraphQL API'de var (yönetim panelinde yüzeyi yok) — bu diyalog, giriş noktaları ve “ücretsiz erişim” rozeti kurulacak frontend iş kalemidir.RowActions) tekil “Ücretsiz Erişim Ver” + seçim toplu-işlem çubuğuna toplu varyant (her seçili öğrenci için grantProductAccess, sayı bazlı başlık + kısmi-başarı özeti; ayrı bir toplu uç nokta da eklenebilir). Aksiyon yalnızca yazma yetkisi olan üyeye (Yönetici/Sahip veya ürün eğitmeni) görünür; aksi halde menüde gizlidir.grantProductAccess bugün süre/kaldırma taşımaz, bu yüzden hem backend hem FE işidir.