Yenilikler
Starter kit'e yeni eklenen özellikler ve iyileştirmeler burada listelenir.
2026-10-01 — v13.8.2
Değişti
- Wayfinder artık kullanılmayan
@/actionshelper'larını üretmiyor. Bunlar adı yalnızca büyük/küçük harfle ayrışan iki klasör oluşturuyor ve harf duyarsız sistemlerdevue-tsc'yi kırıyordu.@/routesaltındaki route helper'ları aynı; yeniden üretmek içinphp artisan wayfinder:generate --skip-actions. - api-dock attribute'ları
Lvntr\ApiDocknamespace'ini kullanıyor (api-dock 0.0.8). Eski yazımla yapılmış import'lar çalışmaya devam ediyor.
2026-09-25 — v13.8.1
Eklendi
- Zengin metin editörüne buton eklenebiliyor. Link açık olan editörlerde yeni araç çubuğu düğmesi, seçili metni ya da yazdığınız etiketi bir adrese giden butona çevirir; üç stil var (ana, ikincil, çerçeveli) ve renk editör paletinden seçilebiliyor. İçerik düz HTML olarak kalır: yönetim ekranlarında buton olarak görünür, mobil uygulama da kendi native butonu olarak çizebilir; butonları tanımayan bir uygulama ise çalışan bir link gösterir. Buton stilleri için
php artisan sk:updateçalıştırın.
Düzeltildi
sk:installvesk:updateartık kurulu olan sürümü gösteriyor. Başlıkta, hangi sürüm kurulu olursa olsun hepv13.7.xyazıyordu.
2026-09-23 — v13.8.0
Eklendi
-
Ayarlar → Depolama ekranında artık Hetzner Object Storage ve Amazon S3 seçilebiliyor. Yerel disk ve DigitalOcean Spaces'in yanında depolama sürücüsü seçicisi artık Hetzner (Falkenstein / Nürnberg / Helsinki bölge seçimiyle) ve Amazon S3 seçeneklerini de sunuyor. Mevcut kurulumlarda yeni
hetznerdiskiphp artisan sk:updateileconfig/filesystems.phpdosyasına eklenir. Hetzner gizli anahtarı, diğer depolama anahtarları gibi şifreli saklanır. Uç nokta ve URL için artıkhttps://yazmanız gerekmiyor; bölge seçince uç nokta, bucket adı girince URL otomatik doluyor, bölge listelerinde arama yapılabiliyor. -
Zengin metin editörü artık içeriğin HTML'ini gösterip düzenletiyor, biçimlendirme araçları da arttı.
</>düğmesi editörü HTML kaynağına geçirir; yazılanlar anında forma işlenir, kaynak açıkken kaydedilse de kaybolmaz, editörün saklayamadığı etiketler de yazarken kutunun altında gösterilir; tam ekran düğmesi içeriği tüm ekrana yayar (Esc ile çıkılır). Araç çubuğuna altı çizili, vurgu rengi ve biçimi temizle eklendi;standardpreset'e görev listesi ve iki yana yaslama,fullpreset'e H4, satır içi kod, alt/üst simge, yazı tipi / boyut / satır aralığı seçicileri ve YouTube videosu geldi. Yeni editör paketleri içinphp artisan sk:updateve ardındannpm installçalıştırın.
Güvenlik
- Kaydedilen editör içeriğinde yalnızca YouTube video gömmeleri kalıyor. Diğer tüm
<iframe>'ler kayıtta silinmeye devam ediyor; yeni yazı stilleri de yalnızca düz değerleri kabul ediyor. config/settings.phpdosyanız kit'ten eski olsa bile gizli ayarlar şifreli kalıyor. Yeni eklenen bir gizli ayar, uygulamanın yayınlanmış settings config'inde henüz listelenmiyorsa şifrelenmeden kaydediliyordu; kit'in yerleşik listesi artık her zaman uygulanıyor.
2026-09-22 — v13.7.6
Değiştirildi
- Log görüntüleyici artık en yeni kayıtları en üstte gösteriyor. Bir günün log dosyası açıldığında ilk sayfa günün en eski kayıtlarıyla geliyordu; aradığınız son hataya ulaşmak için defalarca "daha fazla yükle" demek gerekiyordu. Artık liste en yeniden eskiye geliyor, daha fazla yükle bir sonraki (daha eski) sayfayı listenin altına ekliyor. Çok satırlı hata izleri ve Laravel formatı dışındaki satırlar eskisi gibi görünmeye devam ediyor.
2026-09-16 — v13.7.5
Eklendi
- Tablolar artık arama satırı ile sütun başlıkları arasında bir mesaj şeridi gösterebiliyor — "bu liste salt okunur" ya da "içe aktarma başarısız" gibi durumlar için tam genişlikte bir uyarı. Ton seçilebiliyor (
info,success,warn,danger, …), isteğe bağlı ikon ve kapatma butonu eklenebiliyor. Sayfa açıkken değişen bir mesaj için#messageslot'u devreye giriyor. - Tablo toolbar'ının
#toolbar-endslot'u artık çalışıyor. İçine koyduğunuz şey önceden kayboluyordu; şimdi sağda, filtre ve sütun butonlarının ardından görünüyor.
Değiştirildi
- Satır içi filtre etiketleri artık arama kutusunun hemen yanında değil, sağdaki filtre ve sütun butonlarının yanında duruyor — filtre eklendikçe arama kutusu itilmiyor ve arama satırının çevresindeki boşluk dengeli.
2026-09-14 — v13.7.4
Düzeltildi
- Toplu rol silme, tekil silmenin zaten reddettiği eşit-rütbeli bir rolü silebiliyordu — çünkü rütbe kontrolünü biraz daha gevşek bir karşılaştırmayla kendi içinde yeniden uyguluyordu. İki yol artık tek bir rütbe kontrolünü paylaşıyor. Scaffold tarafı (
stubs/): mevcut bir kuruluma yalnızcask:updateile ulaşır —BulkDeleteRoleAction.php'ı özelleştirmiş bir uygulamanın düzeltmeyi elle uygulaması gerekir. - Kayıt akışı artık login formunun zaten uyguladığı hız sınırlaması ve Turnstile CAPTCHA'sından geçiyor — bu da otomatik bir istemcinin CAPTCHA'yı çözmeden hesap açmasına izin veren açığı kapatıyor. Scaffold tarafı: mevcut kuruluma yalnızca
sk:updateile ulaşır — özelleştirilmiş birFortifyServiceProvider.php'ın bu değişikliği elle alması gerekir. - Parola sıfırlama artık hesabı her yerde oturumdan çıkarıyor — sıfırlamayı isteyen oturum dışında, tüm API token'ları ve tüm diğer aktif oturumlar iptal ediliyor. Giriş yapılmışken uygulama içinden parola değiştirme veya bir yöneticinin parolanızı belirlemesi henüz kapsanmıyor; bu yollar eski oturumları hâlâ canlı bırakıyor.
- Dosya yöneticisinin çöp kutusu, başka bir kullanıcının silinmiş dosyası için çalışan bir önizleme ve gerçek bir indirme linki döndürebiliyordu, ve yalnızca oluşturma yetkisi olan bir yükleyici kendine ait olmayan bir dosyayı geri yükleyebiliyordu. İkisi de artık engellendi.
- Yazma yetkiniz olmayan bir klasöre dosya yüklemek artık reddediliyor, sessizce geçmek yerine.
- Bir klasörü kendi alt klasörüne taşımak artık engelleniyor, klasör ağacını bozmak yerine.
- Zengin metin editörünün HTML sanitizer'ı, içine gizlenmiş bir kontrol karakteriyle tehlikeli bir link şemasını (örn.
javascript:) korumaya kandırılabiliyordu. Artık değeri kontrol etmeden önce tarayıcının yaptığı gibi normalize ediyor. - Dosya yöneticisinde yerel bir HTML dosyasını önizlemek artık onu canlı bir sayfa olarak çalıştırmıyor. Artık tamamen sandbox'lanmış bir frame içinde render ediliyor ve bu dosya türü için "yeni sekmede aç" seçeneği gizlendi — çünkü tarayıcı sekmesinde açmak, sandbox'lı önizlemeden daha az güvenli olurdu.
encryption:keyartık macOS'ta.envdosyanızın izinlerinin yeniden yazımdan sağlam çıktığını doğrulayamazsa döndürmeyi reddediyor, belirsiz bırakarak döndürmek yerine. Kontrol ettikten sonra yine de devam etmek için--allow-acl-lossverin.
Değiştirildi
- "Debug Mode" rozeti artık ortama değil role bakıyor — böylece unutulmuş bir
APP_DEBUG=truetam da bedelinin ödendiği yerde görünüyor.HandleInertiaRequests,appDebugdeğerini production'ın tamamındafalsepaylaşıyordu; yani debug çıktısının hâlâ açık olduğunu söyleyen tek uyarı, açık kalmasının asıl önem taşıdığı sunucuda sönüyordu. Kapı artık ortam yerine izleyici:appDebug,config('app.debug')VE izleyeninsystem_adminrolüne sahip olması, her ortamda. Sistem yöneticisi rozeti production'da görüyor; bayrak başka hiç kimseye gitmiyor, dolayısıyla ortam kontrolünün yazılma sebebi olan parmak izi kaygısı da yerinde duruyor.appEnvproduction'dakinulldeğerini koruyor — "Dev Mode" rozeti zaten yalnızcalocal'de çiziliyor.rolesilişkisiauthpaylaşımı için hâlihazırda yüklendiğinden kontrol ek sorgu maliyeti getirmiyor.HandleInertiaRequests.phppublish edilen bir dosya — kendi kopyasını düzenlemiş uygulama onu korur ve değişikliği elle uygular; ayrıntı UPGRADE.tr.md içinde.
2026-09-10 — v13.7.3
Düzeltildi
sk:updateartık kendi bağımlılık yükseltmesinin yol açtığıERESOLVEhatasından nasıl çıkılacağını söylüyor. 13.7.0 frontend araç zincirini güncel sürümlere taşıdı,@tiptap/*dahil (^3.27.1→^3.31.3). Uygulamanınpackage.json'ına birleştirme sorunsuz oturuyor, ama 13.6.x'ten devralınanpackage-lock.jsonhâlâ eski grafiği sabitliyor — ve her@tiptap/extension-*paketi@tiptap/core'a tam sürüm peer bağımlılığı tanımladığı için npm ailenin yarısını yükseltemiyor veERESOLVEile duruyor. İki komut da yalnızcanpm install && npm run buildyazdırıyordu; yani patlayan komutun kendisini.sk:updateartık birleştirmenin uygulamada zaten var olan bir kısıtı değiştirdiğini tespit edip yanına lockfile kurtarma satırını basıyor;sk:upgradede kendinpm installadımı başarısız olduğunda aynı satırı basıyor. Kurtarma UPGRADE.md içinde belgelendi —rm -rf node_modules package-lock.json && npm install;--forceya da--legacy-peer-depsasla, çünkü ikisi de etrafındaki extension'ların derlenmediği bir@tiptap/corekuruyor.
2026-09-08 — v13.7.2
Düzeltildi
- Geri butonu artık yanındaki oluştur butonundan bir satır yukarıda durmuyor.
.admin-page-headersayfa şeridinin kendimb-6'sını taşıyor ve aura bunu host başına sıfırlıyordu —.sk-card__head--page,.sk-card__actionsve.fm-sidebar__page-headeriçin birer kural. Tablonun kendi başlığı olduğunda header'ı host eden datatable toolbar aksiyon satırı bu listede hiç yoktu, dolayısıyla 24px'lik alt boşluğu header'ı satırın merkez çizgisinden yukarı itiyordu. Sıfırlama artık her host'un verdiğidata-sk-page-headerişaretine bağlı; hepsine birden uygulanıyor ve eklenecek yeni host aynı boşlukla gelmek yerine sıfırlamayı devralıyor.FileManagerSidebar'a da eksik olan işaret eklendi.
2026-09-08 — v13.7.1
Düzeltildi
- Datatable toolbar'ındaki geri butonu artık aksiyonlardan önce, diğer tüm kartlarla aynı sırada duruyor.
SkDatatable, host ettiği sayfa header'ını (layout'un geri butonu ve sayfa aksiyonları).sk-dt-toolbar__actionsiçinde en sona çiziyordu;SkForm'un ve düz kartların geçtiğiSkCardise en başa. İkisini birden taşıyan bir ekranda tabloda[+ Oluştur] [← Geri], formda[← Geri] [Kaydet]diziliyordu. Header artık datatable toolbar'ında da ilk sırada render ediliyor; geri, birincil aksiyonun solunda bir gezinme kontrolü olarak kalıyor, aksiyon gibi okunmuyor. Toolbar'ın aksiyon kapsayıcısı ayrıcaSkCard'ın zaten verdiğidata-sk-page-headerişaretini taşıyor, böylece tüketici CSS'i iki host'u tek seçiciyle hedefleyebiliyor.
2026-09-06 — v13.7.0
Eklendi
-
APP_KEY'den bağımsız, adanmış birDATA_ENCRYPTION_KEYartık hassas ayar değerlerini (mail.password,storage.spaces_secret,storage.aws_secret,turnstile.secret_key,postman.api_key,apidog.access_token) ve 2FA secret'ları/kurtarma kodlarını koruyor. Daha önce bu verinin tamamıAPP_KEYile şifrelenirdi; bu yüzden bir sunucu taşımasında çalıştırılan rutin birphp artisan key:generatebu veriyi sessizce kurtarılamaz hale getiriyordu —SettingServiceortaya çıkanDecryptException'ı yutup hata vermek yerinenulldöndürüyordu. Yeni anahtarı yönetmek için üç yeni komut var:encryption:keyanahtarı üretir ve eski anahtarıDATA_ENCRYPTION_PREVIOUS_KEYSiçinde korur;encryption:rekeymevcut satırları, çözemediği bir satıra asla dokunmadan yeni birincil anahtara yeniden şifreler;encryption:healthönceki-anahtar listesinin temizlenmesinin güvenli olup olmadığını raporlar vephp artisan sk:doctorbuna karşılık gelen birData Encryption Keykontrolü kazandı. Benimseme opt-in'dir — bunların hiçbirini çalıştırmayan bir kurulum tıpkı öncekiyle aynı, bayt bayt çalışmaya devam eder; yeni birsk:installartık anahtarı otomatik üretiyor. Bkz. Veri Şifreleme ve sunucu taşıma runbook'u. -
SkFormbirreload()metodu ve bir.reloadOnDataUrlChange()builder flag'i kazandı.reload()(defineExposeile expose edilir), bir host'undataUrl'i istek üzerine yeniden çekmesine — bir "Yenile" butonu, kardeş bir kaydetme olayı — formu yeniden mount etmeden izin verir..reloadOnDataUrlChange(true),dataUrlprop'u mount sonrası her değiştiğinde formun otomatik olarak yeniden veri çekmesine opt-in olur (örn. farklı bir kayıt için tekrar kullanılan bir dialog); varsayılan mount-only kalır ki config'i her parent render'da yeniden kurulan bir form her rebuild'de yeniden veri çekmesin. Bkz. Form Builder API. -
FB.fileUpload().deferExistingRemoval()ve sürükle-bırak kazandı..deferExistingRemoval(true), zaten kaydedilmiş bir dosyayı silmeyi anlık birDELETE /media/{id}'den ertelenmiş bir silmeye çevirir: öğe yalnızca field'ın keep-list'inden çıkar, silme ise save sırasındaLvntr\StarterKit\Traits\HasMediaCollections::syncMediaCollection()üzerinden gerçekleşir. Upload alanının drop zone'u artık üzerine sürüklenen dosyaları da kabul ediyor; bunlar seçici butonuyla aynıaccept/maxFileSize/fileLimitdoğrulamasından geçiyor. Bkz. Dosya Yükleme Alanı API'si. -
@lvntr/componentspaket kütüphanesi artık CI'da lint ediliyor — yeni bir rootlint:libscript'i ile (eslint --config stubs/eslint.config.js resources/js/components/Lvntr-Starter-Kit); böylece paylaşılan component kütüphanesindeki bir lint regresyonu, stub tarafında zaten yakalanan aynı şekilde yakalanır. -
TabIconColorveTabBadgeSeverityartık TabBuilder core barrel'ından export ediliyor (@lvntr/components/TabBuilder/core), zaten export edilenTabBuilderConfig,TabItemConfigveTabLayoutile aynı şekilde — bir sekmenin icon rengine veya badge severity'sine karşı tip yazan bir consumer artık doğrudan internal./typesmodülüne girmek zorunda değil. -
TB.tabs()panel mount etme ve URL davranışı için beş yeni chainable seçenek kazandı:.lazy(),.keepAlive(),.history('push' | 'replace'),.urlMode('server' | 'client')ve.syncUrl(boolean)..lazy()yalnızca aktif paneli mount eder (yatay düzende bu PrimeVue'nun kendi lazy modudur),.keepAlive()ise her paneli mount edip inaktif olanları gizleyerek sekme bazlı state'i korur;.history()bir geçişin mevcut history girdisini mi değiştireceğini (varsayılan) yoksa yeni bir girdi mi push edeceğini belirler;.urlMode('client')varsayılan Inertia visit'i yerine sunucuya istek atmadan URL'i günceller;.syncUrl(false)URL senkronizasyonunu tamamen kaldırır. Bkz. tabs.tr.md. -
SkTabsartıkv-modeldestekliyor ve birchangeevent'i emit ediyor. OpsiyonelmodelValueprop'u, aktif sekme anahtarını hem URL hem local modda iki yönlü bağlar — mount sırasında bir URL deep link'i farklı bir gelenmodelValue'nun önüne geçer;change, mount sonrası (ilk mount hariç) her geçişte{ key, previousKey, tab }ile tetiklenir. -
SkTabsbiremptyslot'u kazandı; seçilebilir sekme kalmadığında —.permission()/.role()/.visible()yüzünden tüm sekmeler elenmişse ya da görünür sekmelerin hepsi.disabled()ise (eskiden aktif paneli olmayan, tamamen disabled bir şerit kalıyordu) — sidebar veya tab şeridi olmadan tek başına render edilir. -
Dikey
SkTabsartık gerçek bir ARIA tablist'i. Sidebar nav'ırole="tablist"/aria-orientation="vertical"taşır, her sekme butonuaria-selected/aria-controls/aria-disabledve rovingtabindexilerole="tab"'tır, panel iserole="tabpanel"ile sarmalanır; Arrow Up/Down, Home/End enabled sekmeler arasında odağı taşır, Enter/Space seçer. -
TabsBuilder.build()artık yinelenen sekme key'lerini doğruluyor ve immutable bir snapshot döndürüyor. Yinelenen bir key development build'lerinde hata fırlatıyor, production'da ise sessiz kalmak yerine birconsole.errorbasıyor;TabItemBuilder.build()artık yalnızca eksik değil, yalnızca boşluktan oluşan bir key'i de reddediyor; herbuild()çağrısı config'in ve sekmelerinin taze bir kopyasını döndürüyor, böylece aynı builder üzerinde sonraki bir.addTabs()ya da döndürülen config'i mutate etmek, zaten build edilmiş bir config'i artık etkileyemez. -
TabPanelMode,TabHistoryMode,TabUrlMode,TabChangePayloadveSkTabsExposedartık TabBuilder core barrel'ından export ediliyor (@lvntr/components/TabBuilder/core), mevcutTabBuilderConfig,TabItemConfig,TabLayout,TabIconColorveTabBadgeSeverityexport'larıyla birlikte. -
useUrlTab()artıktabsargümanı için düz bir dizinin yanı sıra birrefveya bir getter da kabul ediyor, ayrıca yeni bir{ history: 'push' | 'replace' }üçüncü argümanı eklendi. Değer her erişimdetoValue()ile okunuyor;history: 'push', her geçişe varsayılan'replace'yerine kendi history girdisini veriyor. -
CI'de artık
src/üzerinde statik analiz (Larastan/PHPStan, level 5) çalışıyor, Pint'in yanında.phpstan.neon, kitinApp\*referanslarının (kitin var saydığı tüketici-sahipli sınıflar, örn.App\Models\User) tam bir tüketici uygulaması olmadan çözülebilmesi içinstubs/app'ı tarıyor;phpstan-baseline.neonmevcut bulguları anlık görüntü olarak dondurarak gate'in yalnızca yeni kodu bu çıtaya tabi tutmasını sağlıyor. Yereldecomposer analyseile çalıştırılır. Baseline daha sonra, düzeltilebilir bulgular ayıklanarak 259'dan 238 bulguya daraltıldı. -
make:sk-domainbir--with-permissionsopt-in flag'i kazandı (--with=permissionsile de seçilebilir). Yeni domain'in kaynağını — tüm varsayılan ability'lerle —config/permission-resources.php'ye bir EN görünen adla birlikte kaydeder; TR etiketi ve rol ataması bilinçli olarak elle doldurulmaya bırakılmıştır, çünkü ikisi de yalnızca domain adından güvenle çıkarılamaz. Bkz. artisan-commands.tr.md. -
CI'de artık bir Playwright admin duman testi paketi çalışıyor.
tests/e2e/specs/admin-smoke.spec.ts,scripts/bootstrap-fixture-app.shile iskeletlenipscripts/e2e/fixtures/E2EAdminSeeder.phpile seed'lenen gerçek bir fixture uygulamayı login, domain CRUD ve ayarlar ekranları üzerinden sürüyor; yeni bire2eGitHub Actions job'ı her push'ta fixture'ı kurup paketi headless çalıştırıyor. Yereldenpm run test:e2eile çalıştırılır. Bkz. testing-e2e.md. -
sk:installopsiyonel gözlemlenebilirlik (observability) reçeteleri için opt-in bir--modules=telescope,pulse,horizon,sentryflag'i kazandı. Flag verilmezse, bir TTY kurulumu Laravel Telescope, Laravel Pulse, Laravel Horizon ve Sentry'den hangilerinin ekleneceğini sorar; non-interactive bir çalıştırma (veya boş bir--modules=) adımı tamamen atlar, yani bu flag'i kullanmayan bir kurulum için hiçbir şey değişmez. Seçilen her reçete kendicomposer require'ını ve post-install komutlarını (örn.telescope:install,horizon:install,vendor:publish --tag=pulse-migrations,vendor:publish --tag=sentry-config) best-effort bir adım olarak çalıştırır — bir reçetenin başarısız olması kurulumu iptal etmez veya diğerlerini engellemez; tam kurulamayan bir reçete sonda elle çalıştırılması gerektiğine dair bir notla listelenir. Telescope dev bağımlılığı olarak değil, normal bağımlılık olarak kurulur:telescope:install, Telescope'un kendi provider'ından türeyen bir provider'ıbootstrap/providers.phpdosyasına kaydeder ve bunu üretimdeki bircomposer install --no-devyükleyemezdi. -
Kitin API dökümantasyonu artık Scramble'ın kendi arayüzü yerine yeni bir bağımlılık olan
lvntr/api-dock'u okuma yüzeyi olarak kullanıyor.sk:installher kurulumdaconfig/api-dock.php'yi yayınlıyor; api-dock, panelini/api-dockadresine (ham belge/api-dock/spec) mount ediyor ve kitin route attribute'larından zaten ürettiği aynı OpenAPI belgesini belgeliyor. Yerini aldığı Scramble yüzeyinin aksine, panel artık seed edilenapi-docs.readiznine karşı korunuyor — daha önce o docs rotasına hiçbir izin bağlı değildi. Bu koruma kurulum adımının koşmasına bağlı değil: api-dock'un paket varsayılanı paneli,/api-dock/spec'i ve try-it proxy'sini yalnız['web']arkasında sunuyor; bu yüzdenapi-dock.middlewarehâlâ o dokunulmamış varsayılandayken kit üzerine['web', 'auth', CheckApiDocsAccess::class]yığınını kuruyor — middleware sınıfı uygulamada henüz yoksa api-dock'u anonim sunmak yerine tamamen kapatıyor. Beraberinde dört yeni komut geliyor:api-dock:exportbelgenin bir anlık görüntüsünü alır,api-dock:diffonu kayıtlı bir baseline ile karşılaştırır,api-dock:synconu Postman/Apidog'a gönderir veapi-dock:agent-guideAI odaklı çıktılar üretir — birllms.txtve bir MCP tool export'u (opt-in, ve yalnızcaAiToolattribute'u taşıyan operasyonlar için). Bkz. api.tr.md. -
sk:updatevesk:doctorartık kitin gerektirdiği ama uygulamaya hiç kurulmamış bir Composer paketini tespit ediyor.sk:updateeksik paketleri yazdırır ve gerçek bir TTY'de,--dry-run/--no-interactionyokken,composer update lvntr/laravel-starter-kit -Wkomutunu çalıştırmadan önce sorar;--no-interactionve--dry-runyalnızca komutu yazdırır.sk:doctoraynı durumu raporlar. -
Kitin kendi auth ve definitions API operasyonları artık
lvntr/api-dock'un AI metadata attribute'larını taşıyor (AiHint,AiPitfall,AiExample,AiTool,ApiFeature).login, üç sonucunun da 200 döndüğünü ve tamamlanmış bir login'i yalnızcatoken'ın varlığının işaret ettiğini belgeliyor;register, kayıt kapalıyken bilerek 404 değil 403 döndüğünü belgeliyor. Yalnızcameve definitions lookupAiTooltaşıyor, çünkü yan etkisiz tek okumalar bunlar. Yalnızca metadata — davranış veya route değişmedi. Bkz. api-ai-metadata.tr.md.
Güvenlik
-
Local ya da public disk üzerindeki bir FileManager dosyası artık kalıcı, kimlik doğrulaması gerektirmeyen bir public URL'e çözülmüyor. Disk temporary/signed URL desteklemediğinde (her local/public disk desteklemez) daha önce
Media::getUrl()'e düşülüyordu — bu link yetkilendirmeyi tamamen atlıyor, bir izin iptalinden ya da dosyanın çöp kutusuna taşınmasından sonra da çalışmaya devam ediyordu. Artıkfiles.download'ın zaten kullandığı aynı kontrolden geçen yeni bir yetkilifiles.previewroute'una düşülüyor; S3 ve temporary URL destekleyen herhangi bir disk etkilenmiyor. Bu route üzerinden yalnızca pasif olarak render edilen tiplerin (görsel, ses, video, PDF, düz metin, CSV) tutucu bir allow-list'i inline sunuluyor — geri kalanı attachment olarak gönderiliyor. Bkz. UPGRADE.tr.md. -
Logout — ve bir kullanıcının erişimini iptal etmek — artık geride canlı bir OAuth refresh token bırakmıyor. Bir refresh token, kendi access token'ından tasarım gereği daha uzun yaşıyor; ama
RevokeUserAccessActionyalnızca hâlâ "canlı" işaretli access token'ları iptal ediyordu. Bu yüzden bir kez logout olmuş ya da bir kez iptal edilmiş bir hesap, o iptal edilmiş access token'a bağlı bir refresh token'ı hâlâ elinde tutup istediği zaman yeni bir access token basabiliyordu. HemRevokeUserAccessActionhem de stubLogoutUserAction, yeni birRevokesOAuthCredentialstrait'i üzerinden artık önce bir token'a bağlı refresh token'ı, sonra access token'ı iptal ediyor.LogoutUserAction'ı özelleştirdiyseniz bkz. UPGRADE.tr.md. -
FileManager'da bir dosyayı kopyalamak artık depolama kotasını atlatamıyor. Yalnızca upload yolu
storage.quota'yı kullanıma karşı kontrol ediyordu;CopyFileActionhiçbir tavan olmadan kopya başına tam bir yeni blob oluşturuyordu. Artık fiziksel kopyadan önce aynı kota kontrolünü çalıştırıyor ve upload yolunun kullandığı aynıquota_exceededmesajıyla reddediyor. -
DATA_ENCRYPTION_KEYrotasyonu artık.envüzerindeki dosyaya özel bir ACL'i sessizce ne düşürüyor ne de kazandırıyor..envüzerinde birsetfacl/chmod +aiznifileperms()için görünmez; sahip/grup/mode hayatta kalırken bu izin atomic rename'i atlatamıyordu.encryption:keyartık ACL'i taşıyor ve geri okuyarak doğruluyor; taşınamıyorsa rotasyonu reddediyor. Ayna durum da kapatıldı: dizin seviyesinde bir inheritance kuralı, anahtar henüz yazılmadan geçici dosyaya.env'in hiç sahip olmadığı bir ACL koyabiliyordu — bu miras alınan girdi artık yazımdan önce normalize ediliyor. İki yöndeki uyuşmazlık da reddediliyor; yeni--allow-acl-lossbayrağı bu reddi, durumu elle uzlaştıracak bir operatör için uyarıya düşürüyor. -
stubs/package.json'daki@tiptap/*paketleri^3.22.4'ten^3.31.3'e taşındı, upstream düzeltmeleri almak için;stubs/package-lock.jsonyeniden üretildi. Bu aralıkta kitin kullandığı hiçbir API değişmedi. -
Dosya yüklemeleri artık kabul edilen MIME tiplerinden türetilen bir uzantı allow-list'ine karşı da kontrol ediliyor;
media-library'nin aktif-içerik uzantıları da artık koşulsuz engelleniyor. FileManager'ın public disk'i saklanan bir dosyayı kendi client adıyla geri sunuyor ve mevcutmimetypes:kuralı yalnızca sniff edilen içeriğe bakıyordu — bu yüzden byte'ları kabul edilen bir tipe uyan ama client adı.htmlile biten bir dosya daha önce olduğu gibi kaydedilip aktif içerik olarak sunulabiliyordu.UploadFileRequest, yeni birmimeExtensionMap()üzerinden birextensions:kuralı türetiyor ve mevcutsk-file-manager.errors.upload_invalid_typemesajını yeniden kullanıyor; böylece örneğinpayload.htmladlı bir yükleme, byte'ları geçerli kabul edilen bir tip olsa bile 422 ile reddediliyor. YayınlananUploadAvatarRequeststub'ı da aynıextensions:jpg,jpeg,png,webpkuralını taşıyor — mevcut kurulumlar bunuphp artisan sk:updateile ya da kuralı elle ekleyerek alır.media-library.disallowed_extensionsartık opt-out olmadan koşulsuz sertleştiriliyor vehtml,htm,xhtml,xht,svg,svgz,xml,xsl,xslt,js,mjs,hta'yı da engelliyor: Spatie, client adının yalnızca son değil her nokta segmentini kontrol ediyor; bu yüzdenname.html.pdfgibi çift bir uzantı,.pdftek başına request seviyesindeki kuralı geçse bile bu katmanda reddediliyor. Spatie'nin kendiFileNameNotAllowedistisnası artık belirsiz bir 500 yerine 422 ("The uploaded file name is not allowed.") olarak dönüyor. Aynı segment bazlı kontrol artıkUploadFileRequest'in kendi içinde de çalışıyor (istisna yolu yerine alan seviyesinde 422; kurulu media-library sürümünden bağımsız) ve bir dosyayı yeniden adlandırmak artık uzantısını değiştiremiyor:RenameFileRequest, yeni adın mevcut uzantıyı (büyük/küçük harf duyarsız) korumasını zorunlu kılıyor ve yasaklı bir segment içeren adı reddediyor — media libraryfile_namedeğişince saklanan dosyayı fiziksel olarak yeniden adlandırdığından,.html'e rename doğrulanmış bir görseli aktif içeriğe çevirirdi.mimeExtensionMap()dışındaki MIME tipleri (admin'in eklediği PPTX, RAR, Markdown, …) uzantılarını artık ham alt tip yerine Symfony'nin MIME veritabanından çözüyor;text/plainda.txt,.log,.md,.csv,.json,.ini,.ymlgibi metin adlarını kabul ediyor. Spatie'ninFileIsTooBigistisnası (requestmax:kuralından bağımsız kendimedia-library.max_file_sizetavanı, varsayılan 10 MB) da artık 422 olarak dönüyor; yayınlananSettingsServiceProviderstub'ı bu tavanı FileManager'ınmax_size_mbayarıyla hizalıyor. Kit artıkspatie/laravel-medialibrary^11.23istiyor (segment bazlı engelleme 11.23.0 ile geldi);composer updatelisteyi uygulayan bir build'i çeker. Bkz. UPGRADE.tr.md. -
Ayarlar cache'i artık şifrelenmiş değerler için çözülmüş düz metin yerine ciphertext saklıyor.
SettingService::allGrouped(), tamamen çözülmüş satır kümesini bir saat boyuncasettingsanahtarı altında cache'liyordu; bu yüzden herhangi bir cache backend'i (Redis, bir dosya store'u, başka bir uygulamayla paylaşılan bir store)mail.password, storage secret'ları ve benzeri değerleri o saat boyunca düz metin olarak tutuyordu. Ham satırlar artık yeni birsettings:v2anahtarı altında cache'leniyor ve her cache okumasından sonra çözülüyor; eskisettingsanahtarı yeni snapshot ilk kurulduğunda unutuluyor,php artisan encryption:rekeyise satırları yeni anahtara yeniden şifreledikten sonra aynısettings:v2'yi temizliyor. Çözülemeyen şifreli bir satır (rotasyona uğramış ya da yanlış birDATA_ENCRYPTION_KEY, bozuk ciphertext) artık her okumada — loglanarak — yeniden deneniyor; tam bir saat boyuncanullolarak cache'lenmek yerine, doğru anahtarı geri koymak cache'in süresi dolmasını beklemeden bir sonraki istekte etkili oluyor. -
API login endpoint'i artık mevcut IP-başına limitin üstüne kendi hesap-başına rate limitine de sahip.
POST /api/v1/auth/login, yeni birapi-loginlimiter'ına taşındı: IP başına dakikada 5 (değişmedi) artı e-posta adresi başına dakikada 3 yeni — dolayısıyla tek bir hesap için denemelerini birçok IP'ye yayan bir saldırgan artık da durduruluyor. Bu limiter, yalnız ayrı web login rotasını etkileyenauth.login_throttleayarıyla asla gevşetilemez. Kaydı publish edilenFortifyServiceProvider'da değil paketin kendisinde yapılıyor; böylecesk:updatepublish edilmiş dosyalardan birini yenileyip diğerini koruduğunda limiter asla kaybolmuyor. Publish edilmişroutes/api/public-api.php'yi özelleştirdiyseniz, rota değişikliğini elle taşımak için UPGRADE.tr.md'ye bakın. Üç/api/v1/auth/*endpoint'i daha önce isimsiz tek bir IP kovasını paylaştığı veloginartık kendi kovasına sahip olduğu için, grubun toplam IP-başına payı dakikada 5'ten 10'a çıkıyor; login rotasının kendisi IP başına 5/dakikada değişmedi. -
Yeni bir opt-in bayrak, admin panelinizin script etiketini
'unsafe-inline'yerine istek-başına bir CSP nonce'ıyla sunabilir; bu da enjekte edilmiş bir inline<script>'in çalışmasını kapatır. Açmak içinSTARTER_KIT_CSP_NONCE=trueayarlayın. Varsayılan olarakfalse'tur çünkü publish edilmişresources/views/app.blade.php'nizdenonce="{{ Vite::cspNonce() }}"özniteliğini gerektirir — bu olmadan bayrağı açmak panelin tema script'ini sessizce kırar. Yepyeni birsk:installher iki parçayı da zaten yerine koyar. Mevcut bir kurulumda bunu açmadan önce UPGRADE.tr.md'ye bakın.
Değişti
-
Başlıklı
SkDatatabletoolbar'ı artık iki satıra ayrılıyor: üstte başlık ve butonları, altta arama ve filtreler.DB.table().title(), başlığı, arama kutusunu, satır içi filtre pill'lerini, filtre/kolon butonlarını, create butonunu,#toolbar/#toolbar-startslot'larını ve — aura temasında — sayfa header'ını tek satıra diziyordu; tabloda birkaç filtreden fazlası olduğunda satır yetmiyordu. Başlık satırının padding'i artık.sk-card__headile birebir aynı (solda başlık/alt başlık, sağda create butonu ve toolbar slot'ları), yani başlıklı bir tablo normal bir kart başlığı gibi okunuyor; arama, satır içi filtre pill'leri ve filtre/kolon grubu ise altındaki kendi satırına iniyor. Başlıksız toolbar aynı kaldı — tek satır, aksiyonlar en sonda. -
Aura temasında kart yüzeyli
SkDatatable, sayfa başlığını artık üstündeki ayrı bir şerit yerine kendi toolbar'ında çiziyor. Layout'un sayfa header'ını — başlık, alt başlık, geri butonu ve#page-actions— sarmalayanSkCardüstleniyor ve tablo toolbar'ının hemen üstünde kendi başlık satırı olarak çiziyordu; Kullanıcılar, Roller, Aktivite Kayıtları ve Log Dosyaları ekranlarında önce bir başlık bloğu, altında ayrı bir toolbar görünüyordu. Header'ı artık tablonun kendisi üstleniyor ve toolbar'ın başlık satırı olarak render ediyor — başlıklı toolbar'ın zaten başlık ile arama/filtre satırı arasına koyduğu ayıracın üstünde. Böylece başlık, sayfa aksiyonları ve tablonun kendi kontrolleri tek bir header gibi okunuyor.DB.table().title()taşıyan tablo aynı kaldı (kendi başlığı yerinde durur, üstlenilen header yalnızca geri butonu ve sayfa aksiyonlarını katar); sayfa header'ını yerinde çizen ve zaten karta devretmeyenmainteması etkilenmedi. Aktivite Kayıtları ve Log Dosyaları ekranları artık gereksiz kalan.title()çağrısını bıraktı — başlıkları diğer ekranlar gibi sayfadan geliyor. -
Yatay
SkTabsartık sekme şeridini kendi kartının içinde çiziyor. Şerit, panelin üstünde sayfa zemininde çıplak duruyordu; artık birSkCardiçinde ve aura temasında layout'un sayfa header'ını da bu kart üstleniyor — böylece sekmeli ekran tek blok halinde okunuyor: başlık, alt başlık, ayıraç, sekme satırı, sonra panel. Sekmeler PrimeVue'nun varsayılan görünümünü bıraktı: düz ikon + etiket, pasifken soluk, aktifken primary renk ve tek gösterge olarak 2px alt çubuk. Paneller kendi kartlarını aynen koruyor, dikey düzen değişmedi. Kendi stilini yazdıysan tek sınıf adı değişikliği: yatay sekme ikonu artık.sk-vtab__icondeğil.sk-tabs__icon(dikey nav eskisini kullanmaya devam ediyor). -
Aura teması artık sayfa başlığını üst bara taşımıyor;
AdminLayouttek page header'ını içerik kartının kendi head'ine devrediyor. Aura başlığı, alt başlığı ve geri butonunuAdminHeader'a devrediyordu; bu da içeriğin ilk kartını başlıksız bırakıyor ve başlık ya da aksiyon isteyen her sayfayı kendi tema dalına zorluyordu —Users/Rolesindex sayfaları datatable'ın.title()'ını kuruyor ve create butonunu yalnızca aura'da tablo toolbar'ına taşıyordu,ApiRoutes/Indexise aura'ya özel komple bir başlık kartını elle yazıyordu..title()çağrısı koşulsuzdu, dolayısıylamainteması sayfa başlığını iki kez basıyordu. Hepsi kaldırıldı.AdminLayoutartık tek birAdminPageHeaderçiziyor — başlık, alt başlık, geri butonu,#page-actions— ve onu aktif temaya devrediyor:main'de yerinde kalıp içeriğin üstündeki şerit olarak duruyor, aura'da ise başlığı talep eden ilkSkCardonu kendi ayrı head satırında çiziyor (datatable kartı, form kartı, aktif sekmenin kartı). DevriSkCardyönetiyor: uygun kartlar mount sırasına göre aday listesine yazılıyor ve listede kalan ilk kart başlığı çiziyor; böylece sekme değişimi ya da Inertia gezinmesi — gelen kartın giden karttan önce mount olduğu durum — başlığı doğrudan devrediyor, kartın dışına düşürmüyor. Toolbar'ında başlık taşıyanSkDatatable(DB.table().title()) header'ı o toolbar'da barındırıyor ve sarmalayan kartı devre dışı bırakıyor; böylece tablo başlığı sayfa başlığının altına düşmüyor. Kendi başlığı olan kart başlığını koruyor ve page header'ı aynı head satırına katlıyor — sadece geri butonu ve sayfa aksiyonları, kart başlığının üstünde ikinci bir sayfa başlığı yok. Başlığı olmayan kart (datatable kartı, düz form kartı) ise header'ı kendi ayrı head satırında alıyor. Transparan sarmalayıcılar ve dialog gövdeleri hiç kaydolmuyor; chrome kartlarhost-page-header="false"ile dışarıda kalıyor — dikeySkTabsnavigasyon kartı,AvatarUploadve FormBuilder section'ı, böylece başlık gerçek içerik kartına iniyor, sayfanın kenar çubuğuna değil. Kendi kart yüzeyini elle yazan kit ekranları (ayarlardaki Görünüm sekmesi, API rotaları sayfası, log görüntüleyici) artıkSkCardkullanıyor; aura'da başlık her ekranda aynı yerde duruyor. Sayfa bileşeni aktif temaya göre dallanmıyor. Dosyalar ekranı hiçSkCardçizmiyor — dosya yöneticisi kendi yüzeyi — bu yüzden başlığıFileManager.vuekendisi talep ediyor ve kenar çubuğunun en üstünde, Yeni dosya yükle butonunun üstünde çiziyor; aura artık yöneticinin üstündeki çıplak şeride düşmüyor. Tüketici sayfaları için kırıcı:AdminLayout'unheader-in-cardprop'u veusePageHeader()composable'ı (resources/js/composables/usePageHeader.ts) kaldırıldı — prop'u silin vepageHeader.activeokuyan#title-endgeri butonlarını kaldırın; bu butonu artık layout çiziyor.AdminHeader'ınpage-title,page-subtitle,show-backprop'ları vebackevent'i de birlikte kaldırıldı. Adaylık iki eksende de reaktif: Görünüm ekranından tema değiştiğinde kartlar mount hâlde kalsa bile yeniden karar veriliyor (eskiden setup'ta donuyordu ve aura → main geçişinde başlık iki kez çiziliyordu), ve mount hâlde ama pasif bir sekme panelindeki kart adaylıktan çekiliyor (yataySkTabsya dapanels: 'all'), böylece başlık gizli panelle birlikte kaybolmak yerine görünür panele geçiyor.AdminHeader.vueeski opsiyonelpageTitle/pageSubtitle/showBackprop'larını hâlâ kabul ediyor vebackolayını hâlâ yayıyor:sk:updatebu dosyayı veAdminLayout.vuedosyasını birbirinden bağımsız yeniliyor, dolayısıyla layout'u özelleştirmiş bir uygulama bunları hâlâ bağlayan eski layout'ta kalıyor. -
Dikey
SkTabssekme butonları artık açık bir role taşımamak yerinerole="tab"taşıyor, panel içeriği de kart gövdesi içinde yeni birrole="tabpanel"<div>ile sarmalanıyor. Bir sekme butonunugetByRole('button')ile seçen bir testgetByRole('tab')'a geçmeli; kart gövdesi altında direkt-child selector'a dayanan özel CSS'in bir kontrolü hak edebilir. -
TabsBuilder.build()artık development build'lerinde yinelenen bir sekme key'inde hata fırlatıyor, production'da ise sessiz kalmak yerine aynı mesajıconsole.errorile basıyor. Yinelenen key'ler daha önce slot çözümlemesini ve URL seçimini sessizce bozuyordu — ikinci sekme birincinin içeriğini render ediyor ve?tab=ile asla erişilemiyordu. -
SkTabsartık@/composables'daki yayınlanmışuseUrlTabkopyasını import etmiyor; bunun yerine kendi internal, eşdeğer bir aktif-sekme state'ine sahip. Bu bir version-skew riskini ortadan kaldırıyor (sk:publish --tag=composables, bir uygulamayı shipped bileşenin beklediğinden daha eski biruseUrlTabile bırakabiliyordu), ama yayınlanmışuseUrlTab.ts'ini özellikleSkTabsdavranışını değiştirmek için elle düzenlemiş bir proje bu düzenlemenin artık etkili olmadığını görecek —useUrlTab()'ın kendisi, onu doğrudan çağıran uygulama kodu için etkilenmiyor. -
Sayfalar-arası "tümünü seç" toplu seçim artık desteklenmeyen bir filtrede sessizce düşürmek yerine fail-closed davranıyor.
BulkFilterSnapshot::normalize(), uygulayamadığı aktif birfilter[...]anahtarını snapshot'tan düşürmek yerine 422 (sk-bulk.unknown_filters) ile reddediyor; önceki davranış tablonun gösterdiğinden daha geniş bir küme çözüyor ve toplu işlemin düşürülen filtrenin gizlediği satırlara ulaşmasına izin veriyordu. GönderilenUserBulkSelectionQueryveRoleBulkSelectionQuery'yi etkiler. Yalnızcanulldeğer ya da boş dizi pasif sayılır — Spatie'ninAllowedFilter'ının atladığı iki şekil; boş ya da yalnızca boşluktan oluşan bir string olduğu gibi geçirilir ve tablonun kendi koşuluyla uygulanır (exact bir filtre tablonun gösterdiği aynı boş kümeyi verir,search/tarih sınırları onu yok sayar), böylece boş bir değer de toplu kümeyi asla genişletemez. -
DatatableQueryBuilder::columns()payload şekillendirmesi fail-closed. Hiçbir tanımlı sütunla eşleşmeyen bir?columns=istek parametresi önceden tam satıra geri dönüyordu; artık her satırı yalnızcaalwaysInclude()anahtarlarına indirgiyor — "tanımlı sütun anahtarları frontend ile eşleşmeli" sözleşmesiyle uyumlu. -
TB.tabs().queryParam()artık boş veya yalnızca boşluktan oluşan bir ismi reddediyor. Development build'lerinde hata fırlatıyor, production'daconsole.errorbasıp önceden ayarlı ismi (tabvarsayılanı ya da önceki çağrı) koruyor — boş isim eskiden olduğu gibi saklanıyor ve hiçbir şeyin geri okuyamadığı bir?=keyURL parametresi üretiyordu; sekmeler sessizce URL ile senkronu kaybediyordu. -
Kurulum komutları artık zorunlu bir adım başarısız olduğunda sıfırdan farklı bir çıkış kodu döndürüyor.
sk:install,sk:update,sk:upgrade(ve yayınlanansite:installstub'ı)migrate,db:seed,vendor:publish,sk:seed-permissions,passport:keys,key:generate,composer dump-autoload,npm installvenpm run buildçağrılarının sonucunu hiç okumuyordu: bozuk bir bağlantıda ölenmigrateyineDONEyazıyor, resume checkpoint'i adımı tamamlanmış olarak kaydediyor, stub-hash registry'si yazılıyor ve komut0ile çıkıyordu — CI, yarım kurulmuş bir uygulamanın üzerinden yeşil geçiyordu. Artık her alt komut sonucu denetleniyor; başarısız bir zorunlu adım (publish, migration, seeder, izin tohumlama, Passport anahtarları, şifreleme anahtarları) koşuyu durduruyor, checkpoint'i beklemede bırakıyor (sk:install --resumekaldığı yerden devam ediyor), registry yazımını atlıyor ve başarısız adımı + devam komutunu adlandıran tek satırla bitiyor. Frontend adımları bilerek ölümcül değil —npm install, Wayfinder üretimi venpm run build(ayrıcacomposer dump-autoloadve cache temizlikleri) yalnızca uyarıyor, elle çalıştırılacak komutu yazıyor ve kapanış özetinde tekrar listeleniyor; böylece Node ya da composer'ı olmayan bir makine bugünkü gibi kurulmaya devam ediyor. Sessizce başarısız olan bir migration'la şu an geçen bir CI hattı artık kırmızıya dönecek — bkz. docs/UPGRADE.tr.md.site:installdeğişikliği bir stub'ta yaşıyor: yalnızca yeni kurulumlara vesk:updateile tazelenen uygulamalara ulaşır, mevcut tüketici kopyası olduğu gibi kalır. -
Kırıcı değişiklik: kitin API dökümantasyonu Scramble'ın varsayılan
/docs/apiadresinden yeni api-dock paneline,/api-dock'a taşındı. Scramble'ın kendi rotaları artık bilerek devre dışı bırakıldı, yani/docs/apive/docs/api.jsongüncelleyen her uygulamada 404 dönüyor. Eski URL'i yer imlerine ekleyen veya ona link veren her şeyin/api-dock'a taşınması gerekiyor; kendiconfig/scramble.php'sini yayınlamış bir tüketici, artık rakip bir docs rotası kaydetmediğinden emin olmak için o dosyayı kontrol etmeli. Bkz. UPGRADE.tr.md. Kapatma işlemi artık yerine geçecek olanın gerçekten var olmasına bağlı:Scramble::ignoreDefaultRoutes()çağrısıLvntr\ApiDock\ApiDockServiceProvidersınıfının varlığını da şart koşuyor. Böylece bu sürümün kaynağını taşıyıp Composer'ın yeni bağımlılığı çözmesine izin vermemiş bir kurulum —dev-mainizleyen bir path/VCS repository'si, eski bir lock'tan geri yüklenmiş birvendor/, api-dock'u dışarıda bırakan bir kısıt — hiç dökümantasyon yüzeyi kalmaması yerine Scramble'ın rotalarını koruyor (o pencerede api-dock da kayıtlı değildir, API Routes ekranı da aynı eksik rota yüzünden panel butonunu gizler). Normal yükseltme yolu etkilenmiyor:composer update lvntr/laravel-starter-kitapi-dock'u kitle birlikte kuruyor. -
@tiptap/extension-task-itemve@tiptap/extension-task-list,stubs/package.json'dan kaldırıldı — hiçbiri kitin kendi kodunda hiçbir yerde import edilmiyor. Kendi kodunuz bunları doğrudan import ediyorsa uygulamanızın kendipackage.json'ına ekleyin. -
stubs/app/Models/User.php'ın@propertydocblock'u, modelin gerçek kolonlarına ve ilişkilerine uyacak şekilde düzeltildi. Runtime davranışı değişmedi. -
phpstan-baseline.neon, 259'dan 238 bulguya daraltıldı — bir avuç gerçekten düzeltilebilir bulgu (bayat docblock'lar, ulaşılamayan dallar) taşınmak yerine düzeltildi. -
CI'nin gerçek veritabanı job'ları (MySQL, MariaDB) artık yalnızca raporlamıyor, merge'leri de engelliyor — bir sürüm boyunca yeşil kaldıktan sonra.
-
release.shartık GitHub CLI (gh) ve etiketlenecek tam commit için yeşil bir uzak CI koşusu istiyor, yerel kalite kapısından önce kontrol ediliyor. Ayrıca artıkcomposer analyseve tam bir frontend kapısı (build/typecheck/lint/test) çalıştırıyor. Yayın akışı değişti:./release.shçalıştırmadan önceorigin main'e push edip CI'nin yeşillenmesini bekleyin. Bu yalnızca repo tooling'i —composer updateveyask:update'i etkilemiyor. -
sk:doctor'ın 22 kontrolü artık isim, mesaj ve ipucu metinlerini PHP içinde sabit kodlamak yerinesk-doctor.*lang key'lerinden çözüyor.src/Console/Doctor/Checks/altındaki her sınıf kullanıcıya görünen metni__('sk-doctor.<kontrol>.<durum>', [...])ile çağırıyor; böylece hem admin panelindeki Sistem Sağlığı ekranı hem dephp artisan sk:doctorartık her zaman İngilizce basmak yerine uygulamanın aktif dilini takip ediyor. İngilizce metin byte-byte değişmedi; bir tüketici uygulamasıapp/lang/<locale>/sk-doctor.phpyayınlayıp yalnızca ilgili key'i yeniden tanımlayarak tek bir string'i override edebilir —sk-bulk.*ve benzerlerinin zaten kullandığı namespace'siz arama sayesinde uygulama kopyası paketinkinin önüne geçiyor.sk:doctor --only=<seçici>çeviriden etkilenmiyor: seçiciler artık kontrolün görünen adından değil SINIF adından türetiliyor (DatabaseConnectionCheck→database-connection), yani her dilde aynı kalıyor; sınıf adıyla örtüşmeyen üç belgeli seçici (filemanager-disk,permission-matrix,unresolved-routes) takma ad olarak çalışmayı sürdürüyor. -
stubs/package.jsoniçindeki frontend build/lint/test araçları güncel sürümlerine taşındı:@types/node^26.5.0,concurrently^10.0.5,eslint-plugin-vue^10.11.0,typescript-eslint^8.70.0veunplugin-vue-components^32.1.0. Hiçbiri yayınlanan bundle'a girmiyor — runtime bağımlılığı değişmedi, komponent kaynağına dokunulmadı — ancakunplugin-vue-componentsbir major atladığı için tüketicinin kendi Vite build'ini etkiliyor; bu yüzden kapının tamamı yeniden koşturuldu:vue-tsc --noEmit, hemstubshem@lvntr/componentskütüphanesi üzerinde ESLint, 290 testlik Vitest paketi ve her iki Vite build'i (client ve SSR).
Düzeltildi
-
oauth_device_codes.user_idonarım migration'ının geri alınması artık hiç dokunmadığı bir kurulumun şemasını yeniden yazmıyor. İleri adım koşullu — yalnızca legacy bigintuser_id'yi uuid'ye çeviriyor, create migration'ın zatenforeignUuidtanımladığı taze kurulumda hiçbir şey yapmıyor.down()koşullu değildi: kolon uuid okunduğu her durumda bigint'e geri çeviriyordu, ki batch koştuktan sonra bu her iki başlangıç noktası demek. MySQL bu dönüşümü sessizce kabul ediyordu;uuid()'ninchar(36)yerine native 16-baytlık tipe derlendiği MariaDB 10.7+ ise doğrudan reddedip (Cannot cast 'uuid' as 'bigint unsigned' in assignment) rollback'i düşürüyordu.down()artık bilinçli olarak no-op: ileri adımın null'ladığı değerler tanımı gereği geçersiz kimliklerdi ve hiçbir tip değişikliği onları geri getirmiyor, tam batch rollback'i tabloyu zaten create migration üzerinden düşürüyor, tek adımlık rollback ise kolonu uuid bırakıyor — ileri adım da onu zaten-onarılmış okuyup atlıyor. -
Ekranı aşan admin sayfaları artık alttan kesilmek yerine yeniden scroll oluyor. Scroll kabı olan
.admin-contentçocuklarını flex sütun olarak diziyor, yani her sayfa kökü küçülebilir bir flex öğesi — ve kendi taşmasını kırpan bir çocuk (.sk-cardoverflow: hiddentaşır) otomatik minimum boyutunu içerik yüksekliği yerine0olarak çözüyor. Uzun bir form kartı bu yüzden artakalan ekran yüksekliğine sıkıştırılıp kendi alanlarını kırpıyordu; scroll kabında da kaydırılacak bir şey kalmadığı için sayfa donmuş gibi görünüyor, son bölüm ve alttaki butonlar erişilemiyordu. Scroll kabının çocukları artıkmin-height: min-contenttaşıyor; sayfa doğal yüksekliğini koruyor ve kayıyor. Ekranı bilinçli olarak dolduran kökler (dosya yöneticisininmin-h-0 flex-1kabuğu) etkilenmedi, gövde yüksekliğini zaten aynı scroll kabına göre sınırlayan datatable ekranları da birebir aynı render ediliyor. -
sk:doctorartık Horizon çalışırken doğrulanamayan queue worker uyarısı vermiyor.Queue Workerkontrolü tüm async driver'ları aynı sayıyordu, bu yüzdenrediskuyruğu her zaman "worker liveness cannot be verified automatically" raporluyordu — tam da bu canlılığı kendisi yayınlayan Laravel Horizon'un kurulu olduğu birçok kurulumda bile.rediskuyruğunda kontrol artık Horizon kuruluysa Horizon'un master supervisor kaydını okuyor: çalışan bir master supervisor sayısıyla birlikte OK veriyor, tamamı duraklatılmışsahorizon:continue'yu gösteren bir uyarı veriyor, hiç master yoksa Horizon'un kurulu ama başlatılmamış olduğunu uyarıyor, durum okunamıyorsa (örneğin Redis kapalıysa) altta yatan hatayla uyarıyor. Horizon bağımlılık olmuyor — sözleşmesiinterface_exists()koruması ardında FQCN string'i olarak çözülüyor — dolayısıyla Horizon'suz bir kurulum ya dasqs/beanstalkdüzerindeki bir kurulum önceki genel uyarıyı aynen almaya devam ediyor. -
sk:installartık mevcutuserstablosu kitin şemasını taşıyamadığında bir foreign key üzerinde ölmek yerine sebebi adıyla söylüyor. Kituserstablosunu uuid ile anahtarlar; kit kurulmadan ÖNCEphp artisan migrateçalıştırmış stock bir Laravel uygulamasındausersbigIncrementsid taşır — üstelik stock Laravel'in users migration'ı deftere kitin yayınladığı dosya adının aynısıyla (0001_01_01_000000_create_users_table.php) kaydedilmiştir, yani kitin uuid sürümü hiç çalışmaz. Uyumsuzluk birkaç migration sonrafile_folders.created_byileusers.id'yi adlandıran çıplak birSQLSTATE[HY000] ... 3780olarak ortaya çıkıyor, içinde operatörün eyleme dönüştürebileceği hiçbir şey olmadan. Migration adımı artık strateji sunmadan önce mevcutusers.id'yi yokluyor: sebebi ve çözümü yazıyor, ek yapıcı seçeneğiWILL FAILdiye işaretliyor ve yine de o seçilirse (ya da oturum prompt açamıyorsa) adımı bu gerekçeyle durduruyor.migrate:fresh'i koruyan satır yoklamasının aksine bu yoklama fail-open'dır — okunamayan bir şema asla uyumsuzluk sayılmaz, yani cevaplayamadığı bir soru yüzünden bir kurulumu bloklayamaz. Çözüm tam bir sıfırlamadır:migrate:fresh, sunulduğundafreshseçeneği ya da boş bir veritabanı, ardındansk:install --resume. -
sk:installartık mevcut bir proje için kurtarma yolu olarak belgelenmiyor.docs/install.tr.mdvedocs/update.tr.mdkomutu idempotent bir proje-geneli onarım gibi tarif ediyordu. Değil: hash kaydı düzenlediğiniz değil sildiğiniz dosyayı korur ve--forceverilmeden consumer tarafından düzenlenmiş bir published dosya tazelenmek yerine atlanıp raporlanır,--forceile ise doğrudan üzerine yazılır — ikisi desk:updateya da kapsamı daraltılmışsk:publish --tag=<alan>'ın verdiği seçici, düzenlemeyi koruyan tazelemeyi vermez. Her iki rehber de artık uyarıyı taşıyor, sınırUPGRADE.tr.mdiçinde kayıtlı. -
sk:installartık kendisinin kurmadığı bir uygulamada çalışmayı reddediyor. Komut, bir projenin zaten kurulu olduğunu anlamak için yalnızca kendi hash kaydına (storage/starter-kit/hashes.json, git tarafından yok sayılır) güveniyordu; bu kaydın kaybı canlı bir uygulamayı yepyeni gösteriyordu. Artık banner'dan önce fail-closed bir tespit adımı çalışıyor — kit'in şema tabloları ve yalnızca kuruluma özel yollar kontrol ediliyor; bunlardan biri eşleşen bir kayıt olmadan bulunursa komut hiçbir şey yazmadan duruyor. Çıkış yolu olaraksk:updateve yeniphp artisan sk:install --adopt(yalnızca kaydı yeniden inşa eder,--dry-runönizler) adlandırılıyor;--forceyine devam ediyor ama artık ilk kurulum sayılmıyor. -
Mevcut bir
.env, ne ilk kurulumda ne yeniden çalıştırmadask:installtarafından üzerine yazılmıyor. İlk kurulum, mevcut.env'in üzerine.env.example'ı doğrudan kopyalıyordu; buDB_PASSWORD,APP_KEYve yapılandırılmış her şeyi yok ediyordu. Installer artık merge ediyor: eksik.env.exampleanahtarları ekleniyor, ilk-kuruluma-özel anahtarlar ise yalnızca yoksa tohumlanıyor; mevcut hiçbir değer yeniden yazılmıyor..env, yalnızca hiç yoksa.env.example'dan oluşturuluyor. -
Consumer tarafından değiştirilmiş bir published dosya artık yalnızca
sk:update'in değil,sk:install'in yeniden-publish yolunun da atladığı bir dosya. İki komut da aynı üç-yönlü stub/hedef/kayıt-hash karşılaştırmasını paylaşıyor; son kaydedilen hash'le artık eşleşmeyen bir dosya bir consumer düzenlemesi sayılıp sessizce üzerine yazılmak yerine atlanıp raporlanıyor. Opt-out yine--force. -
sk:installartık yeniden kurulumda izlenmeyen bir dosyanın üzerine yazmıyor. Hash kaydında hiç izi olmayan bir dosya — çünkü yeni bir paket sürümü, bu uygulamada daha önce hiç göndermediği bir yola dosya göndermeye başlamıştı —--forcefark etmeksizin üzerine yazılıyordu. Artık bir consumer düzenlemesiyle aynı muameleyi görüyor:--forceverilmedikçe korunup raporlanıyor. Bu koruma yalnızca bir kayıt varken geçerli; gerçek bir ilk kurulum izlensin izlenmesin her yolu yine yayınlıyor. -
sk:install'in yıkıcımigrate:freshseçeneği artık birselect()yanıtı değil, yazılı bir onay istiyor. Kurulum-anı menüsü "tüm tabloları sil ve migration'ları sıfırdan çalıştır" seçeneğini sıradan bir evet/hayır tercihi olarak sunuyordu; geri dönüşü olmayan bir sıfırlamadan yalnızca bir yanlış tuşa basma kadar uzaktaydı. Bu seçeneği seçmek artık veritabanı adını (ya dafreshkelimesini) birtext()prompt'unda yazmayı istiyor; bunun dışındaki her yanıt — boş bir cevap dahil — hiçbir şey silinmeden ek türdenmigrateyoluna düşüyor. Seçenek ayrıcaAPP_ENVproduction benzeri göründüğünde,APP_DEBUGkapalıyken, oturum prompt gösteremediğinde ya da mevcut bir tablo zaten satır içeriyorsa baştan sunulmuyor. -
Oturumu hâlâ açıkken deaktive edilen bir hesap artık bir sonraki istekte oturumdan atılıyor. Login yolu zaten aktif olmayan bir hesabı reddediyordu, ama zaten açık bir oturuma erişemiyordu. Yeni
EnsureUserIsActivemiddleware'i herweb/apiisteğindestatus'u kontrol ediyor ve operatörün deny-list'iyle (starter-kit.security.active_status_denied, varsayılan['inactive', 'banned']) eşleştiğinde oturumu sonlandırıyor; her belirsiz durumda (status attribute'u yok, string olmayan değer, listelenmemiş bir status) kasıtlı olarak fail-open vestarter-kit.security.enforce_active_status = falseile tamamen devre dışı bırakılabiliyor. -
Çözülemeyen bir ayar artık hiç ayarlanmamış bir ayardan sessizce ayırt edilemez değil.
SettingServiceçözme sırasında herExceptiontürünü yakalayıpnulldönüyordu;allGrouped()de bunu bir saate kadar cache'liyordu — yani yanlış anahtar, bozuk payload ya da hatalı yapılandırılmış cipher, mail/storage/Turnstile alanlarında sessizce env/varsayılan değere düşüyordu. Artık yalnızcaDecryptExceptionele alınıyor (yinenull, ama ciphertext yazılmadan loglanıyor); diğer her şey yukarı fırlıyor. -
encryption:healthartık config'i önbelleklenmiş ve bayat olduğunda fail-closed davranıyor.config:cachealtında komut "cache bir.envdüzenlemesinden önce alınmış" ile "değer hiçbir zaman env'den gelmedi" durumlarını ayırt edemiyordu — bayat bir önbelleklenmiş zincir, uygulamanın az sonra kullanmayı bırakacağı bir anahtar kümesi içinsafe-to-clearraporlayabiliyordu. Çözdüğü anahtar zinciri artık.env/süreç ortamıyla eşleşmeyen önbelleklenmiş bir config, sonucuincomplete'e (exit 1) düşürüyor vephp artisan config:clearçalıştırın talimatı veriyor — bu, bir rotasyonu kalıcı veri kaybına çevirebilecek bir yolu kapatıyor. Bkz. encryption.tr.md. -
sk:install'in mevcut-uygulama tespit işaretleri production'da ölüydü.EXISTING_APP_DIRECTORY_MARKERS, stub ağacının hiç göndermediğiresources/js/Pages/Admin(büyük harfliPages) taşıyordu — yalnızca case-insensitive yerel dosya sistemleri (macOS) bu uyumsuzluğu maskeliyordu.KIT_SCHEMA_TABLESise bu kit'in hiçbir zaman oluşturmadığı birfile_manager_folderstablosunu kontrol ediyordu; gerçek tablofile_folders. İkisi de düzeltildi, bu işaretlerin varlık amacı olan fail-closed tespit adımı geri geldi. -
Kurulum sırasında ulaşılamayan bir veritabanı artık başarılı bir kurulum raporlamıyor.
sk:install, bir bağlantı hatasında veritabanı bloğunu (migration, seeder, izin tohumlama) yalnızca ekrandaki bir uyarıyla atlıyor, yine de stub-hash registry'sini yazıyor, resume checkpoint'ini temizliyor ve0ile çıkıyordu. Koşu artık eksik olarak bitiyor: registry yazılmıyor, checkpoint korunuyor (böylece--resumetam kaldığı yerden devam ediyor) ve komut sıfırdan farklı bir çıkış koduyla çıkıyor. Bkz. UPGRADE.tr.md. -
sk:installartık yeniden kurulumda ya da--resumekoşusundapackage-lock.json'ı silmiyor. Lockfile, uygulamanın sabitlenmiş bağımlılık grafiğidir;installFrontend()ise onunpm installöncesinde koşulsuz siliyordu — yani yeniden çalıştırma, koşunun kendi özeti dosyayı "korundu" diye raporlarken bile her paketi uygulamanın hiç test edilmediği sürümlere yeniden çözüyordu. Silme artık yalnızca ilk kurulumda yapılıyor (ilgisiz birpackage.json'dan kalan lock orada yalnızca engel olur) ve kararInstalling npm dependenciesadımının içine taşındı: checkpoint'lenmiş bu adımı atlayan bir--resumekoşusu, ilk koşunun az önce yazdığı lockfile'ı artık silmiyor — silseydi onu yeniden üretecek hiçbir şey kalmıyordu. -
--resumekoşusu artık az önce kurduğunode_modules'ı silmiyor. Eski bağımlılık ağacını temizleme işiInstalling npm dependenciesadımının önünde duruyordu ve yalnızca ortada bir ağaç varsa çalışıyordu — yani ilk koşuda temizlenecek bir şey, dolayısıyla checkpoint'lenecek bir adım yoktu; oysa ağacı OLUŞTURANnpm installcheckpoint'leniyordu. Yarıda kalan bir kurulumun ardındansk:install --resume, yeni kurulmuşnode_modules'ı siliyor, sonra onu yeniden dolduracak kurulumu atlıyor venpm run build'i eksik bağımlılıklarla baş başa bırakıyordu. Temizlik artık aynı adımın içinde, lockfile kararının yanında: adım atlanırsa ikisi de atlanıyor. -
encryption:key'in "Next steps" çıktısı artık belgelenen rotasyon sırasıyla uyuşuyor. Numaralı listeencryption:rekeyile açılıyordu; oysa önbelleklenmiş bir config hâlâ az önce emekliye ayrılan anahtarı çözer — bu yüzden çıktıyı izleyen bir operatör her satırı yanlış anahtara yeniden şifreliyor ya da hiçbir şey yazmıyordu. Config önbellekliysephp artisan config:clearartık rekey'den önce kendi başına birinci adım olarak listeleniyor; tam olarak Veri Şifreleme belgesindeki sıra. -
encryption:key'in.envokumaları artık çalışan uygulamanın gerçekten çözdüğü değerle eşleşiyor.DATA_ENCRYPTION_KEY,APP_KEYveDATA_ENCRYPTION_PREVIOUS_KEYS,.env'den elle yazılmış bir regex ile okunuyordu; bu regex${APP_KEY}gibi enterpolasyonlu bir atamayı çözmeden olduğu gibi döndürüyor, satır-içi yorumlar ve bazı tırnak durumlarında gerçek dotenv ayrıştırıcısından farklı davranıyordu. Okumalar artık uygulamanın önyüklendiği aynı ayrıştırıcıdan (Dotenv::parse()) geçiyor; yani enterpolasyonlu bir referans aynı şekilde çözülüyor veDATA_ENCRYPTION_PREVIOUS_KEYS'e eklenen değer referans değil çözülmüş materyal oluyor. Ayrıştırıcının okuyamadığı bir.envartık — hiçbir anahtar üretilmeden veya hiçbir şey yazılmadan önce — rotasyonu durduruyor; ayrıştırıcının kendi hata mesajı raporda gösterilmiyor, çünkü bozuk satırı olduğu gibi alıntılayabilir ve bu satır anahtar materyali olabilir. Rotasyon ayrıca süreç ortamı bu anahtarlardan birini geçersiz kıldığında da duruyor — doğrudan ya da enterpolasyonlu bir değerin referans verdiği bir değişken üzerinden — çünkü o durumda dosya bir değeri söylerken çalışan uygulama başkasını çözer;.env'i yeniden yazmak bu farkı kapatamaz, süreçteki değer kazanmaya devam eder. Tek güvenli hamle, hiçbir anahtar üretilmeden durup ayrışmayı operatöre bırakmaktır. -
mediatablosu geri alındığında şema ile kayıt defteri artık ayrışmıyor.create_media_table'ın birdown()'ı yoktu ve Laravel'in migrator'ı bu çağrıyımethod_existsile koruyor — yaniphp artisan migrate:rollbacktabloyu sessizce atlıyor, ama migration'ın kayıt defteri satırını yine de siliyordu. Tablo ayakta kalıyor, kaydı kalmıyor ve bir sonrakimigratezaten var olan bir tabloda patlıyordu. Artık yıkmak yerine reddeden birdown()tanımlıyor: boş tablo düşürülüyor, içinde satır varken denenen bir rollback ise hatayla duruyor. Dolu birmedia'yı düşürmek satırları kaldırırdı, dosyaları değil — Spatie alttaki blob'ları yalnızca modelin deleting event'i üzerinden siler, bir şema rollback'i bunu atlar; geriye onları indeksleyecek hiçbir şey kalmadan öksüz dosyalar kalırdı. Geri almak istiyorsanız önce media'yı uygulama üzerinden silin. Aynı zincirdeki iki sonraki migration (add_folder_id_to_media_table,add_soft_deletes_to_media_table) da birebir aynı reddi taşıyor; çünkü bir batch en yeniden en eskiye doğru geri alınır: bu olmadan, create migration'ının koruması hiç devreye girmeden dolu bir tablodanfolder_idvedeleted_atdüşürülmüş olurdu. Bkz. UPGRADE.tr.md. -
definitions.lang, tablonun birleşik unique indeksini InnoDB'nin anahtar-uzunluğu sınırının altında tutmak için daraltılıyor. Üç varsayılan 255 karakterlik sütun üzerindekiunique(['key', 'value', 'lang']), 3072 byte'lık sınırın 3060'ında duruyordu — herhangi bir sütunun tek bir karakter genişlemesi bu sınırı kırardı.lang, kitin herhangi bir yerde kabul ettiği en geniş locale değeri olancontent_languages.code'a (35) daraltılıyor, böylece kitin kendi ekranlarından saklanabilen hiçbir değer etkilenmiyor;keyvevalueyayımlanmış 255 genişliğini koruyor, çünkü tek başınalang~892 byte boşluk bırakıyor ve onları daraltmak yalnızca mevcut şemanın kabul ettiği veriyi bloke ederdi; yeni migration, şemaya dokunmadan önce soft-delete edilenler dahil her mevcut satırı ölçüyor ve tek bir satır bile kırpılacaksa — şemayı değiştirmeden — reddediyor. Her iki yön de unique indeksin var olduğunu doğrulayarak bitiyor; indeksi zaten eksik hâlde migration'a ulaşan bir tablo, garantisi olmadan "migrate edildi" diye kaydedilmek yerine indeksi yeniden kuruluyor. Reddederse ne temizlemeniz gerektiği için bkz. UPGRADE.tr.md. -
sk:installartık yeniden kurulumda ya da güncellemede çakışan varsayılan Laravel dosyalarını silmiyor.package-lock.json,vite.config.*veresources/js/app.js'i koşulsuz silmek, installer'ın ilk kurulum sonrası hiçbir koşuda yetkisi olmayan proje durumunu yok ediyordu. Silme artık yalnızca ilk kurulumda gerçekleşiyor; sonraki bir koşu bulduğu çakışan dosyaları silmek yerine raporlayıp dokunmadan bırakıyor. -
MySQL/MariaDB CI dilimi artık install test suite'i yerine gerçek migration zincirini çalıştırıyor.
tests/Feature/Install, migration'ları değil installer mantığını test ediyordu; bu yüzden MySQL veya MariaDB'nin daha katı DDL'inde kırılan bir migration CI'da fark edilmeden geçebiliyordu. MariaDB job'ı damysqlsürücüsü üzerinden çalışıyordu, dolayısıylauuidsütunları hiçbir zaman MariaDB'nin native yolunu almıyordu. İki job da artık kendi sürücüsüyle (mysql/mariadb)tests/Feature/Migration'ı çalıştırıyor. -
Ayar cache'i dış transaction commit olduktan sonra temizleniyor, sırasında değil.
setValue()/setGroup()Cache::forget('settings')çağrısını satır içi yapıyordu; dış bir transaction içine sarılmış bir yazım (UpdateAuthSettingsAction) satırlar henüz commit edilmemişken snapshot'ı düşürüyordu — araya giren bir okuyucu miss alıp yazım öncesi satırları okuyabiliyor ve bir saat daha cache'liyordu. Temizlik artıkDB::afterCommit()üzerinden geçiyor; açık transaction yokken yine anında çalışıyor. -
Logo, favicon ve avatar yüklemeleri eskiyi düşürmeden önce yeniyi kaydediyor. Üçü de mevcut varlığı önce siliyordu; bu yüzden başarısız bir
store()çağrısı ayarı artık var olmayan bir dosyaya işaret eder halde bırakıyordu. Başarısız bir yükleme artık mevcut görseli yerinde bırakıp hata döndürüyor. -
Bir medya nesnesi diskten, ancak satırının silinmesi commit olduktan sonra kaldırılıyor. Spatie'nin
MediaObserver::deleted()çağrısı dosyayı, satırı silen transaction'ın içinde kaldırıyordu; rollback ise çoktan gitmiş bir dosyaya işaret eden satırı geri getiriyordu. Kaldırma artıkDB::afterCommit()üzerinden geçiyor: rollback'te atılıyor ve geriye kalan en kötü sonuç, kurtarılabilir bir öksüz dosya oluyor. Transaction'sız bir silme bugünkü zamanlamasını koruyor ve hatasını yine yüzeye çıkarıyor. -
Çöpten klasör geri yükleme artık yinelenen isim oluşturmuyor.
CreateFolderActionyinelenen ismi reddediyor, ancak kök seviyede çöp bunun etrafından dolaşmanın bir yoluydu: MySQL ve SQLite iki NULLparent_iddeğerini ayrı sayar ve unique index devreye girmez. Geri yükleme artık aynı domain hatasıyla reddediyor. -
FileManager kota hesabı çıplak Spatie
Mediamodelinde yeniden çalışıyor.computeStorageUsed()koşulsuzwithTrashed()çağırıyordu; SoftDeletes trait'i olmadan bu macro bulunmadığı için her upload doğrulamasıBadMethodCallExceptionfırlatıyordu. Artık trait'in geri kalanının zaten kullandığı yetenek-farkındalıklı yardımcıdan geçiyor. -
file-manager:purge-trashartık tüm çöpü belleğe almıyor ve hataları raporluyor. Komut silmeden önce eşleşen her satırıget()ile okuyordu; artık iki scheduler'ın aynı satırları temizlemesini engelleyen bir cache kilidi alıyor, satırlarıchunkByIdile yürüyor (--chunk=, varsayılan 500), bir öğe hata verdiğinde devam ediyor ve geride bir şey kaldıysa sıfırdan farklı bir çıkış kodu dönüyor. Yayınlanan schedule girdisiwithoutOverlapping()kazandı. -
Konsol çıktısı, kurulu bir uygulamada gerçekten var olan doküman URL'lerine yönlendiriyor.
/docs/**export-ignoreişaretli olduğundanprefer-distkurulumunda docs dizini yoktur — buna rağmensk:install,sk:update,sk:upgradevesk:doctormigration ve anahtar rotasyonu sırasında yereldocs/…yolları basıyordu. Artık kurulu sürüme sabitlenmiş bir URL basılıyor. -
encryption:healthveencryption:rekeyhangi yüzeyler için gerçekten kefil olabildiklerini söylüyor. İkisi de kit'in kendi anahtar zincirini raporluyordu; Fortify ya da model-cast yolunda consumer'ın kurduğu bir encrypter onlara görünmüyordu, dolayısıyla bir rekey hiç yeniden şifrelemediği satırlar için başarı raporlayabiliyordu. Artık her yüzey, kendisine hizmet eden encrypter'la birlikte raporlanıyor; kit'in kurmadığı bir encrypter kefil olunamayan olarak adlandırılıyor (verdict: not-covered, çıkış 1) veencryption:rekeytam bir rekey basmak yerine tek satır okumadan reddediyor. Bayat yayınlanmış config açığı — encryption bloğundan önce yayınlanmış birconfig/starter-kit.php, ki oradaDATA_ENCRYPTION_KEYetkisizken health "temizlemesi güvenli" diyordu — kendi ayrı teşhisi olarak raporlanıyor. -
Şifreleme anahtarı, izinleri kısıtlanamayan bir dosyaya asla yazılmıyor.
encryption:keygeçici dosyasını0600yapıyor ama sonucu kontrol etmiyordu; izinleri yok sayan bir dosya sisteminde bir sonraki satır anahtar materyalini herkesçe okunabilir bir dosyaya yazıyordu. Mod artık dosya hâlâ boşken doğrulanıyor, sağlanmıyorsa komut duruyor. -
encryption:keyveencryption:rekeyaynı anda çalışamıyor. İkisi de anahtar zincirini okuyup yenisine karar veriyor ve geri yazıyor; eşzamanlı iki çalışma mevcut satırları okumak için hâlâ gereken bir anahtarı listeden düşürebiliyordu. Artık tek bir cache kilidini paylaşıyorlar;--dry-runrekey etkilenmiyor. -
FileManager dosya
DELETEisteği context'ini diğer route'lar gibi doğruluyor. Endpoint context DTO'sunu doğrudan request'ten kuruyordu; bozuk bir context belgelenen 422 zarfı yerine 500 olarak yüzeye çıkıyordu. -
Kullanıcı oluşturma/düzenleme dialog'undaki saat dilimi seçimi artık yalnızca site varsayılanını değil, tüm saat dilimlerini listeliyor.
UserFormtanımlayıcı listesini prop olarak alıyor; her iki dialog'un açıldığıAdmin/Users/Indexsayfası ise bunu hiç geçmiyordu, dolayısıyla bileşen boş varsayılanına düşüyor ve seçim kutusunda tek bir "site varsayılanı" seçeneği kalıyordu. Liste artıkUserController::index()tarafından veriliyor ve ikidialog.open()çağrısında da iletiliyor. Tam sayfaUsers/CreateveUsers/Editroute'ları bundan etkilenmiyordu. -
Bir
FB.datePicker()değeri artık form round-trip'inde bir gün kaymıyor. Sunucudan gelen yalnızca-tarih bir string ("2024-03-10"), JavaScript'in UTC gece yarısı saydığınew Date(value)ile parse ediliyordu; submit için geri formatlarken (toLocalDateStr) tarayıcının yerel saat diliminde okunuyordu — bu da UTC'nin gerisindeki her saat diliminde günü kaydırıyordu. Tarih artık geri serileştirilme şekliyle eşleşecek şekilde bileşen bazında (new Date(year, month - 1, day)) yerel gece yarısı olarak parse ediliyor. -
SkFormartık aynı başarısız istek için iki hata toast'ı göstermiyor. Form, kendi spesifik metniyledata_load_error/options_load_errortoast'larını yükseltiyordu, ama internaluseApi()çağrısı da aynı hata için composable'ın varsayılan genel toast'ını tetikliyordu.SkForm'unuseApi()örneği artık{ toast: false }ile opt-out ediyor; consumer'ın kendiuseApi()çağrıları etkilenmiyor. -
FB.checkboxGroup().optionsUrl(...)artık gerçekten uzak seçenekleri çekiyor. Dinamik seçenek watcher'ı, select-benzeri field'larıcheckbox-group'u içermeyen hardcoded bir tip listesiyle eşleştiriyordu; bu yüzdenoptionsUrlile konfigüre edilmiş bir checkbox-group field'ı sessizce hiç veri çekmiyordu — artık her yerdeki aynıSELECT_TYPESsetini kullanıyor. -
Bağımlı bir
optionsUrlfield'ından gelen bayat bir yanıt artık daha yeni bir yanıtın üzerine yazamıyor. Bağımlı bir select'in URL'sini süren field'ı hızlıca değiştirmek (bir arama kutusuna yazmak, hızlı yeniden seçimler) daha eski bir isteğin yanıtının daha yeni birinden sonra gelmesine izin verebiliyordu; bu da eski seçenekleri gösteriyordu. Her field artık monoton bir istek-başına sayaç tutuyor; bir yanıt yalnızca o field için hâlâ en son istekse uygulanıyor, aksi halde sessizce düşürülüyor (seçenek yazımı yok, hata toast'ı yok). -
Salt-okunur işaretlenmiş bir form/field artık field'ın kendi
.props({ disabled: ... })'u ile tekrar aktive edilemiyor. Form-leveldisabled(.permission()'dan) ya da field'ın kendi hesaplanandisabled'ı artık bir varsayılan değil bir taban değeri —.props({ disabled: false })artık salt-okunur bir formu kilidini açamıyor,.props({ disabled: true })ise başka türlü etkin bir field'ı hâlâ disable ediyor. -
Create formundaki çevrilebilir field varsayılanları artık field'ın gerçekten render ettiği locale'lerle eşleşiyor. Boş
{ locale: '' }tohumu, admin-UI locale'lerini listeleyenavailableLocales'i doğrudan Inertia sayfasından okuyordu; field'ın kendisi ise DB-destekli içerik locale'leriniTranslatableInputüzerinden render ediyor. İki liste farklılaştığında, gönderilen payload field'ın hiç göstermediği locale'ler için key taşıyabiliyordu (ya da gösterdiklerini eksik bırakabiliyordu). İkisi de artık aynıcore/localeshelper'ları üzerinden çözülüyor. -
maxFileSizeveya çoklu-dosyafileLimit'i aşan bırakılmış bir dosya artık sessizce eklenmek yerine reddediliyor.FB.fileUpload()'ın sürükle-bırak yolu artık dosya seçiciyle aynı doğrulamadan geçiyor, keep-list'te zaten olan bir dosyayı dedupe ediyor ve kaldırıldığında blob object URL'ini sızdırmak yerine iptal ediyor. -
Altı wrapper-render edilen field tipinde (
input-number,date-picker,select,multiselect,toggle-switchve.feedback()açıkkenpassword) bir<label for>artık odaklanabilir bir elemanı hedefliyor. Bu tipler PrimeVue kontrolünü odaklanamayan bir wrapper içinde render ediyordu; dolayısıyla düz birlabel[for=key]tıklanabilir hiçbir şeyi işaret etmiyordu — iç kontrol artık PrimeVue'nuninputId'si üzerinden${key}__controlalıyor ve label'ınfor'u bu id'yi hedefliyor. -
Dikey
SkTabssekme butonları artık kapsayan bir formu submit etmiyor. Sidebar nav<button>'ının açık birtype'ı yoktu, bu yüzden tarayıcılar onutype="submit"sayıyordu — bir<form>içindeki bir sekmeye tıklamak, yalnızca sekme değiştirmek yerine formu submit edebiliyordu. Artıktype="button"olarak ayarlanıyor. -
Mount sonrası değişen bir sekmenin
visible/disableddurumu artık URL'e senkron aktif sekmeyi doğru şekilde belirliyor.useUrlTab()mount anında alınmış sabit bir sekme listesi snapshot'ını kapsıyordu; bu yüzden sonradan görünür hale gelen bir sekmeye?tab=ile ulaşılamıyordu ve gizlenen ya da disable edilen aktif bir sekme arayüzü artık listede olmayan bir sekmede bırakıyordu. Seçilebilir liste artık canlıvisible/disableddurumuyla senkron tutulan reactive bir dizi — yeni görünür hale gelen bir sekme anında seçilebilir oluyor, gizlenen veya disable edilen aktif bir sekme ise ilk seçilebilir sekmeye düşüyor. -
Disabled bir sekme artık
?tab=üzerinden aktive edilemiyor ve disabled bir ilk sekme artık parametresiz varsayılan olmuyor.useUrlTab()artık hem URL parametresini hem de "parametre yok" varsayılanını tüm liste yerine seçilebilir (disabled olmayan) sekme listesine göre çözüyor. -
Zaten aktif olan sekmeyi tekrar seçmek artık bir Inertia visit'i tetiklemiyor ve
#hashartık sekme geçişinde korunuyor. Aktif sekmeye tekrar tıklamak (veya onu programatik olarak mevcut değerine atamak) hâlârouter.visit()'i çağırıyordu; artık no-op. Sekme değiştirmek ayrıca mevcut URL'deki#hash'i düşürmek yerine koruyor. -
Users tablosunda sayfalar-arası toplu seçim artık datatable'ın render ettiği aynı
created_at_from/created_at_totarih aralığı sınırlarını uyguluyor.UserBulkSelectionQueryartık tarihleri, tablonun kendi sorgusunun kullandığı aynı helper olanDatatableQueryBuilder::applyCalendarDateRange()üzerinden uyguluyor; böylece toplu işlem için çözülen küme, saat dilimi/DST sınırlarında görünür kümeden artık sapamıyor. -
Seçili bir satırın id'si, toplu işleme tablonun gösterdiği şekliyle, sayısal dönüşüm yapılmadan gönderiliyor.
useDatatableSelection()'ınexecuteBulkAction()'ı artık sayısal görünümlü bir id'yi göndermeden önce dönüştürmüyor; UUID/ULID ve integer birincil anahtarlar aynı şekilde değişmeden geçiyor. -
API Token ve API Client tablolarındaki ID kolonu artık yeniden sıralanabiliyor.
ApiTokenController::dtApi()veApiClientController::dtApi()artıknamevecreated_at'in yanınaid'yi de allow-list'e alıyor; ID başlığına tıklamak artık SpatieQueryBuilder'ınInvalidSortQuery400 hatasını döndürmüyor. -
BulkActionRequest,idstaşımayan sayfalar-arası bir toplu isteği artık reddetmiyor. Publish edilen request,select_all_filteredtrueolsa bileids(min:1) istiyordu; bu, belgelenmiş payload'la çelişiyor veuseDatatableSelection().executeBulkAction()'ı "tümü" modunda mevcut sayfada hiçbir şey seçili değilken çağıran bir host'a 422 döndürüyordu (gönderilen Users/Roles sayfaları o duruma hiç düşmez — "tümünü seç" yalnızca toplu işlem çubuğundan sunulur).idsartıkRule::requiredIf(! select_all_filtered); gönderilen id'ler yine şekil olarak doğrulanır (array,max:500, opak string). Değiştirilmemiş bir kopyask:updateile yenilenir. -
Gönderilen
lvntr-kit-frontendvelvntr-starter-kitskill'leri artık gerçek otomatik etiket anahtarını söylüyor. İkisi de ajana, atlanan bir.label()'ın var olmayan birlang/{locale}/sk-attribute.phpdosyasındakisk-attribute.attributes.{key}'den çözüldüğünü söylüyordu;FBalanları ve datatable sütun/filtre etiketlerivalidation.attributes.{key}'den (lang/{locale}/validation.php) çözülür. FormBuilder rehberi ayrıca hariciv-modelmodundainitialData(), bir alanın.default()değeri vedataUrlverisinin yalnızca dahili formu beslediğini, bağlanan nesneyi asla doldurmadığını artık belirtiyor. -
SkTabsikonları yardımcı teknolojilerden gizleniyor ve checked bir sekme durumunu duyuruyor. Her iki düzende de sekme ikonlarıaria-hidden="true"taşıyor (adı zaten label veriyor);.checked()işareti — süs değil, durum — görsel olarak gizli bir metinle (sk-common.completed, EN/TR paketlerine yeni anahtar) eşleştirildi, böylece ekran okuyucu atlamak yerine bunu okuyor. -
Sayfalar-arası "filtrelenmiş tümünü seç" artık literal bir
true/falsefiltre değerini tablonun uyguladığı gibi uyguluyor. Spatie'ninQueryBuilderRequest'i bu iki string'i herhangi bir datatable filtresi çalışmadan önce boolean'a çevirir;BulkFilterSnapshot::normalize()ise onları metin olarak geçiriyordu — bu yüzden birtruearaması, tablo "1" ile eşleşmişken "true" kelimesiyle eşleşen bir toplu küme çözüyor ve tablonun hiç göstermediği satırlara ulaşabiliyordu. Snapshot artık aynı dönüşümü yapıyor; kelime-arama koşulu da tablonunsearchfiltresinin ve gönderilenUserBulkSelectionQuery/RoleBulkSelectionQuery'nin ortak kullandığı tek helper olanDatatableQueryBuilder::applySearchWords()'e taşındı, böylece iki yol bir değerin nasıl bölündüğü, kaçışlandığı ya da dönüştürüldüğü konusunda artık ayrışamaz. -
Datatable arama kutusuna yazılan virgül artık isteği bozmuyor. Spatie'nin query builder'ı her
filter[...]değerini tablonun arama callback'i görmeden önce,üzerinden ayırıyor; bu yüzdenAcar, Leventgibi bir arama callback'e dizi olarak ulaşıyor ve istekTypeErrorile (HTTP 500) düşüyordu.DatatableQueryBuilder::applySearchWords()artık ayrılan değeri aynı ayraçla yeniden birleştirip metni yazıldığı gibi arıyor; sayfalar arası toplu seçim ham metni zaten uyguluyordu, iki taraf da aynı kümeyi çözüyor. -
SkDatatable'ın masaüstü arama kutusundaki temizle (×) kontrolü artık klavyeden erişilip kullanılabilen gerçek bir<button>. Daha önce erişilebilir adı olmayan, yalnız tıklanabilen bir<i>ikonuydu; artık yenisk-datatable.clear_searchetiketini taşıyor ve mobil arama popover'ının temizle butonu da aynı etiketi kullanıyor (eskiden "Kapat" diye okunuyordu). Bu kontrolü<i>elemanı olarak hedefleyen bir test ya da stylesheet artık butonu hedeflemeli —sk-dt-search__clearsınıfı değişmedi. -
TranslatableInputlabel'ları artık input'larıyla ilişkilendiriliyor. Dil seçicinin yanında (ve tek dil modunda) render edilen labelfor= alan key'ini, aktif input da eşleşenid'yi taşıyor; label'a tıklamak alanı odaklıyor — normal form alanlarının zaten kullandığı işaretlemenin aynısı. Tek locale render edildiğinde zorunlu alan ayrıca o input'uaria-requiredile işaretliyor ve dekoratif yıldızı (artıkaria-hidden) sr-only bir "zorunlu" metniyle eşliyor; birden çok locale varsa yıldız yalnız görsel kalıyor, çünküHasTranslatableRules::translatableRules()sadece varsayılan locale'i zorunlu tutup diğerlerininullableyapıyor — her dil sekmesini zorunlu diye okutmak yanlış olurdu.translatable-editoriseforyerinearia-labelledbyile adlandırılıyor: düzenlenebilir düğümülabel[for]'un hedefleyemeyeceği bir contenteditable<div>. -
EditorInput'unidve ARIA attribute'ları artık kullanıcının gerçekten yazdığı düğümde.id<EditorContent>'in sarmalayıcı<div>'ine konuyordu, Tiptap ise contenteditable düğümü onun içine render ediyor; bu yüzdenlabel[for]label'lanamayan bir sarmalayıcıyı gösteriyor ve yardımcı teknolojiler editör için ad, rol ya da zorunluluk durumu okuyamıyordu. Düzenlenebilir düğüm artıkid,role="textbox",aria-multiline="true"ve yeniariaLabelledby/ariaRequiredprop'larını taşıyor. Editörü#<alan key>ile seçen bir stylesheet ya da test artık.sk-rte__bodysarmalayıcısı yerine içteki.sk-rte__contentdüğümüyle eşleşir. -
encryption:keyartık mevcut birDATA_ENCRYPTION_PREVIOUS_KEYSgirdisinin anlamını değiştirmiyor. Komut yalnızca emekliye ayırdığı anahtarı normalize ediyordu; listede zaten bulunan girdiler olduğu gibi kopyalanıyordu. Liste phpdotenv üzerinden okunur (çevreleyen tırnaklar soyulur,${VAR}çözülür) ve tırnaksız geri yazılır; bu yüzden#,$veya boşluk içeren bir girdi bir sonraki boot'ta farklı bir anahtar olarak dönüyordu —#bir yorum açıp anahtarı kısaltıyor. Artık her girdi, ham hâli bir.envsatırında hayatta kalamıyorsa env-güvenli hâle getiriliyor (aynı baytlara çözülenbase64:biçiminde yeniden yazılıyor). -
encryption:keyartık geçici.envdosyasının tam yazıldığını ve diske indiğini doğrulamadan onu yerine taşımıyor. Dolu bir diskFilesystem::put()'un hata fırlatması yerine kısa bir bayt sayısı döndürmesine yol açar; bu yüzden kırpılmış bir gövde eksiksiz bir.env'in yerine geçebiliyordu — komutun iki yazmasından ilkinde o gövde, emekliye ayrılan anahtarın tek kopyasını taşır. Başarısız bir yeniden-açma,fflush()ya dafsync()de işlemi durduruyor: bu dosyada dayanıklılık güvenlik özelliğinin ta kendisi, sessizce hiçbir şey yapmayan bir flush ise iki-yazma sırasını yeniden salt bir çağrı sırasına indirger. -
encryption:keyartık.env'in sahip ve grup bilgisini yazdığı dosyaya taşıyor; taşıyamıyorsa dosyayı değiştirmeyi reddediyor.www-data:www-datasahipli bir.envüzerindesudo php artisan encryption:key, web kullanıcısının okuyamadığı root sahipli bir dosya bırakıyordu. Sahiplik en iyi çaba ile geri veriliyor (yalnızca root bir dosyayı başka bir kullanıcıya devredebilir) ama SONUÇ doğrulanıyor ve uyuşmazlık rename'den önce işlemi durduruyor:chownyapamayan operatör tam da dizine rename edebilen deploy kullanıcısıdır, yani uyarıp devam etmek servisin okuyamadığı bir.envgönderirken başarı raporluyordu. Mode geri yüklemesi aynı kuralla doğrulanıyor — genişlemiş bir mode anahtarı operatörün dışladığı okuyuculara sızdırır, daralmış bir mode ise onu okuması gereken servisi kilitler; ikisi de durdurur. Bu yolların hiçbirinde mevcut.envdeğiştirilmez. -
Kitin dosya yazan komutları artık kitin kendi paket klasörü üzerinde çalışmayı reddediyor. Kapsam:
sk:install,sk:update,sk:upgrade,sk:publish,sk:eject,make:sk-domain,remove:sk-domain,env:syncveencryption:key. Paketvendor/bin/testbenchile geliyor; bu yüzden bir klon içindevendor/bin/testbench sk:installçalıştırmak, temel dizini klonun içinde duran Testbench iskeleti olan gerçek bir Laravel uygulamasını ayağa kaldırıyordu — ve o iskeletinvendor/dizini doğrudan klona sembolik bağdır. Boş iskelet üzerinde "zaten kurulu" işaretlerinin hiçbiri tetiklenmediği için çalışma tertemiz bir ilk kurulum sayılıyor ve zorla-üzerine-yaz yoluna giriyordu: stub'ları yayınlıyor,package.json'ı birleştiriyor,.env'i yeniden yazıyor, domain üretiyor ve migration'ları paket kaynakları üzerinde çalıştırıyordu. Her komut artık ilk bayt yazılmadan duruyor: yazma hedefi paket kökü ise ya da onun içinde kalıyorsa ve o dizin kitivendor/lvntr/laravel-starter-kitüzerinden composer ile gerektirmiyorsa reddediyor. Bir tüketici uygulaması hiçbir zaman klonun içinde olmaz; klonun altında duran ama kiti gerçekten gerektiren bir deneme uygulaması (type: pathdeposu, sembolik bağ dahil) normal şekilde kurulmaya devam eder. Guard yalnızca yazma ile ilgili:--dry-run(sk:install,sk:update,sk:eject),encryption:key --showve klon dışını gösteren bir--destination=(sk:publish,sk:eject) geçer — henüz var olmayan bir hedef, mevcut en yakın üst dizinine göre sınıflandırılır, dolayısıyla klon içinde henüz oluşturulmamış bir dizin adı vermek bir atlatma yolu değildir.--forcede bunu aşmaz: anlamı "adını verdiğim dosyaların üzerine yaz", asla "kiti kitin içine kur" değildir. Paketin kendi Pest test paketi muaftır; çünkü bu komutları iskelet üzerinde bilerek çalıştırır. -
sk:doctor'ın FileManager disk kontrolü artık FileManager'ın gerçekten yazdığı diski takip ediyor. Kontrol daha önceconfig/file-manager.php'nin hiç tanımlamadığı birfile-manager.diskconfig anahtarını okuyordu; bu yüzden fallback (filesystems.default) kontrolün gerçekte baktığı tek şeydi — Storage'ı uygulamanın varsayılanından farklı bir diske (media-library.disk_name,SettingsServiceProvidertarafından set edilir) yönlendiren bir kurulum, FileManager'ın hiç kullanmadığı bir diski sessizce doğrulatıyordu. Artık öncemedia-library.disk_name'i okuyor, bu anahtar yoksa yalnızcafilesystems.default'a düşüyor.filesystems.disksaltında hiç tanımlı olmayan bir disk adı artık FAIL veriyor (öncekinde disk "configured" ve OK olarak raporlanıyordu); kökü var olan ama web sunucusu kullanıcısı tarafından yazılabilir olmayan bir local/public disk artık OK yerine WARN veriyor. -
Yeni
files.previewroute'u artık HTTP Range isteklerini yanıtlıyor.FilesystemAdapter::response()birStreamedResponsedöndürüyor; bu daRangebaşlığını tümüyle yok sayıp gövdenin tamamını200ile veriyordu —FileItemDTObu route'a yönelmeye başlayıncaFilePreviewModaliçindeki satır içi oynatıcıda ileri/geri sarma çalışmaz oldu, Safari ise oynatmayı hiç başlatmadı.localsürücülü disklerde her iki servis eylemi de artıkBinaryFileResponsedöndürüyor;Accept-Ranges/Content-Range/206işiniprepare()üstleniyor. Gerçek bir dosya sistemi yolu olmayan uzak sürücüler akış yanıtını korur. -
Editörden eklenen görseller yeniden yayımlanabiliyor.
EditorInput.vue, yüklenen (veya seçilen) dosyanın URL'sini doğrudan kalıcı içeriğe<img src>olarak yazıyor ve bu içerik hiç kimlik doğrulamayan ziyaretçilere gösteriliyor — dolayısıyla oturuma bağlı önizleme route'una işaret etmek yayımlanmış tüm görselleri bozdu.FileItemDTOartık ikinci bir alan taşıyor:public_url— disk'visibility' => 'public'ilan edilmişseMedia::getUrl(), aksi hâldenull. Editörpublic_urlgömüyor, yalnızca yoksa oturuma bağlıurl'ye düşüyor. Bu ek bir açığa çıkarma değil: public disk o baytları, API ne döndürürse döndürsün, yolu bilen herkese sunar; dosya tarayıcısı ise her yerde oturuma bağlıurl'yi kullanmayı sürdürür. Private disktepublic_urltasarım gereğinull'dır — yayımlanacak bir bağlantı yoktur. -
sk:installartık zaten kurulu bir uygulamanın üzerine sessizce yeniden yayımlamıyor. Yarım kalan önceki bir çalışmadan kalaninstall-progress.jsoncheckpoint'i — örneğin veritabanına ulaşılamadığı bir çalışmadan —--resumeverilip verilmediğine bakmaksızın hem existing-app-markers guard'ını hem de onay istemini her sonraki düz yeniden çalıştırmada devre dışı bırakıyordu;stepAlreadyCompleted()bir adımı gerçekten atlamak için zaten açık bir--resumeistiyordu, yani aslında hiçbir şey "resume" edilmiyordu, sadece guard'sız kalıyordu. Yeni birconfirmReinstall()guard'ı artık hash registry'si (storage/starter-kit/hashes.json) zaten mevcutken ve çalışma gerçek bir--resumedeğilken yeniden yayımlamadan önce soruyor;--no-interactionaltında--forceverilmediği sürece kapalı başarısız oluyor ve tek başına eski bir checkpoint artık iki guard'ı da bastıramıyor. -
İki noktalı bir özel izin adı (örn.
system.health.view) artık yanlış noktadan bölünmüyor.GroupedPermissionsQueryve_01_RolePermissionSeederbir izin adını kaynak/yetenek çiftine ayırmak için İLK noktayı kullanıyordu; çoğu izinresource.ability(tek nokta) şeklinde olduğundan sorun çıkarmıyordu, ama iki noktalı özel bir izinde kaynaksystem, yetenek isehealth.viewgibi yanlış bölünüyordu — oysa kaynaksystem.health, yetenek yalnızcaviewolmalı. İkisi de artık SON noktadan bölüyor. Bu aradapermission-resources.phpve EN/TRsk-roledil dosyalarına eksikdeveloper/apikaynak grupları ilefiles,api-clients,api-tokens,dashboard,system.healthkaynak etiketleri veviewyetenek etiketi eklendi. -
Roller formu artık pasif bir sekmedeki doğrulama hatasını gizlemiyor. Dikey
SkTabsyalnızca aktif paneli mount ediyor; Yeni Rol ekranında varsayılan aktif sekme "İzinler" olduğundan,name/display_name/colorgibi Temel Bilgiler sekmesindeki zorunlu bir alan boş bırakılıp gönderildiğinde hata hiçbir yerde görünmüyordu. Form artık başarısız bir gönderimde hatalı alanı taşıyan sekmeye otomatik geçiyor. -
Yeni bir kurulumda artık başarılı login 404'e düşmüyor.
FortifyServiceProvider, Fortify'ın kendi post-login redirect hedefi olanconfig('fortify.home')'u (/home) hiç ezmiyordu — bu kit o route'u hiç kaydetmiyor, gerçek iniş sayfasıdashboard.index(/dashboard). Yayınlanan provider artıkboot()içindeconfig(['fortify.home' => '/dashboard'])set ediyor; kendi kopyasını özelleştirmiş mevcut bir kurulum yeniden yayımlanana kadar etkilenmez.
2026-08-25 — v13.6.16
Düzeltildi
- Bir datatable, sayfa URL'inde kalan komşu tablonun sıralaması yüzünden artık boş açılmıyor.
sortsayfa genelinde tek bir query parametresi olduğu için, birden fazla tablo barındıran bir sayfada (sekmeler, yan yana paneller) ikinci mount olan tablo URL'deki ilk tablonunsortdeğerini okuyup kendi endpoint'inden o endpoint'in hiç izin vermediği bir kolona göre sıralama istiyordu —Spatie\QueryBuilderbuna HTTP 400 (InvalidSortQuery) ile yanıt veriyor ve tablo boş geliyordu. Bir kolon yeniden adlandırıldıktan veya kaldırıldıktan sonra yer imine alınmış bir bağlantı da aynı şekilde kırılıyordu.SkDatatableartık geri yüklenen sıralama anahtarını kullanmadan önce kendi kolonlarıyla doğruluyor —columnsiçinde görünmediği hâlde sıralanabilir olduğu için id kolonu dâhil, ayrıca bu route'a kayıtlı kolon sırası da dâhil; böylece yalnızca sunucunun yayınladığı bir kolon (örneğin gizliupdated_at), kullanıcı onu açtıktan sonra sıralamasını geri yüklemeye devam ediyor. Yabancı bir sıralama taşıyan URL başka bir tablonun URL'i sayılıp bütünüyle yok sayılıyor —page,per_pageve filtreler dâhil; çünkü yarısını okumak bu tabloyu yalnızca komşusunun sayfa numarasında açardı. Route bazlı session kaydından dönen eskimiş bir anahtar da aynı şekilde düşürülüyor; tablonun gerçekten kendi olan sıralaması ise her iki kaynaktan da geri yüklenmeye devam ediyor.
2026-08-24 — v13.6.15
Değişti
- Varsayılan panel artık işlevsiz kontroller içermiyor. Yeni bir kurulumun header'ında arkasında hiçbir
commandolmayan dört kullanıcı menüsü girdisi (hesap ayarları, bildirim tercihleri, parola değiştir, yardım) ile uydurma sipariş, ödeme ve kişilerle doldurulmuş bildirim ve mesaj popover'ları vardı — iki dilli bir kitte sabit Türkçe metinler, sürekli yanan bir rozet ve hiçbir şey yapmayan bir "tümünü okundu işaretle" aksiyonu. Hepsi kaldırıldı; profil bağlantısı, dil alt menüsü, çıkış, görünüm popover'ı ve system_admin'e özel geliştirici popover'ı yerinde kaldı. Dashboard'daki aynı ölçüde işlevsizExport,New Report,View AllveView Reportbutonları da kaldırıldı ve demo dashboard artık metriklerinin örnek içerik olduğunu belirten çevrilmiş bir bilgi bandıyla (sk-common.demo_banner) açılıyor. Grafikler, KPI kartları ve tablolar olduğu gibi duruyor: ekran kitin bileşenlerinin neler yapabildiğini göstermeye devam ediyor, yalnızca uydurma iş verisini tüketicinin kendi verisiymiş gibi sunmuyor. Kaldırılan menü girdilerinin çeviri anahtarları dil dosyalarında bırakıldı. - Frontend lint kapısı artık yalnızca çalışmıyor, gerçekten uyguluyor.
npm run lint33 dosyada 2.708 uyarı bildirdiği hâlde 0 ile çıkıyordu (2.473vue/html-indent, 231vue/max-attributes-per-line, dört başka şablon biçimlendirme bulgusu); dolayısıyla CI'ın lint adımı hiçbir zaman kırılamıyor ve gerçekten yeni bir uyarı bu gürültünün içinde görünmez kalıyordu. Tüm baselineeslint --fixile mekanik olarak düzeltildi — yalnızca biçimlendirme, davranışa dokunulmadı. Kapı, kitin kendi CI'ının koştuğu yenilint:ciscript'i (--max-warnings=0) üzerinden uygulanıyor; tüketiciye gidennpm run lintise uyarıları bildirmeye devam ediyor ama başarısız olmuyor — böylece kurulu bir uygulamanın kendi kodundaki uyarılar onun lint adımını ve pipeline'ını kırmıyor. - Inertia sayfaları lazy çözümleniyor; ilk ziyaret artık tüm paneli indirmiyor.
resources/js/app.tsiçindeki iki sayfa glob'u da eager'dı; bu, login formunda bekleyen bir ziyaretçi için bile 54 Vue sayfasının tamamını — dosya yöneticisi, Tiptap editörü, tüm ayar ekranları — initial bundle'a koyuyordu;vite.config.tsiçindeki catch-allvendorchunk'ı da bu ağır feature bağımlılıklarını aynı yüke sabitliyordu. Glob'lar artık lazy ve modül kapsamına taşındı,resolveeşleşen loader'ın promise'ini döndürüyor (Inertia v3 async resolver'ı hem client'ta hem SSR'da await eder; dolayısıyla eski "SSR sync resolver ister" varsayımı geçerli değil) ve catch-all chunk kaldırıldı, böylece tek sayfada kullanılan bağımlılıklar kendi dinamik import sınırlarına düşüyor. Ölçülen initial payload 652,2 kB'den 390,4 kB gzip'e iniyor (%40 azalma); çıktı 121 chunk'a bölünüyor ve entry'den 54 dinamik import ayrılıyor. Sayfa çözümünde app'in vendor'ı geçmesi,Page not foundhatası ve dil glob'ları (eager kalır) değişmedi.scripts/ci/check-bundle-budget.mjsartık entry'nin statik import kapanışını gzip'leyip 500 kB üzerinde CI'ı kırıyor; böylece bir regresyon yayınlanmadan yakalanıyor. - Dağıtılan iskeletten iki eskimiş kalıntı kaldırıldı.
app.blade.phpiçindeki<title>yedeğiStarter Kit 12yazıyordu — her sürümde eskiyen ve yalnızcaapp.nameboşken ortaya çıkan bir sürüm numarası; yedek artık sürüm taşımıyor, sadeceStarter Kit. Ayrıca Files sayfasıMyShareLinksDrawerbileşenini import edipv-if="false"ile render ediyordu; yani backend ucunu bekleyen ~190 satırlık bir bileşen, hiçbir zaman erişilebilir olmadan Files sayfasının kendi chunk'ına giriyor ve sayfayı açan herkes tarafından indiriliyordu. Bu import ve ona ait ölü state (sessionLinks,drawerVisible,drawerMediaId,onShareRevoked) kaldırıldı; Files sayfası artık onu taşımıyor. Bileşen dosyası yerinde duruyor — özyinelemeli vendor sayfa glob'u onu hâlâ görüyor ve build hâlâ (artık hiç çekilmeyen) bir chunk üretiyor — veGET /file-manager/share?media_id=Xucu geldiğinde nelerin yeniden bağlanacağı bir yorumla kayıt altına alındı.
Düzeltildi
- Kurulum dokümanları artık yeni projeleri çok eski bir sürüme yönlendirmiyor. Belgelenen akış paketi
:^13.0ile ekliyordu; bu aralık,spatie/laravel-activitylog:^4.9kabul eden son sürüm olanv13.0.1'i de kapsayacak kadar geniş.laravel/laraveliskeleti yalnızca PHP 8.3 isterken bu kit (veactivitylog:^5.0) PHP 8.4 istediği içincomposer create-projectPHP 8.3'te başarıyla tamamlanıyor, ardından Composer platform uyuşmazlığını bildirmek yerine sessizcev13.0.1'e iniyordu; sonrasındacomposer updatede haklı olarak "nothing to update" diyordu. README ve kurulum kılavuzları artık:^13.6kullanıyor — böylece Composer gerçek sebebi hata olarak veriyor — ve PHP 8.4 tabanını açıkça belirtip beklenmedik bir sürüm çözümlendiğindecomposer why-not lvntr/laravel-starter-kit 13.6.14komutunu gösteriyor. Türkçe README ilesk:upgradekomutunun yönlendirme satırı bu taramada atlanmış ve hâlâ:^13.0yazıyordu; ikisi de artık aynı constraint'i kullanıyor ve Türkçe README İngilizce olanla aynı PHP 8.4 / Node 20.19+ uyarısını taşıyor. - Production CSP'si artık bulut depolamadan gelen önizlemeleri bloklamıyor.
img-srcyalnızca'self' data: blob:kabul ederken kitlocal,s3ve DigitalOcean Spaces disklerini destekliyor ve FileManager tarayıcıya bucket'ın kendi origin'indeki imzalı URL'leri veriyordu; yani uzak bir diskte her önizleme ve frontend'in çektiği her indirme, kitin kendi koyduğu politika tarafından bloklanıyordu.SecurityHeadersartık media-library disk'i ile public disk'in origin'lerini türetiyor (CDN tabanı gibi bir diskurl'i, bir s3endpoint'i ve onun*.hostbucket-subdomain biçimi, ya da düz AWS için region/bucket ikilisi) ve bunlarıimg-src, yenimedia-srcveconnect-srcdirektiflerine ekliyor. Ek origin'ler — örneğin karşılama mesajına gömülen uzak bir görsel — yalnızcahttp(s)origin kabul edenstarter-kit.security.csp_extra_originsanahtarına yazılıyor. Hazır bir CSP taşıyan response'a hâlâ dokunulmuyor velocalortamı hâlâ hiç politika almıyor. sk:doctorlog kontrolleri config cache'li uygulamada gerçek ayarı raporluyor.LogChannelCheckveLogStackCheckdoğrudanenv()okuyordu;config:cacheçalıştıktan sonra.envyüklenmediği için ikisi de uygulamanın gerçekten kullandığı değeri değil kendi varsayılanlarını bildiriyordu — üstelik doctor çalıştırmanın en çok önem taşıdığı dağıtımlarda. Artıklogging.defaultvelogging.channels.stack.channelsokunuyor.LogStackCheckayrıca yalnızca gerçekten aktif olan kanalı yargılıyor:logging.channels.stackkoşulsuz okunduğu içinLOG_CHANNEL=dailykullanan bir uygulama, log kayıtlarının hiç uğramadığı bir stack yüzünden uyarı alıyordu; buna karşılık gerçekten rotasyonsuz olanLOG_CHANNEL=singleOK olarak geçiyordu. Kontrol artıklogging.defaultdeğerini çözüyor, bir stack ise üye kanallarına açıyor ve çözülen kanallardan herhangi birisinglesürücüsünü kullanıyorsa uyarıyor — hatalı kanala gerçekten ulaşan ayarı gösteriyor: aktif kanal framework'ün kendistack'i iseLOG_STACK, başka adlı bir stack iselogging.channels.<ad>.channels, diğer durumlardaLOG_CHANNEL. Bu açılımLogManager::createStackDriver()'ı yaklaşık taklit etmek yerine birebir izliyor: string olarak yazılmış birchannelsdeğeri (LOG_STACK=single,daily) tek bir kanal adı gibi okunmak yerine virgülden bölünüyor ve üyeler özyinelemeli çözülüyor; böylece bir stack daha derinde duransingleartık rotasyonlu sanılmıyor. Döngüsel bir yapılandırma, özyinelemeye girmek yerine çözüm yolunda sonlanıyor.- Cache'lenmiş config artık Inertia SSR'ı sessizce kapatmıyor. Tüketici
config/inertia.phpdosyasını publish etmediğinde service provider her boot'tainertia.ssr.enableddeğerinienv('INERTIA_SSR_ENABLED')ile ayarlıyordu.config:cachebu override'ı.envhâlâ yüklüyken doğru şekilde yakalıyor, ancak aynı kod cache'li her istekte tekrar çalışıpenv()null döndüğü için cache'e yazılmıştruedeğerinifalseile eziyordu. Config cache'liyken bu override artık atlanıyor. Mevcut kurulumlar için not:INERTIA_SSR_ENABLED=trueyazıpconfig:cacheçalıştırmış bir uygulama aslında hâlâ client-side render ediyordu; bu düzeltmeden sonra SSR gerçekten devreye giriyor —php artisan inertia:start-ssrsüreçinin çalıştığından emin olun. Çalışmıyorsa Inertia hata vermek yerine client-side render'a düşer (HttpGateway::dispatch(), bundle yoksa ya da bağlantı başarısızsanulldöner;inertia.ssr.throw_on_erroraçık değilse). - HTTPS asset URL'i artık protokol-relative hâle getirilmiyor.
SettingsControllerveSettingsDefaultsQueryiçindeki mixed-content koruması public disk URL'lerinin şemasını hemhttp://hemhttps://için siliyordu; bu yüzden HTTP üzerinden açılan bir sayfadahttps://olan bir asset HTTP'ye düşüyordu — koddaki "never a downgrade" yorumunun tam tersi. Artık yalnızcahttp://URL'leri yeniden yazılıyor;https://bir URL hiçbir sayfada mixed content olmadığı için olduğu gibi geçiyor.
Güvenlik
- Kitin kendi route'larından yirmi beşi artık ihmal yüzünden izinsiz kalmıyor.
CheckResourcePermissionbir izni route adından türetir; adı olmayan, adı iki segmentten az olan ya da action segmenti middleware'in ability haritasında bulunmayan bir route hiçbir izne çözülmez — daha önce bu, isteğin tamamen sessizce geçmesi anlamına geliyordu. Paketin kendi kaydettiği yirmi beş route bu boşluğa düşüyordu: beşsettings.contentLanguages.*ucu, on beşsettings.update.*/settings.upload.*/settings.delete.*yazma ucu,settings.testMail,roles.syncPermissionsveroles.bulk/users.bulk. Bunlar artık paketin içinde yaşayan bir route-adı sözleşmesiyle bir izne sabitleniyor; dolayısıyla mevcut bir kurulum düzeltmeyi yalnızcacomposer updateile alır —sk:install'in app'inize kopyaladığı route dosyalarına dokunulmaz. Her eşleme davranış-nötr olacak şekilde seçildi: settings route'ları aynı izni zaten açık bircheck.permission:argümanıyla uyguluyordu,roles.syncPermissionsise kendi controller'ında ayrıcasystem_adminile sınırlı.roles.bulkveusers.bulkeşlenmek yerine muaf ilan edildi: gerektirdikleri ability istek gövdesinde adı geçen aksiyona bağlı veBulkActionDispatcherzaten her item'ı handler'ın kendi ability'siyle yetkilendiriyor; dolayısıyla route seviyesinde statik bir eşleme yalnızca fazla-reddedebilirdi (.delete,.updateve.read'in her biri farklı bir meşru rolü kırar).system-health.runda aynı şekilde adıyla muaf tutuldu, çünkü controller'ı zatenGate::authorize('system.health.view')çağırıyor ve route grubusystem_adminile sınırlı. Ayrıca kendi açıkcheck.permission:<izin>argümanını taşıyan bir route, parametresiz grup geçişi tarafından ikinci kez yargılanmıyor artık.
Eklendi
-
sk:doctorbirunresolved-routeskontrolü kazandı. Tüketici tarafından eklenenler dahil,CheckResourcePermission'ın izin türetemediği her route'u listeler — bunlar şu an çözülmüş bir izin yerine loglanmış bir uyarıyla geçen route'ların ta kendisi. Görmek içinphp artisan sk:doctor --only=unresolved-routesçalıştırın; her biri bir<resource>.<action>route adı, açık bircheck.permission:<permission>argümanı ya da yenistarter-kit.permissions.unrestricted_routesconfig anahtarı altında bir listeleme ile düzeltilir. -
starter-kit.permissionsaltında iki yeni config anahtarı.allow_unresolved(envSTARTER_KIT_ALLOW_UNRESOLVED_ROUTES, varsayılantrue), izni hiç türetilemeyen bir route'un loglanmış bir uyarıyla geçmesini mi yoksa reddedilmesini mi kontrol eder; mevcutallow_unmapped'in aksine, değiştirildikten sonra production'da da uygulanmaya devam eder — çünkü çözülemeyen bir route, host'a özgü bir veri boşluğu değil, route/ability-haritası arasındaki yapısal bir uyuşmazlıktır.unrestricted_routesise bilinçli olarak izinsiz kalacakStr::isroute-adı desenlerini listeler; bunlar hem kontrolden hem doctor uyarısından muaftır. -
Yeni bir proje çözülemeyen route'larda fail-closed kuruluyor; mevcut bir projeye dokunulmuyor.
sk:install, oluşturduğu.envdosyasınaSTARTER_KIT_ALLOW_UNRESOLVED_ROUTES=falseyazıyor. Sıfırdan kurulan bir uygulamada geçmişten devralınacak route olmadığı için sıkı başlıyor ve ilk izinsiz route'u production'da değil geliştirme sırasında ortaya çıkıyor. Bu değeri hâlihazırda var olan bir uygulamaya hiçbir şey taşımıyor:ensureEnvFile().env.exampledosyasını yalnızca ilk kurulumda olduğu gibi kopyalıyor ve yeniden-kurulum yolu artık küçük birFIRST_INSTALL_ONLY_ENV_KEYSlistesini atlıyor; yani kurulu bir uygulamadask:install'ı tekrar çalıştırmak da anahtarı eklemiyor.sk:updatevesk:upgradezaten.envdosyasına hiç dokunmuyor. Mevcut bir kurulumun kendiliğinden reddetmeye başlayacağı bir sürüm yok — anahtarı vermeyen her uygulama içinallow_unresolvedvarsayılanıtruekalıyor; mevcut bir uygulama,sk:doctor --only=unresolved-routestemiz çıktığında satırı kendisi yazarak opt-in yapıyor. Sıralı düzeltme yolu için upgrade rehberine bakın.
2026-08-15 — v13.6.14
Güvenlik
- Aktivite kayıtları artık kimlik bilgilerini saklamıyor. Fillable ve unguarded model loglama;
password,remember_token,two_factor_secret,two_factor_recovery_codesile*_tokenveya*_secretson ekli alanları hariç tutar; yalnız parola değişen bir güncelleme artık aktivite satırı oluşturmaz. Aktivite Kaydı arayüzü de eski satırlardaki bu anahtarları maskeler. Yeni geri döndürülemez veri migration'ı ve idempotentsk:redact-activity-secretskomutu bu anahtarları hemattribute_changeshempropertiesalanından recursive olarak kaldırır; migration öncesinde veritabanını yedekleyin ve komutun bildirdiği decode edilemeyen JSON satırlarını elle inceleyin. Modeller deny list'isensitiveLogAttributes()ile genişletebilir. Veri migration'ı paketin içinde (database/migrations/) gelir;composer update+php artisan migrateonusk:updateolmadan taşır ve büyük/küçük harfe duyarlı bir JSON collation'da farklı yazılmış anahtar atlanmasın diye tüm satırları tarar.sk:doctorise kimlik bilgisi taşıyan satır kaldığı sürece FAIL verenactivity-log-secretskontrolünü kazandı; bu kontrol, birincil anahtara göre ilk 500 satır üzerinde çalışan, her sürücüde aynı maliyeti taşıyan sınırlı ve salt-okunur bir sondadır ve kararı SQL'deki anahtar-adı filtresiyle değil PHP'de verir; böylecePasswordgibi yazılmış bir anahtar kolonun collation'ı yüzünden atlanamaz. Mesajları ölçüleni bildirir — büyük tablolarda bulgu bir alt sınır ("en az N") olarak raporlanır, temiz sonuç ise tabloyu aklamak yerine taradığı pencereyi adlandırır; tam sayım hâlâsk:redact-activity-secrets --dry-run --allişidir (--all, SQL tarafındaki anahtar-adı ön filtresini kapatan bayraktır). - Kimlik doğrulama ayarları artık Fortify route'larını kaydetmeden önce fail-closed uygulanıyor. Kayıt, parola sıfırlama ve parolamı-unuttum istekleri ilgili ayar kapalıyken 403 döner. İki faktör challenge'ı, store seviyesinde atomik olan "yoksa ekle" (add-if-absent) cache girdisiyle sahiplenilir; böylece eşzamanlı iki denemeden yalnızca biri token üretebilir —
Cache::pull()sahiplenme gibi görünse de ayrı bir get + forget'tir ve rate limit bu yarışı daraltır, sıraya sokmaz. Recovery code kullanımı ayrıca veritabanı satır kilidiyle korunur. - Kullanıcı kontrollü datatable etiketleri
v-htmlyüzeyine ulaşmadan escape ediliyor. Rol görünen adları, aktivite kaydı causer değerleri ve API client grant type'ları artık markup enjekte edemez. Frontend dependency lock'ları axios 1.19.0, Vite 7.3.6, esbuild 0.28.2, form-data 4.0.6, shell-quote 1.9.0 ve undici 7.29.0 dahil non-breaking güncellemelerle yenilendi; hem production hem tamnpm auditartık 0 güvenlik açığı raporluyor ve frontend CInpm audit --audit-level=high --omit=devkontrolünü zorunlu tutuyor.
Eklendi
sk:doctor,permission-matrixkontrolünü kazandı.config/permission-resources.phpkullanıcıya aittir vesk:updatebu dosyaya asla yazmaz; dolayısıyla paketin sonraki bir sürümde eklediği kaynak ve yetenekler mevcut kuruluma hiç ulaşmaz — bunun ilk belirtisi de genelde daha önce çalışan bir ekranda alınan 403'tür. Kontrol, paketin gönderdiği matris ile uygulamanın yüklü matrisini karşılaştırır, eksik olanları (files.update,files.deletevb.) raporlar vesk:seed-permissionskomutunu işaret eder. Tek yönlüdür: consumer'ın kendi eklediği kaynaklar asla raporlanmaz. Yetenekleri backing value üzerinden karşılaştırır; böylecePermissionEnumcase'i olarak yazılmış bir girdi, string yazılmışla aynı sayılır. Paket tarafındakinull(tüm yetenekler) tanımını, consumer'ın genişletebildiğiPermissionEnumyerine paketin kendi gönderdiği yetenek listesinden açar; uygulama tarafındakinulldeğerini ise her şeyi kapsıyor kabul eder.
Düzeltildi
sk:updateartık consumer'ın genişlettiğiPermissionEnumdosyasını ezmiyor.app/Enums/PermissionEnum.phppaket sahiplidir ve her güncellemede yenilenir; ancak aynı zamanda publicfor()/allFor()yardımcılarına sahip backed bir enum olduğu için ona bir proje yeteneği eklemek (case Approve = 'approve';) yapılacak en doğal şeydir — ve şimdiye kadar bu case, dosya stub'dan sırf farklı olduğu için üzerine kopyalanıyordu: registry kontrolü yok, yedek yok, özet çıktısında tek satır yok. Kopyalama artık, diğer tüm consumer sahipli dosyaların zaten kullandığı kurulum-anı hash'i ile korunuyor: dokunulmadığı kanıtlanabilen dosya yenilenir, düzenlenmiş olan korunur ve birleştirme talimatıyla ayrıca raporlanır, hash kaydı olmayan dosya "dokunulmamış" varsayılmak yerine mevcut etkileşimli seçim ekranına düşer,--forceise yine üzerine yazar.- FileManager istekleri artık alt dizine kurulumlarda çalışıyor.
withBasePath()idempotent hale geldi veuseApi.request()bunu merkezi olarak uyguluyor; eksik veya iki kez eklenmiş base path oluşmuyor. - Dashboard ve
SkDatatable, SSR sırasında artık yalnız tarayıcıda bulunan global değerlere erişmiyor.
Kırılmalar
- FileManager context yetkilendirmesi artık mutasyonları
writealtında birleştirmek yerineread,create,updatevedeletekullanıyor. Built-inglobalcontext bunları birebirfiles.read,files.create,files.updatevefiles.deleteile eşler; bilinmeyen ability'ler fail-closed davranır. Önceden yalnızfiles.createsahibi bir rol silme ve çöpü boşaltma erişimini, yalnızfiles.updatesahibi bir rol ise okuma erişimini kaybeder. Her role gereken belirlifiles.*yetkilerini verin, ardındanphp artisan sk:seed-permissionsçalıştırın. Consumer context closure'ları dört yeni adı işlemeli ve artık hiçbir zamanwritealmayacaktır; yükseltme rehberine bakın. Doğrudan çağıranlar içinauthorizeWrite(),authorizeUpdate()metoduna delege eden deprecated alias olarak kalır. - İki faktörlü kimlik doğrulama kapatıldığında Fortify'nin 2FA route'ları artık kaldırılıyor. Kayıtlı kalmak yerine 404 dönerler.
fortify-options.two-factor-authenticationroute kaydından önce ayarlandığı için 2FA yönetim endpoint'leri artıkpassword.confirmmiddleware'ini de taşır; doğrudan API tüketicileri bu doğrulama round-trip'ini tamamlamalıdır.
2026-08-15 — v13.6.13
Değiştirildi
- Kit artık MIT lisanslı (önceden PolyForm Noncommercial 1.0.0). Ticari kullanım kısıtsız serbest — telif ve izin bildirimi korunduğu sürece kit'i kapalı kaynaklı ve ücretli ürünlerin içinde dağıtabilirsiniz.
- Davranış değişikliği: API Resource tarihleri artık önceden formatlanmış gösterim string'i yerine offset içeren ISO-8601 değerleri yayıyor. Böylece frontend, parse edilebilir tek bir anı kullanıcının çözümlenen saat diliminde tutarlı biçimde formatlayabilir.
format_date()fonksiyonunun kendisi değişmedi; mevcut Blade, e-posta, dışa aktarma ve diğer gösterim çağrılarıyla uyumlu kalır. - Davranış değişikliği: saklama ve gösterim saat dilimleri ayrıldı.
APP_TIMEZONE=UTCdeğerini koruyun;display_timezoneartıkAPP_TIMEZONEyerine yeniAPP_DISPLAY_TIMEZONEdeğişkenini okur. Mevcut kurulumlar değişkeni eklemeli veconfig/app.phpdosyasını güvenli, tekrarlanabilir config rewrite adımıyla güncellemek içinphp artisan sk:upgradeçalıştırmalıdır. Saklama UTC değilsesk:doctor --only=timezone-storagebaşarısızlık raporlar. - MySQL/MariaDB bağlantı oturumları artık UTC'ye sabitleniyor.
sk:installvesk:upgrade, consumer değerlerinin üzerine yazmadan veya diğer sürücülere dokunmadanconfig/database.phpiçindeki mevcutmysql/mariadbdizilerine literal'timezone' => '+00:00'girdileri ekler. Mevcut kurulumlarda uygulama tarafından yazılmış offset'liTIMESTAMPverileri bulunabilir; Saat Dilimleri belgesindeki tek seferlik dönüşüm tamamlanana kadar bu veriler offset'li kalır.DEFAULT CURRENT_TIMESTAMPkolonları zıt yönde hareket eder ve dönüşümün dışında bırakılmalıdır.sk:upgrade, veri içeren UTC dışı oturumu değiştirmeden önce uyarır ve onay ister (--forcebulunmayan etkileşimsiz çalışmalar atlar), ancak satırları hiçbir zaman dönüştürmez.sk:doctor --only=timezone-storageartıkSYSTEMdahil UTC dışı MySQL/MariaDB oturumunu tespit eder; oturum okunamazsa başarılı saymak yerine uyarır. - Kullanıcılar kendi gösterim saat dilimini seçebilir ve datatable tarih filtreleri artık bunu dikkate alır. Boş kullanıcı tercihi “Genel site ayarını takip et” anlamına gelir ve açıkça UTC seçmekten farklıdır. Ortak kullanıcı → site → uygulama → UTC fallback'i backend ve frontend formatlamasında uygulanır; takvim-tarihi filtreleri, indeksli kolonu sarmadan DST-doğru, yarı açık UTC aralıkları kullanır.
2026-07-25 — v13.6.12
Eklendi
- Kit'in AI skill'leri artık Claude Code'un yanı sıra Codex ile de çalışıyor.
sk:installüç skill'i.claude/skills/dizinine yayınlar ve OpenAI Codex CLI'ın native okuduğu.codex/skills/dizinine aynalar. Özelleştirmek için.claudekopyalarını düzenleyin —.codexaynası hersk:install/sk:update'te yeniden üretilir ve o dizindeki kendi skill'lerinize asla dokunmaz.sk:install --without-ai-skilliki ağacı da atlar;sk:update --without-ai-skilltek bir çalışmada aynanın yeniden üretilmesini atlar.
Değiştirildi
- Paketle gelen AI skill'leri güncel kit ile hizalandı (hâlâ v13.6.0 öncesi yapıyı anlatıyorlardı): vendor-first mimari,
sk:ejectve kurulum sırasındaki User/Role eject'i,sk:doctor, tamsk:publishtag listesi,make:sk-domain --with=ekleri, gerçeksk:updateüzerine-yazma kuralları, güncel composable'lar ve FormBuilder alan tipleri, SkForm güvenlik korumaları ve tema sistemi. Skill gövdeleri artık İngilizce (Türkçe tetikleyici anahtar kelimeler korundu) — tek skill seti iki asistana da hizmet ediyor.
2026-07-22 — v13.6.11
Düzeltildi
- Yüklenen dosya artık iki kez görünmüyor, dosya alanı olan formlarda "kaydedilmemiş değişiklikler" uyarısı nihayet kapanıyor. Dosya yükleme alanı olan bir formu kaydettikten sonra, seçtiğiniz dosya sunucuya kaydedilmiş kopyasının yanında formda da duruyordu — aynı görsel iki satır olarak listeleniyordu. Formda kalan bu dosya aynı zamanda formu kalıcı olarak "değişmiş" gösteriyordu; bu yüzden kaç kez kaydederseniz kaydedin kaydedilmemiş-değişiklik banner'ı ve "sayfadan ayrılmak istediğinize emin misiniz?" uyarısı hiç kaybolmuyordu. Kayıt artık yüklenmiş dosya listesini sunucudan tazeleyip seçiciyi temizliyor: tek kopya görüyorsunuz, form temize geçiyor ve az önce yüklediğiniz dosya formu ikinci kez kaydettiğinizde kaybolma riski taşımıyor.
2026-07-21 — v13.6.10
Düzeltildi
- "Kaydedilmemiş değişiklikler" uyarısı artık kayıttan sonra ekranda kalmıyor. Kendi kendine gönderim yapan formlarda kayıt başarıyla tamamlanıyordu ama form kendini hâlâ "değişmiş" sayıyordu — bu yüzden kaydedilmemiş-değişiklik banner'ı görünmeye devam ediyor, sayfayı kapatmak veya sayfadan ayrılmak her şey kaydedilmiş olmasına rağmen onay soruyordu. Kayıt artık formu anında temiz olarak işaretliyor. Kayıt sürerken yazmaya devam ederseniz, o yeni değişiklikler kaydın parçası değildi — form onlar için "kaydedilmemiş" kalmaya devam ediyor, böylece hiçbir şey sessizce kaybolmuyor. Kayıttan sonra kendini temizleyen oluşturma formları eskisi gibi temizlenmeye devam ediyor.
2026-07-08 — v13.6.9
Güvenlik
- Seed'lenmemiş izinler artık yalnız production'da değil, staging/demo'da da reddediliyor.
CheckResourcePermissionmiddleware'i, gerekli izin veritabanında yoksa production dışındaki tüm ortamlarda (staging, uat, demo, testing) isteği geçiriyordu — böylece public bir staging veya demo host'u, izin satırı unutulmuş bir endpoint'i sessizce açığa çıkarabiliyordu. Artıklocaldışındaki her ortamda reddediyor (localgeliştirici kolaylığı için yine uyarıp geçiriyor). Eski davranışı bilinçli olarak production dışı host'larda istiyorsanızSTARTER_KIT_ALLOW_UNMAPPED_PERMISSIONS=trueayarlayın. Bkz. UPGRADE.tr.md. - İzin sorguları artık Octane-güvenli — seed'lenmiş izin listesi tüm worker ömrü boyunca değil, kısa süreli (60sn) cache'leniyor ve hem
php artisan sk:seed-permissionshem de Roller ekranındaki izin senkronu bunu hemen temizliyor; böylece yeni seed'lenen izinler Octane altında anında etkili oluyor.
Değiştirildi
- Datatable kolon görünürlük/sıra tercihleri
sessionStorage'danlocalStorage'a taşındı. BirSkDatatable'da kolon gösterme/gizleme veya sıralama tercihiniz varsa, yükseltme sonrası bu tercih bir kez sıfırlanır — veri kaybı yok, tamamen kozmetik; tercihi yeniden ayarlamanız yeterli.
2026-07-04 — v13.6.8
Kalite ve UX sprint'i
Geniş kapsamlı bir kalite-kontrol turu: audit-log kapsamı, kurulum/yükseltme DX'i, erişilebilirlik ve bir login-throttle güvenlik düzeltmesi. sk:update gerektiren tek publish edilmiş dosya değişikliği var — bkz. UPGRADE.md.
Güvenlik
login_throttle = '0'artık web login rate limiter'ını tamamen devre dışı bırakmıyor — throttle'ı tamamen kaldırmak yerine bilinçli olarak gevşek bir taban limiter'a geçiyor; böylece hiçbir admin ayarı web login'i tamamen limitsiz bırakamaz.
Eklendi
- Audit log artık rol/yetki değişikliklerini, Ayarlar'ı, API Client/Token'ları, paylaşım linklerini ve İçerik Dillerini kapsıyor — bunlar önceden bir log dosyasının dışında görünmüyordu (ya da hiç loglanmıyordu); artık ActivityLog yönetim ekranında görünüyorlar. Ayar değerleri asla loglanmıyor, yalnızca hangi anahtarların değiştiği kaydediliyor.
sk:installbir hatadan sonra devam edebiliyor —php artisan sk:install --resume, yarıda kalmış bir kurulumu tam olarak kaldığı yerden sürdürüyor; başarısız bir adım artık ham stack trace yerine net bir mesaj basıyor. Baştan bir Node.js sürüm kontrolü çalışıyor; eski/eksik Node artık kurulum ortasında kriptik bir çökme yerine uyarı üretiyor.sk:doctorNode.js sürümünü ve bir queue worker'ın fiilen çalışıp çalışmadığını kontrol ediyor, cron heartbeat'i tespit edemediğinde artık sessizce "OK" demiyor. Tekil kontroller artık tüm komutu asılı bırakmak yerine zaman aşımına uğruyor.sk:ejectartık bir domain'i eject etmeden önce onay istiyor (--force/--dry-run/--no-interactionverilmediği sürece) — eject etmek domain'in kit güncellemelerini almayı bırakması demek; artık sessiz, tek yönlü bir kapı değil.- Datatable klavyeyle erişilebilir — sıralanabilir başlıklar, arama-temizle butonu ve filtre-kaldırma butonları artık Tab + Enter/Space ile çalışıyor; boş bir tablo, hiç veri olmadığı için mi yoksa filtrenizin hiçbir sonuç bulamadığı için mi boş olduğunu söylüyor (tek tıkla "filtreleri temizle" ile).
- Formlar daha güvenli — çift gönderim artık imkânsız, kaydedilmemiş değişiklikli bir formdan çıkmak onay istiyor, başarısız bir veri/seçenek yüklemesi sessizce başarısız olmak yerine yeniden deneme seçeneği gösteriyor, zorunlu alanlar screen reader'lara bildiriliyor.
- FileManager, birden çok eşzamanlı yükleme genelinde toplam ilerleme gösteriyor, görsel lightbox'ı da ok tuşlarıyla görseller arası gezinmeyi destekliyor.
Değiştirildi
- CI artık lint hatalarında build'i sadece uyarmak yerine başarısız kılıyor.
--no-interactionkurulumları artık eski sabitpasswordyerine taze, rastgele bir admin parolası alıyor (sonunda ekrana basılır).- Görünür davranış değişikliği olmayan birkaç backend tutarlılık temizliği (merkezi 422 hata maplemesi, paylaşılan definition-controller mantığı, birleştirilmiş definition cache invalidation).
2026-07-03 — v13.6.7
Rich-text editor'daki boş alan artık tıklanabiliyor
Tek hedefli bir CSS düzeltmesi — API veya kurulum değişikliği yok.
Düzeltildi
- Rich-text editor'da son metin satırının altına tıklamak hiçbir şey yapmıyordu —
EditorInput.vueminHeight'ı editor sarmalayıcısına inlinemin-heightolarak veriyordu, ama içteki ProseMirror elemanıheight: 100%kullanıyordu. Yüzde yükseklikler yalnız kesin yüksekliği olan bir ebeveyne karşı çözülür; bu yüzden ProseMirror yalnız kendi içeriği kadar büyüyordu — görsel olarak uzun kutunun geri kalanı gerçekcontenteditablebölgesinin dışında kalıyor, oraya tıklama/yazma yok sayılıyordu. Sarmalayıcı artık flex column, ProseMirror daheight: 100%yerineflex-1kullanıyor; böylece düzenlenebilir alan tüm yapılandırılmış yüksekliği dolduruyor.
2026-06-20 — v13.6.6
Activity log artık UUID ve sayısal subject'leri birlikte kabul ediyor
Tek hedefli bir veritabanı düzeltmesi — API veya kurulum değişikliği yok.
Düzeltildi
sk:seed-permissionsartık uuid cast hatasıyla çökmüyor — activity-log tablosu polimorfiksubject_id/causer_idkolonlarını nativeuuidolarak oluşturuyordu. Ama kit aktiviteyi hemUser(uuid anahtar) hem de SpatiePermission/Rolemodelleri (sayısal/bigint anahtar) üzerinde logluyor; bu yüzden permission seed'iSQLSTATE[HY000] 4078: Cannot cast 'bigint' as 'uuid'hatasıyla başarısız oluyordu. Yeni bir migration her iki id kolonunuchar(36)'ya genişletiyor; bu hem 36 karakterlik uuid'yi hem de herhangi bir sayısal id'yi saklar — tek polimorfik kolon artık her denetlenen modele uyuyor. Migration önceki tüm durumları (native uuid, legacy bigint, legacy char(36))char(36)'ya yakınsıyor; mevcut uygulamalar düzeltmeyi bir sonrakiphp artisan migrate'te alır.
2026-06-14 — v13.6.5
Çeviri bundle'ı artık paketle birlikte geliyor
Paketleme düzeltmesi — API veya kurulum değişikliği yok.
Düzeltildi
- Taze kurulumlar artık ham çeviri anahtarı göstermiyor — önceden derlenmiş kit çeviri bundle'ları (
resources/js/lang/php_{en,tr}.json).gitignore'daydı; bu yüzden hiç Git'e girmiyor ve Composer dist'inde (yalnızca tracked dosyalarıngit archive'ı) bulunmuyordu. Taze kurulan bir uygulama bundle'ları değil yalnızca build script'ini alıyordu; sonuçta tüm kit i18n anahtarları (sk-menu.*,sk-setting.*, …) çevrilmiş etiket yerine ham anahtar olarak render ediliyordu. İki bundle artık tracked ve shipped. Consumer paketi build etmediği için — consumer-build theme bundle'ının aksine — bunlarınvendor/'a ulaşması için commit edilmesi gerekir; build script'in kendi dökümanı zaten "COMMITTED and shipped" diyordu.
2026-06-14 — v13.6.4
Datatable inline filtre dropdown düzeltmesi
Tek hedefli bir düzeltme — API veya kurulum değişikliği yok.
Düzeltildi
- Inline filtre dropdown'u artık kesilmiyor — bir select filtresinin inline pill menüsü tablo kartının içinde
absoluteöğe olarak çiziliyordu; bu yüzden uzun seçenek listesi kart / scroll-containeroverflowkenarında kesiliyordu. Menü artık<body>'ye fixed overlay olarak teleport ediliyor (PrimeVueSelect'inappendToile yaptığının aynısı): trigger'ından konumlanıyor, scroll/resize'da yeniden hizalanıyor,min(60vh, 420px)ile sınırlanıp kendi scroll'una sahip oluyor, dış-tık / Escape ile kapanıyor.panelyerleşimli popover variant'ı değişmedi (zaten PrimeVue'nun overflow-visible portalını kullanıyor).
2026-06-13 — v13.6.3
Admin arayüz rötuşları
Yönetim panelinde bir dizi arayüz iyileştirmesi — API veya kurulum değişikliği yok.
Değiştirildi
- Aura sidebar footer artık bir sürüm pill'i — aura teması sidebar footer'ı tek satırlık pill kart oldu: solda yeşil durum noktası ve uygulama adı, sağ kenara yaslanmış sürüm (monospace). Sol/sağ boşluğu üstündeki nav item kartlarıyla aynı hizada. Yalnızca aura temasına özel;
mainteması footer'ı değişmedi. - Hesap menüsünde normal linklerden dış-bağlantı oku kalktı — üst bar kullanıcı/hesap menüsünde sıradan link öğelerinde (Profilim, Hesap Ayarları, Şifre Değiştir, Yardım, Çıkış) hover'daki
↗oku artık gösterilmiyor. Açılır (alt menü) öğeleri chevron'unu, aktif dil de tik işaretini korur. - Datatable filtre popover'ı yalnızca panel filtreleri için — funnel butonu ve popover'ı yalnızca
panelyerleşimli bir filtre varsa görünüyor;inline()filtreler artık popover içinde tekrarlanmıyor. Aktivite Kayıtları sayfasında üç filtre de (Olay, Model, Tarih) artık toolbar'da inline; bu sayfada funnel/popover tamamen kalktı.
Düzeltildi
sk:install/sk:updatebanner sürüm etiketi — kurulum/güncelleme başlığı artıkv13.6.xyazıyor (bayatv13.5.xidi). Yalnızca kozmetik; geçmişv13.5.0+davranış notları değişmedi.- Datatable
valuemodu tag'leri i18n anahtarını render anında çözüyor —tagLabels()değerleri artık builder kurulurken değil, hücre render edilirken çevriliyor. Builder bir sayfanın<script setup>gövdesinde, i18n bundle yüklenmeden önce kuruluyor; oradaki eagertrans()ham anahtarı donduruyordu (İçerik Dilleri tablosu "Soldan sağa (LTR)" yerinesk-content-languages.directions.ltrgösteriyordu). Düz (anahtar olmayan) etiketler etkilenmez —trans()onları değiştirmeden döndürür. - İçerik Dilleri formu — yersiz zorunlu yıldızları kaldırıldı — FormBuilder alanları varsayılan olarak zorunlu, bu yüzden
flag,fallback_codevesort_order(sunucuda hepsinullable) kırmızı*çiziyordu. Artık.optional()işaretli, validation kurallarıyla uyumlu;code,name,native_name,directionyıldızı korur.
2026-06-13 — v13.6.2
Admin panel layout ve form hizalama düzeltmeleri
main teması için bir dizi görsel düzeltme — API veya kurulum değişikliği yok, yalnızca görsel doğruluk.
Düzeltildi
- Roller formu temel bilgiler 3 kolonlu responsive grid — ad / görünen ad / etiket rengi alanları yan yana dizilir (
FB.form().cols(3)); küçük ekranlarda hep tam genişlik yerine alt alta yığılır. - İzin tablosu kart kenarına yaslı — roller izin matrisi
SkCardflushprop'unu kullanır; satır border'ları body padding'i içinde yüzmek yerine kart kenarına ulaşır (hücreler kendi iç boşluğunu korur). - Translatable alan input'ları komşularıyla hizalı — dil sekmesi pill'leri (
TranslatableInput) düz label'dan yüksekti ve input'u aşağı itiyordu; pill'ler artık düz-label yüksekliğine eşit, böylece grid satırındaki her input aynı hizada başlar. - Sidebar artık satırları ezmiyor — birden çok menü grubu açıkken nav, scroll'a düşmeden çocukları sıkıştırıyordu; doğrudan çocuklar artık
shrink-0, taşma üst üste binmek yerine scroll olur. - Sidebar footer'ı sayfa footer'ıyla hizalı — sidebar footer yüksekliği
h-footer(56px) ile sabitlendi; üst border'ı ekran altındaki sayfa footer border'ıyla aynı hizaya gelir.
Değişti
- Güvenlik ayarları alt sekmesi "Cloudflare Turnstile" → "Bot Protection" — güvenlik alt sekmesi etiketi (EN/TR) ve ilgili
SecurityTabbölümü artık sağlayıcıdan bağımsız adı kullanır.
2026-06-13 — v13.6.1
sk:update bayat bileşen import'larını kendiliğinden onarıyor
Tek hedefli bir düzeltme — API veya kurulum değişikliği yok.
Düzeltildi
sk:updateartık bir bileşen vendor'a taşındıktan sonra bayat import bırakmıyor — bir bileşen stub'lardan@lvntr/components'e taşındığında eski yerel kopyası force-delete ediliyor, ama silinen yerel yolu hâlâ import eden kullanıcı-özelleştirmeli sayfalar dokunulmadan kalıyor ve Vite build'iniENOENTload-fallback hatasıyla kırıyordu (örn.@/components/Auth/TurnstileWidget.vue).sk:updateartık bu tür bayat import specifier'larınıresources/jsgenelinde vendor yoluna (@lvntr/components/ui/TurnstileWidget.vue) yeniden yazıyor; böylece v13.6.0'da başlayan migrasyon, mevcut kullanıcıların özelleştirdiği Auth sayfalarında (Login,Register,ForgotPassword) tamamlanıyor.
2026-06-13 — v13.6.0 (devam)
Vendor-first Faz 2 — Settings-sekmesi controller'ları, Definitions/Media, ContentLanguage
Faz 2, Faz 1'de başlayan vendor-first taşımayı; vendor Settings sekmelerini destekleyen kalan controller'ları artı iki API/Service controller'ını taşıyarak ve ContentLanguage domain'ini tamamen vendorize ederek tamamlıyor. Vue ve migration'lar zaten vendor'daydı — bu yalnızca PHP katmanı taşıması. Sıfır kurulumlar bu dosyaların app kopyasını almaz; mevcut kurulumlar aynı hash guard altında sk:update ile taşınır.
Değişti
- ApiClient, ApiToken, SystemHealth, ContentLanguage, Definitions (Api + Service) ve MediaUpload için vendor-first HTTP katmanı — bu controller'lar (varsa FormRequest / API Resource'larıyla birlikte) artık
Lvntr\StarterKit\Http\...altında yaşıyor ve geriye dönük uyumluluk içinApp\Http\...FQCN'lerine alias'lanıyor. Bir app kopyası alias'ı otomatik olarak devre dışı bırakır; böylece özelleştirmeniz kazanmaya devam eder. Route adları, permission anahtarları ve Passport secret'ının tek-seferlik gösterimi değişmedi. - ContentLanguage domain'i vendorize edildi —
Actions/DTOs/QueriesLvntr\StarterKit\Domain\ContentLanguage\altına taşındı.App\Models\ContentLanguagemodeli app-sahipli kalır (asla alias'lanmaz — policy discovery + route-model binding'i korur); vendor kodu onaApp\FQCN'iyle referans verir.
Eklendi
sk:ejectbeş yeni giriş kazandı —SystemHealth,ContentLanguage,Definitions,MediaUploadve (ApiTokencontroller/request/resource'unu da eject eden) tam-HTTP-katmanlı birApiClient. Eject edilebilir domain sayısı 10'dan 14'e çıkıyor.
Migrasyon
composer update lvntr/laravel-starter-kit && php artisan sk:update çalıştırın. Bkz. docs/UPGRADE.tr.md (v13.5.11 → v13.6.0, "Behavior-module HTTP katmanı vendor'a taşındı — Faz 2").
2026-06-13 — v13.6.0 (devam)
Behavior-module HTTP + Vue katmanları vendor'a taşındı; sk:eject artık Files'ı destekliyor
Beş yerleşik yönetim modülü — Files, Logs, ActivityLogs, ApiRoutes, Settings — artık controller'larını, FormRequest'lerini ve Vue yönetim sayfalarını tamamen vendor paketinden çalıştırıyor. Sıfır kurulumlar bu modüllerin app kopyasını almaz. Mevcut kurulumlar hash guard altında sk:update ile taşınır (değişmemiş kopyalar kaldırılır; değiştirilmiş kopyalar korunur ve raporlanır). Vue migrasyonu ayrıca app.ts'te @lvntr/pages vendor-fallback glob'unu gerektirir.
Eklendi
sk:eject Files— FileManager yönetim Vue sayfalarını (resources/js/pages/Admin/Files/) UI özelleştirmesi için app'inize eject eder. FileManager backend'i (controller, FormRequest'ler, route-registry altyapısı) her zaman vendor-yönetimli kalır; yalnızca Vue katmanı kopyalanır. Geri almak kopyalanan sayfaları siler; vendor kopyasıapp.tsfallback'i üzerinden devam eder.- Logs, ActivityLogs, ApiRoutes, Settings için vendor-first HTTP katmanı — controller'lar ve FormRequest'ler artık
Lvntr\StarterKit\Http\...altında yaşıyor ve geriye dönük uyumluluk içinApp\Http\Controllers\Admin\*'e alias'lanıyor. App'inizdeki birapp/Http/Controllers/Admin/SomeController.phpdosyası alias'ı otomatik olarak devre dışı bırakır; böylece kopyanız kazanmaya devam eder. sk:update'te grup-atomik migrasyon — vendor-first modüller katman bazında (PHP ve Vue bağımsız olarak) taşınır. Bir katmandaki herhangi bir dosya değiştirilmişse, o katmanın tamamı korunur. Hiçbir zaman yarı silinmiş bir modül üretilmez.
Değişti
sk:ejectmanifest'i genişledi —Filesdomain'i eklendi (yalnızca Vue:backend: ''). Komut imzasındaki eject edilebilir domain listesi artıkFiles'ı içeriyor.
Migrasyon
composer update lvntr/laravel-starter-kit && php artisan sk:update && npm run build çalıştırın. Özelleştirilmiş bir modül için sk:update onu korur ve raporlar; tam açık sahiplik almak için sk:eject <Module> çalıştırın. Üç senaryolu rehber için bkz. docs/UPGRADE.tr.md (v13.5.11 → v13.6.0, "Behavior-module HTTP + Vue katmanları vendor'a taşındı").
2026-06-11 — v13.6.0 (devam)
Kurulum anında User + Role domain eject'i
Sıfır kurulumlar artık User ve Role domain runtime'ını otomatik olarak app/Domain/ altına eject eder. Bu iki domain gerçek projelerde en çok özelleştirilen alanlardır; dolayısıyla ek bir adım gerekmeksizin proje sahipli dosyalar olarak gelirler.
Sıfır kurulumda ne değişir
app/Domain/User/veapp/Domain/Role/, backend sınıfları (App\Domain\namespace'iyle yeniden yazılmış Actions, DTOs, Queries, Events, Listeners) ile oluşturulur.DomainServiceProvider, altı audit event içinEvent::listenbinding'lerini alır; aktivite kaydı kesintisiz devam eder.- Sonraki
composer updateçalıştırmalarında bu dizinlere dokunulmaz — dosyalar size aittir.
Devre dışı bırakma
php artisan sk:install --without-eject
Her iki domain vendor'da kalır ve class_alias ile çözülür. sk:eject User / sk:eject Role komutlarını istediğiniz zaman manuel olarak çalıştırabilirsiniz.
Kurulumdan sonra geri alma
app/Domain/User/ ve app/Domain/Role/ dizinlerini silin, app/Providers/DomainServiceProvider.php içinden enjekte edilen Event::listen satırlarını kaldırın ve composer dump-autoload çalıştırın.
Mevcut kurulumlar
Değişiklik yok. Eject adımı yalnızca storage/starter-kit/hashes.json henüz yoksa (ilk kurulumda) çalışır. Mevcut kurulumda registry zaten mevcut olduğundan adım atlanır. Mevcut projeler etkilenmez.
sk:eject'e yeni flag
sk:eject, installer tarafından dahili olarak kullanılan --skip-autoload flag'ini kazandı; bu sayede installer her domain başına composer dump-autoload koşturmaz (tüm eject'ler tamamlandıktan sonra tek bir toplu dump gerçekleştirir). Bu flag normal manuel sk:eject kullanımında gerekmez.
2026-06-06 — v13.6.0
Minor sürüm — Vendor-runtime migrasyonu tamamlandı + yapılandırılmış tema/layout/CSS sistemi
13.6.0, son yayınlanan sürümden (v13.5.11) bu yana yapılan tüm değişiklikleri tek sürümde toplar. "Paket runtime'ı vendor'dan çalışır" migrasyonunu hem backend hem frontend'de tamamlar ve admin-panel layout'unu ve CSS'i yapılandırılmış, override edilebilir bir tema sistemine yeniden düzenler. Görsel değişiklik yok — varsayılan build (VITE_SK_THEME=main) v13.5.11 ile byte-identical'dır. Aşağıdaki bölümler toplanan değişiklikleri alana göre gruplar.
İzin direktif plugin'i vendor'dan çözülüyor
v-can / v-role Vue plugin'i (resources/js/plugins/permission.ts) artık varsayılan olarak vendor paketinden sunuluyor — kit composable'larının zaten kullandığı çözümün aynısı. @/plugins/<name> import'u yerel bir kopya varsa ona, yoksa vendor kopyasına düşer; böylece kit, stub yeniden kopyalamadan direktif düzeltmeleri gönderebilir. Davranış değişikliği yok: direktifler aynı ve app.ts hâlâ @/plugins/permission'ı değişmeden import ediyor.
Değişti
resources/js/plugins/permission.ts— vendor paketine taşındı. Ölü, kullanılmayanuseCan()export'u kaldırıldı (canlı composable@/composables/useCan'dir); dosya artık yalnızcaPermissionPlugin'i (v-can/v-roledirektifleri) içeriyor, auto-import bağımlılığı yok.vite.config.ts—@/composables/*'ı aynalayan yeni@/plugins/*aliascustomResolver'ı (resolvePlugin): önce yerel-override, sonra vendor fallback; düz@alias'ından önce sıralı.tsconfig.json— yeni@/plugins/*path eşlemesi (yerel + vendor).
Eklendi
sk:publish --tag=plugins— izin direktiflerini özelleştirmek için Vue plugin'lerinin yerel, düzenlenebilir bir kopyasını publish eder.
Geçiş
İşlem gerekmez — çözüm otomatik. Mevcut resources/js/plugins/permission.ts'iniz vendor kopyasını gölgelemeye devam eder; vendor sürümünü almak için silin. UPGRADE.md'ye bakın.
Tüm CSS cascade katmanları artık override edilebilir slot
Tema sistemindeki her CSS katmanı artık override edilebilir bir slot'tur. Daha önce fonts.css, _base.scss, _auth.scss ve utilities.css, resolver'ın dışında sabit import'lardı; artık themes/main/ altında yaşıyor ve scripts/sk-theme-build.mjs tarafından tokens, layout/* ve components/* ile birlikte doğru cascade sırasında emit ediliyor. Görsel değişiklik yok — VITE_SK_THEME=main ile varsayılan build v13.5.11 ile byte-identical'dır. Tek fark, custom temanın artık themes/custom/ altına eşleşen bir dosya bırakarak fonts, base reset, auth stilleri ve utility override'ları dahil her katmanı override edebilmesidir.
Değişti
themes/main/fonts.css,themes/main/_base.scss,themes/main/_auth.scss,themes/main/utilities.css—resources/css/theme/kökündenthemes/main/dizinine taşındı. İçerik değişmedi.scripts/sk-theme-build.mjs— HEAD slot'ları (tokens.css,fonts.css,_base.scss) ve TAIL slot'ları (_auth.scss,utilities.css) artıkresolveSlot()üzerinden çözümleniyor (layout/*vecomponents/*için kullanılan override-veya-main fallback ile aynı). Cascade sırası korunur:tokens → fonts → _base → layout/* → components/* → _auth → utilities.theme/theme.css— artık yalnızca@import './_active.css'içeriyor; eski sabit_auth.scssimport'u kaldırıldı.app.css— eski sabitutilities.csstail import'u kaldırıldı;utilities.cssartık resolver'ın emit ettiği son slot'tur.themes/custom/README.md—fonts.css,_base.scss,_auth.scssveutilities.cssdahil tüm override edilebilir slot'ları listeleyecek şekilde güncellendi.
Geçiş
Herhangi bir işlem gerekmez. sk:update güncellenmiş dosyaları iletir. Varsayılan build byte-identical'dır. Daha önce sabit olan bir katmanı override etmek için themes/custom/ altına eşleşen dosyayı bırakın (örn. themes/custom/fonts.css). Bkz. docs/theme.tr.md — Tam slot referansı.
AppShell layout kompozisyonu + build-zamanı tema-override sistemi (themes/main / themes/custom)
Admin panel layout'u ve CSS'i yapılandırılmış, override'a hazır bir sisteme yeniden düzenlendi. Görsel değişiklik yok — varsayılan build önceki yayınlanan sürümle byte-identical'dır. Layout kabuğu, yeniden kullanılabilir bir AppShell.vue (yapısal omurga, sidebar durumu, adlandırılmış bölgeler) ve standart admin bileşenlerini bağlayan ince bir AdminLayout.vue kompozisyonuna bölünür. CSS monoliti (_admin.scss ve dağınık _*.scss partial'ları) ayrı slot dosyalarından oluşan bir themes/main/ dizin ağacına dönüştürülür. Yeni opt-in themes/custom/ dizini ve scripts/sk-theme-build.mjs tema resolver'ı, build zamanında slot bazında override'a olanak tanır: VITE_SK_THEME=custom ayarlayın, themes/custom/components/datatable.css dosyası ekleyin — yalnızca o slot değiştirilir, geri kalanı main'e döner. Tam referans ve özel override reçetesi için bkz. docs/theme.tr.md.
Eklendi
AppShell.vue(resources/js/layouts/AppShell.vue) — yeniden kullanılabilir yapısal layout kabuğu..admin-layout/.admin-main/.admin-contentiskeletini veuseSidebardurumunu sahiplenir (tek sahip). Beş adlandırılmış slot sunar:#sidebar(scoped:collapsed,mobileOpen,isMobile,closeMobile),#header(scoped:collapsed,isMobile,toggle),default,#footer,#overlays.themes/main/CSS ağacı —tokens.css(CSS custom property'leri, aydınlık + karanlık),layout/{shell,sidebar,header,page-header,footer}.css,components/{card,confirm,datatable,dialog,editor,formbuilder,menus,navigation,primevue,tabs,tag,toast}.css. Değerler kaldırılan partial'larla byte-identical'dır.themes/custom/iskeleti — tam-değiştirme + fallback modelini açıklayanREADME.mdile birlikte boş override-tema dizini.scripts/sk-theme-build.mjs— tema resolver'ı.VITE_SK_THEME'yi okur (varsayılanmain); kanonikleri slot listesi içinthemes/main/'i dolaşır; her slot için varsathemes/<aktif>/<slot>, yoksathemes/main/<slot>emit eder;theme/_active.css'i yazar. Override slot'ları çıktıda/* override */ile işaretlenir.devvebuild'e açık&&adımı olarak zincirlenir — npm lifecycle hook kullanılmaz — bu nedenleignore-scripts=truealtında da doğru çalışır.npm run theme:build— resolver için bağımsız script alias'ı (devvebuild'in açık bir adımı olarak da çalışır).VITE_SK_THEME=mainsatır içi dokümantasyonuyla.env.example'a eklendi.- PrimeVue preset resolver —
scripts/vite-plugin-sk-theme.mjsartık@/theme/presetimport'unu build zamanında yakalar;resources/js/theme/themes/<aktif>/preset.tsmevcutsa ona, yoksa tabanresources/js/theme/preset.ts'e çözümler. Taban dosya yerinde kalır — consumer geçiş adımı gerekmez.resources/js/theme/themes/custom/iskeleti boş gelir; varsayılan build önceki sürümle byte-identical'dır. docs/theme.md+docs/theme.tr.md— güncellendi: iki katmanlı genel bakış tablosu (CSS override ve PrimeVue preset), PrimeVue preset katmanı bölümü (dizin düzeni, custom palet reçetesi ve bağımlılık zinciri notu —tokens.css--p-*değişkenlerini okur).
Değişti
AdminLayout.vueince birAppShellkompozisyonuna dönüştürüldü. Dış prop/slot kontratı (title,subtitle,backUrl,default,page-actions) değişmedi — mevcut tüm sayfalar değişiklik gerektirmeden çalışmaya devam eder.theme.cssartık açık bir partial listesi yerine tek bir_active.cssimport eder. Import sırası korunur._base.scssyalnızca base/reset kurallarını barındırır;:root/.darkCSS custom-property bloklarıthemes/main/tokens.css'e taşındı.
Kaldırıldı
_admin.scss—themes/main/layout/*ile değiştirildi._datatable.scss,_formbuilder.scss,_dialog.scss,_toast.scss,_tag.scss,_card.scss,_editor.scss,_tabs.scss,_menus.scss,_navigation.scss,_confirm.scss,_primevue.scss—themes/main/components/*ile değiştirildi.
Düzeltildi
- Tema resolver'ı artık
ignore-scripts=truealtında da çalışıyor — resolver doğrudandevvebuildscript'lerine zincirlendi (node scripts/sk-theme-build.mjs && vite …). Daha öncepredev/prebuildlifecycle hook'ları olarak çalışıyordu; npm bu hook'larıignore-scripts=trueayarlandığında (consumer projelerde ve CI'da yaygın) sessizce atlıyor, bu da_active.css'in oluşturulmamasına ve build'in hard-fail vermesine neden oluyordu.predevveprebuildgirdileri kaldırıldı.
Geçiş
sk:update tüm yeni stub'ları iletir. Taşınan dosyalardan hiçbiri özelleştirilmediyse geçiş adımı gerekmez — npm run build byte-identical panel üretir. Taşınan bir dosyayı özelleştirdiyseniz, değişikliklerinizi ilgili themes/main/ slot'una kopyalayın veya izole bir override için themes/custom/ kullanın. Ayrıntılar için bkz. docs/UPGRADE.tr.md (v13.5.11 → v13.6.0).
Kit composable'ları vendor'dan çalışıyor; local-first resolver; sk:publish --tag=composables
v13.5.12 ile 15 kit composable'ı stub scaffold'undan çıkarılarak vendor kütüphanesine taşındı. Artık doğrudan vendor/lvntr/laravel-starter-kit/resources/js/composables/ üzerinden çalışıyor ve her composer update ile güncelleniyor. Import yolları tamamen değişmedi — @/composables/<name> önce local dosyayı kontrol eder (varsa tüketici dosyası kazanır), yoksa vendor kopyasına döner; bu nedenle hiçbir import ifadesinin değişmesi gerekmez. useAdminMenu ve index.ts, tüketicinin ürettiği route dosyalarına ve projeye özgü menü tanımına bağımlı olduğundan düzenlenebilir stub olarak kalmaya devam eder. TurnstileWidget.vue da aynı sürümde vendor kütüphanesine taşındı (@lvntr/components/ui/TurnstileWidget.vue).
Eklendi
- Vendor'da 15 composable —
useApi,useCan,useConfirm,useDarkMode,useDatatableSelection,useDefinition,useDialog,useFileShare,useFlash,useImageLightbox,useMenuBuilder,usePageLoading,useRefreshBus,useSidebar,useUrlTabpakete dahil edildi.composer updateile güncellenir — elle dosya yönetimi gerekmez. sk:publish --tag=composables— vendor composable'larını özelleştirme içinresources/js/composables/dizinine kopyalar. Local-first resolver local kopyayı otomatik olarak seçer; alias veya build config değişikliği gerekmez.TurnstileWidget.vuevendor'a taşındı — artık@lvntr/components/ui/TurnstileWidget.vueüzerinden kullanılabilir.
Kaldırıldı
- 15 composable stub — scaffold'dan kaldırıldı. Mevcut projeler etkilenmez (local-first resolver local kopyaları kullanmaya devam eder). Vendor tarafından yönetilen güncellemelere geçmek için: özelleştirmediğiniz composable dosyalarını
resources/js/composables/dizininden silin;useAdminMenu.ts,index.tsve düzenlediğiniz dosyaları koruyun.
Backend runtime sınıfları ve üçüncü-parti config'ler vendor'dan çalışıyor
Aynı sürüm, v13.5.0'daki "runtime vendor'dan çalışır" geçişini backend tarafında sürdürür. Bir grup yardımcı sınıf, validation kuralı ve middleware publish edilen scaffold'dan çıkıp vendor paketine taşındı; üç üçüncü-parti config dosyası artık app'inize kopyalanmıyor. Mevcut app'ler etkilenmez — App\… import'ları çözülmeye devam eder (tam taşınanlar için class_alias, geri kalanlar için ince bir App\ shim), ve önceden publish ettiğiniz bir config kazanmayı sürdürür. Tek zorunlu adım composer update'tir. Tam geçiş rehberi için bkz. docs/UPGRADE.tr.md (v13.5.11 → v13.6.0).
Eklendi
- Vendor-resident backend sınıfları —
HtmlSanitizer,TranslatableQueryHelpers,MediaPathGenerator,Scramble\ApiResponseExtensionveAssignTraceId/SetLocale/ValidateTurnstilemiddleware'leri artıkLvntr\StarterKit\*'ten çalışır. App'e stub kopyalanmaz; eskiApp\…import'larıclass_aliasile çözülür.ApiResponseExtensionartık Scramble'a düzgün kaydedilir. - İnce
App\shim'li vendor sınıfları —DatatableQueryBuilder,HttpsOrLocalhostUrlveTurnstileRulevendor'dan çalışırkenApp\…import yolunu korur. HasTranslatableRulestrait'i → vendor (doğrudan import) — artıkLvntr\StarterKit\Support\HasTranslatableRules. Trait'ler alias'lanamadığı için vendor namespace'inden import edin (HasActivityLogging/HasMediaCollectionsile aynı konvansiyon).
Değişti
- Üçüncü-parti config override'ları runtime'da —
config/activitylog.php,config/inertia.phpveconfig/media-library.phpartık publish edilmiyor.StarterKitServiceProvider::applyVendorConfigDefaults()yalnızca kit'in gerekli anahtarlarını (media-librarypath_generator+media_model, activityloginclude_soft_deleted_subjects, inertiassr.enabled) runtime'da uygular ve publish ettiğiniz config'i atlar. Installer artık media-library path generator'ı AST ile enjekte etmez.
Kaldırıldı
- Backend scaffold stub'ları —
app/Support/{HtmlSanitizer,TranslatableQueryHelpers,MediaPathGenerator,HasTranslatableRules}.php,app/Support/Scramble/ApiResponseExtension.php,app/Http/Middleware/{AssignTraceId,SetLocale,ValidateTurnstile}.phpveconfig/{activitylog,inertia,media-library}.phpscaffold'dan kaldırıldı. Yükseltilen app'ler mevcut kopyaları korur (sk:updatebilgilendirme bildirimi gösterir, asla otomatik silmez).HasTranslatableRulestrait'i için yerel kopyayı silmeden önceuseimport'larını vendor namespace'ine çevirin.
2026-06-04 — v13.5.11
Yama sürüm — Monolit skill kaldırıldı, yerine bağımsız 3-skill seti eklendi
v13.5.11 ile 723 satırlık monolit skill dosyası (stubs/.claude/skills/lvntr-starter-kit/SKILL.md) kaldırıldı ve yerine stubs/.claude/skills/ altında dağıtılan üç odaklı, kendi kendine yeten skill geldi. Yeni skill'ler ek bir araç gerektirmeden çalışır ve starter-kit projesinin üç ana alanını kapsar: çekirdek kurallar, backend/DDD ve frontend builder kalıpları.
sk:install komutuna --without-ai-skill flag'i eklendi; bu flag ile skill dosyalarının host uygulamaya yayımlanması atlanabilir.
Eklendi
stubs/.claude/skills/lvntr-starter-kit/— çekirdek skill: zorunlu kurallar, reçete pointer'ları, permissions/i18n yapılandırması, alan arasıreferences/bağlantıları.stubs/.claude/skills/lvntr-kit-domain/— backend / DDD skill: Action, Service, FormRequest, Resource, Repository kuralları ve domain sınır rehberi.stubs/.claude/skills/lvntr-kit-frontend/— frontend skill: FormBuilder / DatatableBuilder / TabBuilder kalıpları, composable'lar (useApi,useDialog,useForm) ve starter-kit bileşen kuralları.sk:install --without-ai-skill— opt-out flag'i; skill dosyalarının host uygulamaya yayımlanmasını atlar.
Kaldırıldı
stubs/.claude/skills/lvntr-starter-kit/SKILL.md— 723 satırlık monolit skill kaldırıldı. Bu dosyayı daha önce host uygulamanıza yayımladıysanızvendor:publishkomutunu tekrar çalıştırmadan önce.claude/skills/lvntr-starter-kit/SKILL.mddosyasını silin.
2026-05-30 — v13.5.10
Yama sürüm — SkCard primitive, card başlığı sağ slot ve caption alt çizgisi
v13.5.10 ile PrimeVue Card'ı sarmalayan paylaşımlı bir wrapper olan SkCard eklendi; kit'in tüm card yüzeyleri için tek doğru kaynak. Aynı sürümde tüketiciye iki yeni slot açılıyor: SkForm'un root card'ında #title-end ve her FB.section() card'ında per-section #section-${key}-title-end. İkisi de başlığın sağına, aynı satırda render olur — action button, durum badge'i veya kontekste duyarlı gösterge için. Section slot'u scoped'tur ve { values } (mevcut form değerlerinin reaktif snapshot'ı) verir; tüketici koşullu render yapabilir. SkCard'ın kendi API'si: title, subtitle, transparent, divider ve pt prop'ları + header/title/subtitle/content/footer/title-end slot'ları; inheritAttrs: false + useAttrs kombinasyonu sayesinde dış class fallthrough'u Card root'una düşer (PrimeVue Card kendi root'unda inheritAttrs: false yaptığı için aksi halde class kaybolur). SkForm.vue ve SkFormFieldRenderer.vue <Card> yerine <SkCard> kullanacak şekilde refactor edildi — cardPt/transparentCard/sectionCardPt helper'ları kaldırıldı, title flex wrapper ve caption alt çizgi stilleri _formbuilder.scss'ten _card.scss'e taşındı (.sk-card--divider .p-card-caption). Artık SkCard ile sarmalanan herhangi bir tüketici aynı caption davranışını alır: başlık metni solda, #title-end sağda, alt başlık altta, caption bloğunun altına ayırıcı çizgi.
Eklendi
SkCardUI primitive —resources/js/components/Lvntr-Starter-Kit/ui/SkCard.vue.SkForm(ve gelecekteSkDatatable/ sayfa düzeyi card'lar) tarafından kullanılması amaçlanan, PrimeVue Card etrafındaki paylaşımlı wrapper. Caption davranışı,#title-endslot'u ve alt çizgi tek implementasyondan geliyor.- Props:
title?: string,subtitle?: string,transparent?: boolean(varsayılanfalse—truearka plan/shadow/padding'i kaldırır; dialog veya nested card için),divider?: boolean(varsayılantrue— caption bloğunun altına alt çizgi),pt?: Record<string, any>(PrimeVue Card pt'sine merge edilir; consumer key'leri çakışmada kazanır). - Slot'lar:
header,title,subtitle,content(default slot da content'e map'lenir),footer,title-end(sağa hizalı action/badge/durum slot'u). inheritAttrs: false+useAttrsile dışclassfallthrough'u Card root'una geçer (PrimeVue Card kendi root'undainheritAttrs: falseyaptığı için aksi halde class düşmüyordu).index.ts'tenSkCardolarak export edildi.
- Props:
SkForm.vue—#title-endslot — form-level card başlığının sağına render edilen yeni slot. Başlık metniyle aynı satırda action button, badge veya durum göstergesi yerleştirmek için kullanılır. Slot yalnızca içerik verildiğinde render edilir.SkFormFieldRenderer.vue— per-section#section-${key}-title-endslot — her section card başlığının sağına render edilen scoped slot.SkForm.vuezaten genericv-for $slotsforwarding yaptığı için tüketici doğrudan<SkForm>üzerinden<template #section-address-title-end="{ values }">şeklinde kullanır. Slot scope:{ values }— mevcut form değerlerinin reaktif snapshot'ı, koşullu render için kullanışlı.- Docs —
docs/ui-components.mdvedocs/ui-components.tr.md'ye yeni "SkCard" bölümü;docs/formbuilder.mdvedocs/formbuilder.tr.md'ye "Card Title Actions Slot" / "Card Başlık Sağ Slot" bölümü. BaseFieldConfig.colSpan?: number— field'ın (ya da section içindeki field'ın) form grid'inde kaç sütun kaplayacağını belirtir (1..cols). Belirtilmezse mevcut davranış geçerli (1 hücre).colsdeğerini aşan değerler otomatik clamp'lenir; section içinde clamp,sectionCols'u referans alır.BaseFieldBuilder.colSpan(n: number)— her field builder'ına zincirlenebilir.colSpan(n)eklendi. Örnek:FB.inputText().key('baslik').label('Başlık').colSpan(12).SkColorSelector— 5 nötr Tailwind ailesi — tüm 50–950 shade'leriyleslate,gray,zinc,neutral,stoneeklendi (Tailwind v4 resmi hex değerleri). Toplam palette: 22 aile.stubs/components.d.ts—SkCardexport tipi eklendi.
Değiştirildi
SkForm.vue— root<Card>→<SkCard>refactor — kendi içindekicardPtcomputed'i vetransparentCardstyle sabiti kaldırıldı;:transparent="isTransparentCard"prop'u ile SkCard'a devredildi. Form card'ının başlık ve alt başlığı:title/:subtitleprop'larıyla geçirilir; flex title wrapper ve caption alt çizgisi SkCard içinde tek noktadan üretilir.SkFormFieldRenderer.vue— section render'ı<SkCard>'a geçirildi —sectionCardPtyerinesectionIsTransparenthelper'ı +:transparentprop'u kullanılır. Section title flex wrapper vetitle-endslot'u SkCard'a delege edildi; icon'lu title (SkIcon+ metin) doğrudan SkCard'ın#titleslot'unda render edilir.RenderCtx(SkFormFieldRenderer.vue) —transparentCardalanı kaldırıldı — SkCard'ıntransparentprop'u tek doğru kaynak; ctx üzerinde dolaşan style sabiti gerek bırakmıyor.stubs/resources/css/theme/_card.scss— SkCard stilleri eklendi:.sk-card__title-row(flex w-full justify-between, başlık satırı).sk-card__title-text(başlık metni, ikon hizalama için inline-flex).sk-card__title-end(sağ slot kapsayıcısı, shrink-0).sk-card--divider .p-card-caption— caption bloğunun altınapb-3 mb-1 border-b+--p-surface-200/--p-surface-700dark varyant. Yalnız SkCard içinde tetiklenir, diğer PrimeVue Card kullanımlarını etkilemez.
stubs/resources/css/theme/_formbuilder.scss— bu çalışmanın ilk turunda eklenen geçici selektörler (.sk-fb__card*,.sk-fb__section-title-wrapper,.sk-fb__section-title-end,.sk-fb__card .p-card-caption,.sk-fb__section .p-card-caption) kaldırıldı. Yerine_card.scss'e işaret eden kısa bir not eklendi.SkForm.vue—colsClassMap1–12'ye genişletildi — 7–12 aralığı artık default grid'e düşmüyor;cols(7)–cols(12)doğrudanmd:grid-cols-Nuygular.SkForm.vue+SkFormFieldRenderer.vue—colSpanClassMap— purge-safe statik map eklendi; üst seviye ve section içi field wrapper'larıcolSpandeğerine göremd:col-span-Nalır.colSpanbelirtilmemiş field'lar öncekiyle birebir render edilir (regression yok).
2026-05-21 — v13.5.9
Yama sürüm — SkIcon primitive, section/card gruplama ve icon API'leri
v13.5.9 ile SkIcon eklendi: tek icon: string prop'tan üç formatı otomatik algılayan paket-bağımsız bir icon renderer. Ham SVG → v-html, URL → <img>, diğer → <i :class> (PrimeIcons, FontAwesome, MDI, Lucide, Iconify ve diğer class tabanlı icon set'leri). BaseFieldConfig'e eklenen birleşik icon API tüm field tiplerine yayıldı: labelIcon / labelIconPosition her layout'ta label yanına icon koyuyor, icon / iconPosition input içine koyuyor (input-text, input-number, input-mask, password destekli). Başlık field'larına da kendi icon / iconPosition çifti eklendi. Öne çıkan özellik ise SectionFieldConfig (type: 'section') ve FB.section() fluent builder'ı — field'lar artık başlık, alt başlık, ikon ve ayarlanabilir kolon sayısıyla bir PrimeVue Card içinde görsel olarak gruplandırılabiliyor; form payload'ı flat kalmaya devam ediyor (section key'leri hiçbir zaman emit edilmiyor). SkForm.vue'ya iterateAllFields generator destekli flatFields computed eklendi; bu sayede section'lar tüm mevcut field işleme mantığı için (dosya upload, tarih dönüşümleri, definition preload, dynamic select) şeffaf. SkFormFieldRenderer.vue ayrıştırılarak recursive render ve slot forwarding bu bileşene taşındı. InputTextFieldConfig.icon / iconPosition artık deprecated; BaseFieldConfig seviyesindeki API kullanılmalı.
Eklendi
SkIconUI primitive — paket-bağımsız icon renderer. Tekicon: stringprop'tan otomatik algılama:<svg…→ ham SVG (v-html),^(https?:|data:)→<img>, diğer →<i :class>(PrimeIcons, FontAwesome, MDI, Lucide, Iconify ve diğer class tabanlı icon set'ler). Güvenlik:iconyalnızca builder config'ten (geliştirici kontrollü) geçirilmeli — kullanıcı kaynaklı string XSS riskidir (<svg…path'iv-htmlile render eder).BaseFieldConfigicon alanları — tüm field tipleri için ortak icon API'si:labelIcon?: string+labelIconPosition?: 'left' | 'right'(varsayılan:'left') — tüm layout path'lerinde label yanına icon.icon?: string+iconPosition?: 'left' | 'right'(varsayılan:'left') — input içine icon. Desteklenen tipler:input-text,input-number,input-mask,password(custom path —feedback: trueise icon yok).groupPrefix/groupSuffixönceliklidir; varsa input icon devre dışı kalır.
TitleFieldConfigicon alanları —icon?: string+iconPosition?: 'left' | 'right'. Örnek:FB.title('Genel').icon('pi pi-info-circle').SectionFieldConfig(yeni field tipitype: 'section') — form içinde Card ile görsel field gruplama:title?(translation key, label fallback),subtitle?,icon?,iconPosition?cols?: number(varsayılan: parent formuncolsdeğeri)fields: FieldConfig[](tek seviye nested — iç içe section desteklenmez)isCard?: boolean(varsayılan: card görünür;false→ şeffaf Card)- Form veri yapısı flat kalır — section'ın
key'i payload'a girmez; section yalnızca görsel gruplama primitive'idir.
SectionBuilderveFB.section(title?)factory — fluent API:.title(t),.subtitle(s),.icon(str),.iconPosition(p),.cols(c),.isCard(enabled),.addFields(...).BaseFieldBuilderfluent metotları —.labelIcon(str),.labelIconPosition(p),.icon(str),.iconPosition(p)artık tüm field builder'larında mevcut (InputTextBuilder'dan base'e taşındı — imza aynı, davranış değişmedi).TitleBuilder.icon()ve.iconPosition()metotları eklendi.SkFormFieldRenderer.vue— ayrıştırılmış recursive field renderer. Section render, slot forwarding ve label/title icon render bu bileşene taşındı;SkForm.vuetemplate'i basitleşti.- Docs —
docs/formbuilder.mdvedocs/formbuilder.tr.md'ye 5 yeni bölüm: İkonlar (Paket-Bağımsız), Label İkonları, Input İkonları, Başlık İkonları, Section / Card Gruplama. XSS güvenlik notu her iki dilde mevcut.
Değiştirildi
AppDialog.vue—confirmSeverityartık varsayılan'primary'kullanmıyor —state.footer?.severity ?? 'primary'→state.footer?.severity. Onay düğmesi artıkseveritybelirtilmediğinde PrimeVue Button'ın kendi varsayılan görünümünü kullanır (tema preset'inden gelir).DialogFooter.severityaçıkça set edilmemiş mevcut dialog'lar görsel değişiklik yaşayabilir.useDialog.ts—DialogFooterSeveritytipi genişletildi —'primary'kaldırıldı (PrimeVue Button'da geçerli değil);'info','help','contrast'eklendi. Tam liste:'secondary' | 'success' | 'info' | 'warn' | 'help' | 'danger' | 'contrast'.SkForm.vue— flat field iterasyonu —derivedDefaults,currentValues,definitionKeys,dynamicSelectFields,hasFileFields,dateOnlyFieldscomputed'leri artık yeniflatFieldscomputed'i (iteratifiterateAllFieldsgenerator) üzerinden çalışıyor. Section içindeki field'lar otomatik olarak doğru kategorize ediliyor (dosya upload existingMediaKey çözümü, tarih dönüşümleri, definition preload, dynamic optionsUrl fetch). Section içermeyen mevcut formlar birebir aynı render ediliyor (regression yok).SkFormInput.vue— generic input icon — daha önce yalnızcainput-text'te aktif olanIconFieldwrapping pattern'i artıkinput-number,input-maskvepasswordiçin de (custom path) aktif. Icon descriptor'larSkIconüzerinden render ediliyor; PrimeIcons dışında MDI/FA/Lucide/Iconify/SVG/img URL de çalışıyor.BaseFieldConfig.iconönceliklidir,InputTextFieldConfig.iconlegacy fallback olarak korunur.stubs/resources/css/theme/_formbuilder.scss—.sk-fb__titleve.sk-fb__labelselector'larına icon hizalaması için minimalinline-flex items-center gapeklendi (line-height ve padding değişmedi). Yeni bölümler:SKICON & LABEL/TITLE ICONS(.sk-icon,.sk-icon--svg svg,.sk-icon--img,.sk-fb__label-icon,.sk-fb__title-icon,.sk-fb__section-icon+--left/--rightmodifier hook'ları),SECTION CARD(.sk-fb__section,.sk-fb__section-title,.sk-fb__section-field).
Deprecated
InputTextFieldConfig.iconveInputTextFieldConfig.iconPosition— yeniBaseFieldConfig.iconveBaseFieldConfig.iconPositionkullanın. Legacy alanlar geriye uyumluluk için korundu (SkFormInput.vuebase ?? legacyfallback ile aynı render üretiyor), gelecek major versiyonda kaldırılacak.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# stubs/resources/css/theme/_formbuilder.scss
# stubs/resources/js/composables/useDialog.ts ← DialogFooterSeverity tipi değişti
php artisan vendor:publish --tag=starter-kit-stubs --force
DialogFooterSeverity breaking change: 'primary' artık geçerli bir değer değil. useDialog().open(...) çağrılarında severity: 'primary' kullandıysanız kaldırın (Button kendi tema varsayılanını uygular) ya da 'secondary' / 'contrast' gibi geçerli bir değerle değiştirin. TypeScript bu satırları zaten hata olarak işaretleyecektir.
Migration: legacy InputTextFieldConfig.icon çağrılarınız çalışmaya devam eder (deprecated, kaldırılana kadar fallback). Yeni özellikleri kullanmak için:
// Label icon — her field tipinde
FB.inputText().key('email').label('E-posta').labelIcon('pi pi-envelope')
// Input icon — input-text/number/mask/password
FB.inputText().key('search').icon('pi pi-search') // PrimeIcons
FB.inputText().key('user').icon('mdi mdi-account') // Material Design Icons
FB.inputText().key('star').icon('fa fa-star').iconPosition('right') // FontAwesome
FB.inputText().key('logo').icon('https://cdn.example.com/icon.svg') // URL
// Başlık icon'u
FB.title('Genel Bilgiler').icon('pi pi-info-circle')
// Section / Card gruplama
FB.form()
.isCard(false)
.addFields(
FB.section('Kişisel Bilgiler').icon('pi pi-user').cols(2).addFields(
FB.inputText().key('first_name').label('Ad'),
FB.inputText().key('last_name').label('Soyad'),
),
FB.section('Adres').icon('pi pi-map-marker').addFields(/* ... */),
)
.build();
2026-05-20 — v13.5.8
Yama sürüm — AppDialog Material Flat shell, zengin header & footer API, scrollbar-gap düzeltmesi
AppDialog, PrimeVue Dialog'un #container template'i etrafında bağımsız bir "Material Flat" shell olarak yeniden tasarlandı: header'da gradient ikon lozenge + başlık + alt başlık, opsiyonel slate-100 sticky footer (solda hint ikon/metin, sağda İptal/Onay butonları), daha yumuşak iki katmanlı drop shadow ve özel "rise" enter/leave animasyonu. Shell tamamen sk-dlg PT class'ı ile scope'lanmış durumda; ConfirmDialog ve diğer Dialog kullanımları etkilenmiyor. useDialog composable'ı subtitle, icon ve footer open option'ları, yeni DialogFooter interface'i ve setFooter() / patchFooter() metotları ile genişletildi — dialog içinde render olan bileşenler artık footer'ı (örneğin onay butonunu loading state'e geçirme) dialog'u yeniden açmadan değiştirebiliyor. v13.5.7'den kalan son sticky-bar sorunu — form scroll ettiğinde gri footer'ın sağında kalan ~10 px beyaz boşluk — dialog body'sinin scrollbar'ını görsel olarak gizleyerek çözüldü; scroll hâlâ wheel / trackpad / klavye ile çalışıyor, slate-100 bar artık dialog'un sağ kenarına temiz biçimde dayanıyor.
Eklendi
AppDialogMaterial Flat shell — header artık ikon lozenge (state.icon), başlık (state.header) ve alt başlık (state.subtitle) basıyor; PrimeVue'nun default close butonu yerine slate temalı bir close butonu kondu. Opt-in footer slate-100 sticky action bar üretiyor (hint ikon/metin + İptal/Onay).useDialogzengin header & footer API —OpenOptions.subtitle,OpenOptions.icon,OpenOptions.footereklendi. YeniDialogFootertipi:icon,text,cancelLabel,confirmLabel,confirmIcon,severity,onConfirm,hideCancel,disabled,loading. YenisetFooter()vepatchFooter()metotları eklendi._dialog.scss—theme.css'ten import edilen yeni stylesheet. Shell parçalarını (mask, root, head/lead/title-block, body, foot/info/actions) tanımlıyor vesk-dlgPT class'ı ile scope'lanmış durumda.
Değiştirildi
preset.tsmodal token —borderRadius.xl→borderRadius.md(6 px),padding: 1.25rem→padding: 0(shell-level padding artıkAppDialogiçinde), drop shadow daha yumuşak iki katmanlı versiyona güncellendi (0 24px 60px -20px ...,0 6px 20px -6px ...).
Düzeltildi
- Form scrollbar boşluğu (footer'ın sağında) —
AppDialogiçindeki uzun formlarda slate-100 action bar'ın sağ kenarı ile dialog'un sağ kenarı arasında ~10 px beyaz boşluk kalıyordu (body'nin scrollbar'ı içerik genişliğini yiyordu, bar'ın-mx-8uzatması yalnızca body'nin content kenarına dayanıyordu)..sk-dlg__body:has(.sk-fb--dialog)artık scrollbar'ı görsel olarak gizliyor (scrollbar-width: none+::-webkit-scrollbar { width: 0 }); scroll wheel / trackpad / yön tuşları / Page Up–Down / Home–End ile çalışmaya devam ediyor.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# stubs/resources/css/theme/{_dialog.scss,_formbuilder.scss,theme.css}
# stubs/resources/js/composables/useDialog.ts
# stubs/resources/js/theme/preset.ts
php artisan vendor:publish --tag=starter-kit-stubs --force
Davranış notu: Form dialog'ları içinde Dialog body'sinin scrollbar'ı bilinçli olarak görünmez. Görünür track gizlendi ki slate-100 action bar dialog kenarına boşluksuz dayansın; scroll wheel, trackpad, yön tuşları, Page Up/Down, Home/End ile çalışmaya devam ediyor.
2026-05-19 — v13.5.7
Yama sürüm — Dialog sticky bar sızıntısı düzeltildi, AvatarUpload yenilendi, 14px root tipografi
AppDialog içindeki form sticky action bar'ı (Cancel / Update), uzun formlarda alttan akan içeriği gizleyemiyordu — temel sorun, PrimeVue Dialog content'inin default padding: 1.25rem değerinin sticky barın altında transparan bir boşluk bırakmasıydı. Dialog content padding-bottom PT API ile sıfırlandı, SkForm artık dialog mode'da sk-fb--dialog marker class ekliyor ve _formbuilder.scss sticky barı dialog kenarına yapıştırıp rounded-b-xl ile alt köşelerini Dialog'un yuvarlatmasına eşliyor. AvatarUpload dikey kart düzeninden tek satır row layout'a (avatar · başlık/hint · butonlar) geçirildi; 56px küçültülmüş avatar, primary border vurgusu ve yeni initials prop'u eklendi. title ve subtitle prop'larının davranışı netleştirildi: verilmezse default i18n, dolu string → o metin, boş string '' → satır tamamen gizlenir (eski geçici davranış yeniden bozmadan eski API uyumu sağlanıyor). Tipografi 14px root tabanlı rem sistemine geri çevrildi (kullanıcı tarayıcı font-size ayarları ve a11y zoom orantılı çalışıyor); önceki geçici mutlak-px override'ı kaldırıldı. Profil dikey sekmelerine description metni ve sekme başına ikon rengi eklendi.
Eklendi
- Profil sekmeleri —
Profile/Index.vueartık her tab içindescription()veiconColor()çağırıyor;sk-profile.tab_descriptions.{general,password,security,sessions}i18n key'leri tanıtıldı (TR/EN). AvatarUpload :initials—avatarUrlyokken avatar kutusunda kullanıcının baş harflerini gösterir; verilmezse mevcutpi-userfallback'i korunur.
Değiştirildi
AvatarUploadrow layout — avatarsize-14boyutuna küçültüldü, primary-200 border + primary-50 zemin, "Kaldır"severity-secondary text, "Değiştir"outlined. Başlık ve hint inline basılır;:title=""ve/veya:subtitle=""ile başlık bloğu komple gizlenebilir.AvatarUploadtitle/subtitlesemantiği —undefined→ default i18n key, dolu string → birebir metin,''→ elementv-ifile gizli. Etiketleri tamamen kapatma yetkisi geri geldi.sk-avatar.hint— metni teknik formata güncellendi:"JPG · PNG · GIF — en fazla 2 MB · 512×512 önerilir"(EN:"JPG · PNG · GIF — max 2 MB · 512×512 recommended").- Tipografi (14px root, rem) —
_base.scssartıkhtml { font-size: 0.875rem }ile root'u 14px'e sabitliyor (browser default 16px'ten ölçeklenir);utilities.csstüm--text-*token'larını bu root'a göre rem cinsinden tanımlıyor (--text-base: 1rem,--text-xs: 0.857remvb.). Geçici mutlak-px override'ı kaldırıldı, a11y zoom yine orantılı çalışıyor. - FileManager metin dengeleme — favoriler/çöp boş durum başlık/altyazıları ve dosya tipi filtre pill'leri
text-lg→text-base.sk-user-menu__itemisetext-sm→text-baseile büyütüldü, yeni base ile hizalandı.
Düzeltildi
- Sticky action bar sızıntısı (
AppDialog/SkForm) — Dialog içindeki uzun formlar, sticky alt barın altından scroll içeriği akıtıyordu. Çözüm üç parçalı:AppDialog.vue— DialogcontentPT'sinepadding-bottom: 0+ flex column layoutSkForm.vue— dialog mode'dask-fb--dialogmarker class_formbuilder.scss—.sk-fb__actionsopakvar(--p-content-background)zemin; dialog mode'da-mx-5 px-5ile edge-to-edge, alt köşelerrounded-b-xlile Dialog'unborderRadius.xl'sine eşitlendi.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# stubs/resources/css/theme/{_base.scss,utilities.css,_formbuilder.scss,_tabs.scss,_menus.scss}
# stubs/resources/js/pages/Profile/Index.vue
# stubs/resources/js/pages/Profile/components/ProfileInfoTab.vue
# stubs/lang/{tr,en}/{sk-avatar.php,sk-profile.php}
php artisan vendor:publish --tag=starter-kit-stubs --force
AvatarUpload davranış notu: Eğer kodunuzda :subtitle="" geçip default hint'in yine de basılmasını bekliyorduysanız, artık '' hint satırını gizler. Default i18n davranışını geri getirmek için prop'u tamamen kaldırın veya dolu bir string verin.
2026-05-10 — v13.5.6
Yama sürüm — SystemHealthTab'dan axios kaldırıldı, API envelope uyumu, FileManager tip düzeltmesi
SystemHealthController, zorunlu to_api() yardımcısı yerine response()->json() kullanıyordu; bu, useApi composable'ının parse edemediği standart dışı bir JSON gövdesi (success envelope yok) üretiyordu. Düzeltildi. SystemHealthTab.vue, tüm API çağrılarının useApi composable üzerinden yapılması gerektiği SK kuralını ihlal ederek doğrudan axios import edip çağırıyordu; useApi({ toast: false }) ile değiştirildi. FileManager.vue'daki TypeScript hatası giderildi: busy tipi BusyState | null ve vue-tsc, event handler içinde v-if üzerinden daraltma yapamıyor; çift isteğe bağlı zincirleme busy?.onCancel?.() her iki null durumunu çözüyor.
Düzeltmeler
SystemHealthController@run—response()->json()→to_api([...], $message)ile değiştirildi; return tipiApiResponse|RedirectResponseolarak güncellendi. Ham JSON yanıtı,useApi'nin beklediği standart{ success, data, message }envelope'unu atlıyordu ve frontend'de parse hatasına neden oluyordu.SystemHealthTab.vue—import axios from 'axios'kaldırıldı;useApi({ toast: false })composable eklendi.axios.post<...>(url)→api.post<...>(url)ile değiştirildi. Axios'u doğrudan kullanmak SK kuralını ihlal ediyor; tüm API çağrılarıuseApiüzerinden yapılmalı.FileManager.vue—@click="busy.onCancel"→@click="() => busy?.onCancel?.()"olarak düzeltildi.busytipiBusyState | null,onCanceltipi(() => void) | null; vue-tsc event handler içindev-ifüzerinden hiçbirini daraltamıyor; çift isteğe bağlı zincirleme gerekli.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# SystemHealthController.php, SystemHealthTab.vue
php artisan vendor:publish --tag=starter-kit-stubs --force
2026-05-07 — v13.5.5
Yama sürüm — System Health Settings'e taşındı, paylaşım iptali UUID düzeltmesi, kurulum güvenilirliği
System Health artık bağımsız bir admin sayfası değil; içeriği SystemHealthTab.vue içinde PrimeVue Card ile sarılmış bir Settings sekmesi olarak sunuluyor. Admin kenar menüsü girişi kaldırıldı. Bir migration hatası düzeltildi: file_manager_share_revocations tablosundaki revoked_by_user_id kolonu unsignedBigInteger olarak tanımlanmıştı ancak users tablosu UUID primary key kullanıyor; kolon artık doğru şekilde uuid olarak beyan ediliyor. InstallCommand'a composer dump-autoload çalışmadan önce app/Helpers/custom.php dosyasını otomatik oluşturan bir guard eklendi; bu dosyanın yokluğu temiz kurulumda her artisan çağrısını kırıyordu. ApiClientsManageTab ve ApiTokensManageTab stub'ları el yapımı <header> bloklarını DatatableBuilder kart API'si (isCard, cardTitle, cardSubtitle, create()) lehine bıraktı. SkDatatable kart başlığı artık doğru body padding'ine sahip; başlık ve altyazı standart Card body ritmiyle hizalanıyor.
Değişiklikler
- System Health Settings sekmesine taşındı.
/admin/system-healthbağımsız sayfası, bir Settings sekmesiyle değiştirildi.useAdminMenu.ts'teki kenar menüsü girişi vesystem-healthroute import'u kaldırıldı.SystemHealthTab.vueartık PrimeVueCardiçinde title, subtitle ve content slot'larıyla sarılı; yenile butonu#titleslot'unasize="small"ile yerleştirildi. SystemHealthController@run—back()kullanımına geri döndürüldü. v13.5.4'te eklenenredirect()->route('admin.system-health.index'), System Health artık Settings sayfasının içinde olduğu için anlamsız hale geldi.ApiClientsManageTab.vue/ApiTokensManageTab.vue— özel<header>bloğu ve bağımsızButtonimport'u, tablo builder üzerindekiisCard(true).cardTitle(...).cardSubtitle(...)ile değiştirildi; create actiontableBuilder.create({ label, onClick })ile kaydediliyor, tam kart düzeni artıkDatatableBuildertarafından yönetiliyor.
Düzeltmeler
file_manager_share_revocationsmigration —revoked_by_user_idkolonu,userstablosundaki UUID primary key ile uyumlu olması içinunsignedBigInteger'danuuid'e değiştirildi. v13.5.3'ten yükseltiyorsanız aşağıdaki migration notuna bakın.ShareRevocationmodeli —$revoked_by_user_idPHPDoc tipiint|null'danstring|null'a düzeltildi.InstallCommand—app/Helpers/custom.phpyoksacomposer dump-autoload'dan önce otomatik oluşturuluyor (minimal<?phpstub). Bu dosyanın yokluğu temiz kurulumda sonraki her artisan çağrısını kırıyordu.DatabaseTestCase— bellek içifile_manager_share_revocationsşeması, düzeltilen migration ile uyumlu olması içinrevoked_by_user_idalanındauuidkullanacak şekilde güncellendi.
UI
SkDatatable—isCardmodundacaptionPT slot'u artıkpadding: var(--p-card-body-padding) var(--p-card-body-padding) 0alıyor; başlık ve altyazı standart Card body hizalamasına oturuyor, tablo araç çubuğu ve içerik tam genişlikte kalmaya devam ediyor.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# useAdminMenu.ts, SystemHealthController.php, SystemHealthTab.vue,
# ApiClientsManageTab.vue, ApiTokensManageTab.vue
php artisan vendor:publish --tag=starter-kit-stubs --force
Migration notu — file_manager_share_revocations tablosunu v13.5.3'te yayınladıysanız kolon tipini düzeltmek için yeni bir migration çalıştırın:
Schema::table('file_manager_share_revocations', function (Blueprint $table) {
$table->dropForeign(['revoked_by_user_id']);
$table->dropColumn('revoked_by_user_id');
$table->uuid('revoked_by_user_id')->nullable()->after('revoked_at');
$table->foreign('revoked_by_user_id')->references('id')->on('users')->nullOnDelete();
});
Bu sürümde yeni izin, config anahtarı veya davranış değişikliği bulunmuyor.
2026-05-07 — v13.5.4
Yama sürüm — v13.5.3 sonrası stub düzeltmeleri, tip uyumlulukları ve CI pipeline iyileştirmeleri
Bu yama sürüm, v13.5.3 sonrası ortaya çıkan stub regresyonlarını gideriyor: AdminHeader'da role yazım hatası, eksik System Health menü item'ı, SettingsDefaultsQuery'de storage_usage payload eksikliği, SystemHealthController'da yanlış redirect hedefi ve Logs sayfalarındaki trans() count tipi sorunları. TabBuilder rose icon rengini kazandı (System Health sekmesinin derlenmesi için gerekli). CI pipeline'ı yeniden sıralandı: auto-imports.d.ts ve components.d.ts artık typecheck'ten önce üretiliyor; vite.config.ts'e PHP olmayan ortamlar (Wayfinder) ve Vitest çalıştırması (laravel-vite-plugin HMR kontrolü) için yeni guard'lar eklendi. Yeni izin, migration veya config anahtarı yok.
Eklenenler
- TabBuilder —
roseicon rengi.TabIconColorartıkrose'u kabul ediyor;_tabs.scss'e karşılık gelen--p-rose-*light/dark kuralları eklendi. Settings'teki System Health sekmesi bunu kullanıyor.
Düzeltmeler
AdminHeader.vue—page.props.auth?.role(singular, var olmayan)roles?.[0]'a düzeltildi; shared page-proproles: string[]shape'iyle uyumlu.useAdminMenu.ts— eksikimport systemHealth from '@/routes/system-health've System Health menü item'ı (permission: 'system.health.view') eklendi. v13.5.3 sayfasına yalnızca URL üzerinden erişilebiliyordu.SettingsDefaultsQuery.php—storage_usage(used_bytes,quota_bytes) payload'ıResolvesMediaModeltrait'i (computeStorageUsed()/storageQuotaBytes()) üzerinden eklendi. v13.5.2'de gelenStorageQuotaCard'ı besliyor.SystemHealthController@run—back()yerineredirect()->route('admin.system-health.index')(POST → güvenli GET).Admin/Logs/{Index,Show}.vue—trans()/$t()countparametreleriString(...)ile sarmalandı;laravel-vue-i18nv2.8 strict tipi number değer kabul etmiyordu.tsconfig.json—@lvntr/components/*path mapping Vite alias'ıyla hizalandı;@lvntr/components/FormBuilder/coregibi yollar artık vue-tsc altında çözümleniyor.env.d.ts—window.turnstileiçin tipli global Window genişletmesi ve@/routes/*wildcard module declaration (wayfinder dosyaları henüz üretilmediğinde fallback) eklendi.
Build / CI
vite.config.ts—isWayfinderAvailable()artisanyoksa wayfinder plugin'ini atlar (CI / paket reposu);isVitestguard'ıvitest runsırasındalaravel-vite-pluginveinertia()'yı atlar (CI'da "Vite HMR server" startup hatası giderildi).- GitHub Actions Node job yeniden sıralandı —
npm ci→ vendor symlink → route stub generation → build → typecheck → lint (continue-on-error) → test. Build artıkauto-imports.d.tsvecomponents.d.ts'i vue-tsc çalışmadan önce üretiyor. scripts/ci/generate-route-stubs.mjs— node-only CI fallback'i; 16@/routes/*modülü için minimal stub dosyaları yazar. Çıktı dizini gitignore'lı; host app'lerde wayfinder gerçek dosyaları üretmeye devam ediyor.- Doctor testleri — kasıtlı olarak İngilizce kalan check mesajları için beklentiler güncellendi.
.gitignore— wayfinder routes dizini, CI vendor symlink ve Vite build artifact'ları (stubs/public/build/,stubs/bootstrap/ssr/) eklendi.
Yükseltme
composer update lvntr/laravel-starter-kit
# Etkilenen stub'ları yeniden yayınla (DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın)
# AdminHeader.vue, useAdminMenu.ts, SystemHealthController.php, SettingsDefaultsQuery.php,
# Logs/{Index,Show}.vue, env.d.ts, tsconfig.json, vite.config.ts
php artisan vendor:publish --tag=starter-kit-stubs --force
# Yeni rose tab color CSS'ini içeren tema dosyalarını yayınla
php artisan vendor:publish --tag=starter-kit-theme --force
npm run build
Özelleştirilmiş bir tsconfig.json kullanıyorsanız @lvntr/components/* mapping'ini elle ekleyin (@lvntr/*'dan önce gelmeli):
"paths": {
"@/*": ["resources/js/*"],
"@lvntr/components/*": [
"vendor/lvntr/laravel-starter-kit/resources/js/components/Lvntr-Starter-Kit/*"
],
"@lvntr/*": ["vendor/lvntr/laravel-starter-kit/resources/js/*"]
}
Yeni izin, migration veya config anahtarı yok.
2026-05-06 — v13.5.3
Sürüm — sk:doctor, System Health, Signed Share Link, Bulk Action API, API Client Admin UI, güvenlik güncellemeleri ve hata düzeltmeleri
Bu sürüm sk:doctor sağlık kontrol komutunu ve System Health admin sayfasını, HMAC imzalı dosya paylaşım bağlantılarını, DatatableBuilder için cross-page Bulk Action API'sini, Domain Generator v2 opt-in flag'lerini ve tam Passport API Client & Token admin arayüzünü ekliyor. Güvenlik bağımlılık güncellemeleri, iç içe klasör silme için event-dispatch düzeltmeleri, bulk controller'lar için Inertia flash response düzeltmeleri ve UUID/ULID bulk-action ID desteği de bu sürüme dahildir. Mevcut uygulamalar aşağıdaki yükseltme adımlarını uygulamalı.
Eklenenler
sk:doctorartisan komutu — 12 kontrol noktasını kapsayan sistem sağlık denetimi: PHP extension'ları, veritabanı bağlantısı, Redis, Passport anahtarları, storage symlink, yazılabilir dizinler, queue driver, schedule çalışması, mail driver, npm build artifact'ları, config cache, FileManager disk bağlantısı.--jsonile makine okunabilir çıktı;--only=database,redis,...ile seçili kontroller çalıştırılabilir. Exit kodları:0OK,1WARN,2FAIL.- Admin Panel — System Health sayfası (
/admin/system-health) —sk:doctorçıktısını UI'da görselleştirir; kontrol başına durum rozeti ve manuel yenile butonu. Erişim izni:system.health.view. - File Manager — Signed Share Link — HMAC imzalı genel erişim URL'leri.
POST /file-manager/shareile TTL belirterek paylaşım oluşturulur;POST /file-manager/share/revokeile iptal edilir;GET /file-manager/share/{media}?expires&signatureile doğrulama yapılır. Config anahtarları:file-manager.share.enabled,default_ttl_hours(varsayılan 24),max_ttl_hours(varsayılan 720),allow_revoke. Token iptalifile_manager_share_revocationstablosunda(media_id, signed_token_hash)composite unique index ile yönetilir. Yeni izinler:share-media,revoke-share-media. - DatatableBuilder — Bulk Action API —
BulkActioninterface veBulkActionDispatcherile sayfa sınırını aşan toplu işlem desteği.SkDatatable,select_all_filteredmodunu (filtre snapshot ile) ve cross-page seçimi destekler. Request payload:{action, ids, select_all_filtered, filter_snapshot}; response:{processed, skipped, failed, message}. Stub örnekleri:BulkDeleteUserAction(rank-aware) veBulkDeleteRoleAction(sistem rollerine karşı koruma). - Domain Generator v2 (
make:sk-domain) — opt-in flag'ler —--with-policy,--with-factory,--with-seeder,--with-test,--with-relationstek tek ya da--with=policy,factory,testtoplu syntax ile kullanılabilir.--relations="belongsTo:User,hasMany:Comment,morphTo:commentable"ile ilişki scaffold'ı otomatik üretilir. Flag'siz çağrım v13.5.x davranışını korur (geriye dönük uyumlu). - API Client & Token Admin UI — Passport authorization_code ve client_credentials grant'leri ile Personal Access Token yönetimi için admin arayüzü (
/admin/api-clients,/admin/api-tokens). Client secret ve PAT plaintext yalnızca oluşturma response'unda bir kez gösterilir (Cache-Control: no-store);OneTimeSecretModaldismiss edilemez. Yeni izinler:api-clients.create,api-clients.read,api-clients.update,api-clients.delete,api-tokens.create,api-tokens.read,api-tokens.delete. Yeni validation rule:HttpsOrLocalhostUrl(RFC 8252 §8.3 — yalnızca HTTPS, localhost istisnası ile HTTP). - CI Workflow (GitHub Actions) — PHP test (
pest), lint (pint), Node 22 build/typecheck/lint job'ları. Aynı branch/PR'da eş zamanlı çalışan job'larconcurrency: cancel-in-progressile iptal edilir. composer test(vendor/bin/pest tests/Feature) vecomposer lint(vendor/bin/pint --test) script'leri katkıda bulunanlar için eklendi.
Düzeltmeler
DeleteFolderAction— alt klasörler, Eloquent model event'lerini atlayan query-builderforceDelete()çağrısıyla kalıcı siliniyordu.FileFoldermodelindekiforceDeletedgözlemcisi (favori kayıtlarını temizlemekten sorumlu) alt klasörler için hiç tetiklenmiyordu; bu dafile_favoritestablosunda sahipsiz kayıtlar bırakıyordu. Model bazlı iterasyona geçildi, artık herforceDeletedevent'i doğru şekilde tetikleniyor.sk:update—node_modules/stubs taramasından filtrelendi.NEVER_UPDATE_PATHSsabitinenode_modules/eklendi;isNeverUpdate()kontrolüupdateModifiableFiles,addNewFiles,migrateHashRegistryveupdateHashRegistrydöngülerinin tamamına uygulandı. Sembolik link (path repository) ortamındastubs/node_modules/varlığı aday dosya listesine sızıyordu.sk:doctorvesk:updateconsole çıktısı İngilizceye çevrildi.DoctorCommand,UpdateCommandve 12DoctorChecksınıfındaki tüm kullanıcıya gösterilen mesajlar, ipuçları ve tablo başlıkları İngilizce; PHP kod yorumları değiştirilmedi.- Bulk action controller'lar — Inertia flash response.
UserBulkControllerveRoleBulkControllerartıkApiResponse(JSON) yerineback()->with('success'/'error', ...)döndürüyor. Önceki JSON response Inertia'nınonSuccess/onErrorakışını kırıyor, ham JSON'u ekrana basıyordu; başarı/hata mesajları artıkHandleInertiaRequestsflash paylaşımı üzerindenSkFlash/useFlashbileşenine ulaşıyor. - Bulk action validasyonu — UUID/ULID/integer ID desteği.
BulkActionRequest::rules()güncellendi:ids.*kuralıinteger'danstring|min:1|max:64'e değiştirildi;prepareForValidation()tüm ID'leri string'e cast ediyor. ÖncekiintegerkuralıHasUuidskullanan modellerde (User, FileBucket, FileFolder vb.) "The ids.0 field must be an integer" hatasına yol açıyordu. Yeni kural integer auto-increment, UUID (36 karakter) ve ULID (26 karakter) primary key'leri tek payload şemasında destekler.
Güvenlik
dedoc/scramble^0.13'ten^0.13.22'ye yükseltildi — v0.13.22'de giderilen RCE sınıfı advisory (GHSA) için.phpseclib/phpseclib3.0.51'den3.0.52'ye güncellendi —laravel/passportüzerinden gelen yüksek önem dereceli DoS advisory için.- Signed Share Link — cross-media token hijack koruması.
(media_id, signed_token_hash)composite unique index, bir token'ın farklı media kayıtlarında geçerli sayılmasını engeller. - Personal Access Token — privilege escalation guard.
user_idbody alanı kabul edilmez; token her zaman kimliği doğrulanmış kullanıcı için mint edilir. - Passport client
confidentialzorunluluğu. API Client UI üzerinden yalnızcaconfidential=trueclient oluşturulabilir; authorization_code grant için min:1 redirect URI ve HTTPS zorunlu. Mevcut DB kayıtları etkilenmez.
Değişiklikler
StarterKitServiceProvider— Passport scope veGate::beforekayıtları tek kaynak haline getirildi;AppServiceProviderstub'ından duplicate kayıtlar kaldırıldı.
Yükseltme
composer update lvntr/laravel-starter-kit
# Yeni migration'ları yayınla ve çalıştır
php artisan vendor:publish --tag=starter-kit-migrations
php artisan migrate
# Yeni share.* anahtarlarını içeren file-manager config'ini yayınla
php artisan vendor:publish --tag=starter-kit-config --force
# Yeni admin sayfa ve controller stub'larını yayınla
# DİKKAT: özelleştirilmiş stub'lar override edilir — önce diff alın
php artisan vendor:publish --tag=starter-kit-stubs --force
# Yeni izinleri ekle ve permission cache'ini temizle
php artisan db:seed --class=PermissionResourcesSeeder
php artisan permission:cache-reset
Yeni izinler: system.health.view, share-media, revoke-share-media, api-clients.create, api-clients.read, api-clients.update, api-clients.delete, api-tokens.create, api-tokens.read, api-tokens.delete.
Davranış değişiklikleri:
confidential=falseile authorization_code Passport client'ları UI üzerinden artık oluşturulamaz. Mevcut DB kayıtları etkilenmez.- Personal Access Token mint:
user_idbody alanı kaldırıldı; admin başka kullanıcı adına PAT oluşturmak istiyorsa artisan komutu veya özel action kullanılmalıdır. AppServiceProviderstub'ında duplicate Passport scope /Gate::beforebloğu varsa silinmeli;StarterKitServiceProviderüzerinden çalışmaya devam eder.
2026-05-06 — v13.5.2
Yama sürüm — Ayarlar güvenlik sekmesi birleştirmesi, FileManager geri yükleme düzeltmesi ve i18n iyileştirmeleri
Ayarlar paneli Kimlik Doğrulama ve Turnstile sekmelerini tek Güvenlik sekmesinde birleştirdi; disk kullanımını görselleştiren bir Depolama Kotası kartı eklendi. File Manager çöp kutusu geri yükleme hatası giderildi: çöp kutusu artık yalnızca kök seviyedeki silinmiş öğeleri gösteriyor, böylece tekil ve toplu geri yükleme işlemleri "parent in trash" hatasıyla karşılaşmıyor. Tüm File Manager bileşenlerindeki metin boyutları text-lg (14 px) olarak standardize edildi, onay diyalogları trans() üzerinden çevrildi ve filtre pill etiketleri i18n'e geçirildi. Mevcut uygulamalar composer update lvntr/laravel-starter-kit && php artisan sk:update && npm run build çalıştırmalı.
Added
SecurityTab.vueKimlik doğrulama ve Cloudflare Turnstile ayarlarını tek sekmede birleştirir; kaldırılanAuthTab.vueveTurnstileTab.vuestub'larının yerini alır.StorageQuotaCard.vueAyarlar panelinde disk-genel depolama kotası kullanımını progress bar ile gösterir.SettingsDefaultsQueryartık Inertia payload'ındastorage_usage(used_bytes,quota_bytes) döndürür.- i18n key'leri eklendi —
sk-setting(güvenlik/depolama bölüm etiketleri),sk-file-manager(filtre pill etiketleri:all,image,video,pdf,audio,archive) vesk-common(onay diyalog string'leri). config('file-manager.settings.enable_trash')— FileManager genelinde soft-delete vs hard-delete davranışını kontrol eden yeni config key'i.true(varsayılan) silinen dosya ve klasörleri Çöp Kutusu'na gönderir;falseanında kalıcı olarak siler.DeleteFileActionveDeleteFolderActionsilme anında bu config'i okur. Değer Inertia üzerinden otomatik paylaşılır (fileManagerSettings.enable_trash); Vue bileşeni:enable-trashprop'u verilmediğinde config değerine geri döner. Prop yine de instance bazında override için geçilebilir.
Fixed
- Çöp kutusu geri yükleme hatası.
TrashContentsQueryartık yalnızca kök seviyedeki silinmiş öğeleri döndürüyor. Üst klasörü de çöp kutusunda olan öğeler bağımsız öğe olarak listeleniyordu ve tekil/toplu geri yüklemede "Cannot restore: the parent folder is also in trash" hatasına yol açıyordu. Kök filtresiyle geri yükleme işlemleri her zaman ağacın tepesinden başlar.
Changed
- FileManager minimum metin boyutu
text-lg(14 px) olarakFileManager.vue,FileGrid.vue,FileManagerSidebar.vueveFileManagerStats.vuegenelinde standardize edildi. useConfirmcomposable — onay diyalog string'leri yenisk-commonçeviri key'lerini kullanantrans()çağrılarına taşındı.Admin/Files/Index.vuesadeleştirildi — gereksiz sarıcı<div>kaldırıldı.- File Manager sekmesi — Video/Audio yükleme toggle'ları artık görsel açıdan Images ile aynı checkbox-grid tasarımını kullanıyor.
Removed
AuthTab.vueveTurnstileTab.vuestub'ları — içerikSecurityTab.vue'a taşındı.sk:update,DEPRECATED_PATHSüzerinden otomatik temizler.
Upgrade
composer update lvntr/laravel-starter-kit
php artisan sk:update
npm run build
2026-05-05 — v13.5.1
Yama sürüm — NPM exports düzeltmesi, sk:publish iyileştirmeleri, depolama kotası ve yükleme validasyonu
NPM paketi main ve exports path'leri gerçek dosya yapısıyla eşleştirildi. sk:publish bireysel tag'leri artık doğru çalışıyor. Admin Settings > File Manager panelinden GB cinsinden depolama kotası ayarlanabilir; kota aşıldığında yükleme istekleri yerelleştirilmiş hata ile 422 döndürür. Mevcut uygulamalar composer update lvntr/laravel-starter-kit && php artisan sk:update && npm install && npm run build çalıştırmalı.
Fixed
- NPM paketi
mainveexportspath'leri artık gerçek dosya yapısını yansıtıyor (resources/js/components/Lvntr-Starter-Kit/...). FileManager export'u eklendi. sk:publishbireysel tag'leri (form,datatable,tabs,skeleton,ui) eski yapıya göre kırık source path'lere sahipti;Lvntr-Starter-Kit/segment'i ile düzeltildi.vendor:publish --tag=starter-kit-componentsiç içe path bug'ı giderildi. Önceki:resources/js/components/Lvntr-Starter-Kit/Lvntr-Starter-Kit/.... Şimdi: doğrudanresources/js/components/Lvntr-Starter-Kit/.vendor:publish --tag=starter-kit-file-manager-componentsartık aktif. Source path eski dizin adına işaret ediyordu (file-manager); gerçek dizin yapısıyla (Lvntr-Starter-Kit/FileManager) hizalandı.index.tsbarrel'da eksik 9 component export eklendi:EditorInput,EditorImagePicker,EditorColorPalette,TranslatableInput,ImageLightbox,FilePreviewModal,ToggleFeatureCard,MimePickerField,SkTag.
Added
sk:publish --tag=filemanager— FileManager UI'ını ayrıca yayınlamak için yeni tag.sk:install --without-ai-skill— Claude Code skill bundle kullanmayan consumer'lar içinstubs/.claude/skills/yayınını atla..gitattributes— Composer arşivi artıktests/,docs/,.github/,plan-docs/,package-audit-notes/vb. geliştirme dosyalarını dışlıyor; arşiv boyutu küçüldü..npmignore— NPM paketi__tests__/,*.spec.*,*.test.*dosyalarını dışlıyor (root ve alt dizinler; npm 11 davranışıyla uyumlu).- Disk-genel depolama kotası (
storage_quota_gb). Admin Settings > File Manager panelinden GB cinsinden tek kota değeri tanımlanır (varsayılan 10 GB). Tüm context'leri (user,global, özel morph map girişleri) ve çöp kutusunu (withTrashed) kapsar. - Upload kota validasyonu.
UploadFileRequest::withValidator()kota kontrolü ekler; kota aşıldığında HTTP 422 ve yerelleştirilmişerrors.quota_exceededmesajı döner.
Removed
- Stub'dan duplike vendor-owned domain command'ları silindi:
EnvSyncCommand,MakeDomainCommand,RemoveDomainCommand. Vendor'dan tek kaynak olarak çalışmaya devam eder.sk:updatemevcut consumer projelerdeDEPRECATED_PATHSile otomatik temizler. App\Http\Responses\ApiResponse.phpstub'ı silindi.StarterKitServiceProvideralias guard'ı (App\Http\Responses\ApiResponse→Lvntr\StarterKit\Http\Responses\ApiResponse) consumer dosyası silindikten sonra otomatik devreye girer; mevcutuse App\Http\Responses\ApiResponse;import'ları değişmeden çalışır.Lvntr\StarterKit\Enums\PermissionEnumvendor'dan silindi. Resmi konumApp\Enums\PermissionEnum(stubs altında). Vendor'da referans yoktu (grep onayladı). Kodunuz doğrudan bu namespace'i import ediyorsaApp\Enums\PermissionEnum'a güncelleyin.
Changed
sk:publishprimary publish komutu olarak konumlandırıldı. Granular interactive flow ve namespace rewrite desteği.vendor:publish --tag=starter-kit-*BC için korunur;sk:publishartık install ve komut dokümantasyonunda öne çıkar.ResolvesMediaModel::computeStorageUsed()imzası değişti (internal trait). Parametre almaz hale geldi;Media::withTrashed()->sum('size')ile disk-genel toplam döndürür. Önceki davranışmodel_type+model_idfiltreli per-context hesaplamaydı. Bu trait'i extend edipcomputeStorageUsed($context)çağırıyorsanız parametreyi kaldırın.FolderContentsQuery,FavoritesContentsQuery,TrashContentsQuery—stats.storage_quotaalanı byte cinsinden eklendi.FileManager.vue—STORAGE_QUOTA_BYTEShardcoded sabiti kaldırıldı;quotaBytescomputed değeristats.storage_quota'dan okunuyor. Kota sıfır veya tanımsızsa sidebarv-if="quotaBytes > 0"ile gizlenir.
Upgrade
composer update lvntr/laravel-starter-kit
php artisan sk:update
sk:update çıktısında "Removed" listesinde 4 path görünecek — bu beklenen davranış.
2026-05-05 — v13.5.0
Major sürüm — Vendor-first runtime ve frontend UI lib taşıması
Starter kit runtime tamamen vendor'a taşındı. FileManager backend, paylaşılan base sınıflar, trait'ler, helper'lar, middleware'ler, ApiResponse ve route loader artık vendor/lvntr/laravel-starter-kit/src/ altında Lvntr\StarterKit\ namespace'iyle çalışıyor. Frontend bileşen kütüphanesi (DatatableBuilder, FormBuilder, TabBuilder, FileManager, Skeleton, ui) de artık paketin canonical konumunda, app tarafı vendor symlink üzerinden tüketiyor. Mevcut uygulamalar yalnızca composer update çalıştırmalı; hiçbir dosya değişmez, rota adı kırılmaz, php artisan migrate "Nothing to migrate" döner. Frontend geçişi tamamen isteğe bağlıdır. Yükseltme talimatları: UPGRADE.md.
Changed
- Vendor-first yapıya geçildi. Paket runtime artık stub akışından değil, doğrudan
vendor/altından çalışıyor.sk:installiskelet dosyalarını (auth, layout, user/rol/ayar domain, config) publish eder; FileManager ve Shared katmanlarınıapp/dizinine kopyalamaz. sk:updatebasitleştirildi. Vendor runtime için kopyalama yapmıyor;composer updateyeterli. Hash takipli stub'lar (auth/layout/user/rol/ayar) için mevcut davranış korundu.- Frontend UI lib taşındı.
resources/js/components/Lvntr-Starter-Kit/{DatatableBuilder,FormBuilder,TabBuilder,FileManager,Skeleton,ui,index.ts}artık paketin canonical konumudur. App tarafı vendor symlink üzerinden tüketir. stubs/vite.config.tsalias güncellendi. Yeni install için@lvntr/componentsalias'ıvendor/lvntr/laravel-starter-kit/resources/js/components/Lvntr-Starter-Kitpath'ini kullanır;preserveSymlinks: true;Components({ dirs })array'inde vendor path mevcut.FileManagerActionabstract base +ResolvesMediaModeltrait.media-library.media_modelconfig'i üzerinden Media model resolve eder. App-specificApp\Models\Mediaoverrider'ları (örn. SoftDeletes ile) backward compatible çalışır.Http/Requests/FileManager/UploadFileRequest. Protected method'lar — app tarafında override edilebilir (Setting entegrasyonu vb.).
Added
src/Domain/FileManager/— Actions, DTOs, Queries, Services, SupportLvntr\StarterKit\Domain\FileManager\namespace'iyle vendor'da.src/Domain/Shared/— BaseAction, BaseDTO, ActionPipeline, PipeableActionLvntr\StarterKit\Domain\Shared\namespace'iyle vendor'da.src/Traits/— HasActivityLogging, HasMediaCollectionsLvntr\StarterKit\Traits\namespace'iyle vendor'da.src/sk-helpers.php—to_api(),definition(),definitionLabel(),sk_locale_keys(),sk_default_locale(),format_date()fonksiyonlarıfunction_existsguard'larıyla vendor'da.src/Http/Responses/ApiResponse.php—{success, status, message, data, errors?}envelope formatı korunarak vendor'a taşındı.src/Http/Middleware/— CheckResourcePermission, SecurityHeadersLvntr\StarterKit\Http\Middleware\namespace'iyle vendor'da.src/Http/Controllers/FileManagerController.phpvesrc/Http/Requests/FileManager/*— vendor'da.src/Console/Commands/PurgeFileManagerTrashCommand.php—file-manager:purge-trashsignature AYNEN korundu.src/Exceptions/— ApiException, ApiExceptionHandler vendor'da.src/Facades/FileManager.php—FileManager::routes()ile tek satır route mount.src/routes/file-manager.php— 19 route, isimler AYNEN. Consumer'ın kendi route dosyası varsa vendor mount edilmez.database/migrations/— 3 FileManager migration, dosya adı ve içerik AYNEN korundu.config/file-manager.php—models.*vesettings.*key'leri eklendi.
Deprecated
sk:sync(PackageSyncCommand). Composer path symlink workflow'unda gereksiz hale geldi.--forceile escape hatch korunur.
Upgrade
Güncelleme sonrası yeterli:
composer update lvntr/laravel-starter-kit
php artisan migrate
Mevcut app/Domain/FileManager/, app/Domain/Shared/, app/Traits/, app/Helpers/sk-helpers.php gibi dosyalar yerinde kalır ve çalışmaya devam eder. Bu dosyaları vendor versiyonuyla değiştirmek tamamen isteğe bağlıdır. Frontend cleanup (Vite alias'ını vendor path'e yönlendirme ve app tarafındaki kopyayı silme) da opt-in'dir. Her iki rehber için bkz. UPGRADE.md.
2026-05-04 — v13.4.10
Minor sürüm — Çevrilebilir FormBuilder alanları ve Sample Contents referans modülü
FormBuilder artık çok dilli metin alanlarını kutudan çıktığı gibi destekliyor. Üç yeni builder — FB.translatableText(), FB.translatableTextarea() ve FB.translatableEditor() — aktif her dil için ayrı input render eder ve Spatie Translatable modelleriyle uyumlu JSON locale map'i submit eder. Bu sürüm ayrıca validation, datatable arama/sıralama ve resource çıktısı için backend helper'ları ve tüm pattern'i uçtan uca gösteren Sample Contents modülünü ekler. Mevcut uygulamalar composer update lvntr/laravel-starter-kit && php artisan sk:update && php artisan migrate && npm install && npm run build çalıştırmalı.
Added
- Çevrilebilir FormBuilder alanları.
FB.translatableText(),FB.translatableTextarea()veFB.translatableEditor(), aktif dil listesine göre locale bazlı input'lar render eder. Locale filtreleme (onlyLocales,exceptLocales), inline/tab layout ve locale label stilleri (badge,name,flag) desteklenir. - Backend translatable helper'ları.
HasTranslatableRules, FormRequest kurallarını ve validation label'larını locale bazında üretir.TranslatableQueryHelpers, JSON kolon araması, locale-aware sıralama ve datatable/edit form içinresourceShape()çıktısı sağlar. - Locale helper fonksiyonları.
sk_locale_keys()aktif locale kodlarını sırayla döndürür;sk_default_locale()primary locale'i çözer ve gerekirseapp.fallback_localedeğerine düşer. - Sample Contents modülü. Translatable model, migration, factory, domain action/event/listener'ları, FormRequest'ler, resource, datatable query, Vue sayfaları ve menü/yetki kayıtlarıyla tam bir admin CRUD referansı gelir.
- Dokümantasyon. Yeni Translatable Fields ve Çevrilebilir Alanlar rehberleri backend/frontend akışını, migration stratejisini ve Sample Contents referans implementasyonunu anlatır.
- Paket bağımlılığı. JSON tabanlı çevrilebilir attribute'lar için
spatie/laravel-translatableartık uygulama dependency set'ine dahil.
Improved
- FormBuilder dokümanı. FormBuilder rehberi translatable builder'ları listeler ve özel rehbere bağlanır.
- Çöp kutusuz File Manager dokümanı. File Manager rehberi,
enableTrash=falsedurumunda tekil ve toplu silmelerin kalıcı silmeye yönlendiğini ve bulk delete içinforce_delete=truegönderildiğini açıklar. - Lvntr builder skill dokümanları. Proje ajan rehberi FormBuilder translatable alanlarını kapsar; gelecekte üretilen admin formlar desteklenen API'yi kullanır.
Upgrade
Güncelleme sonrası migration ve frontend build çalıştırın:
composer update lvntr/laravel-starter-kit
php artisan sk:update
php artisan migrate
npm install
npm run build
Kendi dil/settings akışını özelleştirmiş uygulamalar general.languages üzerinden okunan aktif dil listesini doğrulamalı. Mevcut düz string kolonlar otomatik taşınmaz; bir model attribute'unu Spatie HasTranslations altına almadan önce kolonları aşamalı migration ile JSON'a çevirin.
2026-05-02 — v13.4.9
Minor sürüm — Dosya Yöneticisi favoriler, çöp kutusu, geri yükleme, kalıcı silme, kopyalama ve yeniden adlandırma
Dosya Yöneticisi’nde v13.4.8’de placeholder olarak görünen yüzeyler artık gerçek özelliklere dönüştü. Favoriler ve Çöp Kutusu gerçek hızlı-erişim görünümleri; klasör/dosya tile’ları yıldızlanabiliyor; silinen öğeler varsayılan olarak çöp kutusuna taşınıyor; çöp kutusundaki öğeler geri yüklenebiliyor veya kalıcı olarak silinebiliyor; çöp görünümünde Çöpü Boşalt aksiyonu var. Dosyalar context menüden çoğaltılabiliyor ve yeniden adlandırılabiliyor. Bu sürüm iki migration (file_favorites ve media soft delete), yeni backend action/query/request sınıfları, yeni File Manager route’ları, genişletilmiş EN/TR dil key’leri ve günlük çalışan file-manager:purge-trash komutu getirir. Mevcut uygulamalar composer update lvntr/laravel-starter-kit && php artisan sk:update && php artisan migrate && npm install && npm run build çalıştırmalı.
Added
- Favoriler. Yeni
file_favoritestablosu veFileFavoritemodeli, klasör/dosyaları owner context’e göre yıldızlı tutar.FavoritesContentsQuerysidebar’daki Favoriler görünümünü besler;FolderContentsQueryartık öğeleriis_favoritedile işaretler; grid ve context menüler Add/Remove Favorite aksiyonlarını gösterir. - Çöp kutusu ve geri yükleme akışı.
enableTrashaçıkken dosya ve klasörler soft-delete ile çöp kutusuna taşınır.TrashContentsQueryÇöp Kutusu hızlı görünümünü besler; silinmiş tile’lar silinme zamanını gösterir; çöp context menüleri Restore / Permanently Delete aksiyonlarına döner. - Çöpü Boşalt.
EmptyTrashActionveDELETE /file-manager/trash/empty, mevcut context’teki tüm çöp öğelerini kalıcı olarak siler; dosyalar klasörlerden önce, klasörler ise çocuklar önce olacak şekilde post-order silinir. - Dosya kopyalama ve yeniden adlandırma. Dosyalar
photo (copy).jpg/photo (copy 2).jpggibi çakışmasız isimlerle çoğaltılabilir ve shipped dialog +PATCH /file-manager/files/{media}endpoint’iyle yeniden adlandırılabilir. - Trash purge komutu.
php artisan file-manager:purge-trash --days=7, seçilen yaştan eski File Manager çöpünü kalıcı olarak siler.routes/console.phpiçinde günlük schedule edilmiştir. enableTrashprop’u.FileManagervarsayılan olarak soft-delete davranışıyla gelir;:enable-trash="false"verildiğinde çöp kutusu akışı kapatılıp doğrudan kalıcı silme davranışı kullanılabilir.
Security
- Context doğrulaması merkezileştirildi.
FileManagerContextRequest, sanal görünümler ve item mutasyonlarında geçerli File Manager context’ini tutarlı şekilde doğrulayıp çözer; favorites/trash endpoint’lerinin normal klasör içerik kontrollerinden sapma riski kapandı. - Soft-delete scope sertleştirildi. Geri yükleme, kalıcı silme, kopyalama, yeniden adlandırma ve favori action’ları öğeleri açıkça mevcut context’e scope eder ve gerektiği yerde
withTrashed()/onlyTrashed()kullanır; cross-context erişim engellenir, trashed öğeler yalnız doğru yollarda bulunur. - Klasör geri yükleme cascade korumaları. Trashed bir klasör geri yüklenirken alt klasörleri ve File Manager media kayıtları transaction içinde geri yüklenir. Parent hâlâ çöpteyse işlem reddedilir; parent kalıcı silinmişse orphan oluşmaması için öğe root’a geri döner.
Fixed
- Toplu force delete artık trashed öğeleri buluyor.
BulkDeleteAction,force=truedurumundawithTrashed()kullanır; Trash görünümünden kalıcı silme, zaten soft-delete edilmiş öğeleri artık kaçırmaz. - Dil key çakışması düzeltildi.
labels.detailsartık detay bölümü array’i; action labellabels.details_actionoldu. Böylece dosya detay dialog’u label’ları context-menü aksiyon string’iyle ezilmiyor. - Collection scope sıkılaştırıldı. Trash purge ve kalıcı silme yalnız File Manager media kayıtlarını (
collection_name = files) etkiler; avatar, logo, editor upload veya diğer MediaLibrary collection’larına dokunmaz.
Upgrade
Güncelleme sonrası migration çalıştırın:
composer update lvntr/laravel-starter-kit
php artisan sk:update
php artisan migrate
npm install
npm run build
API response tarafında breaking değişiklik yok. File Manager stub’larını özelleştirmiş uygulamalar sk:update --force kullanmadan önce özellikle FileManager.vue, useFileManager.ts, FileGrid.vue, FileManagerController.php, routes/web/file-manager-route.php, lang/{en,tr}/sk-file-manager.php, yeni request/action/query dosyaları ve iki migration ile kendi dosyalarını karşılaştırmalı.
2026-04-30 — v13.4.8
Minor sürüm — Dosya Yöneticisi UX yenilemesi (sidebar + stats + details + arama)
Dosya Yöneticisi UX yenilemesi — backend aynı, route'lar aynı, media tablosu aynı; yeni bir kabuk. Tek-kolon grid yerine sidebar + ana-kolon layout'u; üç yeni shipped component (FileManagerSidebar, FileDetailsDialog, FileManagerStats); mevcut klasörü client-side filtreleyen üst-bar arama kutusu; ve yeni girişlerle genişletilmiş sağ-tık menüsü (Yeni sekmede aç, Önizle, Paylaş, Kopyala, Yeniden Adlandır, Favorilere Ekle, Detaylar). Önceden belgelenmiş tüm davranışlar — yüklemeler, drag-and-drop taşıma, toplu silme, image lightbox, preview dialog'u, özel context'ler, settings, permission'lar — birebir aynı çalışır; değişiklik tamamen shipped frontend (FileManager.vue + üç yeni component + types.ts + lang/{en,tr}/sk-file-manager.php). Yeni composer veya npm bağımlılığı yok, migration yok, config yok, permission girdisi yok. Mevcut consumer uygulamaları composer update lvntr/laravel-starter-kit && php artisan sk:update && npm install && npm run build çalıştırarak yamayı çeker; breaking change yok.
Added
-
FileManagerSidebar.vue— dairesel storage-kullanım halkası, hızlı-erişim listesi, klasör ağacı ve "Yeni Klasör" butonuyla sol panel. Storage halkası,circumference - dashOffsetdoluluğuyla bir SVG çember kullanır ve renk-bandı eşiği uygular (primary < 70 %, amber 70–90 %, rose ≥ 90 %); kullanılan byte'larfm.contents.stats.total_size'tan gelir, kota şimdilik backend setting'i bağlanana kadar görsel olarak makul 10 GB default'tur. Klasör ağacı, taşıma modalı'nın zaten yüklediğifm.treeverisini tekrar kullanır. Hızlı-erişim hedefleri: Tüm Dosyalar root'a name asc sıralı döner, Son Yüklenenler root'a date desc sıralı döner, Favoriler ve Çöp Kutusu yaklaşan özelliğin placeholder'ı olarak yenicoming_soontoast'unu gösterir. -
FileDetailsDialog.vue— dosya detayları modali (Ad, Tip, Boyut, Yüklenme, Klasör ve resimlerde Boyutlar). Resim boyutları async yüklenir — dialogfile.url'a karşı gizli birnew Image()tetikler veonloadçalıştığındanaturalWidth × naturalHeight'ı render edilen satıra düşer. Dialog, sağ-tık menüsündekidownloadFilehandler'ını yeniden kullanan bir "İndir" footer butonuyla gelir; böylece action yüzeyleri hizalı kalır. Dosya context menüsündeki yeni "Detaylar" girişinden açılır. -
FileManagerStats.vue— üst-bar stats widget'ı (Toplam Dosya, Toplam Boyut, Klasör Sayısı, Favoriler, Son Yükleme). Yatay bir icon-tinted kart sırası render eder (light'tabg-{renk}-100, dark'tabg-{renk}-900/40). Klasör sayısı tüm nested ağacı dolaşır (flattenTree(fm.tree.value)); son yükleme mevcut klasördeki en yenicreated_at'i yansıtır ve "Az önce / X dk / X sa / X g / locale-tarih" formatında yenistats.time_*key'leri üzerinden gösterilir. -
Üst-bar arama. Body'nin üzerinde bir
IconField+InputTextşeridi,fm.contents.foldersvefm.contents.files'ıname/file_nameüzerinde case-insensitiveincludesile filtreler — yenifilteredFolders/filteredFilescomputed'leri üzerinden yüzeye çıkar. Filtre render edilen klasörle sınırlıdır; navigasyonfm.loadContents()bir sonraki çağrıda filtreyi örtük olarak temizler. -
Genişletilmiş dosya context menüsü — Aç / Önizle / İndir / Paylaş / Taşı / Kopyala / Yeniden Adlandır / Favorilere Ekle / Detaylar / Sil. "Aç" artık dosyayı yeni sekmede açar (
window.open(file.url, '_blank', 'noopener,noreferrer')); "Önizle" mevcut lightbox / dialog akışını korur; "Paylaş" mutlak dosya URL'sini panoya kopyalar (navigator.clipboard.writeText(...)), başarıda yerelleştirilmiş "Bağlantı kopyalandı" toast'u, izin reddindecoming_soontoast'u gösterir; "Detaylar" yeni dialog'u açar; "Kopyala", "Yeniden Adlandır", "Favorilere Ekle" yaklaşan özelliklerin placeholder'larıdır. Destructive Sil satırı, ayrı styling için yeni birfm-menu-dangerclass'ı alır. -
Klasör context menüsü — Sil'den önce "Favorilere Ekle" (placeholder) eklenir. Dosya menüsündeki placeholder'larla aynı
coming_soontoast pattern'i. -
types.ts—ViewMode = 'grid' | 'list'veQuickView = 'all' | 'recent' | 'favorites' | 'trash'eklenir.ViewModeyaklaşan list-view renderer için ayrılmıştır (şu an yalnızca grid);QuickViewsidebar hızlı-erişim akışı tarafından tüketilir. Mevcut export'lar değişmez. -
lang/{en,tr}/sk-file-manager.php— yeni key'ler. Üst seviye:link_copied,coming_soon. Label'lar:upload_new,preview,share,copy,add_to_favorites,details,search_placeholder,view_grid,view_list,files_section,folders_section,no_results. Yeni iç içe gruplar:labels.sidebar.*,labels.stats.*,labels.details.*.
Removed
FileManager.vue'dan eski header back-button + sort dropdown kaldırıldı. Önceki kabukta header'da←back butonu + sort key içinSelectdropdown + yön-toggle butonu vardı; navigasyon artık sidebar (klasör ağacı + breadcrumb) üzerinden, sıralama ise hızlı-erişim akışı ("Son Yüklenenler" =setSort('date', 'desc')) üzerinden gerçekleşir.useFileManagercomposable'ı doğrudan çağrı yapanlar için hâlâsetSort/toggleSortDirectionexport eder.
Upgrade
Breaking change yok. Mevcut consumer uygulamaları composer update lvntr/laravel-starter-kit && php artisan sk:update && npm install && npm run build çalıştırır — sk:update yeni shipped dosyaları ve genişletilmiş dil key'lerini çeker. Wire üzerindeki veri şekli değişmez; backend değişmez.
2026-04-26 — v13.4.7
Patch sürüm — EditorInput'da duplicate Link extension uyarısı susturuldu
Tek-fix patch — Tiptap'ın EditorInput ayağa kalkarken yazdığı Duplicate extension names found: ['link'] uyarısını susturur. Tiptap v3'ün @tiptap/starter-kit'i Link extension'ını default olarak bundle'lamaya başladı, ama editör hâlâ @tiptap/extension-link'i opsiyonel props.links branch'i üzerinden kendi openOnClick: false, autolink: true config'imizle push ediyordu — yani aynı editöre iki link registration'ı giriyordu. Düzeltme StarterKit çağrısında tek bir config flag (link: false); böylece bundle'lanmış kopya devre dışı, manuel-push branch'imiz tek kaynak. Davranış hem props.links === false (Link hiç yok) hem de props.links === true (sadece manuel-push) için birebir aynı; sadece console gürültüsü kalkıyor. Mevcut consumer uygulamaları composer update lvntr/laravel-starter-kit && php artisan sk:update çalıştırır — migration yok, config yok, breaking yok.
Fixed
EditorInput.vue— duplicate Link extension uyarısı susturuldu. Tiptap v3'ün@tiptap/starter-kit'i Link extension'ını default olarak içeriyor; editör ayrıcaprops.linksopsiyonel branch'i üzerinden@tiptap/extension-link'i de manuel olarak push ediyordu — sonuç: editör console'daDuplicate extension names found: ['link']uyarısıyla ayağa kalkıyordu.StarterKit.configure({ heading: { levels: [2, 3, 4] }, link: false })ile bundle'lanmış kopya devre dışı bırakıldı; tek kaynak artık manuel-push branch'i (kendiopenOnClick: false, autolink: trueconfig'imizle).props.links === falsedurumunda Link tamamen kalkıyor;props.links === truedurumunda sadece manuel-push branch'i çalışıyor — aynı davranış, uyarı yok.
Upgrade
Breaking change yok. composer update lvntr/laravel-starter-kit && php artisan sk:update patch'i çeker — düzeltme sk:update'in zaten takip ettiği aynı shipped Vue dosyası üzerinden geliyor; ek adım gerekmez.
2026-04-26 — v13.4.6
Patch sürüm — Vite optional-peer-dep stub'ı + sk:update package.json merge
EditorInput öncesi bir kit sürümünden (13.4.0 ve öncesi herhangi bir kurulum) 13.4.2+ sürümlerine yükseltirken yüzeye çıkan iki ilişkili build/upgrade düzeltmesi. Paketin package.json'u artık @tiptap/* setini peerDependencies + peerDependenciesMeta.optional ile bildirmiyor — bu bildirimler, deps consumer'ın project root'unda yüklü olsa bile, vendor/lvntr/laravel-starter-kit/ altından resolve edilen import'larda Vite'ın optional-peer-dep stub fallback'ini (__vite-optional-peer-dep:@tiptap/extension-table:@lvntr/starter-kit:false) tetikliyordu. Sonuç: build sırasında "Table" is not exported by …, runtime'da does not provide an export named 'BubbleMenu' — ikisi de Vite'ın stub modülünden (export default {}; throw …) geliyordu, gerçek paketten değil. Ayrıca sk:update artık sk:install'in mergePackageJson() adımını mirror'lıyor; böylece yeni @tiptap/* seti yükseltmede consumer'ın package.json'una otomatik düşüyor — daha önce yalnızca fresh install bunu çekiyordu, <13.4.2'den yükselen her consumer 16 dependency entry'sini elle kopyalamak zorundaydı. Ortak key'ler için stub-version-wins, user extra'ları korunur, tekrar çalıştırılınca idempotent.
Fixed
-
Paket
package.json—@tiptap/*seti içinpeerDependencies+peerDependenciesMetakaldırıldı. Paket composer üzerinden dağıtılıyor (npm'de yayınlanmadı) — peer-dep bildirimlerininnpm installüzerinde hiçbir etkisi yoktu; pratikte tek etkileri Vite'ıntryNodeResolvefallback'iydi. Bare bir import (import { Table } from '@tiptap/extension-table'), normalnode_moduleswalk-up'tan resolve edilemediğinde — paketvendor/altında olunca tetiklemesi kolay — Vite importer'in en yakınpackage.json'una bakıyor, dep'i optional peer olarak buluyor ve hata yerine__vite-optional-peer-dep:<dep>:<parent>:<isRequire>döndürüyordu. Stubexport default {}; throw new Error("Could not resolve …")olarak yüklenir — named export yok; build'deki yanıltıcı"Table" is not exported by …ve@tiptap/vue-3/menussubpath'i için runtime'dakidoes not provide an export named 'BubbleMenu'bu yüzden çıkıyordu. Bildirimler kaldırılınca düznode_modulesresolve geri devreye giriyor, project root'a kadar walk-up edip gerçek paketleri buluyor. -
sk:updateartıkstubs/package.json'u consumer'ınpackage.json'una merge'liyor.UpdateCommanddaha önce sadeceapp/,config/,resources/veroutes/altındaki dosyalara dokunuyordu — projeninpackage.json'una asla. Bu yüzden 13.4.2'nin stub'a eklediği 16@tiptap/*entry'si,composer update lvntr/laravel-starter-kit && php artisan sk:updateyapan consumer'lara hiç ulaşmıyordu. Yeni adım (handle()'da 4c),InstallCommand::mergePackageJson()'u mirror'lıyor: stub key'leri root'ta kazanır,array_merge-ddependencies/devDependencies(sıralı), user extra'ları korunur, sadece render'lanan JSON gerçekten farkını yansıttığında yazar (tekrar çalıştırma no-op). Özet, değişikliğipackage.json (merged stub dependencies — run npm install)olarak gösterir; böylece kullanıcı sonradannpm installçalıştırması gerektiğini bilir.
Upgrade
Breaking change yok. Mevcut consumer uygulamaları composer update lvntr/laravel-starter-kit && php artisan sk:update && npm install && npm run build çalıştırır — sk:update artık eksik @tiptap/* entry'lerini package.json'unuza sync'ler ve Vite stub'lar yerine gerçek paketleri resolve eder.
2026-04-26 — v13.4.5
Patch sürüm — code-review taraması (API hiyerarşi + role-data + 2FA loading + permission directive + i18n)
v13.4.x yüzeyinin takip eden bir kod incelemesinden çıkan küçük bir bulgu paketini kapatır. İki güvenlik / bilgi-sızdırma düzeltmesi (API kullanıcı listesi artık admin panelinin uyguladığı aynı role-hiyerarşi filtresini uyguluyor; rol JSON data endpoint'i artık edit/destroy action'larıyla aynı CanManageRoleQuery guard'ından geçiyor), bir UX düzeltmesi (2FA enable/disable butonları yalnızca happy path'te değil, hata yollarında da loading state'lerini sıfırlıyor), bir latent-bug düzeltmesi (v-role directive'i Inertia paylaşımlı prop'unun yanlış key'ini okuyup sessizce hep false döndürüyordu) ve bir i18n temizliği (useApi composable'ının hata toast'ları ve sentezlenmiş envelope mesajları artık hardcoded Türkçe stringler yerine sk-message.* key'leri üzerinden geçiyor). Tüm değişiklikler wire üzerinde additive — aynı response shape, aynı status kodları, aynı UI. Üç regression test'i iki güvenlik düzeltmesini koruyor. Mevcut tüketici uygulamalar php artisan sk:update ile yamaları çeker; migration yok, config yok, breaking yok.
Security
-
Api/UserController::indexartıkUserDatatableQuery'ye delegasyon yapıyor — admin paneliyle aynı role-hiyerarşi filtresi. Önceki haliyle API,UserDatatableQuery'nin uyguladığıwhereDoesntHave('roles', sort_order < me)clause'unu atlayan kendine özel birDatatableQueryBuilderzinciri kullanıyordu. Sonuç:users.readizni olan amasystem_adminolmayan bir API tüketicisiGET /api/v1/usersile her üst-rank kullanıcıyı —system_adminhesapları dahil — görebilirdi; admin UI ise onları gizliyordu. Controller artıkUserDatatableQuery'yi method-inject edip doğrudanresponse($request->user())döndürüyor. Query'nin allowlist'leri legitimate API çağrılarının wire kontratı değişmesin diyefirst_name,last_name,email,status,id,created_atsortable key'leri (önceden API'a özeldi) ile genişletildi. Yenitests/Feature/Api/UserTest.php"hides higher-rank users from non-system_admin api callers" regression test'iyle korunuyor. -
Admin/RoleController::dataartık rol JSON'unu döndürmeden önceCanManageRoleQueryçalıştırıyor.data(),edit()'in JSON kardeşidir (admin rol formu bunuuseApi().get('/admin/roles/{role}/data')ile pre-fetch ediyor).edit()vedestroy()zaten role hiyerarşisini zorlamak içinCanManageRoleQuery::check()'ten geçiyordu;data()geçmiyordu — bu yüzden alt-rank bir admin, render edeceği form hiyerarşi-aware olduğu halde, üst-rank bir rolün tüm permission setini JSON üzerinden okuyabiliyordu. Kontrol artıkdata()'nın en üstüne inline edildi (abort(403)mismatch'te),edit()davranışını mirrorluyor. İki yenitests/Feature/Admin/RoleManagementTest.phpregression test'iyle korunuyor ("forbids non-system_admin from reading higher-rank role data" + same/lower rank için pozitif kardeş).
Fixed
-
2FA enable/disable butonları artık hata durumunda takılı kalmıyor.
Profile/components/TwoFactorTab.vue, Fortify'a çağrı atmadan öncetwoFactorProcessing = trueset ediyordu ama yalnızca success branch'inde sıfırlıyordu. Bir axios 4xx/5xx (tipik: süresi dolmuş bir oturum, password-confirm timeout'u) ya da bir Inertiarouter.reloadhatası, butonu tam sayfa yenilemeye kadar spinner'da bırakıyordu.enableTwoFactor()vedisableTwoFactor()artık flag'i birfinallybloğunda sıfırlıyor; herhangi bir hata buton'u tekrar tıklanabilir + bir toast olarak yüzeye çıkıyor (donmuş UI yerine). -
v-roledirective'i artık doğru Inertia paylaşımlı prop key'ini okuyor.resources/js/plugins/permission.tsauth.roles'u kontrol ediyordu amaHandleInertiaRequestskullanıcı rol isimleriniauth.role_namesaltında paylaşıyor. Directive sessizce hepfalse'a düşüyordu —<div v-role="'system_admin'">markup'ı, actor'ün rolü ne olursa olsun hiç görünmüyordu. Plugin artıkauth.role_names'i okuyor. Plugin dosyasındaki duplicateuseCanexport'u (aynı yanlış key'i okuyordu) da kaldırıldı — kanonikuseCan()@/composables/useCanaltında yaşıyor ve zaten doğruydu, yani uygulama kodu etkilenmedi. Plugin dosyası artık yalnızcaPermissionPlugin'i export ediyor (v-can+v-rolekayıt eder). -
useApicomposable'ı hata mesajlarısk-message.*i18n key'leri üzerinden akıyor.resources/js/composables/useApi.tsüç hardcoded Türkçe hata stringi içeriyordu (non-JSON response için sentezlenmiş envelope, network-failure toast detayı, toastsummary).trans('sk-message.invalid_response'),trans('sk-message.request_failed', { status }),trans('sk-message.network_error'),trans('sk-message.error_summary')ile değiştirildi. Dört yeni key hemlang/en/sk-message.phphemlang/tr/sk-message.phpiçine eklendi. EN-locale kullanıcıları artık bir API çağrısı normal envelope yolu dışında başarısız olduğunda Türkçe metin görmüyor.
New
- İki güvenlik düzeltmesi için regression test'leri.
tests/Feature/Api/UserTest.phphides higher-rank users from non-system_admin api callerstest'ini kazanıyor —RoleEnumindex'i üzerinden role hiyerarşisini seed ediyor,users.read+adminrolünüapiguard'ına da mirrorlayıp (Spatie'ninGuard::getDefaultName()'iPassport::actingAsaltındaapi'ye geçiyor), bir admin kullanıcısına web + api versiyonlarını birlikte assign ediyor ve response'un üst-ranksystem_adminpeer + actingsystem_adminuser'ını dışlayıp same-rank admin peer'ı içerdiğini assert ediyor.tests/Feature/Admin/RoleManagementTest.phpikisini kazanıyor:forbids non-system_admin from reading higher-rank role data(admin/admin/roles/{system_admin}/data'da 403 alır) veallows non-system_admin to read lower-rank role data(admin/admin/roles/{user}/data'da 200 alır).
2026-04-25 — v13.4.4
Patch sürüm — system-admin log görüntüleyici (/logs)
storage/logs/ altındaki Laravel log dosyalarını listelemek, aramak ve silmek için yalnızca bakım rolüne açık bir admin bölümü ekler. Kendi içinde tamamlanmıştır — yeni composer/npm bağımlılığı, migration veya permission girdisi gerekmez. Yalnızca system_admin kullanıcılarına görünür; geri kalan herkes paneli aynı şekilde görür. Tamamı additive.
Added
-
/logsadmin bölümü — yalnızca system-admin log görüntüleyici. "Sistem" başlığı altındaki yeni sidebar öğesistorage/logs/içeriğini birSkDatatable'da listeler (dosya adı, kanal tipi, boyut, değiştirilme zamanı, aktif flag'i); dosya bazlı görüntüleyici sayfası ise yapısal filtreler (seviye, tarih aralığı, anahtar kelime) altında cursor sayfalanmış kayıt akışını gösterir. Tekli + toplu silme aynı endpoint üzerinden kısmi-başarı semantiğiyle çalışır — aktif dosyalar (bugünün günlük log'u, son 5 saniyedir yazılanlar) tek tek reddedilir vefailed[]listesinde geri döner; geri kalan dosyalar silinir. Her silme batch'iLogFilesDeletedevent'i dispatch eder; yeniLogActivityForLogFilesDeletedlistener'ılog_name = systemaltında birspatie/activitylogkaydı yazar — silme işlemi Admin → Activity Logs sayfasında otomatik görünür. -
app/Domain/Logs/bounded context. Dört DTO (LogFileDTO,LogEntryDTO,LogEntryFilterDTO,DeleteLogFilesDTO), iki query (LogFileQuerydosya listesi için,LogEntryQuerykayıt stream'i için), bir action (DeleteLogFilesAction), bir event/listener çifti ve statelessLaravelLogParserservisi.LogEntryQuery::paginate()dosyayıfopen('rb')+ 64KB ile sınırlıfgets()ve byte offset cursor ile okur; bellek kullanımı dosya boyutundan bağımsız olarak sabit kalır; çok satırlı stack trace'ler ait oldukları kayda eklenir; ilk Laravel-format başlığından önce gelen (veya hiç başlık içermeyen dosyalarda kalan) satırlar tek bir rawLogEntryDTOolarak basılır (is_raw = true, gri chip, gizli timestamp) — yani dosya içeriği sessizce kaybolmaz. Yapısal filtre uygulandığı an (level / from / to / keyword) raw entry'ler doğal olarak listeden düşer. -
logs.*isimli route grubu.routes/web/log-route.phpbeş route içerir —index,dtApi,show,entries,destroy— hepsirole:system_adminile sarılır.{filename}parametre kısıtı ([A-Za-z0-9._-]+\.log) hemshowhementriesüzerinde zorlanır; path traversal ve.logolmayan istekler controller'a hiç ulaşmaz. Bölüm role-gated olduğu (permission-gated olmadığı) için dosyaroutes/web.phpiçindeki$routesWithoutPermissionMiddlewareallowlist'ine eklenmiştir. -
lang/{en,tr}/sk-log.phpçeviri dosyası. Tüm UI metinleri (filtre etiketleri, boş durumlar, silme onayları, hata sebep kodları) iki dilde desk-log.*namespace'i altındadır. Yenisk-menu.logskey'i sidebar'daki menü öğesini etiketler.
Security
-
Üç katmanda path-traversal koruması. Güvenli dosya adı regex'i
^[A-Za-z0-9._-]+\.log$(1) route parametre kısıtında, (2)DeleteLogFilesRequestkurallarında ve (3)DeleteLogFilesAction::execute()içinde (defence in depth) zorlanır. Kalan her şeylog.invalid_filenameolarak failure döner ya da route binding'den 404 alır — disk path'i ham input'tan inşa edilmez. -
Aktif dosya silme reddi.
LogFileQuery::isActive(), bugünün günlük dosyasını (laravel-{today}.log) vemtime'ı son 5 saniye içinde olan her dosyayı işaretler.DeleteLogFilesActionişaretli dosyaları item-bazlıreason: 'active_file_protected'ile reddeder; toplu submit, Laravel'in o anda yazdığı dosyayı kazara truncate edemez. -
role:system_adminroute gate'i, permission girdisi yok. Görüntüleyici bilinçli olarakconfig/permission-resources.php'ye eklenmemiştir.adminrolü vermek bunu açmaz; yalnızca özelsystem_adminrolü açar. system-admin olmayan kullanıcılar route'a 403 alır ve menü öğesini hiç görmez — özellik onlara görünmez. -
64KB satır okuma sınırı.
LogEntryQueryfgets($handle, 65536)çağırır; sınırsız uzunlukta tek satırlık bir kayıt process belleğini tüketemez. Uzun satırlar isteği abort etmeden temiz şekilde truncate olur.
2026-04-25 — v13.4.3
Patch sürüm — zengin dikey tab'lar + datatable per_page üst sınırı
TB builder üzerinden daha zengin bir dikey tab görünümü (icon tile, description satırı, trailing badge veya check) ve DatatableQueryBuilder tarafında ?per_page= parametresi için opsiyonel üst sınır geliyor. Değişikliklerin tamamı additive — breaking yok. sk:update yeni TabBuilder Vue bileşenlerini, yeniden yazılmış _tabs.scss'i ve EN/TR sk-setting.tab_descriptions dil anahtarlarını taşır; paket katmanındaki max_per_page config için composer update yeterli.
Added
-
TB.item()zengin dikey tab fluent metodları. Dört yeni fluent metod:.description(text)label altında ikincil bir satır,.iconColor(color)renkli icon tile preset'i (13 renk:blue,amber,emerald,purple,teal,red,indigo,slate,pink,orange,cyan,green,yellow),.badge(value, severity?)sağ tarafta badge (5 severity:success,warn,info,danger,secondary) ve.checked()sağ tarafta yeşil check (badge üzerinde önceliklidir). Mevcut tab tanımları olduğu gibi çalışır. Ayarlar → Genel sayfası yeni API'yi kullanacak şekilde güncellendi (per-tab description + icon color); kanonik örnek olarak hizmet veriyor. Yeni i18n bloğusk-setting.tab_descriptionsyedi ayar tabını kapsar. -
STARTER_KIT_DATATABLE_MAX_PER_PAGEenv var +config('starter-kit.datatable.max_per_page').DatatableQueryBuilderüzerinde?per_page=parametresi için opsiyonel üst sınır. Anahtar tanımlı değilse100'e düşer.
Security
DatatableQueryBuilder—?per_page=üst sınırı zorlanır. Önceki sürümlerde bir istemci?per_page=99999gönderip builder'ı tüm tabloyu tek payload olarak materialise etmeye zorlayabiliyordu. Yeni tavan (config('starter-kit.datatable.max_per_page'), default 100) değeri sessizce kırpıyor — tavanın altında her şey aynı çalıştığı için meşru çağrılar etkilenmiyor.
Improved
- Dikey tab sidebar —
.isCard(true)ile PrimeVue Card sarmalayıcı. Tab'lar seviyesinde (per-tab değil) ayarlanır; dikey sidebar daha az iç padding'le bir Card içine sarılır. Yeni icon tile + description alanlarıyla birleştirildiğinde Ayarlar sayfasının sidebar'ı kutudan çıkar çıkmaz modern admin-panel düzenine uyuyor.
Fixed
- Branding — legacy "Starter Kit 12" referansları. İki yer hâlâ "Starter Kit 12" diyordu —
config/scramble.phpAPI açıklaması veapp.blade.phpfallback title; her ikisi de artık "Starter Kit 13" diyor.
2026-04-24 — v13.4.2
Patch sürüm — Tiptap editor input, şifre üreticisi, dashboard hoş geldin mesajı + güvenlik sertleştirmesi
Zengin metin editörü olarak çalışan FB.editor() FormBuilder alanı (arkasında Tiptap v3) server-side HtmlSanitizer utility'si ile birlikte, FB.password()'a crypto-safe şifre üreticisi ve Ayarlar → Genel altında editor ile yazılan admin dashboard hoş geldin mesajı bu sürümde geliyor. Dosya yükleme, editor-scoped upload'ların gruplu kalması için opsiyonel folder_name parametresi kazandı; FileManager artık HTTP 413 Payload Too Large için özel bir hata mesajı gösteriyor. Değişikliklerin tamamı additive — breaking yok. sk:update publish edilmiş dosyaları (yeni Vue bileşenleri, HtmlSanitizer, dil anahtarları) taşır; paket-katmanı değişiklikleri için composer update yeterli.
Added
-
Tiptap tabanlı
FB.editor()FormBuilder input'u. Tiptap v3 üzerine kurulan yeni bir form alanı tipi; bubble menu, link / image / table / task list / text align / text color / text style ve placeholder extension'ları içerir. Araç çubuğu düzeni.toolbar('minimal' | 'standard' | 'full')ile seçilir; resim yüklemeleri FileManager context'i üzerinden opsiyonel folder-grouping parametresiyle yönlendirilir; yardımcı bileşenler (EditorColorPalette,EditorImagePicker) renk ve görsel seçici akışlarını karşılar. Çevirilerlang/{en,tr}/sk-editor.phpdosyalarında. İçerik kaydedilirken yeniApp\Support\HtmlSanitizerüzerinden geçer — yalnızca allowlist'teki tag / attribute / URL scheme'leri DB'ye yazılır. -
FB.password().generator()— crypto-safe şifre üreticisi. Parola alanlarının yanına generate butonu ekleyen opt-in fluent metodu;crypto.getRandomValues()kullanır. Default'lar bilinçli olarakPassword::defaults()'tan daha sıkı (16 karakter, mixed case + harf + rakam + sembol) — böylece üretilen her değer ilk submit'te proje-wide parola politikasını geçer. Aynı değişiklikte yeniden yazılmış custom eye toggle ilepasswordvepassword_confirmationalanlarıInputGroupiçinde birebir aynı görünüyor. PrimeVue<Password>artık yalnızca.feedback()ile strength meter'a opt-in edildiğinde kullanılır — diğer tüm kullanımlar daha hafifInputText + eyeyoluna düşer. Admin User formunda kutudan çıkar çıkmaz aktif. -
Admin dashboard hoş geldin mesajı. Ayarlar → Genel altına
FB.editor()ile yazılan opsiyonel birwelcome_messageWYSIWYG alanı geldi. Dashboard sanitize edilmiş HTML'i Inertia prop'u olarak paylaşıyor,resources/js/pages/Admin/Dashboard/Index.vueisesk-prosecontainer'ındav-htmlile render ediyor. Değer hem yazılırken (FormRequestprepareForValidationhook'u) hem okunurken (DashboardController defense-in-depth geçişi) sanitize ediliyor; böylece on-disk değer bozulsa bile eski kayıtlardaki kötü niyetli HTML frontend'e ulaşmıyor. -
folder_nameupload parametresi.POST /file-manager/filesartık opsiyonelfolder_namestring'i kabul ediyor (nullable,max:100, sıkı regex: yalnızca harf / rakam / boşluk / tire / altçizgi — path traversal ve keyfi karakter riski validation'da kapatıldı). GeçildiğindeUploadFileAction::ensureManagedFoldermevcut context için o isimde root-level bir klasörün varlığını atomik şekilde garanti ediyor ve upload'ı içine koyuyor. Welcome-message editor'ü bu parametreyi kullanarak tüm inline görsel upload'larını tek "Welcome Message" klasörü altında gruplar — eski read-query side-effect pattern'i geri gelmiyor. Frontend'tekiEditorImageUploadConfigaynı alanıfolderNameüzerinden expose ediyor.
Security
-
App\Support\HtmlSanitizer— tag, attribute ve URL scheme allowlist'i. Editor payload'larından allowlist'te olmayan tüm tag / attribute / URL scheme'lerini süzen yeni utility. URL işleme blocklist'ten allowlist'e çevrildi: relative URL'ler +http://,https://,mailto:,tel:kabul ediliyor — diğer her şey (blob:,data:,file:,ftp:,javascript:,vbscript:) reddediliyor. Kenditests/Unit/HtmlSanitizerTest.phpregression suite'i ile kapsanıyor. -
SettingService::normalizeValue()— tüm yazma yollarında HTML sanitize.setValue()vesetGroup()her değeri paylaşılannormalizeValue()hook'undan geçiriyor. YeniHTML_SAFE_KEYSwhitelist'inde listelenen anahtarlar (şu angeneral.welcome_message) DB'ye ulaşmadan önceHtmlSanitizer::sanitize()'den geçiyor; yani FormRequest dışı tüm yazma yolları (tinker, scheduled command, queue job) da sanitize'e tabi — normal setting API'si üzerinden sanitize edilmemiş HTML DB'ye asla yazılamıyor. -
Dashboard welcome message — defense-in-depth okuma sanitize'i.
DashboardController::indexsaklanmış welcome message'ı Inertia'ya paylaşmadan önceHtmlSanitizer::sanitize()'den ikinci kez geçiriyor. Write-path sanitize'i gelmeden önce yazılmış tarihi kayıtlar ve drift etmiş veya manuel poison edilmiş DB değerleri browser'a ulaşamıyor. -
UploadFileAction::ensureManagedFolder— concurrency-safe managed folder oluşturma. Ensure path'iDB::transactioniçinde aday satıralockForUpdateile kilit koyuyor, unique-constraint yarışı içinQueryExceptioncatch ile refetch'e düşüyor ve soft-deleted klasörleri yeniden oluşturmak yerinewithTrashed()ile restore ediyor. Üç katman birlikte, iki paralel editor upload'unun aynı klasör adında deadlock'a girmesi veya soft-deleted bir satırı silip unique index'e çarpan bir sibling oluşturması yarışını kapatıyor. -
UploadFileRequest—folder_nameinput'u sıkı validasyonla geçiyor. Yeni alannullable|string|max:100|regex:/^[\pL\pN _-]+$/ukullanıyor; path-traversal ve keyfi karakterli içerik downstream'e değil, FormRequest sınırında reddediliyor.
Improved
-
FileManager upload hata mesajları. Client composable artık HTTP 413 (Payload Too Large) durumunda jenerik hata yerine yeni
too_largeçevirisini gösteriyor (EN + TR); diğer tüm non-200 yanıtlar ise client-side mesajda status code'u da taşıyor — upload hatalarını devtools network sekmesini açmadan teşhis etmek kolaylaştı. -
Password alanı default render yolu. Yukarıdaki
.generator()eklemesine ek olarak, defaultFB.password()render'ı PrimeVue<Password>yerineInputText+ custom eye toggle'a geçti.<Password>'un kendi eye ikonununInputGroupaddon'larında kaybolma sorununu çözüyor vepassword/password_confirmationalanlarının birebir aynı görünmesini sağlıyor..feedback()çağrıldığında (strength meter yolu) hâlâ PrimeVue<Password>kullanılıyor. Yeni i18n anahtarları:generate_password,password_generated,password_generated_detail,show_password,hide_password(EN + TR).
Fixed
-
SettingsDefaultsQueryread path'i artık yazma yapmıyor. Önceki sürümde Ayarlar → Genel ekranı okunduğundaresolveWelcomeMessageFolderId()yan etkisi olarakFileFolder::firstOrCreate(...)çağırıyordu. Aynı isimde soft-deleted bir klasör barındıran install'larda unique index insert'i reddediyor ve admin, saf bir okuma ekranında 500 alıyordu. Folder ensure yolu artık yalnızca upload anında çalışanUploadFileAction::ensureManagedFolder'da;SettingsDefaultsQueryyeniden tamamen side-effect-free. Frontend'tekiwelcome_message_folder_idInertia prop bağımlılığı da kaldırıldı — editor doğrudanfolderNameüzerinden çalışıyor. -
Editor upload — stale
blob:URL'lerinin form payload'una sızması engellendi.EditorInput.vueartıksetContent({ emitUpdate: false })sonrasında parentv-model'i elle senkronlıyor; taze bitmiş bir upload'tan geride kalan / kırık<img src="blob:...">parçaları submit edilen HTML'de sunucuya gitmiyor.
2026-04-22 — v13.4.1
Patch sürüm — API response sertleştirme + Postman/Apidog sync + OAuth UUID fix
Bu sürüm, baştan sona elden geçirilen API response zarfı (trace-id pipeline, merkezi exception handler, leak kapatan controller patch'leri) ile iki yeni API client entegrasyonu (Postman ve Apidog sync) ve iki adet kurulum fix'ini (OAuth UUID uyumluluğu, otomatik Passport personal access client) birlikte getiriyor. Çoğu değişiklik additive (yeni body alanı + header'lar, yeni admin butonları) ama üç adet API-response davranışsal breaking noktası strict client'lar için önemli — detay için docs/UPGRADE.tr.md. Taze kurulumlar her şeyi otomatik alır; mevcut projeler upgrade rehberini takip etmelidir. sk:update publish edilmiş dosyaları taşır; controller patch'leri ve sonrası Passport adımı manueldir.
Security
-
Controller
$e->getMessage()leak'leri kapandı (11 yer).FileManagerController(bulkDelete/createFolder/renameFolder/moveItem/deleteFolder/upload/deleteFile),Api/UserController::destroyveApi/Auth/AuthController::login+twoFactorChallengeiçindeto_api(null, $e->getMessage(), 4xx)pattern'ithrow ApiException::*ile değiştirildi. Mesaj metni aynı şekilde client'a gidiyor ama artık merkezi handler'dan geçiyor —trace_ideşleniyor, 500+ log'lanıyor,X-Correlation-IDecho ediliyor. IçLogicExceptionmesajı yerine kontrollüApiExceptiontipine geçiş, gelecek refactor'larda iç mesaj sızıntısı riskini kapatıyor. -
abort($code, 'msg')raw mesajı artık client'a sızmıyor.HttpExceptionInterfacedalı$e->getMessage()yerine sabitdefaultMessageForStatus()tablosunu kullanıyor.abort(400, 'SQL error: ...')çağrısı artık body'de"Bad request."döndürür; iç detay sadeceAPP_DEBUG=trueikendebug.messagealanında görülür. Controlled mesaj içinthrow ApiException::badRequest('...')kullanın. -
Api/AuthControllerham User model'i yerineUserResourcedönüyor.register,login(default kind),twoFactorChallengevemeendpoint'leridata.useriçin artıkUserResource::toArray()çıktısı veriyor. Ham Eloquent serializasyonu$hidden'a güveniyordu; ileride eklenecek hassas bir alan unutulursa sessizce sızabilirdi. Resource artık kontrat — hangi alan client'a gidiyor açıkça yazılı.
Added
-
Postman sync — admin butonu + CLI. API Rotaları sayfasındaki "Postman'e Gönder" aksiyonu (ve
php artisan postman:synckomutu) Scramble OpenAPI spec'ini Postman'in/import/openapiendpoint'inefolderStrategy=Tagsparametresiyle push ediyor — tag'ler doğrudan folder'a dönüşüyor. Her sync önce taze koleksiyonu import ediyor, yeni UID'yi ayarlar tablosuna yazıyor, ardından eski koleksiyonu best-effort siliyor.import-first, delete-aftersırası sayesinde Postman tarafında geçici bir hata veya geçersiz token, mevcut çalışan koleksiyonu kaybetmeden geçiyor. Yapılandırma: Settings → API Clients → Postman card'ı (API Key + Workspace ID; collection ID otomatik yönetiliyor). -
Apidog sync — admin butonu + CLI. Aynı pipeline Apidog'un
POST /v1/projects/{projectId}/import-openapiendpoint'ine inline JSON input veOVERWRITE_EXISTINGdavranışıyla push ediyor.php artisan apidog:syncolarak da çağrılabiliyor. Yapılandırma: Settings → API Clients → Apidog card'ı (Access Token + Project ID). -
Settings → API Clients tabı. Postman ve Apidog yapılandırması için ayrı card'lar içeren tek bir tab. Gizli alanlar (
postman.api_key,apidog.access_token)config/settings.php'dekisensitive_keyslistesi aracılığıyla DB'de encrypted tutuluyor. EskiPOSTMAN_*.envanahtarları artık kullanılmıyor — mevcut değerler ayarlar tablosuna migrate ediliyor. -
Ortak
OpenApiExporterhelper. İki sync Action'ı aynı exporter'ı paylaşıyor:scramble:exportçalıştırıyor,storage/app/postman/altına her çağrı için benzersiz bir geçici dosya yazıyor,finallybloğunda temizliyor — CLI komutu ve admin butonu eş zamanlı çalıştığında paylaşılan bir dosyada yarışmıyorlar. Spec değişmeden gönderiliyor: content-type rewrite yok, push edilen koleksiyon gerçek sunucu kontratını aynen yansıtıyor (client'lar kendi UI'larında body görünümünü istedikleri gibi raw/form-data arasında değiştirebilir).
Improved
-
Başarılı ve hatalı response'lar aynı
trace_idaltında eşleşiyor. YeniAssignTraceIdmiddleware'i API grubuna prepend edildi; her request'te UUID üretiyor ve$request->attributes->get('trace_id')üzerinden hem success (ApiResponse::toResponse) hem error (ApiExceptionHandler) dalı aynı id'yi pick-up ediyor. Body'detrace_id+ header'daX-Request-ID+ client'ın sanitize edilmişX-Request-ID'siX-Correlation-IDolarak echo. Müşteri destek senaryolarında client log'u ile sunucu log'u tek id ile eşleşebiliyor. -
ModelNotFoundExceptionmesajı model ismini içeriyor."The requested resource was not found."→"User not found."(veyaRole,Product, …).ApiExceptionHandler::modelNotFoundMessageclass_basename($e->getModel())ile resolve ediyor. Bir önceki AGENTS.md vaadini karşılıyor; model sınıf adı zaten URL'den tahmin edilebildiği için güvenlik etkisi yok. -
429 Too Many Requests response'una
Retry-Afterheader'ı propagate ediliyor.ThrottleRequestsException::getHeaders()içindeki tüm rate-limit header'ları (Retry-After,X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset) response'a kopyalanıyor. Rate-limit'e takılan client'lar artık kaç saniye bekleyeceğini mesajdan parse etmek yerine standart header'dan okuyabiliyor. -
simplePaginate()desteği.to_api(Model::simplePaginate(15))artık type error vermiyor;meta.has_moreile yetinen lightweight pagination için destek eklendi.LengthAwarePaginatorveCursorPaginatordavranışı değişmedi. -
to_api(paginator, 'msg', 201)artık pagination meta'sını kaybetmiyor. Helper'da paginator-detect 201/202 branch'lerinden önce çalışıyor; batch-create tipinde endpoint'ler bile meta üretiyor (önceki sürüm paginator'u ham nesne olarak serialize ediyordu — sessiz bug düzeldi). -
ApiResponseDRY +final.paginated()vepaginatedCollection()meta üretim mantığı tek bir private helper'a çekildi. Sınıf artıkfinal— subclass invariant'ı kırma riski kapandı. Controller'ların dönüş tipi imzasında davranışsal değişim yok; public API surface aynı. -
Scramble
ApiResponseExtensionşema açıklamaları zenginleşti. Envelope'daki her alan için tanım + örnek + validation rule description eklendi. Multi-status şema (201 / 204 / 4xx / 5xx için ayrı Response) ScrambleTypeToSchemaExtensionAPI'siyle direct desteklenmediği için sonraki sürüme taşındı —OperationExtensionile modellenecek.
Fixed
-
OAuth migration'ları UUID uyumlu.
oauth_access_tokens.user_idveoauth_auth_codes.user_idartıkforeignUuid(öncedenforeignId/bigint unsigned);oauth_clients.owner_*artıknullableUuidMorphs. Starter kit'in UUIDusers.idprimary key'i ile birlikte önceki uyumsuzluk login akışındaSQLSTATE 1265: Data truncated for column 'user_id'hatasını tetikliyordu — login akışı artık kutudan çıkar çıkmaz temiz çalışıyor. -
site:installPassport personal access client'ı otomatik oluşturuyor.passport:keysile admin-user seed adımları arasınapassport:client --personal --provider=userseklendi. Taze kurulumlar artık API token üretebiliyor; önceden operatörün manuel olarak bu komutu çalıştırması gerekiyordu. -
202 Accepted'ın ölü kodu temizlendi.
to_api($data, '', 202)için'Operation queued.'fallback'i zaten hiç devreye girmiyordu ($messagedefault'u truthy). Helper tek bir mantıksal akışa sadeleşti. -
ApiResponse::toResponse()request attribute'u değerlendiriyor. Önceki sürümResponsable::toResponse($request)imzasını alıyordu ama$request'i kullanmıyordu — yeni middleware ile entegrasyon bu parametreye bağlı, artık değerlendiriliyor. -
Exception handler
matchsıra kritikalitesi yoruma bağlandı.ApiException extends HttpException,HttpExceptionInterfacedalından önce kalmalı — aksi halde custom API exception'lar genericabort()handling'e düşerdi. Fragile sıralama yorum satırıyla ve regression test (tests/Feature/Api/ApiResponseTest.php) ile güvence altına alındı.
New
-
Regresyon test dosyası:
tests/Feature/Api/ApiResponseTest.php(16 test, 57 assertion). Envelope şekli, exception → status mapping, trace id eşleşmesi, 204 boş body,Retry-Afterpropagation,debugsadeceAPP_DEBUG=trueiken, sanitize edilmişX-Correlation-IDecho — tüm kontrat testleri. Paketten örnek olarakvendor/lvntr/laravel-starter-kit/tests/examples/ApiResponseTest.php'tan kopyalanabilir. -
sk:updateotomasyon kapsamı genişledi.app/Http/Middleware/AssignTraceId.phpveapp/Helpers/sk-helpers.phpartık safe-update listesinde;php artisan sk:updatebu iki dosyayı otomatik senkronize ediyor.ApiResponse.phpveApiExceptionHandler.phpzaten listedeydi.
Breaking
Detaylı migration adımları için docs/UPGRADE.tr.md. Özet:
abort($code, 'custom message')artık mesajı göstermiyor —ApiException::*throw kullanın.ModelNotFoundExceptionmesajı model adını içerir ("User not found."). Frontend regex eşleşmeleri güncellenebilir.Api/Auth/AuthControllerdata.useralanlarıUserResource::toArray()çıktısıyla sınırlı. Ham modelin bir alanına bağımlıysanız resource'u güncelleyin.
2026-04-21 — v13.4.0
Minor sürüm — Güvenlik sertleştirme sprinti
Paralel bir kod inceleme turu ~37 bulgu çıkardı — 13 HIGH, 14 MEDIUM, 4 LOW. Bu sürümde 36 tanesi kapatıldı; 1 HIGH (git history'deki Passport private-key rotation'ı) operatörün manuel adım atması gereken bir düzeltme. Patch'lerin büyük çoğunluğu publish edilmiş dosyalara (yani sk:install'ın sizin uygulamanıza kopyaladığı dosyalara) dokunuyor; bu yüzden mevcut consumer projeler docs/UPGRADE.tr.md içindeki diff'leri uygulamalı. Taze kurulumlar her şeyi otomatik alıyor. Nadir paket-katmanı değişiklikleri (HSTS preload, stub güncellemeleri) composer update lvntr/laravel-starter-kit ile geliyor.
Security
-
UserPolicy::delete'te self-delete engellendi + APIUserController::destroynull guard.UserPolicy::deleteactor === target durumundatruedönüyordu, bu nedenleusers.deleteizni taşıyan herhangi bir authenticated userDELETE /api/v1/users/{self}ile kendini silebiliyordu. Self branch'i artıkfalsedönüyor — kendi kendini silmenin desteklenen tek yolu Profile sayfasındaki password-confirmed Fortify akışı.Api\UserController::destroyayrıca$request->user()null olduğunda (stale / expired bearer) temiz bir 401 dönüyor — önceki(string) null = ''cast'i boş performer id log'luyordu. -
CreateRoleAction+UpdateRoleActionrole + permission sync'iniDB::transactioniçinde çalıştırıyor.Role::create(...)ardından->syncPermissions(...)transaction dışında koşuyordu; iki write arasında permission-cache race veya bağlantı düşmesi olursa role satırı permission'sız kalıyordu. İki action da artıkDB::transaction(...)içinde çalışıyor;RoleCreated/RoleUpdatedcommit sonrası dispatch ediliyor, listener'lar tutarlı state görüyor. -
UpdateAuthSettingsAction2FA revoke loop'unuDB::transaction'a aldı. Adminauth.two_factor'ı off'a çevirdiğinde action önce ayar satırını yazıyor, sonra her user'datwo_factor_secret/two_factor_recovery_codes/two_factor_confirmed_atalanlarını temizliyor. Loop ortasında bir fail, sistemi yarı-revoke durumunda bırakıyordu — ayar "2FA off" diyordu ama bazı user'ların aktif TOTP secret'ı hâlâ duruyordu. Tüm operasyon artık atomik. -
LogoutUserActionnull-safe token revoke. API logout endpoint'i$user->token()->revoke()çağırıyordu; request controller'a aktif access token'sız ulaştığında (stale token, cache temizliği, worker race) zincirli çağrıError: Call to a member function revoke() on nullfırlatıp endpoint 500 dönüyordu. Artık?->revoke()kullanılıyor — token yokken bile temiz 204 dönüyor. -
FileManager subtree walk'ları N sorgudan 1'e indi.
BulkDeleteAction::collectDescendantIdsveDeleteFolderAction::collectDescendantIdssilinen klasörün alt ağacını yürürken hop başına birFileFolder::findsorgusu atıyordu — 50 seviyelik ağaç 50 sıralı sorgu demekti, sibling sayısı arttıkça maliyet büyüyordu ve saldırganlara açık bir request-timing DoS kulbu veriyordu. İki action da artık owner-scoped(id, parent_id)map'ini tekselectile yükleyip ağacı PHP'de visited-set cycle guard ile yürüyor. -
SMTP
encryption=noneartık TLS'i doğru devre dışı bırakıyor. Publish edilen Mail ayarları ekranı "No encryption" seçeneği sunuyordu amaSettingsServiceProvider'none'string'iniconfig('mail.mailers.smtp.encryption')'a olduğu gibi yazıyordu. Laravel'in SMTP transport'u null dışındaki her değeri —'none'dahil — "bu TLS modunu kullan" olarak yorumluyor, yani kayıtlı "No encryption" ayarları ilk connect'te default STARTTLS upgrade'ine düşüyor ve offer etmeyen sunucularda fail edebiliyordu. Provider artık outbound config write'ında'none' → nulleşlemesi yapıyor. -
ApiExceptionHandler— exception mesajı sızıntısı +X-Request-IDlog injection. Exception→status mapping'indefaultarm'ıconfig('app.debug') ? $e->getMessage() : 'A server error occurred.'dönüyordu;APP_DEBUG'ın yanlışlıkla açık kaldığı her ortamda handle edilmemiş exception'lar API tüketicilerine stack-trace-grade detay sızdırıyordu. Handler artık generic mesajı koşulsuz dönüyor; debug detayı sadeceLog::error'a ve zatenAPP_DEBUGile gated olandebugblock'una yazılıyor. Trace id artık her zamanStr::uuid()ile sunucu tarafında üretiliyor; client'tan gelenX-Request-IDheader'ı yalnızca charset + length-cap sanitizer'dan ([A-Za-z0-9._-], ≤128 char) geçtikten sonra correlation metadata olarak kabul ediliyor veclient_request_idolarak log'lanıyor — kötü niyetli bir client artık uygulama log'una CRLF payload veya sahte trace id enjekte edemiyor. -
SecurityHeadersHSTS direktifinepreloadeklendi. Baseline HSTS header'ımax-age=31536000; includeSubDomains'tenmax-age=31536000; includeSubDomains; preload'a çevrildi; deployment artık HSTS preload listesi için uygun. Paketsrc/katmanından geliyor —composer updateile otomatik. -
Parola politikası 10+ / mixed case / digits / symbols seviyesine çıkarıldı.
AppServiceProviderartık proje-wide birPassword::defaults(...)kuruyor; default'a güvenen her FormRequest (register, password reset, password confirm, profile password change) otomatik devralıyor. Mevcut user'ların parolası invalidate olmuyor — yalnızca yeni parolalar daha sert kurala karşı ölçülüyor. -
Axios CSRF + credential default'ları.
resources/js/app.tsartıkaxios.defaults.withCredentials = true,xsrfCookieName = 'XSRF-TOKEN',xsrfHeaderName = 'X-XSRF-TOKEN'+X-Requested-With: XMLHttpRequest+Accept: application/jsonset ediyor. Admin UI Fortify endpoint'lerini (2FA, sessions, password-confirm) Axios üzerinden doğrudan çağırıyor;withCredentialsve XSRF header olmadan tarayıcı session cookie'sini gönderiyordu ama mutating request'lerde CSRF token'ı göndermiyordu — yani compromised bir origin, web flow'unun güvendiği CSRF check'ini bypass edebiliyordu. -
2FA QR kodu
v-htmlyerine<img src="data:image/svg+xml;base64,...">ile render ediliyor. Fortify QR kodunu SVG string olarak döner. Öncekiv-html="qrCodeSvg"çalışıyordu ama man-in-the-middle (veya bozulmuş bir Fortify override'ı) SVG'ye<script>/onloadiliştirirse çalıştırırdı. Yeni yaklaşım SVG'yi base64'lü<img>data URL'ine çeviriyor —<img>sandbox'ı inline script'leri SVG içinde olsa dahi çalıştırmaz. -
useDefinition.load()/loadAll()fail eden fetch'teloaded.value = trueyapmıyor. Composable datatable / form option dropdown'larını besleyen definition JSON'ının tek durak yükleyicisi. Daha önce.then(r => r.json())zincirini doğrudan kuruyordu — fetch fail ederse (network, 500, parse)loaded.valuetruekalıyor ve UI hiçbir konsol geri bildirimi olmadan stale / boş option listesi göstermeye devam ediyordu. İki metod da artıktry/catchiçinde,res.okkontrolü var, hatalar konsola yazılıyor ve fail'daloaded.valuefalsekalıyor böylece consumer retry edebiliyor. -
On bir
FormRequest::authorize(): return true;ihlali kapatıldı. Şu request'ler — admin user store, API user store, admin role store, admin settings (auth/general/mail/storage/filemanager/turnstile), test-mail, destroy-sessions — artıkauthorize()'ı ilgili*.create/*.updatepermission check'ine delege ediyor (destroy-sessions sadece$this->user() !== nullkontrolü yapıyor).CheckResourcePermissionmiddleware'i zaten bunları route seviyesinde zorluyordu ama kontrolü request'e taşımak, controller action'ının off-route çağrıldığı (test, internal dispatch) veya action map'in yeni route isimleriyle drift ettiği anda açılacak defense-in-depth boşluğunu kapatıyor. Public auth endpoint'leri (Api/Auth/*Request) ve FileManager context-based request'leri bilinçli olarak dokunulmadı. -
2FA challenge artık kesinlikle tek kullanımlık.
TwoFactorChallengeActionyanlış TOTP / yanlış recovery code / boş submit durumundaapi:2fa_challenge:{uuid}cache entry'sini bırakıyordu; geçerli bir challenge id'yi ele geçirmiş saldırgan 5 dakikalık TTL ×throttle:5/minpenceresinin tümünü kod denemesi için kullanabiliyordu. Her fail arm'ı artıkCache::forget($cacheKey)çağırıyor — challenge id kesinlikle bir kez çalışıyor; sonraki denemelerinvalidChallenge()'a düşüyor ve client yeni bir uuid almak için tekrar login olmak zorunda. -
SettingService::getValue/getGroupallGrouped()cache'inden okuyor +setGroup()DB::transaction'da. Sıcak okuma yolu, fullallGrouped()sonucu için zaten bir cache katmanı olmasına rağmen çağrı başına bir sorgu atıyordu. Settings-yoğun request path'leri (Dashboard, FileManager, Admin sayfaları) request başına birkaç round-trip kazandı. Bulk write path'i de artık atomik — multi-setting save sırasında bir fail, DB'yi karışık durumda bırakmıyor. -
MoveItemRequest—item_type'a göreitem_idtiplendirmesi. Kurallar heritem_typeiçin heritem_iddeğerini kabul ediyordu. Effective kural artıkitem_type=fileiçininteger|min:1,item_type=folderiçinuuid— DB şemasıyla birebir uyumlu;item_type'ın kendisistring|in:...string formu yerineRule::in([...])kullanıyor. -
DeleteFolderRequest— explicit FormRequest, çıplakRequestyerine.FileManagerController::deleteFolderönceden hamRequestalıyor, context'i controller içinde kuruyor ve authorizer'ı doğrudan çağırıyordu. YeniDeleteFolderRequest,FileManagerRequest'i extend ediyor, paylaşılan context kurallarını çalıştırıyor ve$request->context()expose ediyor — diğer FileManager endpoint'leriyle aynı yüzey; controller iki satır boilerplate düşürdü. -
UserController::uploadAvatarartık explicitGate::authorize('update', $user)çalıştırıyor.UploadAvatarRequest::authorize()zaten{user}route parametresi bind'li olduğundaUserPolicy::update'e delege ediyor ama controller'daki ikinci Gate çağrısı view/update/delete'de kullanılan belt-and-braces pattern'ini yansıtıyor ve controller'ı yalnız başına okurken kontrolü görünür tutuyor.
Security — manuel operatör adımı
- GV-H1 — Passport private keys rotation.
.gitignorekuralı düşmeden önce bu dosyaları commit etmiş legacy install'lardastorage/oauth-private.keyvestorage/oauth-public.keygit history'de duruyor. docs/UPGRADE.tr.md §6git filter-repo+passport:keys --force+passport:purge+ takım-geneligit reset --hardakışını belgeliyor; bu adım paket tarafında otomatize edilemez. Repo'nuz key dosyalarını hiç commit etmediyse adımı atlayın.
Changed
-
LOG_LEVELdefault'u artıkerror..env.exampledaha önceLOG_LEVEL=debugshipping ediyordu — production'da (verbatim commit edilirse) log'u SQL trace, Passport token debug'ı vb. ile dolduruyor, gürültülü ve zaman zaman hassas. Production profilierrorveyawarninggöndermeli. -
laravel/tinkerrequire-dev'e taşındı. Tinker geliştirici kolaylığı — production dependency olarak shipping edilmesi PsySH'ı ve transitive zincirini her container build'e çekiyordu. Local devrequire-dev'de olduğu için yine kuruyor. -
.env.examplePassport key + Turnstile placeholder'ları kazandı. İki yorumlanmışPASSPORT_PRIVATE_KEY/PASSPORT_PUBLIC_KEYstub'ı env-based key-loading path'ini (önerilen alternatif,storage/oauth-*.keycommit etmek yerine) belgeliyor; uncommentedTURNSTILE_ENABLED=false+ boş site/secret key'ler taze install'larda Turnstile middleware'ini admin açana kadar no-op yapıyor. -
Inertia
appEnv/appDebugshared prop'ları artık production'da sızmıyor.HandleInertiaRequests::shareöncedenconfig('app.env')+config('app.debug')koşulsuz dönüyordu. Production'da bu, ortam adını her authenticated user'a sızdırıyor veAPP_DEBUG'ın açık olup olmadığını ilan ediyordu. İki anahtar da artıkapp()->environment('production')altındanull/falsedönüyor; non-prod'da dev overlay için gerçek değeri taşıyor. -
CORS preflight cache'i 0'dan 7200 saniyeye çıkarıldı.
config/cors.phpöncedenmax_age => 0shipping ediyordu, her mutating request'te tarayıcıya preflight rerun ettiriyordu.max_age=7200ile SPA / mobile client'lar OPTIONS cevabını 2 saat cache'liyor.
Fixed
-
useDialog/useImageLightbox— 300 ms timer leak. İki composable daclose()'ta 300 mssetTimeoutbaşlatıyordu; exit animasyonu oynasın diye DOM'dan kaldırma işi geciktiriliyordu. Hızlıopen → close → opensekansı iki timer kuyruğa alabiliyordu; sondaki, dialog yeniden açıldıktan sonra fire ediyor ve render'ı iptal ediyordu. Module-seviyesi timer ref'i artık hemopen()hemclose()girişinde temizleniyor; timeout gövdesi fire ettiğinde ref'i null'luyor. -
SkFormdirty-form guard — parent prop update'leri user input'unu silmiyor.watch(derivedDefaults, ...)block'u parent her yeni object gönderdiğinde form'u koşulsuz default'lara reset ediyordu. User form'u yarı doldurmuşken parent poll etse (örn. sibling datatable refresh paylaşılan-state update tetiklerse), yazılmakta olan input siliniyordu. Watcher artıkinternalForm.isDirty'i kontrol ediyor — form dirty ise yeni değerler default olarak kaydediliyor (sonraki birreset()onları alsın diye) ama canlı form state'i korunuyor. -
SkDatatableURL filtreleri —api.get+Promise.allSettled. URL-driven filter loader çıplakfetch(...)+Promise.allkullanıyordu, yani bir filtrenin options endpoint'indeki tek bir 500, handle edilmemiş rejection ile tüm filter bar'ını zehirliyordu. Loader artık paylaşılanapi.get<T>()helper'ını kullanıyor (Axios default'larını + XSRF'i devralıyor) vePromise.allSettledkullanıyor; her filtre bağımsız, fail eden endpoint boş listeye düşüyor ve konsola warning basılıyor. Aynı dosyadalet activeMenuItems→const activeMenuItems(ref hiç re-assign edilmiyordu). -
TwoFactorTab.enableTwoFactorInertia reload'u await ediyor. Orijinal kodrouter.reload({ only: [...] })'u await etmeden fire ediyor, sonra hemenloadQrAndSetupKey()'e geçiyordu. Yavaş bağlantıda QR fetch reload'la race edip stale ekran render edebiliyordu.router.reloadartıkonFinish'te resolve olan bir promise'e sarılı. -
ProfileInfoTab/UserForm—as anyavatar cast'leri kaldırıldı. İki(x as any)?.avatar_urlerişimi tiplendirilmiş shape ile değiştirildi — davranış değişikliği yok ama cast, backing tipavatar_urlaccessor'ını kaybettiği anda ortaya çıkacak gerçek bir TypeScript hatasını gizliyordu. -
DashboardController::indexexplicit: Responsereturn type aldı. Proje Larastan seviyesinde kalan sonreturn_type_missingbulgusunu kapatıyor.
Yükseltme
composer update lvntr/laravel-starter-kit --with-all-dependencies yalnızca paket src/ katmanını (HSTS preload, stub güncellemeleri) alıyor. Yukarıdaki diğer her fix publish / stub-backed dosyalarda yaşıyor. Tam diff listesi ve smoke-test checklist'i için docs/UPGRADE.tr.md.
2026-04-20 — v13.3.3
Patch sürüm — Builder core importları için Windows build düzeltmesi
Fixed
- Windows production build
Could not load .../FormBuilder/corehatasıyla patlıyordu.FormBuilder,DatatableBuilderveTabBuilderbileşenlerinin her biri,index.ts'i@lvntr/components/<Builder>/coreolarak import edilen bircore/klasörüne sahip. Bazı Windows kurulumlarında Vite resolver'ı dizin→index.tsadımını atlayıpvite:load-fallback'e düşüyor, klasörü dosya gibi okumaya çalışıpENOENTfırlatıyordu. Düzeltme: her üç builder içincore/klasörünün yanına,./core/index'ten re-export yapan bircore.tsbarrel dosyası eklendi; böylece import her platformda gerçek bir dosyaya rezolve oluyor. macOS/Linux davranışı değişmedi,/core/buildergibi mevcut subpath importları da etkilenmedi. Fixes lvntrdev/laravel-starter-kit#1.
2026-04-19 — v13.3.2
Patch sürüm — güvenlik sertleştirmesi, user audit event'leri, Logo API zarfı, media-delete policy, permission-middleware cache doğruluğu, test bootstrap
Tam test suite auditi sırasında ortaya çıkan gizli bug'ların toplu düzeltmesine ek olarak, admin user flow'undaki bir privilege-escalation yolunu kapatan, Settings ekranının SMTP/S3/Turnstile sırlarını frontend'e sızdırmasını durduran ve API auth akışını web akışıyla aynı seviyeye (email verification + iki-adımlı doğrulama) çeken bir güvenlik incelemesi yapıldı. Orijinal bug'ların çoğu sadece belirli runtime'larda (Octane/queue worker) veya site:install atlanmış taze clone'larda görünen, ya da user write'ları için audit log'u sessizce düşüren sorunlardı.
Security
-
Rol atamasında privilege escalation — admin user flow.
StoreUserRequestveUpdateUserRequesteskidenrolealanını yalnızcaRule::exists('roles', 'name')ile doğruluyordu; yaniusers.createveyausers.updateizni olan herhangi bir kullanıcı, admin UI dropdown'ının sunduğundan bağımsız olarak ham HTTP isteğiylerole=system_admingönderebiliyordu —Gate::beforeüzerinden tüm yetki kapılarını bypass eden super-admin rolüne anında atlıyordu. AyrıcaUpdateUserRequesthedef kullanıcının rank'ine bakmıyordu; bu nedenle düşük rank'lı bir actor, kendinden üstün rank'lı birini (örn.system_admin) edit edip düşürebiliyordu. Düzeltme:roleartıkRule::in(...)ile doğrulanıyor — liste, dropdown'ı besleyen hiyerarşi-farkındaRoleSelectOptionsQuerytarafından üretiliyor (sort_order >= actor'ın min sort_order,system_adminnon-system_admin actor'lara kapalı).UpdateUserRequest::authorize()da hedefin top-rank'i actor'un rank'inden yüksek olduğunda 403 dönüyor. Rolü olmayan ama Spatie direct permission ileusers.*taşıyan bir actor, mümkün olan en düşük rank olarak muamele görür — hiçbir rol atayamaz ve kendisinden başkasını edit edemez; önceki(int) null = 0fallback'i kazarasystem_admindahil tüm rol listesini açıyordu. -
Settings sırları artık frontend'e sızmıyor. Admin Settings sayfası
mail.password,storage.spaces_secret,storage.aws_secretveturnstile.secret_keydeğerlerini,settings.readizni olan her kullanıcıya Inertia prop olarak düz metin gönderiyordu. Yalnızca.env'de duran değerler bileconfig()fallback'i üzerinden sızıyordu. Düzeltme:SettingsDefaultsQueryher secret alan içinnulldönüyor ve yanında*_is_set: boolflag'i ekliyor. Admin UI değer set olduğunda••••••••placeholder'ı gösterip, form boş submit edildiğinde sıfırdan boş string yolluyor — backend bunu "mevcut değeri koru" olarak yorumluyor; boş olmayan değer yazılırsa üstüne yazar. Yenitests/Feature/Admin/Settings/SecretsDisclosureTestInertia payload'ının ham secret string'ini hiçbir yerde taşımadığını doğruluyor. -
storage.aws_secretartık DB'de şifreli saklanıyor.config/settings.phpiçindekisensitive_keyslistesinestorage.aws_secreteklendi — daha öncemail.password,storage.spaces_secretveturnstile.secret_keylistede vardı ama AWS muadili yoktu, UI üzerinden kaydedilen S3 secret'larısettingstablosunda plaintext duruyordu.SettingServicelistedeki her anahtarı yazarkenCrypt::encryptStringile şifreliyor, okurken çözüyor. -
check.permissionmiddleware'i production'da fail-closed. Middleware, route'tan çözülen permission (örn.users.indexiçinusers.read) DB'de seed edilmemişse isteği geçiriyordu. Production'da bu, permission kaydı unutulmuş her yeni rotayı sessizce korumasız bırakmak anlamına geliyordu. Middleware artıkapp()->environment('production')altında çalışırkenAuthorizationException(403) fırlatıyor, non-production ortamlarda ise seed edilmemiş permission'ıLog::warningile kaydediyor — dev ergonomisi korundu, production foot-gun'ı kapatıldı. -
Test-mail endpoint'i artık ham exception detayını yansıtmıyor.
SettingsController::testMail()eskiden SMTP exception mesajını (host / username / TLS detayları) tarayıcıya flash ediyordu. Mesaj artıkLog::error'a sınıf + message context'iyle yazılıyor; kullanıcı yalnızca generic bir "Failed to send test email. Check the server logs for details." görüyor — aynı başarı/başarısızlık sinyali, bilgi ifşası olmadan. -
API auth — email verification ve iki-adımlı doğrulama web flow'uyla paritede. API eski durumda register ve her başarılı parola login'inde hemen access token veriyordu, web flow'unun zorunlu kıldığı email-verification ve 2FA checkpoint'lerini bypass ediyordu. Üç
POST /api/v1/auth/*endpoint'i yeniden düzenlendi:register— Fortify'ınemailVerificationfeature'ı açıkken (default), register'da token verilmiyor. Endpoint kullanıcıyı oluşturuyor,Illuminate\Auth\Events\Registeredfırlatıyor (Fortify'ın notification pipeline'ı verification link'ini gönderiyor) ve{ data: { user, requires_verification: true } }+ 201 dönüyor. Feature kapalıysa eski token-on-register davranışı korunuyor.login— discriminated payload dönüyor:{ user, token }— normal başarı{ requires_verification: true }— credential'lar geçerli ama email verify edilmemiş (verification feature açıkken){ requires_two_factor: true, challenge: "<uuid>" }— credential'lar geçerli ama hesapta 2FA confirmed; tek kullanımlık bir challenge id veriliyor (5 dakikalık cache TTL). Henüz access token yok.
two-factor-challenge— yeni endpointPOST /api/v1/auth/two-factor-challenge(throttle5/dk). TOTP için{ challenge, code }veya{ challenge, recovery_code }kabul ediyor. Başarıda{ user, token }dönüyor. TOTP Fortify'ınTwoFactorAuthenticationProvider'ı ile doğrulanıyor; recovery code'larhash_equalsile eşleştirilipreplaceRecoveryCodeüzerinden tüketiliyor, böylece yeniden kullanılamıyorlar. Geçersiz / bilinmeyen / süresi dolmuş challenge'lar 401 dönüyor.
API tüketicileri için breaking —
register/login'dan gelen her 2xx yanıtta{ user, token }bekleyen client'ler artıkdata.requires_verificationvedata.requires_two_factorflag'lerine göre dallanmalı ve hesapta 2FA onaylıysa token almadan önce/api/v1/auth/two-factor-challengeendpoint'ini tamamlamalıdır. 2FA'sız, verify edilmiş kullanıcılar eski şekli görmeye devam ediyor. -
Settings
requiredvalidation'ı UI secret göstergesiyle uyumlu.UpdateMailSettingsRequestveUpdateTurnstileSettingsRequest, bir secret'ın "zaten set" olup olmadığına karar verirken yalnızca DB kaydına bakıyordu; eğer değer sadece.env'de duruyorsa UI'daki*_is_setflag'itruedönüyordu (çünküSettingsDefaultsQueryconfig()'e fallback yapıyor) ama password / secret_key alanı boş bırakılmış form submit edilince kafa karıştırıcı birrequiredhatası veriyordu.requiredbranch'i artık query ile aynı mantığı izliyor — DB satırı VEYA config fallback — yani env-destekli kurulumlar artık bu hatayı görmüyor. -
Admin avatar upload / delete'te IDOR.
POST /users/{user}/avatarveDELETE /users/{user}/avatarrotalarıCheckResourcePermissionaltında herhangi bir permission'a map'lenmiyordu — çünkü route action'larıuploadAvatar/deleteAvatar, middleware'inACTION_ABILITY_MAPtablosunda yoktu; middleware permission kontrolü olmadan$next($request)dönüyordu.UploadAvatarRequest::authorize()de koşulsuztruedönüyordu. Bu kombinasyonla, yalnızcadashboard.readtaşıyan biruserrolü bile — email verified şartıyla — herhangi bir kullanıcının (sistem admini dahil) avatar'ını üzerine yazabiliyor veya silebiliyordu. Düzeltme: action map'ineuploadAvatar => updatevedeleteAvatar => updateeklendi;UploadAvatarRequest::authorize()route'ta{user}parametresi varsaUserPolicy::update'e delege ediyor (profile self-upload akışı aynı kalıyor);SettingsController::deleteAvataraçık olarakGate::authorize('update', $user)çağırıyor. -
Admin
UserControllerve APIUserController: view / update / delete için rank-hiyerarşisi guard'ı.GET /users/{user}/data,GET /users/{user}/edit,DELETE /users/{user},PATCH /api/v1/users/{user}veDELETE /api/v1/users/{user}yalnızcausers.read/users.update/users.deletepermission kontrolüne ve (yalnızca admin UI'daki)UpdateUserRequest::authorize()rank check'ine güveniyordu. Permission taşıyan düşük rütbeli bir admin, data endpoint veya API üzerinden yüksek rütbeli bir kullanıcıyı hâlâ okuyabiliyor veya silebiliyordu. Düzeltme:UserPolicy::view / update / deleteartık aynıcanManage()rank kontrolünü çalıştırıyor (system_admin bypass, rolsüz actor'lar en düşük rütbe sayılıyor). Admin ve API controller'ları her cross-user operasyondaGate::authorize('view' / 'update' / 'delete', $user)çağırıyor. Admin ve APIUpdateUserRequest'lerauthorize()'ıUserPolicy::update'e delege ediyor; böylece rank kontrolü tüm akışlarda aynı. -
POST /api-routes/regenerate-docsherhangi bir authenticated kullanıcı tarafından çağrılabiliyordu. Route action'ıregenerateDocsdaACTION_ABILITY_MAP'te yoktu, bu yüzdenCheckResourcePermissionpermission kontrolsüz$next($request)dönüyordu. Email verified her authenticated kullanıcı, sunucuda artisan komut çalıştıran OpenAPI regeneration'ı tetikleyebiliyordu. Düzeltme:regenerateDocs => updatemap'e eklendi;config/permission-resources.php'yeapi-routes.updateeklendi; seeder permission kaydını oluşturuyor. -
Logo + FileManager'da SVG upload yasaklandı. Hem admin logo uploader (
SettingsController::uploadLogo) hem de FileManager default MIME listesiimage/svg+xml'i kabul ediyor ve dosyayıpublicdisk'e kaydediyordu. SVG<script>,onloadve foreignObject JavaScript'i gömebilir; mağdur direkt/storage/...URL'sini açtığında script app origin'de çalışır (stored XSS). Düzeltme: logo validation artıkmimes:png,jpg,jpeg,webp+dimensions:max_width=4096,max_height=4096sabitliyor.UploadFileRequestiçineBLOCKED_MIMESlistesi (image/svg+xml,image/svg,text/html,application/xhtml+xml) eklendi —file_manager.accepted_mimes'te ne yazılı olursa olsun effective liste bu değerlerden arındırılıyor.UpdateFileManagerSettingsRequestkayıt sırasında bu MIME'larıRule::notIn(...)+^[a-z0-9.+-]+/[a-z0-9.+-]+$regex ile reddediyor. Admin UI picker'ları (MimePickerField,FileManagerTab,GeneralTablogo input) artık SVG listelemiyor.SettingsDefaultsQuery::fileManager()eski install'lardaki seed'lenmiş SVG'yi UI'a göndermeden önce süzüyor; böylece geçmiş kurulumlar formda SVG'yi seçili görmüyor. -
Avatar rule'u sertleştirildi.
UploadAvatarRequest::rules()eskiden['required','image','max:2048']idi —imagerule'u SVG'yi kabul ediyor ve piksel boyutu için sınır koymuyordu, bu da polyglot dosyalar ve decompression-bomb PNG'ler için kapı açıktı. Yeni rule:required | image | mimes:jpg,jpeg,png,webp | max:2048 | dimensions:max_width=4096,max_height=4096. -
media-library.disk_nameartık defaultlocal. Önceki defaultpublicidi — installer seeder başarısız olsa, admin FileManager disk toggle'ını değiştirse veya seeder atlansa, kullanıcının yüklediği belgeler dünya-okunabilir URL üzerinden servis ediliyordu. Default artıklocalolduğu için eksik konfigürasyon fail-closed; FileManager zaten indirmeleriDownloadFileActionüzerinden stream ediyor, public URL'e ihtiyacı yok. -
SESSION_ENCRYPT+SESSION_SECURE_COOKIEdefaulttrue.config/session.phpiçinde'encrypt' => env('SESSION_ENCRYPT', false)ve'secure' => env('SESSION_SECURE_COOKIE')(null default) vardı. Bu env değişkenlerini set etmeyi unutan deploy'lar, HTTPS üzerinde bile plaintext session payload + secure bayraksız cookie gönderirdi. İki default de artıktrue;.env.examplezaten ikisinitrueolarak shipping ediyor ve Herd HTTPS'le serve ettiği için local dev de etkilenmiyor. -
SecurityHeadersmiddleware'i baseline CSP header ekliyor. Middleware X-Frame-Options / X-Content-Type-Options / Referrer-Policy / Permissions-Policy / HSTS ekliyordu amaContent-Security-Policyyoktu. Kodbase'de ikiv-htmlsink'i olduğu için (Fortify 2FA QR SVG ve DataTablecolumn.renderescape hatch) CSP saldırı alanını anlamlı ölçüde daraltıyor. Header yalnızca non-local ortamlarda set ediliyor — local dev'deki Vite HMR, script/connect/style için dev-server origin'ine ihtiyaç duyuyor ve bu değer geliştiriciye göre değişiyor, bu yüzden local'de tight CSP dev akışını bozmaktan başka işe yaramaz. -
Scramble "Try It" production'da kapalı.
config/scramble.phphide_try_it: false+try_it_credentials_policy: 'include'ile shipping ediliyordu — production'daapi-docs.readtaşıyan herhangi bir admin'e, kendi session cookie'lerini her isteğe iliştiren in-browser API tester'ı sunuyordu. İki değer de artıkAPP_ENV === 'production'kontrolüne göre ayrılıyor (prod'da gizli +omit, local/staging'de interaktif). -
Passport access-token TTL kısaltıldı, scope kataloğu eklendi. Access token'lar 15 gün, personal access token'lar 6 ay geçerli tutuluyordu — sızan bir bearer token haftalarca kullanılabilir kalıyordu. Yeni default'lar:
access_token_minutes=60,refresh_token_days=14,personal_token_days=30; eskiPASSPORT_TOKEN_DAYS/PASSPORT_PERSONAL_TOKEN_MONTHSenv anahtarları set edilmişse yine öncelikli, bu yüzden mevcut kurulumlar etkilenmiyor.config/starter-kit.phpartık opt-in bir scope kataloğu (users.read,users.write,files.read,files.write,admin) shipping ediyor;Passport::tokensCan()önceden bağlı — spesifik API rotalarınamiddleware('scope:...')eklediğin anda per-scope erişim devreye giriyor. -
API register / login artık
turnstilemiddleware'ini çalıştırıyor. Cloudflare Turnstile tarayıcı auth formları içinFortifyServiceProvider+ValidateTurnstileüzerinden bağlıydı, ama API rotaları (POST /api/v1/auth/register,POST /api/v1/auth/login) yalnızcathrottle:5,1limit'i taşıyordu — saldırgan dakika başına IP başına beş hesap açabiliyordu. İki rota da artık mevcutturnstilemiddleware alias'ından geçiyor; Turnstile settings'te kapalıysa middleware no-op, açıldığında API de aynıcf_turnstile_responsekontrolünü devralıyor.
Fixed
-
User domain event'leri artık Create/Update/Delete'te dispatch ediliyor.
App\Domain\User\Actions\CreateUserAction,UpdateUserActionveDeleteUserActioniçindekiUserCreated::dispatch(...)/UserUpdated::dispatch(...)çağrıları daha önce yorumda veya eksikti —DomainServiceProvider'da register edilen listener'lar (audit-log listener dahil) user write'ları için hiç çalışmıyordu.CreateveUpdateartık gerçekten değişiklik olduğunda dispatch ediyor (no-op updateUserUpdatedfırlatmıyor);Deleteise silmeden önce id/email yakalayıp başarı halindeUserDeletedfırlatıyor —Role*action pattern'iyle aynı. -
Admin
users.showrotası 500 dönsüyordu.routes/web/user-route.phpiçindekiRoute::resource('users', UserController::class)örtük olarakGET /users/{user}rotasını açıyordu amaUserControllerhiçshow()metodu taşımıyordu — o URL'ye her istekBadMethodCallExceptionfırlatıyordu. Resource kaydı artık->except(['show'])ile daraltıldı; detay verisi admin UI'nın zaten kullandığıGET /users/{user}/dataendpoint'inden okunuyor. -
Settings logo endpoint'leri artık
ApiResponsezarfı dönüyor.App\Http\Controllers\Admin\SettingsControlleriçindekiPOST /settings/logoveDELETE /settings/logoeskiden çıplakresponse()->json([...])/response()->json(status: 204)dönsüyordu — admin API'nın geri kalanının izlediği "her JSON yanıt{ success, status, message, data }zarfı taşır" sözleşmesini kırıyordu. Her ikisi de artıkto_api(...)üzerinden geçiyor. Frontend (GeneralTab.vue)json.data.logo_urlokuyor, şekil aynı. -
App\Policies\UserPolicy'yedeleteability'si eklendi.DELETE /media/{media}MediaUploadController'daGate::authorize('delete', $media->model)çağırıyor. Medyanın sahibi birUserise,UserPolicy'dedeletetanımlı olmadığı için (sadeceviewveupdatevardı) Gate fallback'ten deny'a düşüyor ve 403 dönüyordu — kendi avatar/dosyasını silmeye çalışan sahip için bile. Yenidelete(User $actor, User $user)metoduupdate'i birebir yansıtıyor: self her zaman izinli, aksi halde actor'unusers.deletepermission'ına ihtiyacı var. -
CheckResourcePermissionmiddleware: process-geneli cache yerine request-scoped cache. Middleware içindeki permission-existence lookup'ı sonucustatic $cacheddeğişkeninde tutuyordu. Uzun ömürlü worker'larda (Laravel Octane, container'ı job'lar arası sıcak tutan queue worker'lar) bu cache hiç yenilenmiyordu — yeni oluşturulan permission kayıtları worker restart edene kadar görünmez kalıyordu. Daha kötüsü, test suite içinde static test'ler arası hayatta kalıyordu:RefreshDatabasepermissionstablosunu truncate ediyordu ama middleware önceki test'in seed ettiği permission isimlerini hâlâ "var" olarak raporluyor ve permission'sız olması gereken rotalarda aralıklı 403'ler üretiyordu. Cache artıkapp()->instance('check-permission.cache', ...)ile saklanıyor — prod'da request-scoped, test container'ında test-scoped. -
UserFactorytwo_factor_*kolonlarını default olaraknullseed ediyor. Eloquent strict mode (Model::shouldBeStrict(! isProduction()),Lvntr\StarterKit\StarterKitServiceProvidertarafından set ediliyor), kod taze bir factory instance üzerinde o kolonları okuduğunda (örn.$this->actingAs(User::factory()->create())sonrasıProfileController) "attribute [two_factor_secret] either does not exist or was not retrieved" fırlatıyordu. Factory artıktwo_factor_secret,two_factor_recovery_codesvetwo_factor_confirmed_atiçin açıknullyazıyor — in-memory model->refresh()gerekmeden üçünü de taşıyor. -
CreateUserActionveUpdateUserActionartık write + role sync'i transaction içinde çalıştırıyor.User::create(...)ardından->syncRoles(...)transaction dışında koşuyordu —syncRolesbaşarısız olursa (bağlantı düşmesi, permission cache invalidation, role-not-found race) user row'u kalıyor ama rol atanmıyordu, admin listede tutarsız kayıt görünüyordu. İki action da artıkDB::transaction(...)içinde çalışıyor; event dispatch commit'ten sonra yapılıyor, böylece listener'lar tutarlı state görüyor. -
MoveItemAction::wouldCreateCycleartık her ancestor için SELECT atmıyor. Method folder ağacınıFileFolder::find($parentId)ile her hop'ta tek tek yürüyordu; N ancestor'ı olan bir klasör taşındığında N sorgu atılıyordu. Büyük ağaçlarda hem performans ayak tuzağı hem de slow-query DoS için potansiyel yoldu. Ancestor haritası artık tek sorguda yükleniyor (SELECT id, parent_id WHERE owner_type=? AND owner_id=?) ve walk in-memory, cycle-visited guard'ıyla yapılıyor. -
Folder create / rename / move artık unique-constraint ihlallerini yakalıyor.
CreateFolderAction,RenameFolderActionveMoveItemAction(owner_type, owner_id, parent_id, name)için check-then-act yapıyordu. Eş zamanlı iki istek exists kontrolünü eş anlı geçince, ikincisi temiz validation hatası yerine hamQueryException(500) veriyordu. Race pencere artık kapalı — her action SQL-state23000(veya MySQL 1062) yakalayıp localizedLogicExceptionfırlatıyor; controller'lar bunu zaten 422 +sk-file-manager.errors.duplicate_foldermesajına çeviriyor. Mevcut pre-checkparent_id=NULLsenaryosunu (MySQL/SQLite NULL'ı farklı saydığı için unique index korumuyor) korumak üzere duruyor. -
UserDatatableQueryartıkmediarelation'ını eager load ediyor.UserResource::$appendsavatar_urlaccessor'ını zorluyor, o da$user->getFirstMedia('avatar')çağırıyor. Datatable query yalnızcaroleseager load ettiği için her satır ayrı bir media lookup tetikliyordu (N+1).mediaartık eager load listesinde; per-page render1 + nsorgudan2'ye düştü. -
RoleController@datave@editartık$role->toArray()spread yerineRoleResourcekullanıyor. Spread eklemesi hızlı olmuştu ama projenin "response'lar bir Resource üzerinden geçer" konvansiyonunu kırıyor verolestablosuna eklenecek gelecekteki herhangi bir hassas kolonu otomatik yayınlayacaktı. YeniApp\Http\Resources\Admin\Role\RoleResourcealanları açıkça listeliyor (id,name,display_name,group,sort_order,guard_name,seeded_permissions, timestamps +permissionsyüklendiğinde conditional). Frontend payload şekli korundu. -
resources/js/pages/Admin/ApiRoutes/Index.vue: external link'erel="noopener noreferrer"eklendi. "Open API Docs" anchor'ıtarget="_blank"kullanıyor ama rel attribute'u eksikti. Projenin geri kalanıyla tutarlı hale getirildi. -
2FA disable confirmation dialog'u için eksik çeviriler.
sk-setting.auth.two_factor_disable_titlevesk-setting.auth.two_factor_disable_warninganahtarları Auth settings tab'ından referans ediliyordu ama lang dosyalarında tanımlı değildi. EN ve TR için eklendi.
Added
-
API test suite'i için Passport key otomatik üretimi.
tests/Pest.phpartıktests/Feature/Apiscope'una birbeforeEachhook'u kaydediyor —storage/oauth-private.keyeksiksepassport:keys --forceçalıştırıyor. Taze clone ve CI runner'lar artık Passport-destekli testler (AuthTest,UserTest) geçsin diyephp artisan site:installçalıştırmak zorunda değil — eski davranışleague/oauth2-servertarafından atılan anlaşılmaz birLogicException: Invalid key suppliedidi. -
tests/Feature/Domain/User/UserEventsTest.php. Yukarıdaki fix'in getirdiği event-dispatch sözleşmesini kilitler —UserCreatedcreate'te dispatch ediliyor,UserUpdatedsadece takip edilen en az bir alan değiştiğinde fırlıyor,UserDeletedbaşarılı silmede fırlıyor, self-delete guard false dispatch üretmiyor. -
tests/Feature/Admin/SettingsTest.php'ye logo upload/delete coverage'ı eklendi.POST /settings/logoüzerindeApiResponsezarfını (200 +data.logo_url) veDELETE /settings/logoüzerinde 204 sözleşmesini kilitliyor.
2026-04-18 — v13.3.0
Özellik sürümü — Cloudflare Turnstile, last-login takibi, dosya önizleme modalları, shipping edilen validation.php ve sk-* çeviri namespace'i
Geniş bir sürüm. Birkaç bağımsız yeni özellik ve çeviri katmanında mimari bir değişiklik.
Eklenen
-
Auth akışlarında Cloudflare Turnstile captcha. Login, register ve şifre sıfırlama formlarında artık bir Turnstile widget'ı (
resources/js/components/Auth/TurnstileWidget.vue) render ediliyor ve token sunucu tarafında doğrulanıyor. Shipping:turnstilemiddleware alias'ı (App\Http\Middleware\ValidateTurnstile), ad-hoc validasyon içinApp\Rules\TurnstileRule,App\Domain\Setting\DTOs\TurnstileSettingsDTO, ve Ayarlar → Turnstile admin sekmesi (site key / secret key UI üzerinden yönetiliyor). Kurulum bazlı açılıp kapatılıyor; feature kapalıysa widget'lar temiz şekilde short-circuit olur. -
Last-login takibi. Yeni
App\Listeners\UpdateLastLoginlistener'ıIlluminate\Auth\Events\Login'e bağlı: her başarılı girişte user'alast_login_atvelast_login_ipyazılıyor. Kullanıcı detay sayfasında ve users datatable'ında sıralanabilir kolon olarak görünür. -
Girişte pasif kullanıcı engeli.
App\Providers\FortifyServiceProviderartık authenticate olan kullanıcının status'üactivedeğilse login attempt'i reddediyor ve net bir hata dönüyor — session başlamıyor. Bir hesabı askıya almak için artık silmek gerekmiyor. -
FormBuilder.trans(bool). Her field builder'a eklenen yeni fluent method (FB.inputText(),FB.select(),FB.toggleSwitch(), …). Label'ın çeviri anahtarı olarak mı (varsayılan,true) yoksa önceden çevrilmiş raw string olarak mı (false) render edileceğini belirler. Script içindetrans('admin.example')gibi çevrilmiş bir değer vermek istediğinde işe yarar — normalde form template'i$t()'i tekrar çağırdığı için anahtar bulunamaz, fallback'e düşer..trans(false)ile template ikinci çeviri adımını atlar. Varsayılan davranış değişmedi; mevcut sayfalar hiç dokunmadan çalışmaya devam eder.FB.inputText().key('last_name'); // varsayılan — label → $t('validation.attributes.last_name') FB.inputText().key('x').label(trans('admin.example')).trans(false); // raw render, ikinci $t() çağrısı yok -
Uygulama içi dosya önizlemeleri (lightbox + modal). Yüklenen dosyalar — file manager'da ve her
FB.fileUpload()form alanında — thumbnail'a veya dosya adına tıklandığında artık yeni tarayıcı sekmesi açmıyor. Resimler tam ekran lightbox'ta açılıyor (Google Drive tarzı: bulanıklaştırılmış koyu arkaplan, ESC ile kapanır, isim sol üstte). Resim olmayan dosyalar (PDF, video, audio, text) mime-bazlı dialog'ta açılıyor; dialog doğru viewer'ı embed ediyor (iframe /<video>/<audio>), file manager tarafında "İndir" butonu ve tanınmayan formatlar için "Yeni sekmede aç" escape hatch'i var. Lightbox tek bir global overlay —AdminLayout'ta<AppDialog />yanına register ediliyor; modal ise mevcutuseDialogcomposable üzerinden açılanFilePreviewModalcomponent'i. -
Dosya Yöneticisi ayarlarında kategorize mime-type seçici. Ayarlar → Dosya Yöneticisi → Kabul edilen dosya türleri eskiden uzun bir multiselect dropdown'du. Artık kategorize kart-checkbox ızgarası (Görseller / Dokümanlar / Arşiv) — her seçenek eşleşen dosya tipi ikonuyla birlikte. Dropdown listesinden daha kolay taranıyor, tıklama alanı tüm kart, alfabetik sıra yerine mantıklı gruplama var.
-
"Video yükleme" ve "Ses yükleme" için feature-toggle kartları. Dosya Yöneticisi ayarlarındaki iki toggle, mime picker ile aynı kart estetiğini paylaşıyor — solda renkli ikon, ortada kalın başlık + kısa açıklama (örn. "MP4, WebM, MOV, MKV, AVI ve OGG video formatlarına izin ver."), sağda switch. Kartın herhangi bir yerine tıklamak toggle'ı çevirir.
-
lang/{en,tr}/validation.phpartık kit ile shipping ediliyor. Laravel'in default validation rule mesajları + hem Laravel validator'ının hem de FormBuilder / DatatableBuilder'ın kullandığıattributesvecustombölümleri..label()belirtilmediğinde FormBuilder ve DatatableBuilder, alan etiketinivalidation.attributes.{key}üzerinden otomatik çözer. Türkçe mesajlar Laravel-Lang/lang konvansiyonlarını takip ediyor. Tüketici uygulamalar bu dosyaları serbestçe düzenleyip yeni attribute label'ları ekleyebilir — özel bir translation loader'a ihtiyaç yok, her şey Laravel'in native translation sistemi üzerinden çalışıyor. -
Rol ismi lokalizasyonu — zarif bir fallback zinciri ile. Admin topbar / sidebar'da görünen (Inertia üzerinden
auth.roleolarak paylaşılan) rol etiketi artık üç adımda çözülüyor: önceroles.display_name[locale]veritabanından; sonraconfig('permission-resources.display_names.roles.{name}.{locale}')altındaki locale anahtarı; son olarak daStr::headline($role->name)— yani taze seed edilmişsystem_admingibi bir rol, hiçbir lokalize tanım yapılmamış olsa bile raw slug yerine "System Admin" olarak görünüyor.
Değişen — çeviriler sk-* namespace'ine taşındı
Shipping edilen her çeviri dosyası artık sk- dosya adı prefix'i taşıyor: sk-admin.php, sk-auth.php, sk-button.php, sk-datatable.php, sk-menu.php, sk-setting.php, sk-user.php, sk-attribute.php, sk-file-manager.php, sk-activity-log.php, … Shipping edilen tüm Vue sayfaları ve PHP kodu yeni anahtarları kullanıyor (__('sk-button.save'), eski __('button.save') yerine). Amaç: tüketici uygulamalar prefix'siz namespace'i özgürce sahiplensin (örn. lang/en/admin.php'yi starter kit menü metinleriyle çarpışmadan kendi dashboard string'leri için kullansın).
Kaldırılan
13.3 öncesi prefix'siz stub'lar — stubs/lang/{en,tr}/{admin,auth,button,common,datatable,enums,file-manager,message,pagination,passwords,validation}.php (21 dosya) — artık shipping edilmiyor. sk-* geçişinden sonra kit içinde hiçbir kod bunlara referans vermiyordu; taze kurulumlarda tutulması sadece kafa karıştırıyordu. Paket seviyesindeki starter-kit:: namespace'i dokunulmamış — __('starter-kit::admin.menu') çağrıları hâlâ çalışıyor.
Düzeltilen
-
"Video yükleme" açık olsa bile
.oggvideo ve.avidosyaları reddediliyordu. Upload request'inallow_video=truebranch'i yalnızcavideo/mp4,video/webm,video/quicktimevevideo/x-matroskamime'larını whitelist'liyordu.video/ogg,video/x-msvideovevideo/avieklendi; validation hata mesajlarındaki "İzinli tipler" listesine.OGVve.AVIuzantı etiketleri de eklendi. -
npm run buildüzerindeki gereksiz uyarılar susturuldu. Production build'den iki gürültülü uyarı temizlendi: (1)@tailwindcss/viteve@inertiajs/vitetarafından basılan "Sourcemap is likely to be incorrect" uyarıları — iki plugin de transform'dan sonra sourcemap'i yeniden üretmiyor, runtime etkilenmiyor — artıkvite.config.tsiçindeki odaklı bir Rolluponwarnhook'u ile filtreleniyor (diğer uyarılar olduğu gibi geçmeye devam ediyor); (2) shipping edilenSkDatatable.vueveFileManager.vueüzerinde çıkanresolveDirective imported but never useduyarısı — PrimeVue'nunv-tooltip/v-rippledirektifleri artık<script setup>bloğunda açıkça binding ediliyor (const vTooltip = Tooltip) ve template dinamik bir lookup yerine doğrudan referansa derleniyor.
13.2.x'ten yükseltme
sk:update hash-aware çalışır: dokunmadığın dosyalar yeni sürümle değiştirilir; düzenlediğin dosyalar skipped veya untracked olarak raporlanır ve dokunulmaz. 13.3'ün birkaç özellik dosyası — SettingsController, SettingsDefaultsQuery, FortifyServiceProvider, HandleInertiaRequests, AppServiceProvider ve yeni FormRequest sınıfları — büyük ihtimalle bu listede görünecek ve ilgilenilmesi gerekecek.
-
Önce neyin skip/untracked olduğuna bak:
php artisan sk:update --dry-run -
app/katmanında lokal özelleştirmen yoksa tüm dosyalar için paket sürümünü kabul et:php artisan sk:update --force -
Yeni çeviri dosyalarını elle kopyala (
sk:updatelang/'a dokunmaz):cp vendor/lvntr/laravel-starter-kit/stubs/lang/en/sk-*.php lang/en/ cp vendor/lvntr/laravel-starter-kit/stubs/lang/tr/sk-*.php lang/tr/ -
lang/en/altında öncekisk:install'dan kalmaadmin.php,auth.php, … varsa artık öksüzler. Paket onlara referans vermiyor; kendi__('admin.x')çağrılarını__('sk-admin.x')'e taşıdıktan sonra silebilirsin. -
npm run build— yeniTurnstileWidget.vueshipping edilen bir stub veLogin/Register/ForgotPasswordtarafından import ediliyor. Taze kurulumlar otomatik alır. Dosyayı henüz almamış mevcut kurulumlarda build şu hatayla patlıyor:Could not load resources/js/components/Auth/TurnstileWidget.vue;sk:updatedosyayı kopyalamış olmalı (mevcut dosya değil, yeni dosya), kopyalamamışsa şuradan al:vendor/lvntr/laravel-starter-kit/stubs/resources/js/components/Auth/TurnstileWidget.vue.
2026-04-16 — v13.2.9
npm run build — lang JSON çift import uyarısı giderildi
Tüketici projelerde npm run build her seferinde şu iki uyarıyı basıyordu:
(!) lang/php_en.json is dynamically imported by resources/js/app.ts but also statically imported by resources/js/app.ts, dynamic import will not move module into another chunk.
(!) lang/php_tr.json is dynamically imported ...
Sebep: resources/js/app.ts içindeki i18nVue resolve callback'i SSR ve client için iki ayrı import.meta.glob('../../lang/*.json', ...) çağrısı tutuyordu — biri eager: true (statik), diğeri normal (dinamik). Vite iki dalı da statik analiz ediyor, aynı dosyalar için hem statik hem dinamik import gördüğü için "dinamik dal ayrı chunk'a alınmayacak" diyordu. Dinamik dal aslında hiçbir kazanç sağlamıyordu çünkü dosyalar zaten statik bundle'daydı.
Tek eager glob'a indirildi, modül scope'una çıkarıldı, client'ta Promise.resolve() ile sarmalandı:
const langs = import.meta.glob<Record<string, string>>('../../lang/*.json', { eager: true });
const resolveLang = (lang: string) => langs[`../../lang/php_${lang}.json`];
app.use(i18nVue, {
resolve: ssr ? resolveLang : (lang: string) => Promise.resolve(resolveLang(lang)),
});
Lang JSON dosyaları küçük (birkaç KB) olduğu için statik bundling'in bundle boyutuna etkisi sıfıra yakın — uyarı kalıcı olarak kaybolurken davranış aynı kalıyor.
2026-04-16 — v13.2.8
Daha temiz ilk kurulumlar
Yeni kurulumlar artık gereksiz geliştirme kalıntıları ve gürültülü örnek veriler taşımıyor.
.env.exampletemizliği — tekrarlananDB_*satırları ve eski örnek veritabanı adı kaldırıldı. Dosya artık yalnızcayour_database,your_usernamegibi genel placeholder'ları tutuyor.- Frontend/kurulum temizliği — gerekli olmayan geliştirme odaklı frontend tooling kayıtları çıkarıldı; böylece
npm installdaha temiz bir başlangıç yapıyor. - Daha az proje karmaşası — yeni uygulamaya ait olmaması gereken yardımcı/tooling dosyaları artık gönderilmiyor.
2026-04-15 — v13.2.7
File manager upload — HTTP context'i için crypto.randomUUID fallback'i
File manager upload composable'ı, kuyruğa giren her dosya için crypto.randomUUID() ile geçici bir id üretiyordu. Bu API yalnızca secure context'te (HTTPS ya da localhost) tanımlı — dolayısıyla düz HTTP bir dev domain'inde çalışan tüketiciler (Herd'in .test'i, çıplak bir intranet IP'si vs.) TypeError: crypto.randomUUID is not a function alıyor ve upload ilk XHR atılmadan ölüyordu.
useFileManager artık üç kademeli fallback'e sahip lokal bir generateTempId() helper'ından geçiyor:
- Varsa
crypto.randomUUID()(HTTPS / localhost) crypto.getRandomValues(new Uint8Array(16))hex olarak seri hale getirilmiş (her modern tarayıcıda var, secure-context gerektirmez)- Son çare olarak
Date.now().toString(16)+Math.random().toString(16)
tempId yalnızca bir pending-upload satırını tamamlanma/hata callback'iyle eşleştirmek için kullanılıyor — kriptografik güce ihtiyaç yok, bu yüzden fallback güvenli.
Güvenlik başlıkları — geolocation kendi kaynağından izinli
SecurityHeaders middleware'indeki Permissions-Policy geolocation=() idi (tamamen reddediliyordu). geolocation=(self) olarak değiştirildi; böylece first-party script'ler meşru bir ihtiyaç olduğunda geolocation isteyebiliyor — üçüncü taraf frame'ler hâlâ bloklanıyor.
2026-04-15 — v13.2.6
File manager validation mesajları — okunabilir, lokalize, dosya adıyla
File manager'da sunucu reddi durumunda toast'lar artık gerçekten görünüyor ve Laravel'in ham files.0 field must be a file of type: image/webp mesajı yerine anlamlı bir Türkçe mesaj taşıyor.
- Toast group bug fix —
FileManager.vueiçindeki tümtoast.add()çağrılarınagroup: 'bc'eklendi. OrtakToastComponentgroup="bc"ile mount edildiği için bu anahtar olmadan gönderilen toast'lar sessizce düşüyordu. Klasör oluştur/yeniden adlandır/sil/taşı ve dosya yükleme (başarı + hata) toast'ları artık tekrar görünüyor. - Sunucu hata mesajı çıkarımı — Upload XHR önceden 422 cevabında sadece
envelope.message("Validation error.") okuyordu. Composable artıkenvelope.errors'u dolaşıp ilk alan-bazlı mesajı çıkarıyor; toast asıl gerekçeyi taşıyor. - Dosya başına anlamlı validation mesajı —
UploadFileRequestattributes()vemessages()metodlarını override ediyor. Herfiles.{i}slot'u dosyanıngetClientOriginalName()'ine bağlı (toastfiles.0yerinevacation.jpg yüklenemedi: …diyor). Mimetypes / max-size hataları okunabilir uzantı listesi (İzinli tipler: WEBP, PDF, JPG, …) ve insanca boyut limiti (en fazla 10 MB) ile çevrildi. - Çeviri anahtarları —
errors.upload_invalid_type,errors.upload_too_large,errors.upload_invalid_filelang/{en,tr}/file-manager.php'ye eklendi.
İki yeni feature testi mesajları kapsıyor: orijinal dosya adı kontrolü ve okunabilir boyut limiti. File manager + install + publish suite'leri tamamen yeşil (22/22 + 11/11).
Helpers yeniden organize — vendor-owned core, user-owned custom, publishable override
to_api() ve format_date() (artı iki yeni helper — aşağıda) artık paket vendor'undan geliyor ve otomatik autoload ediliyor. Son kullanıcı uygulamaları to_api kopyasını app/ altında tutmuyor — bu da her sk:update'te ortaya çıkan merge baş ağrısını ortadan kaldırıyor.
vendor/lvntr/laravel-starter-kit/src/sk-helpers.phpkanonik konum. Paketincomposer.jsonautoload.files'ı üzerinden register ediliyor;composer requireile birlikte helper'lar anında geliyor.app/Helpers/custom.phpson kullanıcı uygulamasına ilk install'da basılıyor, app'incomposer.jsonautoload.files'ına ekleniyor vesk:updateile asla üzerine yazılmıyor. Kullanıcının kendi global helper'ları buraya yazılır.app/helpers.phpdeprecated.sk:updatemevcut dosyanın md5'ini bilinen stock hash listesiyle karşılaştırıyor; eşleşirse dosya sessizce siliniyor. Kullanıcı kendi fonksiyonlarını eklediyse dosya konsol uyarısıyla yerinde bırakılıyor — kullanıcı kodu korunuyor.composer.jsonautoload entry'si yalnızca dosya gerçekten silinince yeniden yazılıyor; sessizce kullanıcı kodu kırılmıyor.- İki yeni helper —
definition($key, $value)DefinitionService'ten eşleşen definition kaydını (object) döndürüyor;definitionLabel($key, $value)onunlabel'ını döndürüyor. Enum-style değerleri görüntülenecek string'e çevirirken her çağrıda definition listesini tekrar çekmeden işe yarıyor.
sk:publish --tag=helpers — paket helper'larını fork etmeden override et
Yeni bir tag sk-helpers.php'yi publish komutuna açıyor. Publish sonrası dosya app/Helpers/sk-helpers.php'ye iniyor, kullanıcı serbestçe düzenleyebiliyor.
Vendor dosyası autoload anında published kopyayı tespit edip require_once ile route ediyor:
$skPublishedHelpers = dirname(__DIR__, 4).'/app/Helpers/sk-helpers.php';
if (is_file($skPublishedHelpers) && realpath($skPublishedHelpers) !== realpath(__FILE__)) {
require_once $skPublishedHelpers;
return;
}
Realpath guard, dosya published kopya olarak yüklendiğinde self-recursion'ı engelliyor. composer.json değişikliğine gerek yok — composer autoload yine vendor dosyasını tetikliyor, o da kullanıcı dosyasına delegate ediyor. Published dosya silindiğinde anında vendor implementasyonuna geri dönülüyor.
sk:publish interaktif prompt'una dördüncü seçenek geldi: Global Helpers (sk-helpers.php).
2026-04-14 — v13.2.4
Tip güvenliği turu — vue-tsc ve ESLint sıfır uyarı
Starter kit kaynak kodu artık vue-tsc --noEmit ve eslint 'resources/js/**/*.{ts,vue}' altında 0 hata / 0 uyarı ile geçiyor. Davranışta değişiklik yok, tamamen tip ve lint temizliği.
- tsconfig tekilleştirme — tip tarama yolları sadeleştirildi; aynı UI kaynakları artık iki kez taranmıyor. Böylece lokal geliştirmede kafa karıştıran duplicate hatalar kaldırıldı.
- Vite
Componentsplugin tek kaynak —dirsartık yalnızcaresources/js/componentstarıyor; paket yolu kaldırıldı. Auto-generatedcomponents.d.tsartık source yollarına referans veriyor. - SkDatatable filter tipleri genişletildi —
activeFilterstipistring | number | Date | (Date | null)[] | nullile tekFilterValuealias'ı üzerine oturtuldu. DatePicker kullanımlarıv-model→:model-value+@update:model-valueile güvenli cast'lere dönüştürüldü;select,select-button,date,daterangefiltrelerinin her biri kendi tipinde çalışıyor. - Tag icon / pagination i18n fix'leri —
:iconifadesi?? undefinedile null sızmasını kapatıyor,datatable.records_infoçevirisine geçilenfrom/to/totalparametreleri artıkString(... ?? 0)ile zaten beklenenstringtipine uyuyor. SharedPagePropsindex signature —PagePropsconstraint'ini karşılayacak şekilde[key: string]: unknowneklendi.useCan()artıkusePage<SharedPageProps>()generic'iyle temiz derleniyor.env.d.tsauth şekli gerçekle hizalandı — InertiasharedPageProps.authartık{ user, role, role_names, permissions }tutuyor; AdminHeader'dakipage.props.auth?.roleokuması ve benzerleri doğru tiplerle resolve oluyor.appEnv,appDebug,locale,availableLocalesda tiplenmiş şekilde shared prop'larda.- Küçük prop / cast düzeltmeleri —
RoleForm.vueWayfinderupdate.url({ id })şeklinde çağrılıyor (optionalid'yi narrowing ile geçiyor),Settings/Index.vuegeneraltipinelogo_url: string | nulleklendi,Dashboard/Index.vueselamlamadauser?.nameyerine mevcut alan olanuser?.first_namekullanıyor, Inertia v3'te zaten default olanpreserveScroll: trueopsiyonurouter.reload()çağrılarından kaldırıldı. - ESLint uyarıları —
SkDatatableiçindekiv-htmlgerekçeli disable-next-line yorumuyla işaretlendi (render string'i author-tanımlı ve escapeHtml helper'ı sunuluyor).Breadcrumb.rootLabel,FileGrid.emptyLabelveSkTag.{value,icon,color,severity}prop'larınawithDefaultsile default değerler verildi.
Mevcut uygulamalar için aksiyon gerekmiyor — değişiklikler davranışsal değil, tip/lint düzeyinde.
2026-04-14 — v13.2.3
Installer DX — AST tabanlı enjeksiyon, bootstrap helper, preset uyarıları
Fresh bir Laravel üzerinde composer require lvntr/laravel-starter-kit akışını daha güvenli ve daha az invaziv hale getiren installer/upgrade ergonomi turu.
- AST tabanlı config enjeksiyonu —
sk:installartıkconfig/app.php,config/filesystems.phpveconfig/media-library.php'yinikic/php-parserile format-preserving pretty print kullanarak düzenliyor. Regex tabanlı patch kaldırıldı; farklı Laravel config formatlarına toleranslı ve tamamen idempotent (bir kere inject edildikten sonrask:install'ı tekrar çalıştırmak no-op). - Bootstrap helper sadeleştirmesi — middleware ve exception wiring'i tek bir ortak bootstrap helper üzerinden akıyor; bu da kurulum ve güncelleme davranışını daha öngörülebilir hale getiriyor.
bootstrap/app.phpartık ezilmiyor — stub kopyası kaldırıldı. Bunun yerine installer kullanıcının mevcut Laravel default dosyasına sadece üç satır AST-inject ediyor:withRouting(...)içineapi: __DIR__.'/../routes/api.php',withMiddleware/withExceptionsclosure'larına iseBootstrap::middleware(...)/Bootstrap::exceptions(...)çağrıları. Kullanıcının eklediği middleware, trusted proxies, custom exception reporter vs. korunuyor.bootstrap/providers.phpartık ezilmiyor — installer array'eDomainServiceProvider,FortifyServiceProvider,SettingsServiceProviderekliyor (idempotent, zaten kayıtlı olanları atlıyor); kullanıcının mevcut provider'larına dokunmuyor.package.jsonJSON-merge — blind overwrite yerine akıllı merge: ortak dependency'lerde stub versiyonu kazanıyor, kullanıcının eklediği dep/script/workspace/root-level key'ler korunuyor.- Lang dosyaları için first-install tespiti —
lang/*re-install'da hâlâ preservable (customization kaybolmaz), ama gerçek ilk install'da (hash registry yok) installer artık force-copy yapıyor; böylece fresh projeler Laravel'in cılız default lang dosyalarıyla kalmıyor ve starter kit UI eksik çeviri göstermiyor. - Ölü kod temizliği — aktif akışın parçası olmayan eski
IdentityTypeveYesNoenum'ları yeni kurulumlardan ve güncelleme akışından çıkarıldı. - IdeHelper temizliği — yeni kurulumlarda
AppServiceProviderartık gereksizclass_exists(IdeHelperServiceProvider::class)kontrolünü taşımıyor. - Açık
nikic/php-parser ^5.0bağımlılığı — Tinker üzerinden dolaylı yoldan zaten kuruluydu, şimdi pakete direkt dep olarak eklendi. - "Bare Laravel" kurulum uyarısı — README (EN/TR) ve install.md / install.tr.md en üstte uyarıyla açılıyor: starter kit'ten önce
install:inertia,install:api, Breeze, Jetstream veya benzeri preset'leri çalıştırmayın — preset'ler starter kit'in de yayınladığı controller/route/sayfa/layout'ları oluşturur, installer bunları tespit edemez ve yetim "ölü kod" olarak kalırlar. - Testler — 12 yeni
InstallCommandTestsenaryosu: AST config enjeksiyonu (üç dosya için), idempotency, format/yorum koruma,package.jsonmerge, first-install tespiti, bootstrap app/providers AST enjeksiyonu + user-code koruma. Toplam installer test suite 20/20 yeşil.
Mevcut kurulumlar için aksiyon gerekmiyor — installer tarafındaki tüm değişiklikler geriye dönük uyumlu, first-install tespiti ya da idempotent guard'larla korunuyor.
2026-04-14 — v13.2.2
FileManager — ContextRegistry ile pluggable context'ler
FileManager artık user / global ile sınırlı değil. Her Eloquent model'i klasör ağacına sahip olabilir; service provider'a tek satır bile yazmadan.
- Yeni
ContextRegistryservisi (app/Domain/FileManager/Support/) bir context anahtarını üç adımda çözer: explicitregister()→ Laravel morph-map alias →App\Models\{Studly(key)}convention fallback. Tanımsız anahtar yine validation üzerinden 422 döner. - Sıfır-konfig custom context — model class'ı + karşılığında bir policy (
view/update) yeterli:<FileManager context="vehicle" :context-id="vehicle.id" height="100%" /> globalregistry içine gömüldü — öncedenAppServiceProvider::boot()'ta duran kayıt artıkContextRegistryconstructor'ında. Starter kit'i adopt ederken FileManager için boot-time kurulum gerekmez.AppServiceProvidersadece singleton binding yapıyor.usertamamen auto-resolve —App\Models\Userconvention + yeni paketle gelenapp/Policies/UserPolicy.php(self +users.read/users.update).useriçin explicit kayıt kaldırıldı, yetki policy'ye taşındı.- Self-match kısa yollu default authorizer — auto-resolve edilen context'lerde actor kendi kaydına dokunuyorsa (actor IS owner) otomatik izin. Diğer istekler Laravel policy'lerine delegate: okuma
can('view', $owner), yazmacan('update', $owner). - MorphMap uyumu —
FileManagerContextDTOartıkownerType'ı$owner->getMorphClass()ile saklıyor; model morph-map alias'ı olsa bile query ve path üretimi tutarlı. - Runtime-driven validation —
FileManagerRequestsabitin:user,globalkuralı yerine çalışma anındaContextRegistry'ye soran bir closure kullanıyor. Yeni context tanımlamak için hiçbir Request dosyası güncellenmiyor;context_idyalnızca kayıtlı path'te{id}varsa zorunlu. - Custom key'ler için frontend tip gevşemesi —
FileManagerContextartık'user' | 'global' | (string & {}).<FileManager context="vehicle" />tamamen tip-güvenli, built-in anahtarlarda autocomplete kaybolmuyor. - Upload dayanıklılığı —
UploadFileRequest,file_manager.accepted_mimesayarı seed edilmemiş fresh install'larda makul bir MIME listesine (image / pdf / office / text) fallback ediyor; "file must be of type: ." 422 hatası yok. - Testler — yeni
CustomContextTestdosyası: explicit register, path override, folder listing, tanımsız-context reject ve morph-map auto-resolve. 26/26 FileManager testi geçiyor. - Doküman — file-manager.tr.md "Özel (custom) context'ler" bölümü aldı: çözüm sırası, zero-config walkthrough,
VehiclePolicyörneği, contract tablosu ve override rehberi.
2026-04-14 — v13.2.1
FileManager — UX rötuşları ve takip iyileştirmeleri
13.2.0 sürümünün ardından gerçek kullanımdan çıkan bir iyileştirme turu eklendi:
- Önizleme modalı — dosya tile'ına tek tık veya sağ tık Aç artık 90vw'lik bir modal açıyor; resim, PDF, video, ses ve metin dosyaları inline preview; diğer tipler için "Yeni sekmede aç" + "İndir" aksiyonları.
- Tile bazlı yükleme progress'i — her dosya ayrı XHR ile yükleniyor; grid'de optimistic placeholder tile üstünde dolan progress bar gösteriliyor. Başarısız yüklemeler dismissable hata tile'ı olarak kalıyor; başarılı olanlar liste yenilendiğinde yerine geçiyor. Toolbar Upload butonu toplu yükleme sırasında spinner'a dönüyor.
- Drag-and-drop taşıma — tile'lar
draggable; bir klasör tile'ına bırakılınca seçili tüm öğeler hedef klasöre taşınıyor. External (OS) dosya sürüklemesiFilesdata-transfer tipi üzerinden ayırt ediliyor — internal drag artık upload overlay'ini tetiklemiyor. - Klasör ağacı picker'lı Move modalı — folder ve file context menülerinde Taşı aksiyonu; açılan dialog'ta
FolderTreeile hedef klasör seçiliyor. Tek ve çoklu seçim destekleniyor. - Busy overlay (modal kart) — Sil / Taşı / Yeniden Adlandır operasyonlarında FileManager alanının üstüne beyaz modal kart (spinner + başlık + açıklama) çıkıyor; toplu operasyonlarda "N öğe kaldı" canlı sayaç + Durdur butonuyla döngü iptal ediliyor.
- Her zaman görünür seçim checkbox'ı — her folder/file tile'ının sağ üstünde primary-dolu seçili / outline hover-opaq çıkan checkbox var. Klasörlere çift tıkla aç davranışı geri geldi; tek tık sadece seçer. Dosyalar tek tıkla preview'a gidiyor. Tile üstündeki 3-nokta menüler kaldırıldı — sağ tık tek giriş noktası.
- Sağ tık artık zorla seçmiyor — seçili olmayan bir tile'a sağ tık mevcut seçimi bozmuyor; bulk aksiyonlar sadece sağ tık yapılan öğe zaten seçimdeyse tetikleniyor.
- Klavye kısayolları —
Ctrl/Cmd + Amevcut klasörün tümünü seçer,Delete/Backspaceseçimi siler (confirm'lü),Escseçimi temizler. Input içindeyken veya dialog açıkken tetiklenmiyor. - Breadcrumb yeniden tasarlandı — PrimeVue breadcrumb yerine chip/pill stil crumb'lar, arada chevron, konum info bar'ın altına alındı. Uzun klasör isimleri
maxChars(default 18) ile kesiliyor,…ile. Tam adtitletooltip'inde. - Başlıkta mevcut klasör + geri butonu — sol folder tree kaldırıldı (sadece Move picker'da kullanılıyor). Ana alan artık klasör ikonu + mevcut klasör adı; root değilken sol tarafta
←butonu. - Boş klasör illüstrasyonu — boş klasörlerde büyük outline folder SVG'si + başlık + iki satır ipucu ("Sürükle bırak / Yükle" ve "Yeni Klasör").
- Info bar'da aggregate istatistik — dosya sayısı + toplam boyut artık mevcut klasörün tüm alt ağacını tarıyor; yalnızca o klasörün direkt dosyalarını değil.
- Diskler arası download —
DownloadFileActionStorage::disk($media->disk)->download(...)kullanıyor; local, S3 ve DigitalOcean Spaces için aynı şekilde çalışıyor. - Context menu yeniden stillendi — beyaz rounded kart, daha büyük item padding, folder ve file menülerinde Sil'den önce separator.
- Sıralama yönü tooltip'i — asc/desc toggle butonunda dinamik PrimeVue tooltip'i ("Artan sıralama · Azaltana geç" / EN). Yan etki olarak
Tooltipdirective'iapp.ts'de global kaydedildi. - Footer kredisi —
AdminFootersağda Crafted with Lvntr Starter Kit linki (lvntr.dev'e bağlı).
Güncellenmiş kullanım, prop ve composable çıktıları için file-manager.tr.md.
2026-04-14 — v13.2.0
FileManager — dosya yöneticisi modülü
Yeni bir FileManager modülü eklendi: Windows Explorer tarzı bir UI ile kullanıcı-bazlı veya global dosyalar için tam kapsamlı dosya yönetimi.
- Nested klasörler — oluştur, yeniden adlandır, taşı, cascade sil
- Çoklu dosya yükleme — drag & drop veya butonla
- Seçim — tek tık,
Ctrl/Cmd + tık, kauçuk-bant (rubber-band) fare ile toplu seçim - Toplu silme — toolbar butonu veya seçili öğeye sağ tık
- Sıralama — isim / boyut / tarih + asc/desc
- Türe göre önizleme — resim thumbnail + PDF/Word/Excel/Video/Ses/Arşiv için renk kodlu simgeler
- Bilgi çubuğu — mevcut klasörün dosya sayısı ve toplam boyutu
- Context menüler — klasör/dosya/boş alan için ayrı aksiyonlar (Yeni Klasör, Yükle, Tümünü Seç, Yenile)
Eklenen sayfalar: ana menüde Dosyalar, Admin > Kullanıcılar > Düzenle sayfasında Dosyalar tab'ı. Maksimum dosya boyutu, kabul edilen MIME tipleri ve video/ses toggle'ları Admin > Ayarlar > Dosya Yöneticisi altından yapılandırılabilir.
Depolama: user/{id}/files/{uuid}/... ve global/files/{uuid}/... — klasör taşıma tamamen mantıksal, fiziksel dosya hareketi yok.
Kullanım ve API detayları için file-manager.tr.md.
2026-04-13 — v13.1.10
FormBuilder — stale form reset düzeltmesi
FB ile oluşturulan formlarda, Inertia back() navigasyonu veya formConfig'in yeniden hesaplanmasına yol açan herhangi bir page.props tazelenmesi sonrasında formun sessizce eski (stale) remote data'ya resetlenmesine yol açan hata düzeltildi. İç SkForm artık yeni türetilmiş default değerleri öncekilerle shallow-karşılaştırır ve değerler aynıysa reset'i atlar — böylece kullanıcının devam eden düzenlemeleri korunur.
Etkilenen: config'i page.props'a bağımlı olan tüm FB formları (örn. koşullu isFieldsLocked, isSelf, auth'a göre alan görünürlüğü). API değişikliği yok — mevcut formlar otomatik olarak yararlanır.
2026-04-13 — v13.1.8
FormBuilder — ColorSelector çıktı formatı
FB.colorSelector() artık .format() ve .defaultTone() ile yapılandırılabilir çıktı formatlarını destekliyor:
format('name')(varsayılan) →"blue"kaydederformat('name-tone')→"blue-500"kaydederformat('hex')→"#3b82f6"kaydeder
'name-tone' ve 'hex' formatlarında dropdown'un altında tıklanabilir bir tone seçici çıkar; seçilen değer tone pill'lerinin yanında gösterilir. Modele başlangıçta bir hex string geldiğinde, component Tailwind paletinde ters arama yaparak eşleşen renk + tone seçimini geri yükler.
Detaylar için formbuilder.tr.md.