Kurumsal
Commerce CMS
Bir mağazayı ve editoryal sayfalarını tek uygulamadan işleten içerik ve ticaret sistemi. Önbelleğe alınan her ekranın ömrü yazılı duruyor.
Tek uygulamada on dört alan
Kod, dosya türüne göre değil neyle ilgili olduğuna göre gruplanıyor:
commerce, inventory, content, messaging, analytics, branding,
tracking ve yedi tane daha. Her biri kendi arayüzlerini, servislerini ve
tiplerini tutuyor.
Alternatif, paketlerden oluşan bir workspace’ti. Tek bir deploy edilebilir uygulama için bu size build konfigürasyonu getiriyor ve pek bir şey getirmiyor; asıl istenen sınır import sınırı, onu da bir klasörle bir lint kuralı zaten veriyor. Oyunun ekip paneli paketlerden oluşan bir workspace kullanıyor; orada çekirdeğin bir sonraki oyuna taşınması gerekiyor ve sınır konfigürasyonuna değiyor.
Ömrü yazılı önbellek
Her önbellek anahtarı bir sunucu TTL’i ve bir istemci max-age’i taşıyor,
ikisi de tek config dosyasında duruyor, Cache-Control başlığı da route
başına yazılmak yerine buradan türetiliyor. Taze kalması gereken ekran bunu,
beş dakika bayatlayabilen ekranla aynı yerde söylüyor.
Önbellek nesnesinin kendisi globalThis üzerinde duruyor. Next.js birden
fazla modül grafiği kuruyor, modül kapsamındaki bir nesne de sessizce
birbirinin yazdığını görmeyen birkaç önbelleğe dönüşüyor. Kestirme gibi
görünüyor, oysa tam tersini yapıyor.
Sistem
İstemciler
Mağaza yüzü
Next.js · React · TypeScript
Yönetim yüzü
Next.js · React · TypeScript
Uygulama
On dört alan
TypeScript
Neden
Alanlar konuya göre ayrılıyor: commerce, inventory, content, messaging, analytics, branding, tracking ve yedi tane daha. Her biri kendi arayüzlerini, servislerini ve tiplerini tutuyor.
Olay hattı
TypeScript
Neden
Bir yazma neyin değiştiğini yayınlıyor, etkilenen önbellek anahtarları da düşürülüyor. Bu olmazsa tek süre dolduran şey TTL kalıyor ve editör kendi düzenlemesini görmek için beş dakika bekliyor.
Adaptörler
Repository'ler
Prisma · TypeScript
Durum
İlişkisel veritabanı
PostgreSQL · Prisma
Okuma önbelleği
Redis · TypeScript
Neden
Anahtar başına ömrü olan, süreç içi bir LRU çalışıyor; yeniden başlatmayı atlatması gereken durum için arkasında Redis duruyor. Her anahtar sunucu TTL'ini ve istemci max-age'ini tek bir config dosyasında bildiriyor.
1/**2 * Cache Service - Robust in-memory caching with LRU eviction3 *4 * Features:5 * - Max size limit (1000 entries by default) - prevents unbounded growth6 * - LRU eviction - automatically removes least recently used entries when full7 * - TTL support - per-entry expiration from config8 * - Proactive cleanup - automatically purges expired entries9 * - Type-safe API - generic get/set operations10 */24/**25 * Global LRU cache instance using globalThis26 * Ensures same instance across all module graphs in Next.js Turbopack27 */28declare global {29 // eslint-disable-next-line no-var30 var __appCache: LRUCache<string, object> | undefined;31}3233function getOrCreateCache(): LRUCache<string, object> {34 if (!globalThis.__appCache) {35 globalThis.__appCache = new LRUCache<string, object>({36 max: MAX_CACHE_SIZE,37 ttl: DEFAULT_TTL_MS,38 ttlAutopurge: true, // Proactively remove expired entries39 updateAgeOnGet: true, // Reset TTL on access (true LRU behavior)40 allowStale: false, // Don't return stale entries41 });42 console.log(43 `[Cache] Initialized LRU cache (max: ${MAX_CACHE_SIZE}, defaultTTL: ${DEFAULT_SERVER_TTL}s, autoPurge: enabled)`44 );45 }46 return globalThis.__appCache;47}commerce-cms3d1d112src/domain/system/cache/service/cache.service.tsSatır 1 – 4734 satır
/**
* Cache Service - Robust in-memory caching with LRU eviction
*
* Features:
* - Max size limit (1000 entries by default) - prevents unbounded growth
* - LRU eviction - automatically removes least recently used entries when full
* - TTL support - per-entry expiration from config
* - Proactive cleanup - automatically purges expired entries
* - Type-safe API - generic get/set operations
*/
/**
* Global LRU cache instance using globalThis
* Ensures same instance across all module graphs in Next.js Turbopack
*/
declare global {
// eslint-disable-next-line no-var
var __appCache: LRUCache<string, object> | undefined;
}
function getOrCreateCache(): LRUCache<string, object> {
if (!globalThis.__appCache) {
globalThis.__appCache = new LRUCache<string, object>({
max: MAX_CACHE_SIZE,
ttl: DEFAULT_TTL_MS,
ttlAutopurge: true, // Proactively remove expired entries
updateAgeOnGet: true, // Reset TTL on access (true LRU behavior)
allowStale: false, // Don't return stale entries
});
console.log(
`[Cache] Initialized LRU cache (max: ${MAX_CACHE_SIZE}, defaultTTL: ${DEFAULT_SERVER_TTL}s, autoPurge: enabled)`
);
}
return globalThis.__appCache;
}- Önbelleğin cevaplayabildiği bir okuma repository'ye hiç gitmiyor. Oraya bir önbellek koymanın tüm sebebi bu, ve önbelleğin tek bir sorgunun önüne değil veritabanının yanına oturmasının sebebi de aynı.
Düzenlemenin görünmesi
Tek başına TTL, editörün değişikliği yayınlayıp beklemesi demek. Bu yüzden yazmalar bir olay hattına yayın yapıyor ve etkilenen anahtarlar anında düşüyor. TTL de hattın haberi olmayan her şey için emniyet payı olarak kalıyor.
Kurulum
npm run cli ilk kurulumun tamamını zincirliyor: Docker daemon’ını
denetliyor, Postgres, Redis ve Mailpit’i ayağa kaldırıyor, health check’i
bekliyor, şemayı basıyor, seed teklif ediyor. Altı adım. Hiçbiri kurulu
olmayan bir makinede bunları doğru sırayla yapmak gerekiyor.
Katkı
- Yazılan commit
- 545
18 haftanın 17 tanesi aktif · 22 Ara 2025 – 26 Nis 2026
En uzun seri · 14 hafta · Ara – Mar
Geçmişinde ikinci bir geliştirici bulunan ilk proje ve altyapıdan önce yazılan son proje.
Ölçüm 2026-09-08