Skip to content

Kod Konvansiyonları ve Standartlar

İsimlendirme, veri çekme (loader/action, GraphQL vs REST), yetkilendirme, i18n, stil (Tailwind, erişilebilirlik), TypeScript.

Bu sayfa Coursio projesinde ekip içi tutarlılık için kullanılan kod konvansiyonlarını özetler. Yeni geliştiricinin “nasıl yazmalıyım?” sorusuna yanıt vermeyi hedefler.


  • React bileşenleri: PascalCase (örn. CourseCard.tsx, Navbar.tsx, InstructorSidebar.tsx).
  • Route dosyaları: React Router convention — path segment’leri nokta ile birleştirilir, parametre $ ile yazılır (örn. course.$id.tsx, instructor.course.$slug.manage.curriculum.tsx). Detay için Proje Yapısı — Route dosya isimlendirmesi.
  • API route dosyaları: api.*.ts (örn. api.graphql.ts, api.stripe.webhook.ts).
  • Lib ve yardımcı modüller: kebab-case veya camelCase (örn. db-queries.ts, pricing-engine.ts, graphql-client.ts, video-security.ts).
  • Hook’lar: camelCase, use prefix (örn. useLang.ts, useLearningTracker.ts, useChatNotifications.ts).
  • Event handler fonksiyonları: handle prefix (örn. handleClick, handleSubmit, handleLanguageChange, handleKeyDown).
  • Örnek: onClick={handleClick}, onSubmit={handleSubmit}, onKeyDown={handleKeyDown}.
  • Veri çekme: loader export edilir (async fonksiyon; request, params, context alır).
  • Form / mutation: action export edilir (async fonksiyon; form gönderimi ve API mutation’ları için).
  • Sayfa bileşeni: Default export bir React bileşeni.

Veri çekme: loader vs action, GraphQL vs REST

Section titled “Veri çekme: loader vs action, GraphQL vs REST”
  • Sayfa açıldığında ihtiyaç duyulan veri loader ile çekilir.
  • Loader, context.cloudflare?.env veya getDbUrl(env) ile DB bağlantısı alır; gerekirse initAuth ile session kontrolü yapar.
  • Veri useLoaderData() ile bileşende kullanılır.
  • Çoğu sayfa verisi (kurs listesi, kullanıcı bilgisi, müfredat, admin listeleri vb.) GraphQL üzerinden de çekilebilir; sayfa loader’da graphqlClient ile query atılır veya doğrudan Drizzle sorguları kullanılır.
  • Form gönderimi, dosya yükleme, durum güncelleme (örn. onay/red) action ile işlenir.
  • Action, request.formData() veya JSON body ile veri alır; yetki kontrolü yapar; DB/API günceller; redirect veya JSON döner.
  • Upload, webhook, download gibi endpoint’ler REST/action kullanır: api.lesson-resource-upload.ts, api.chat-image-upload.ts, api.stripe.webhook.ts, api.certificate.$id.download.ts, api.invoice.$enrollmentId.download.ts — bunlar sayfa değil, API route’u; loader ve/veya action export edilir.
