Standar dan Konvensi Kode
Standar pengodean, batasan ruang kerja, dan konvensi untuk berkontribusi pada LibreChat.
Batasan Ruang Kerja
LibreChat adalah sebuah monorepo. Semua kode baru harus ditujukan ke workspace yang benar:
| Workspace | Bahasa | Sisi | Tujuan |
|---|---|---|---|
/api | JS (warisan) | Backend | Server Express โ minimalkan perubahan di sini |
/packages/api | TypeScript | Backend | Kode backend baru berada di sini (hanya TS, dikonsumsi oleh /api) |
/packages/data-schemas | TypeScript | Backend | Model/skema basis data dan logika bersama khusus basis data |
/packages/data-provider | TypeScript | Bersama | Tipe API, endpoint, data-service โ digunakan oleh frontend dan backend |
/client | TypeScript/React | Frontend | SPA Frontend |
/packages/client | TypeScript | Frontend | Utilitas frontend bersama |
- Semua kode backend baru harus menggunakan TypeScript di
/packages/api. - Jaga perubahan
/apiseminimal mungkin (pembungkus JS tipis yang memanggil/packages/api). - Logika bersama khusus basis data diletakkan di
/packages/data-schemas. - Logika API yang digunakan bersama oleh frontend/backend (endpoint, tipe, data-service) ditempatkan di
/packages/data-provider. - Bangun semua kode yang dikompilasi dari root proyek:
npm run build. - Bangun ulang kode data-provider bersama setelah perubahan API/tipe:
npm run build:data-provider.
Panduan Umum
- Gunakan prinsip "clean code": jaga agar fungsi dan modul tetap kecil, patuhi prinsip tanggung jawab tunggal (single responsibility principle), serta tulis kode yang ekspresif dan mudah dibaca.
- Gunakan nama variabel dan fungsi yang bermakna dan deskriptif.
- Prioritaskan keterbacaan dan pemeliharaan kode di atas keringkasan.
- Gunakan file
.eslintrcdan.prettierrcyang disediakan untuk pemformatan kode yang konsisten. - Perbaiki semua kesalahan pemformatan lint menggunakan auto-fix jika tersedia. Semua peringatan dan kesalahan TypeScript/ESLint harus diselesaikan.
Penamaan dan Pengorganisasian File
- Gunakan nama file satu kata jika memungkinkan, seperti
permissions.ts,capabilities.ts, atauservice.ts. - Jika diperlukan lebih dari satu kata, gunakan direktori satu kata yang memberikan konteks pada file, seperti
admin/capabilities.tsalih-alihadminCapabilities.ts. - Biarkan direktori memberikan konteks. Lebih disukai
app/service.tsdaripadaapp/appConfigService.ts.
Struktur Kode
- Never-nesting: gunakan early returns, kode yang datar, dan indentasi minimal. Pecah operasi yang kompleks menjadi fungsi pembantu (helpers) dengan penamaan yang tepat.
- Fungsional terlebih dahulu: fungsi murni, data yang tidak dapat diubah (immutable),
map/filter/reducedibandingkan perulangan imperatif. Hanya gunakan OOP jika hal tersebut secara jelas meningkatkan pemodelan domain atau enkapsulasi status. - Tanpa dynamic imports kecuali jika benar-benar diperlukan.
- Ekstrak logika yang berulang ke dalam fungsi utilitas khusus (DRY). Utamakan penggunaan helper yang diparameterisasi, konstanta, validator bersama, penanganan kesalahan terpusat, dan tipe bersama dibandingkan implementasi yang hampir duplikat.
Iterasi dan Performa
- Minimalkan perulangan โ terutama pada struktur data bersama seperti array pesan, yang sering diiterasi. Setiap langkah tambahan akan terakumulasi seiring bertambahnya skala.
- Konsolidasikan operasi O(n) yang berurutan menjadi satu lintasan (single pass) jika memungkinkan; jangan pernah melakukan perulangan pada koleksi yang sama dua kali jika pekerjaan tersebut dapat digabungkan.
- Pilih struktur data yang mengurangi kebutuhan untuk melakukan iterasi (contohnya,
Map/Setuntuk pencarian alih-alihArray.find/Array.includes). - Hindari pembuatan objek yang tidak perlu; pertimbangkan pertukaran ruang-waktu.
- Cegah kebocoran memori: berhati-hatilah dengan closure, buang sumber daya/event listener, dan hindari referensi melingkar.
Type Safety
- Jangan pernah gunakan
any. Tipe eksplisit untuk semua parameter, nilai kembalian, dan variabel. - Batasi
unknownโ hindariunknown,Record<string, unknown>, dan asersias unknown as T.Record<string, unknown>hampir selalu menandakan definisi tipe eksplisit yang hilang. - Jangan menduplikasi tipe โ periksa apakah suatu tipe sudah ada di dalam proyek (terutama
packages/data-provider) sebelum mendefinisikan tipe baru. Gunakan kembali dan perluas tipe yang sudah ada. - Gunakan union types, generics, dan interfaces dengan tepat.
Komentar dan Dokumentasi
- Tulis kode yang mendokumentasikan dirinya sendiri; jangan gunakan komentar inline yang menjelaskan apa yang dilakukan kode tersebut.
- JSDoc hanya untuk logika yang kompleks/tidak jelas atau intellisense pada API publik.
- JSDoc satu baris untuk dokumentasi singkat, multi-baris untuk kasus yang kompleks.
- Hindari komentar
//mandiri kecuali jika benar-benar diperlukan.
Urutan Impor
Impor diatur ke dalam tiga bagian (sesuai urutan):
- Impor paket โ diurutkan dari panjang baris terpendek hingga terpanjang (
reactselalu menjadi impor pertama). import typeimports โ diurutkan dari yang terpanjang hingga terpendek (tipe paket terlebih dahulu, kemudian tipe lokal; pengurutan panjang diatur ulang di antara sub-grup).- Impor lokal/proyek โ diurutkan dari yang terpanjang hingga terpendek.
- Konsolidasikan impor nilai dari modul yang sama sebanyak mungkin.
- Selalu gunakan
import type { ... }mandiri untuk impor tipe; jangan pernah menggunakan kata kuncitypeinline di dalam impor nilai (contoh:import { Foo, type Bar }adalah salah).
Preferensi Loop
- Batasi perulangan sebanyak mungkin. Utamakan transformasi satu kali jalan (single-pass) dan hindari pengulangan data yang sama.
for (let i = 0; ...)untuk operasi yang kritis terhadap performa atau bergantung pada indeks.for...ofuntuk iterasi array sederhana.for...inhanya untuk enumerasi properti objek.
Server API Node.js
Desain API
- Ikuti prinsip RESTful saat merancang API.
- Gunakan nama yang bermakna dan deskriptif untuk routes, controllers, services, dan models.
- Gunakan metode HTTP yang sesuai (GET, POST, PUT, DELETE) untuk setiap rute.
- Gunakan kode status dan struktur respons yang tepat untuk respons API yang konsisten (2xx untuk sukses, 4xx untuk permintaan buruk dari klien, 5xx untuk kesalahan server).
- Gunakan blok try-catch untuk menangkap dan menangani pengecualian dengan baik.
- Terapkan penanganan kesalahan yang tepat dan secara konsisten kembalikan respons kesalahan yang sesuai.
- Gunakan sistem logging yang disertakan dalam direktori
utilsuntuk mencatat peristiwa dan kesalahan penting. - Lakukan autentikasi stateless berbasis JWT menggunakan middleware
requireJWTAuth.
Struktur File
Kode backend baru ditempatkan di /packages/api sebagai TypeScript. Direktori /api lama mengikuti struktur ini:
Rute
Menentukan setiap metode permintaan HTTP, middleware apa pun yang akan digunakan, dan fungsi pengontrol yang akan dipanggil untuk setiap rute.
- Definisikan rute menggunakan Express Router dalam file terpisah untuk setiap sumber daya atau pengelompokan logis.
- Gunakan nama rute yang deskriptif dan patuhi konvensi RESTful.
- Jaga rute agar tetap ringkas dan fokus pada satu tanggung jawab saja.
- Awali semua rute dengan namespace
/api.
Pengontrol
Berisi logika untuk setiap rute, termasuk memanggil fungsi layanan yang sesuai serta mengembalikan kode status respons dan isi JSON yang tepat.
- Buat file controller terpisah untuk setiap rute guna menangani logika request/response.
- Beri nama file controller menggunakan konvensi PascalCase dan tambahkan "Controller" pada nama file (contoh:
UserController.js). - Jaga agar controller tetap ringkas dengan mendelegasikan operasi kompleks ke file service atau model.
Layanan
Berisi logika bisnis atau operasi kompleks yang digunakan bersama di berbagai controller.
- Beri nama file layanan menggunakan konvensi PascalCase dan tambahkan "Service" pada nama file tersebut (contoh:
AuthService.js). - Hindari penggabungan layanan secara ketat dengan model atau basis data tertentu demi kemampuan penggunaan kembali yang lebih baik.
- Pertahankan prinsip tanggung jawab tunggal (single responsibility principle) di dalam setiap layanan.
Model
Mendefinisikan model Mongoose untuk merepresentasikan entitas data dan hubungan antar entitas tersebut.
- Gunakan nama PascalCase tunggal untuk file model dan koleksi terkaitnya (contoh:
User.jsdan koleksiusers). - Sertakan hanya kolom, indeks, dan validasi yang diperlukan dalam model.
- Jaga agar model tetap independen dari lapisan API dengan menghindari referensi langsung ke objek request/response.
Akses Basis Data (MongoDB dan Mongoose)
- Gunakan Mongoose (https://mongoosejs.com) sebagai ODM MongoDB.
- Buat file model terpisah untuk setiap entitas dan pastikan pemisahan kepentingan (separation of concerns) yang jelas.
- Gunakan validasi skema Mongoose untuk menegakkan integritas data.
- Tangani koneksi basis data secara efisien dan hindari kebocoran koneksi.
- Gunakan Mongoose query builder untuk membuat kueri basis data yang ringkas dan mudah dibaca.
Klien React
Praktik Terbaik TypeScript dan React Secara Umum
- Gunakan TypeScript best practices untuk mendapatkan manfaat dari pengetikan statis dan perangkat pendukung yang lebih baik.
- Kelompokkan file terkait di dalam direktori fitur (contoh:
SidePanel/Memories/). - Beri nama komponen menggunakan konvensi PascalCase.
- Gunakan nama yang ringkas dan deskriptif yang secara akurat mencerminkan tujuan komponen tersebut.
- Pecah komponen yang kompleks menjadi komponen yang lebih kecil dan dapat digunakan kembali jika diperlukan.
- Jaga logika rendering di dalam komponen seminimal mungkin.
- Ekstrak bagian yang dapat digunakan kembali ke dalam fungsi atau hook terpisah.
- Terapkan definisi tipe prop menggunakan tipe atau antarmuka TypeScript.
- Gunakan validasi formulir jika diperlukan (kami menggunakan React Hook Form untuk validasi dan pengiriman formulir).
Lokalisasi
- Semua teks yang ditampilkan kepada klien harus dilokalisasi menggunakan hook
useLocalize(). - Hanya perbarui kunci bahasa Inggris di
client/src/locales/en/translation.json(bahasa lain diotomatisasi secara eksternal). - Gunakan prefiks kunci lokalisasi semantik:
com_ui_,com_assistants_, dll. - Selalu sediakan teks cadangan yang bermakna untuk kunci lokalisasi baru.
Layanan Data
- Buat hook penyedia data di
client/src/data-provider/[Feature]/queries.ts. - Ekspor semua hook dari
client/src/data-provider/[Feature]/index.ts. - Tambahkan ekspor fitur ke
client/src/data-provider/index.tsutama. - Gunakan React Query (
@tanstack/react-query) untuk semua interaksi API. - Implementasikan invalidasi kueri yang tepat pada mutasi.
- Tambahkan QueryKeys dan MutationKeys ke
packages/data-provider/src/keys.ts.
Saat menambahkan integrasi API bersama, perbarui:
packages/data-provider/src/api-endpoints.ts(endpoint)packages/data-provider/src/data-service.ts(fungsi-fungsi layanan data)packages/data-provider/src/types/queries.ts(Tipe TypeScript)
Performa
- Prioritaskan efisiensi memori dan kecepatan dalam skala besar.
- Implementasikan penomoran halaman kursor (cursor pagination) yang tepat untuk set data yang besar.
- Hindari re-render yang tidak perlu dengan array dependensi yang tepat.
- Manfaatkan fitur caching dan background refetching dari React Query.
Pengujian dan Dokumentasi
- Tulis unit test untuk semua fungsionalitas yang kritis dan kompleks menggunakan Jest.
- Tulis pengujian integrasi untuk semua endpoint API menggunakan Supertest.
- Tulis pengujian end-to-end untuk semua fungsionalitas sisi klien menggunakan Playwright.
- Gunakan nama kasus uji dan fungsi yang deskriptif untuk menyatakan tujuan pengujian dengan jelas.
- Jalankan pengujian dari direktori workspace-nya:
cd api && npx jest <pattern>,cd packages/api && npx jest <pattern>, dll. - Cakup status pemuatan (loading), keberhasilan (success), dan kesalahan (error) untuk alur UI/data.
- Gunakan
test/layout-test-utilsuntuk merender komponen dalam pengujian frontend. - Utamakan logika nyata daripada mock. Lakukan mock hanya pada hal yang tidak dapat dikontrol secara lokal, seperti API HTTP eksternal, layanan dengan batasan kecepatan (rate-limited), dan panggilan sistem yang non-deterministik.
- Gunakan spies saat Anda perlu melakukan asersi pemanggilan tanpa mengganti implementasi yang mendasarinya.
- Gunakan
mongodb-memory-serveruntuk pengujian berbasis MongoDB agar kueri dan validasi skema menjalankan perilaku basis data yang sebenarnya.
Bagaimana panduan ini?