KullanımTercihAçıklama
Sayfa verisi (liste, detay, profil)GraphQL veya loader içinde DrizzleÇoğu sayfa verisi GraphQL query ile; bazı route’lar doğrudan Drizzle kullanır.
Form gönderimi, buton ile tetiklenen işlemaction (form action veya fetch)Mutation GraphQL veya doğrudan API route’a POST.
Dosya yüklemeREST actionapi.lesson-resource-upload, api.chat-image-upload — FormData, multipart.
WebhookREST actionapi.stripe.webhook — Stripe imza doğrulama, raw body.
PDF/ dosya indirmeREST loaderapi.certificate.$id.download, api.invoice.$enrollmentId.download — GET, Response döner.

  • Layout loader’da yapılır. Örneğin:
    • admin.tsx: auth.api.getSession({ headers: request.headers }); session yoksa veya user.role !== "admin" ise redirect("/404").
    • instructor.tsx: Session + eğitmen kaydı / rol kontrolü.
    • account.tsx, my-courses.tsx: Session yoksa giriş sayfasına yönlendirme.
  • Alt sayfalar layout’tan geçtiği için ayrıca session kontrolü yazmaya gerek yok; gerekirse sayfa loader’da ek kontrol yapılabilir.
  • Admin: session?.user?.id ve veritabanından user.role === "admin" kontrolü (örn. admin.tsx loader).
  • Eğitmen: user.role === "instructor" veya eğitmen kaydı tamamlanmış kullanıcı; instructor layout ve ilgili API route’larında kontrol.
  • Öğrenci / giriş gerekli: Sadece session varlığı; rol kontrolü yok (veya sayfa bazında “sadece enrollment sahibi” gibi kısıtlar).
  • Her API route kendi içinde session alır: initAuth(dbUrl, env)auth.api.getSession({ headers: request.headers }).
  • Gerekirse session?.user?.role === "admin" veya "instructor" kontrolü yapılır; yetkisiz ise 401/403 dönülür.

  • Hook: useTranslation() (react-i18next); const { t } = useTranslation();
  • Metin: t("key") veya t("namespace:key") — örn. t("footer.about"), t("nav.language").
  • Çeviri dosyaları: app/locales/*.jsontr.json, en.json, de.json, es.json vb. Her dosyada aynı key yapısı kullanılır.
  • Yeni key ekleme: Tüm dil dosyalarına aynı key’i ekleyin; eksik dilde fallback için varsayılan dil (örn. en) kullanılabilir.
  • Dil ve path: useLang(), getLocalizedPath("/path") — link’lerde dil prefix’li path üretmek için. Dil değiştirme: lib/i18n-utils.tschangeLangInPath, getLangFromPath, shouldIncludeLang.

  • Tailwind: Tüm stil Tailwind sınıfları ile verilir; className="...". Mümkün olduğunca global CSS veya inline style kullanılmaz.
  • Koşullu sınıf: class: (classList mantığı) veya ternary kullanılır. Ekip tercihi: okunabilir olduğu sürece className={cn("base", condition && "active")} veya className={condition ? "a" : "b"}.
  • Erişilebilirlik (a11y):
    • Etkileşimli öğelerde aria-label (örn. ikon butonları: aria-label={t("nav.language")}).
    • Klavye ile erişim için tabIndex={0} (gerektiğinde); onKeyDown ile Enter/Space ile tetikleme.
    • Form alanlarında label veya aria-labelledby kullanılır.

  • Context tipi: Route loader/action’da context genelde { cloudflare?: { env?: unknown } } veya proje tipi ile tanımlanır. env kullanımı: const env = (context?.cloudflare?.env as any) || process.env; (yerelde process.env fallback).
  • Veritabanı: getDb(env.DATABASE_URL) veya getDb(getDbUrl(env))app/db/index.ts. Hyperdrive kullanıldığında production’da env üzerinden Hyperdrive bağlantısı sağlanır.
  • Auth: initAuth(dbUrl, env)app/lib/auth.ts; session tipi Better Auth tarafından tanımlanır; session?.user?.id, session?.user?.role kullanımı yaygındır.
  • Genel: Mümkün olduğunca any yerine net tipler kullanılır; React Router ve Drizzle şemaları projede tip güvenliği sağlar.

KonuKural
İsimlendirmeBileşenler PascalCase; route dosyaları React Router convention ($param, api.*.ts); event handler’lar handle*; loader/action export.
VeriSayfa verisi → loader (GraphQL veya Drizzle); form/mutation → action; upload/webhook/download → REST action/loader.
YetkiLayout loader’da session ve rol kontrolü; session?.user?.role === "admin" / "instructor"; API route’larında kendi session kontrolü.
i18nuseTranslation(), t("key"); çeviriler app/locales/*.json; yeni key tüm dillere eklenir; getLocalizedPath, useLang.
StilTailwind className; koşullu sınıf class: veya ternary; aria-label, tabIndex, onKeyDown, label kullanımı.
TypeScriptcontext.cloudflare?.env; getDb(env.DATABASE_URL); initAuth(dbUrl, env); net tipler tercih edilir.

Detaylı route ve dosya yapısı için Proje Yapısı (Detaylı) ve Route Haritası sayfalarına bakın.