From d59d1009e74615f7db07ebafa7bd03eb67692225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Fri, 20 Jun 2025 15:38:59 +0300 Subject: [PATCH] =?UTF-8?q?Blog=20sistemindeki=20g=C3=BCncellemeler3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Seeds/SeederData.json | 12 +- .../EntityFrameworkCore/PlatformDbContext.cs | 2 - company/.env | 1 + company/.env.dev | 1 + company/.env.production | 1 + company/package-lock.json | 135 +++++++----------- company/package.json | 1 + company/src/pages/BlogDetail.tsx | 4 +- company/src/services/api/auth.service.ts | 15 ++ company/src/store/authStore.ts | 28 ++-- company/src/vite-env.d.ts | 1 + company/tailwind.config.js | 4 +- ui/src/views/blog/BlogManagement.tsx | 18 ++- ui/src/views/forum/ForumManagement.tsx | 78 +++++----- 14 files changed, 161 insertions(+), 140 deletions(-) diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json index 7a177960..287ec336 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json @@ -20090,7 +20090,7 @@ "TenantId": null, "Title": "blog.posts.ai.title", "Slug": "ai-ve-gelecegi", - "Content": "Yapay zeka günümüzün en hızlı gelişen teknolojilerinden biridir.\nAkıllı asistanlardan otonom araçlara kadar pek çok alanda kullanılmaktadır.\nEtik sorunlar da beraberinde gelmektedir.", + "Content": "

Yapay zeka (YZ), yalnızca teknoloji dünyasının değil; üretimden finansa, sağlıktan eğitime, perakendeden hukuk sektörüne kadar birçok alanın dönüşümünü tetikleyen en güçlü araçlardan biri haline geldi. Son yıllarda yapay zekanın iş dünyasındaki etkisi, yalnızca verimliliği artırmakla kalmıyor; karar alma mekanizmalarını değiştiriyor, yeni iş modellerini mümkün kılıyor ve organizasyonel yapıların yeniden tasarlanmasını sağlıyor.

2020’li yıllarla birlikte, 'Yapay Zeka' kavramı yalnızca araştırma laboratuvarlarının değil, CEO'ların, yöneticilerin, girişimcilerin ve KOBİ’lerin gündemine girdi. Ancak bu hızlı gelişim, bazı etik ve sosyal sorumluluk konularını da beraberinde getiriyor. Bu yazıda, yapay zekanın iş dünyasındaki kullanım alanlarını, sunduğu fırsatları, karşılaşılan zorlukları ve çözülmesi gereken etik meseleleri detaylı şekilde ele alacağız.

🚀 İş Dünyasında Yapay Zeka: Neden Bu Kadar Önemli?

Yapay zeka sistemleri; büyük veri setlerini analiz ederek, kalıpları tanıyarak ve tahminlerde bulunarak işletmelere hızlı ve doğru karar alma fırsatı sunar. Bu durum, insan hatasını azaltırken, operasyonel süreçlerde zaman ve maliyet tasarrufu sağlar.

📈 YZ'nin Kurumsal Faydaları:

🧠 YZ'nin İşlevsel Kullanım Alanları

🏭 1. Üretim ve Lojistik

💰 2. Finans ve Bankacılık

🛒 3. Perakende ve E-Ticaret

👩‍⚕️ 4. Sağlık

🧾 5. İnsan Kaynakları ve İK Analitiği

🌐 YZ’nin Getirdiği Yeni İş Modelleri

⚖️ YZ ve Etik: Geleceği Belirleyen Soru İşaretleri

Her teknolojik ilerleme, yeni sorumlulukları da beraberinde getirir. Yapay zekanın iş dünyasında yaygınlaşması ile birlikte birçok etik tartışma gündeme gelmiştir.

🔍 Başlıca Etik Sorunlar:

🌱 Kurumlar Ne Yapmalı?

👥 İnsan ve Yapay Zeka: Rekabet mi? İşbirliği mi?

YZ’nin insanlar yerine geçtiği değil, insanla birlikte çalıştığı senaryolar her geçen gün daha değerli hale geliyor. Bu bağlamda 'human-in-the-loop' ve 'augmented intelligence' (tamamlayıcı zekâ) yaklaşımları öne çıkıyor.

💡 İnsanlar strateji, empati ve yaratıcılıkta güçlüdür. Yapay zeka ise hız, hesaplama ve analizde. İkisini birlikte kullanmak rekabet avantajı yaratır.

📌 YZ’ye Hazır Olmak İçin Kurumların Atması Gereken Adımlar

  1. YZ Stratejisi Oluşturun: Hangi süreçlerde yapay zekadan fayda sağlanabileceğini belirleyin.
  2. Veri Kalitesine Yatırım Yapın: AI, kaliteli veri ile beslenir.
  3. İçeriden Yetkinlik Geliştirin: Veri bilimciler, ML mühendisleri ve etik uzmanları yetiştirin.
  4. Pilot Projeler Başlatın: Düşük riskli alanlarda başlayarak öğrenme sürecini başlatın.
  5. Etik ve Hukuki Uyum Süreçlerini Tanımlayın.

Sonuç: Yapay Zeka, Geleceğin Değil; Bugünün Gerçeği

Yapay zekâ artık sadece büyük teknoloji şirketlerinin değil, her ölçekteki işletmenin gündeminde yer almalıdır. Karar süreçlerini hızlandırmak, müşteriyi daha iyi tanımak, rekabette öne geçmek için YZ bir lüks değil, stratejik zorunluluk haline gelmiştir. Ancak bu gücün etik, şeffaf ve sorumlu şekilde kullanılması, geleceğimizi şekillendirmede belirleyici olacaktır.

Unutmayın: Yapay zeka, yalnızca bir teknoloji değil; yeni bir iş yapma biçimidir.

", "ReadTime": "5 dk", "Summary": "blog.posts.ai.excerpt", "CoverImage": "https://images.pexels.com/photos/8386434/pexels-photo-8386434.jpeg?auto=compress&cs=tinysrgb&w=1920", @@ -20102,7 +20102,7 @@ "TenantId": null, "Title": "blog.posts.web.title", "Slug": "web-gelistirmede-son-trendler", - "Content": "Web geliştirme dünyası sürekli bir değişim ve evrim içinde. Her yıl yeni teknolojiler, frameworkler ve yaklaşımlar ortaya çıkıyor, bu da web geliştiricilerinin sürekli öğrenmesini ve adapte olmasını gerektiriyor. 2024 yılı da bu açıdan farklı değil; heyecan verici yeni trendler ve gelişmeler web ekosistemini şekillendiriyor.\n\nBu yılın öne çıkan trendlerinden biri Serverless mimarilerin yükselişi. Geliştiricilerin sunucu yönetimiyle uğraşmadan uygulama geliştirmesine olanak tanıyan Serverless, maliyet etkinliği ve ölçeklenebilirlik gibi avantajlar sunuyor. Bir diğer önemli trend ise WebAssembly (Wasm). Web tarayıcılarında yüksek performanslı kod çalıştırmayı mümkün kılan Wasm, oyunlar, video düzenleyiciler ve CAD yazılımları gibi daha karmaşık uygulamaların web'e taşınmasını sağlıyor.\n\nMikro ön uçlar da büyük ölçekli web uygulamalarının yönetimini kolaylaştıran bir mimari desen olarak popülerlik kazanıyor. Bu yaklaşım, büyük ön uç projelerini daha küçük, bağımsız parçalara ayırarak farklı ekiplerin aynı proje üzerinde paralel çalışmasına imkan tanıyor. Bu blog yazısında, bu ve benzeri web geliştirme trendlerini daha detaylı inceleyerek, geleceğin web uygulamalarını şekillendiren teknolojilere derinlemesine bir bakış sunacağız.", + "Content": "

Web teknolojileri, dijital dünyanın kalbinde yer almaya devam ediyor. 1990'ların basit HTML sayfalarından günümüzün dinamik, gerçek zamanlı ve yapay zekâ destekli web uygulamalarına kadar uzanan bu yolculuk, her yıl yeni paradigmalar, araçlar ve yaklaşımlar ortaya koyuyor. 2024 itibarıyla web geliştirme alanında yaşanan dönüşüm, yalnızca geliştiriciler için değil, ürün sahipleri, tasarımcılar ve iş dünyası için de oyunun kurallarını yeniden yazıyor.

Bu yazıda; Serverless mimari, WebAssembly, mikro ön yüzler, edge computing, yapay zekâ destekli geliştirme, Progressive Web Apps (PWA), modern frontend framework gelişmeleri ve daha fazlasını içeren kapsamlı bir trend analizine yer vereceğiz.

☁️ 1. Serverless Mimarilerin Yükselişi

Serverless (sunucusuz mimari), geliştiricilerin altyapı yönetimiyle uğraşmadan, sadece işlev (function) bazlı geliştirme yapmasına olanak tanır. Sunucular elbette vardır, ancak bu sunucuların kurulumu, ölçeklenmesi ve yönetimi bulut sağlayıcılar tarafından yapılır.

🚀 Öne Çıkan Faydalar:

🔧 Popüler Serverless Platformlar:

⚙️ 2. WebAssembly (Wasm): Tarayıcıda Performans Devrimi

WebAssembly, C/C++, Rust, Go gibi dillerde yazılan kodların tarayıcıda neredeyse yerel hızda çalıştırılmasını sağlar. JavaScript’in sınırlarını zorlayan uygulamalar (video düzenleme, oyun, CAD, 3D modelleme) artık web üzerinde kullanılabilir hale geliyor.

🎯 Kullanım Senaryoları:

🔥 Neden Önemli?

Wasm sayesinde web yalnızca formlar ve içerik sunan bir platform değil; yüksek performanslı uygulamalar için gerçek bir çalışma ortamı haline geliyor.

🧩 3. Mikro Ön Uç Mimarileri

Micro Frontends, monolitik frontend yapılarının yönetimini kolaylaştırmak için ortaya çıkmış modern bir yaklaşımdır. Her ekip kendi bileşenini bağımsız geliştirip dağıtabilir.

📦 Faydaları:

📚 Uygulama Teknikleri:

🛰️ 4. Edge Computing ile Daha Hızlı Web Deneyimi

Web içerikleri, CDN’lerin ötesine geçerek doğrudan uç noktalarda (edge) işlenmeye başladı. Bu yaklaşım, sunucuya ulaşma süresini minimuma indirerek milisaniyelik farklarla daha hızlı uygulamalar ortaya çıkarır.

⚙️ Edge Bileşenleri:

🤖 5. AI Destekli Web Geliştirme

Yapay zekâ, artık sadece kullanıcıya sunduğunuz deneyimi değil, doğrudan geliştirme sürecini de dönüştürüyor.

💡 Kullanım Alanları:

📲 6. Progressive Web Apps (PWA): Uygulama Gibi Web

PWA’lar, tarayıcıdan erişilen ama mobil uygulama gibi çalışan web uygulamalarıdır.

Özellikleri:

Kullanım Alanı:

🧪 7. Modern JavaScript Framework Gelişmeleri

🔹 React (Server Components + RSC)

React, sunucu taraflı bileşenlerle (RSC) artık daha az JS yükleyerek SEO ve performans sorunlarını çözmeye yöneliyor.

🔹 Vue 3 + Vite

Composition API, reactive sistem ve Vite entegrasyonu ile Vue 3, performans ve geliştirici deneyimi açısından büyük atılım yaptı.

🔹 Svelte ve SvelteKit

Compile-time çalışan Svelte, JS bundle boyutlarını azaltarak son kullanıcıya neredeyse anında sayfa yükleme deneyimi sunar.

🔹 Astro

'Island Architecture' yaklaşımıyla yalnızca etkileşimli alanlara JS yükler, geri kalanı statik tutar.

🧱 8. Yeni Nesil CSS: Utility-First, CSS-in-JS ve Tailwind Ekosistemi

🔐 9. Web Güvenliği Trendleri

🧠 10. Geliştirici Deneyimini Arttıran Araçlar

🔚 Sonuç: Geleceğe Hazır Web Geliştirici Olmak

2024’ün öne çıkan web geliştirme trendleri, yalnızca araçlarla ilgili değil; aynı zamanda yaklaşım ve mimari farkındalıkla da ilgilidir. Web geliştirici olarak yalnızca bir framework’ü öğrenmek değil, neden o teknolojiyi seçtiğinizi bilmek, yazılım kalitenizi ve uzun vadeli sürdürülebilirliği belirler.

Geleceğin web dünyasında yer almak için:


", "ReadTime": "7 dk", "Summary": "blog.posts.web.excerpt", "CoverImage": "https://images.pexels.com/photos/11035471/pexels-photo-11035471.jpeg?auto=compress&cs=tinysrgb&w=1920", @@ -20114,7 +20114,7 @@ "TenantId": null, "Title": "blog.posts.security.title", "Slug": "siber-guvenlik-tehditleri-ve-korunma-yollari", - "Content": "Dijitalleşmenin hızla artmasıyla birlikte, siber güvenlik tehditlerinin sayısı ve karmaşıklığı da eş zamanlı olarak artmaktadır. Artık sadece büyük şirketler değil, bireyler ve küçük işletmeler de siber saldırganların hedefi haline gelmiştir. Kişisel verilerin çalınması, kimlik avı (phishing) saldırıları, fidye yazılımları (ransomware) ve dağıtılmış hizmet engelleme (DDoS) saldırıları gibi tehditler, hem maddi hem de manevi zararlara yol açabilmektedir.\n\nBu tehditlere karşı korunmak, dijital dünyada güvende kalmak için hayati öneme sahiptir. Güçlü ve benzersiz şifreler kullanmak, iki faktörlü kimlik doğrulama yöntemlerini benimsemek ve yazılımlarımızı düzenli olarak güncellemek, alabileceğimiz temel önlemler arasındadır. Ayrıca, bilinmeyen kaynaklardan gelen e-postalara ve linklere karşı dikkatli olmak, halka açık Wi-Fi ağlarında hassas işlemler yapmaktan kaçınmak da önemlidir.\n\nBu blog yazısında, güncel siber güvenlik tehditlerini daha detaylı bir şekilde inceleyeceğiz. Her bir tehdit türünün nasıl çalıştığını, potansiyel etkilerini ve bu tehditlere karşı bireysel ve kurumsal düzeyde alınabilecek en etkili korunma yollarını ele alacağız. Siber güvenlik bilincini artırmak ve dijital varlıklarımızı korumak için pratik ipuçları sunarak, daha güvenli bir çevrimiçi deneyim için rehberlik edeceğiz.", + "Content": "

Dijitalleşmenin yaşamın her alanına nüfuz ettiği günümüzde, siber güvenlik artık yalnızca bir IT meselesi olmaktan çıkmış, bireylerin, küçük işletmelerin ve devasa kurumların ortak sorumluluğu haline gelmiştir. İnternete bağlı her cihaz, her hesap ve her uygulama, potansiyel bir saldırı yüzeyi olarak değerlendirilebilir. Siber saldırıların sayısı her geçen yıl artarken, saldırıların karmaşıklığı ve hedef kitlesi de genişlemektedir.

Günümüz siber tehdit ortamı; kişisel veri hırsızlığı, fidye yazılımları, kimlik avı saldırıları, sıfır gün açıkları, DDoS saldırıları ve daha pek çok sofistike yöntemle şekilleniyor. Bu yazıda, siber tehditleri daha yakından tanıyacak, bireysel ve kurumsal düzeyde alınabilecek etkili güvenlik önlemlerini ele alacak ve dijital dünyada güvenlik kültürünü nasıl geliştirebileceğinizi detaylarıyla paylaşacağız.

🚨 Siber Tehdit Türleri ve Nasıl Çalışırlar?

🔐 1. Kimlik Avı (Phishing)

Saldırganların sahte e-posta, SMS veya web siteleri aracılığıyla kullanıcıları kandırarak şifre, kredi kartı bilgisi gibi hassas verilerini ele geçirmeye çalıştığı saldırı türüdür. Genellikle aciliyet duygusu yaratılarak kullanıcı aksiyona zorlanır.

Korunma Yolu: E-posta adresinin doğruluğunu kontrol etmek, bilinmeyen bağlantılara tıklamamak, görsel olarak profesyonel görünen ancak dilbilgisi hataları barındıran iletilere karşı dikkatli olmak.

💣 2. Fidye Yazılımı (Ransomware)

Bilgisayarınıza bulaştıktan sonra dosyalarınızı şifreleyen ve şifreyi açmak için fidye talep eden yazılımlardır. En bilinen örneklerinden biri WannaCry saldırısıdır.

Korunma Yolu: Güncel antivirüs kullanmak, sistem ve uygulama yamalarını zamanında yapmak, düzenli olarak offline yedek almak, bilinmeyen dosyaları açmamak.

🌐 3. DDoS (Dağıtılmış Hizmet Engelleme) Saldırıları

Çok sayıda sistemden hedef sunucuya aşırı istek gönderilerek sistemin hizmet veremez hale getirilmesidir. Özellikle online hizmet sunan firmalar için büyük risk taşır.

Korunma Yolu: Yük dengeleyiciler, firewall’lar ve DDoS önleme servisleri (Cloudflare, AWS Shield vb.) kullanmak.

🐞 4. Sıfır Gün Açıkları (Zero-Day Exploits)

Henüz keşfedilmemiş veya yayınlanmamış yazılım açıklarının kötü niyetli kişilerce kullanılmasıdır. Bu tür açıklar genellikle çok hızlı etkiler yaratır.

Korunma Yolu: Yazılım sağlayıcılarının güvenlik duyurularını takip etmek, sistemleri sürekli güncel tutmak, davranışsal tehdit algılama sistemleri kullanmak.

🧑‍💻 5. İç Tehditler (Insider Threats)

Kurum içinde çalışan kişilerin (kasıtlı veya kazara) bilgi sızdırması ya da zarara yol açmasıdır. En tehlikeli ve gözden kaçan tehditlerden biridir.

Korunma Yolu: Rol tabanlı erişim kontrolü, kullanıcı aktivitelerinin loglanması, veri kaybı önleme (DLP) çözümleri.

🛡️ Bireyler İçin Uygulanabilir Siber Güvenlik İpuçları

🔑 Güçlü Şifreler Kullanın

💡 Yardımcı: Bitwarden, 1Password gibi şifre yöneticileri kullanın.

📲 İki Faktörlü Kimlik Doğrulama (2FA) Kullanın

Şifreniz çalınsa bile, ikinci doğrulama faktörü (SMS, e-posta, Authenticator uygulaması) sizi korur.

💻 Yazılımları Güncel Tutun

Güvenlik açıklarının büyük kısmı, zamanında yapılmayan yazılım güncellemeleri nedeniyle istismar edilir.

✉️ E-Posta ve Linklerde Dikkatli Olun

🌐 Halka Açık Wi-Fi Kullanırken Dikkat

🔍 Sosyal Medyada Paylaşımlara Dikkat

🏢 Kurumlar İçin Siber Güvenlik Stratejileri

  1. Güvenlik Farkındalık Eğitimi: Personelin sosyal mühendislik saldırılarına karşı eğitilmesi şarttır.
  2. Yedekleme Politikası: Kritik veriler yedeklenmeli ve test edilmelidir.
  3. Erişim Yetkileri: Her kullanıcı sadece ihtiyacı olan verilere erişebilmeli.
  4. Güvenlik Duvarı ve IDS/IPS Kullanımı: Ağa gelen trafiğin kontrol edilmesi şarttır.
  5. Sızma Testleri ve Güvenlik Denetimleri: Periyodik olarak yapılmalı, zayıf noktalar proaktif olarak kapatılmalı.

🧠 Siber Güvenlik Kültürü: En Güçlü Savunma

En gelişmiş yazılımlar, en pahalı donanımlar dahi, bilinçsiz kullanıcılar tarafından etkisiz hale getirilebilir. Bu nedenle:

Sonuç: Bilgi Güvenliği, Dijital Hayatın Sigortasıdır

Siber güvenlik, artık lüks değil; bir zorunluluktur. Bireyler olarak dijital ayak izimize sahip çıkmalı, kurumlar olarak siber dayanıklılığımızı artırmalıyız. Teknolojinin faydalarını güven içinde kullanabilmek için bilinçli kullanıcı olmak, güvenlik politikalarını uygulamak ve sürekli gelişen tehditlere karşı tetikte olmak şarttır.

Unutmayın: Siber güvenlik sadece bir teknoloji değil, bir yaşam tarzıdır.

", "ReadTime": "6 dk", "Summary": "blog.posts.security.excerpt", "CoverImage": "https://images.pexels.com/photos/5380642/pexels-photo-5380642.jpeg?auto=compress&cs=tinysrgb&w=1920", @@ -20125,7 +20125,7 @@ "TenantId": null, "Title": "blog.posts.mobile.title", "Slug": "mobil-uygulama-gelistirmede-cross-platform-cozumler", - "Content": "Mobil uygulama geliştirme, günümüzün en dinamik ve talep gören yazılım alanlarından biridir. Akıllı telefonların yaygınlaşmasıyla birlikte, işletmeler ve bireyler mobil platformlarda yer almak için sürekli yeni uygulamalar geliştirmektedir. Geleneksel olarak, iOS ve Android gibi farklı mobil işletim sistemleri için ayrı ayrı native uygulamalar geliştirmek gerekiyordu, bu da zaman ve kaynak açısından maliyetli olabiliyordu.\n\nAncak son yıllarda, cross-platform (çapraz platform) mobil geliştirme frameworkleri popülerlik kazanmıştır. Bu frameworkler, geliştiricilerin tek bir kod tabanı kullanarak hem iOS hem de Android platformları için uygulama geliştirmesine olanak tanır. Bu yaklaşım, geliştirme sürecini hızlandırır, maliyetleri düşürür ve bakım kolaylığı sağlar. React Native, Flutter ve Xamarin gibi frameworkler, cross-platform geliştirme alanında öne çıkan çözümlerdir.\n\nBu blog yazısında, cross-platform mobil geliştirmenin avantajlarını ve dezavantajlarını detaylı bir şekilde inceleyeceğiz. Farklı frameworklerin özelliklerini, performanslarını ve hangi senaryolarda daha uygun olduklarını karşılaştıracağız. Mobil uygulama geliştirme projeniz için en doğru cross-platform çözümü seçmenize yardımcı olacak bilgiler sunarak, geliştirme sürecinizi daha verimli hale getirmeniz için rehberlik edeceğiz.", + "Content": "

Mobil teknolojiler, modern yaşamın ayrılmaz bir parçası haline gelmiş durumda. Günümüzde milyarlarca insanın elinde taşıdığı akıllı cihazlar, işletmeler için yeni fırsatlar ve aynı zamanda rekabet baskısı yaratıyor. Kullanıcılar, markalarla etkileşim kurmak, hizmet almak veya ürün satın almak için mobil uygulamaları tercih ediyor. Bu da mobil uygulama geliştirmeyi, yazılım dünyasının en stratejik ve talep gören alanlarından biri haline getiriyor.

📱 Mobil Uygulama Geliştirmeye Genel Bakış

Mobil uygulamalar iki ana kategoriye ayrılır:

  1. Native Uygulamalar: iOS için Swift/Objective-C ve Android için Kotlin/Java kullanılarak geliştirilir. Her platform için ayrı kod yazılır.
  2. Cross-Platform (Çapraz Platform) Uygulamalar: Tek bir kod tabanı ile birden fazla platformda (iOS, Android) çalışabilir uygulamalar geliştirilebilir.

Native uygulamalar yüksek performans ve platforma özel deneyim sunsa da, geliştirme maliyetleri ve zaman açısından zorluklar barındırır. Her platform için ayrı geliştirici, ayrı test ve ayrı sürüm yönetimi gerekir. Bu noktada, cross-platform geliştirme paradigması devreye girer.

🌐 Cross-Platform Geliştirmenin Temel Avantajları

1. Tek Kod Tabanı, Daha Az Geliştirme Süresi

Geliştiriciler yalnızca bir kez kod yazar ve bu kod hem iOS hem de Android için kullanılır. Bu, geliştirme süresini önemli ölçüde azaltır.

2. Maliyet Tasarrufu

Ayrı ayrı mobil geliştirici ekipleri kurmaya gerek kalmaz. Daha küçük bir ekiple daha kısa sürede üretim yapılabilir.

3. Kolay Bakım ve Güncelleme

Tek bir kod üzerinde yapılacak güncelleme, tüm platformlarda etkili olur. Bu da bakım maliyetlerini düşürür ve hata yönetimini kolaylaştırır.

4. Hızlı MVP Geliştirme

Minimum Viable Product (MVP) geliştirmek isteyen startup’lar için idealdir. Hızla piyasaya çıkıp kullanıcı geri bildirimi toplanabilir.

5. Platformlar Arası Tutarlılık

Aynı kod tabanı, UI/UX açısından platformlar arası tutarlılığı sağlar.

🧪 Cross-Platform Geliştirmenin Zorlukları

1. Performans Kısıtları

Native'e göre bir miktar performans kaybı olabilir. Özellikle grafik yoğun uygulamalarda bu fark hissedilir.

2. Donanım Özelliklerine Kısıtlı Erişim

Kamera, Bluetooth, sensörler gibi donanıma erişim native kadar doğrudan olmayabilir. Ek köprü çözümler (bridges/plugins) gerekir.

3. Platforma Özel UX Detayları

Her platformun kendi kullanıcı alışkanlıkları vardır. Tek tip tasarım, platforma özel deneyimi yansıtamayabilir.

4. Framework Güncellemelerine Bağımlılık

Kullandığınız framework’ün gelişim hızına ve topluluğuna bağlı olarak bazı güncellemeler beklemek gerekebilir.

🚀 Popüler Cross-Platform Frameworkler

🔹 React Native (Facebook)

🔹 Flutter (Google)

🔹 Xamarin (Microsoft)

🔹 Capacitor / Ionic (WebView Tabanlı)

🧩 Hangi Framework Hangi Proje İçin Daha Uygun?

Proje TipiÖnerilen FrameworkNeden?MVP geliştirmeFlutter, React NativeHızlı geliştirme ve UI avantajıKurumsal uygulamalarXamarin.NET altyapısıyla uyumGörsel yoğun mobil uygulamalarFlutterYüksek performanslı UIMevcut web projesini mobil yapmakIonic, React NativeWeb bilgi birikiminin kullanımıYüksek performanslı oyun/AR/VRNativeMaksimum donanım kontrolü


🛠️ Performans, Test ve Bakım Açısından Değerlendirme

🎯 Sonuç: Doğru Framework = Başarılı Mobil Strateji

Cross-platform mobil geliştirme, özellikle kaynakları sınırlı ama zaman baskısı yüksek olan projelerde mükemmel bir çözüm sunar. Ancak her çözüm gibi, bu yaklaşım da kendi içinde dikkatli bir değerlendirme ister. Uygulamanızın doğası, kullanıcı kitleniz, performans gereksinimleriniz ve teknik kadronuzun yetkinlikleri bu kararda belirleyici olmalıdır.

Karmaşık donanım etkileşimleri gerektiren oyunlar, yüksek hassasiyetli medya uygulamaları gibi özel durumlar dışında, cross-platform çözümler modern uygulama geliştirme süreçlerinin merkezinde yer almaya devam edecektir.

", "Summary": "blog.posts.mobile.excerpt", "ReadTime": "4 dk", "CoverImage": "https://images.pexels.com/photos/13017583/pexels-photo-13017583.jpeg?auto=compress&cs=tinysrgb&w=1920", @@ -20137,7 +20137,7 @@ "TenantId": null, "Title": "blog.posts.database.title", "Slug": "veritabani-yonetim-sistemleri-karsilastirmasi", - "Content": "Veritabanları, modern yazılım uygulamalarının kalbidir. Uygulamaların veriyi depolaması, yönetmesi ve erişmesi için güvenilir ve etkili bir veritabanı yönetim sistemi (VTYS) seçimi kritik öneme sahiptir. Piyasada birçok farklı türde VTYS bulunmaktadır ve her birinin kendine özgü avantajları ve dezavantajları vardır. Doğru VTYS seçimi, uygulamanın performansı, ölçeklenebilirliği, güvenliği ve geliştirme süreci üzerinde doğrudan bir etkiye sahiptir.\n\nİlişkisel veritabanları (RDBMS), veriyi tablolar halinde düzenler ve SQL (Yapısal Sorgu Dili) kullanarak verilere erişim sağlar. MySQL, PostgreSQL, Oracle ve SQL Server gibi sistemler bu kategoriye girer. RDBMS'ler, veri tutarlılığı ve karmaşık sorgular için güçlü yetenekler sunar. Ancak, büyük ölçekli ve yapısal olmayan verilerle çalışırken performans sorunları yaşanabilir.\n\nNoSQL (Not Only SQL) veritabanları ise daha esnek veri modelleri sunar ve genellikle büyük ölçekli, dağıtık sistemler ve hızlı veri erişimi gerektiren uygulamalar için tercih edilir. MongoDB (belge tabanlı), Cassandra (geniş sütunlu) ve Redis (anahtar-değer) gibi sistemler NoSQL kategorisine örnektir. NoSQL veritabanları, yatay ölçeklenebilirlik ve yüksek erişilebilirlik sağlama konusunda genellikle RDBMS'lerden daha iyidir. Bu blog yazısında, ilişkisel ve NoSQL veritabanı yönetim sistemlerini detaylı bir şekilde karşılaştırarak, farklı kullanım senaryolarına göre hangi VTYS'nin daha uygun olduğunu ele alacağız.", + "Content": "

Veritabanları, günümüzün dijital dünyasında veri temelli karar alma süreçlerinin, web ve mobil uygulamaların, iş zekası çözümlerinin ve büyük veri altyapılarının temel yapı taşlarından biridir. Özellikle veri hacminin, veri çeşitliliğinin ve veri erişim gereksinimlerinin sürekli arttığı günümüzde, uygun bir veritabanı yönetim sistemi (VTYS) seçimi yapmak, teknik olduğu kadar stratejik de bir karardır. Geliştiriciler, yazılım mimarları ve karar vericiler için bu yazı, ilişkisel (RDBMS) ve NoSQL veritabanlarının temel yapılarını, avantajlarını, zorluklarını ve hangi senaryolarda hangisinin tercih edilmesi gerektiğini detaylı bir biçimde ortaya koyacaktır.

📌 Veritabanlarının Rolü ve Önemi

Bir yazılım projesinde veritabanı, genellikle en az görünür ama en kritik bileşenlerden biridir. Kullanıcı verilerinin saklanması, ürün bilgilerinin yönetimi, işlem geçmişlerinin kaydı, raporlama sistemlerinin desteklenmesi ve daha fazlası veritabanı altyapısına dayanır.

Kötü yapılandırılmış veya yanlış seçilmiş bir veritabanı:

Bu nedenle, VTYS seçimi sadece teknik özellikler değil, aynı zamanda projenin iş hedefleri, veri yapısı, ölçeklenebilirlik gereksinimleri ve bütçesi dikkate alınarak yapılmalıdır.

🧱 İlişkisel Veritabanları (RDBMS): Yapı ve Özellikler

İlişkisel veritabanları, verileri satır ve sütunlardan oluşan tablolar şeklinde organize eder. Bu yapı, ilişkisel model olarak adlandırılır ve veri bütünlüğü, normalizasyon, anahtar-kısıt ilişkileri gibi katı yapısal kurallarıyla tanınır. Temel özellikleri şunlardır:

🎯 Öne Çıkan RDBMS Çözümleri:

🚫 Zorluklar:

🔀 NoSQL Veritabanları: Esneklik ve Performans Odaklı Yaklaşım

“NoSQL” kavramı, “Not Only SQL” ifadesinin kısaltmasıdır. Geleneksel tablo yapısının ötesine geçerek daha esnek veri modelleri sunar. NoSQL veritabanları, özellikle yüksek hız, esneklik ve büyük veri senaryoları için tercih edilir.

🧩 NoSQL Kategorileri:

  1. Belge Tabanlı (Document): JSON ya da BSON belgeleriyle çalışır (örneğin MongoDB).
  2. Anahtar-Değer (Key-Value): Hızlı erişim için idealdir (örneğin Redis).
  3. Geniş Sütunlu (Wide-Column): Çok büyük veri kümeleri için optimize edilmiştir (örneğin Cassandra).
  4. Graf Veritabanları: Karmaşık ilişkileri grafik yapılarla modellenir (örneğin Neo4j).

🚀 Avantajları:

🔎 Zorluklar:

🔄 RDBMS vs NoSQL: Hangi Durumda Hangisi Tercih Edilmeli?

KriterRDBMSNoSQLVeri YapısıYapısal, ilişkiselYapısal olmayan, esnekÖlçeklenebilirlikDikeyYataySorgu KarmaşıklığıÇok güçlü (JOIN, subquery vs.)Kısıtlı (ya da yok)Veri TutarlılığıYüksek (ACID)Esnek (BASE)Performans (gerçek zamanlı)OrtaYüksekŞema DeğişikliğiZorKolayTipik Kullanım AlanıFinans, ERP, CRMIoT, sosyal medya, analitik


🧪 Gerçek Hayattan Senaryolar ve Öneriler

🎯 Sonuç: Stratejik Bir Tercih Olarak Veritabanı Seçimi

Doğru veritabanı mimarisi, yalnızca bugünkü ihtiyaçlara değil, gelecekteki büyüme hedeflerine de hizmet etmelidir. İlişkisel ve NoSQL veritabanları birbirinin alternatifi değil, çoğu zaman birbirini tamamlayıcı çözümler olabilir. Mikroservis mimarilerinde her servis kendi ihtiyacına uygun VTYS kullanabilir. Önemli olan, projenin doğasına, verinin yapısına ve iş gereksinimlerine uygun bir karar vermektir.

Unutmayın: Veri stratejiniz, büyüme stratejinizin temelidir.

", "Summary": "blog.posts.database.excerpt", "ReadTime": "8 dk", "CoverImage": "https://images.pexels.com/photos/325229/pexels-photo-325229.jpeg?auto=compress&cs=tinysrgb&w=1920", @@ -20149,7 +20149,7 @@ "TenantId": null, "Title": "blog.posts.digital.title", "Slug": "dijital-pazarlamada-veri-analizi", - "Content": "Dijital pazarlama dünyası, sürekli değişen algoritmalar, yeni platformlar ve gelişen tüketici davranışlarıyla dinamik bir yapıya sahiptir. Bu karmaşık ortamda başarılı olmak için, pazarlamacıların verilere dayalı kararlar alması ve stratejilerini sürekli olarak optimize etmesi gerekmektedir. İşte tam bu noktada veri analizi devreye girer. Dijital pazarlamada veri analizi, kampanyaların performansını ölçmek, müşteri davranışlarını anlamak, hedef kitleyi daha iyi tanımak ve pazarlama yatırımlarının geri dönüşünü (ROI) maksimize etmek için kritik bir araçtır.\n\nVeri analizi sayesinde, hangi pazarlama kanallarının en etkili olduğunu belirleyebilir, hangi içerik türlerinin daha fazla etkileşim aldığını anlayabilir ve müşteri yolculuğunun farklı aşamalarındaki performans darboğazlarını tespit edebiliriz. Google Analytics, Adobe Analytics gibi web analizi araçları, sosyal medya analiz platformları ve müşteri ilişkileri yönetimi (CRM) sistemleri, dijital pazarlamacılara değerli veriler sunar. Bu verilerin doğru bir şekilde toplanması, temizlenmesi, analiz edilmesi ve yorumlanması, daha bilinçli ve etkili pazarlama stratejileri oluşturmanın temelini oluşturur.\n\nBu blog yazısında, dijital pazarlamada veri analizinin neden bu kadar önemli olduğunu detaylı bir şekilde ele alacağız. Kullanılan temel metrikleri (örneğin, dönüşüm oranı, tıklama oranı, müşteri edinme maliyeti), farklı analiz yöntemlerini ve veri görselleştirme tekniklerini inceleyeceğiz. Ayrıca, veri analizinden elde edilen içgörüleri pazarlama stratejilerine nasıl entegre edebileceğinize dair pratik ipuçları sunarak, dijital pazarlama çabalarınızın etkinliğini artırmanız için rehberlik edeceğiz.", + "Content": "

Dijital pazarlama evreni; hızla evrilen algoritmalar, çeşitlenen dijital platformlar ve sürekli değişen tüketici davranışları ile her geçen gün daha da karmaşık bir yapıya bürünüyor. Bu yoğun rekabet ortamında markaların fark yaratabilmesi, yalnızca yaratıcı kampanyalar üretmekle değil, aynı zamanda bu kampanyaların ne kadar işe yaradığını bilimsel olarak analiz edebilmekle mümkün hale geliyor. İşte tam bu noktada veri analizi, dijital pazarlamanın kalbinde yer alan stratejik bir araç olarak devreye giriyor.

Neden Veri Analizi? Dijital Pazarlamanın Yeni Yakıtı

Modern dijital pazarlama, artık yalnızca sezgilere ya da geçmiş deneyimlere dayalı kararlarla yönetilmiyor. Kampanya performansını gerçek zamanlı ölçmek, müşteri davranışlarını detaylıca anlamak, farklı kanallarda elde edilen sonuçları kıyaslayabilmek ve bütçeyi en verimli şekilde yönlendirebilmek için veriye dayalı karar alma süreci vazgeçilmez hale geldi.

Veri analizi, markaların şu konularda rekabet avantajı elde etmesini sağlar:

Dijital Pazarlamada En Çok Kullanılan Temel Metrikler

Veri analizinin ilk adımı, neyi ölçtüğümüzü bilmekten geçer. Dijital pazarlamacılar için kritik olan bazı temel metrikler şunlardır:

Kullanılan Araçlar ve Sistemler

Verilerin sağlıklı bir şekilde toplanması, analiz edilmesi ve görselleştirilmesi için farklı araçlara ihtiyaç vardır. Bu araçlardan bazıları:

Veri Temizliği ve Kalite Kontrolü: Doğru Veri = Doğru Strateji

Analiz edilen verinin kalitesi, sonuçların güvenilirliğini doğrudan etkiler. Eksik, hatalı veya güncel olmayan veriler üzerine kurulmuş analizler, stratejik hatalara yol açabilir. Bu nedenle şu adımlar kritik önemdedir:

Farklı Analiz Yöntemleri ile Derin İçgörü

Veri analizi sadece sayıları okumaktan ibaret değildir; arkasındaki anlamı çözümlemek gerekir. Dijital pazarlamada kullanılan analiz yöntemlerinden bazıları:

Veri Görselleştirme: İçgörüyü Eyleme Dönüştürmek

Karmaşık verileri etkili bir şekilde iletmek için veri görselleştirme olmazsa olmazdır. Power BI, Tableau gibi araçlarla hazırlanan interaktif dashboard’lar, yöneticilere veya ekip üyelerine sezgisel olarak veri ile içgörü kazandırır. Bu sayede;

İçgörüyü Stratejiye Dönüştürme: Pratik Öneriler

Veri analizinden elde edilen bulgular, ancak pazarlama stratejisine entegre edildiğinde anlam kazanır. İşte bazı öneriler:

Sonuç: Veri Odaklı Pazarlama ile Rekabette Öne Geçin

Günümüzde dijital pazarlamanın başarısı, yalnızca yaratıcı kampanyalarla değil, bu kampanyaların etkisini ölçümleyip sürekli olarak iyileştirme becerisiyle ölçülmektedir. Veri analizi, pazarlama ekiplerinin doğru zamanda, doğru mesajla, doğru kişiye ulaşmasını sağlayan güçlü bir rehberdir. Teknolojinin sunduğu analiz araçlarını stratejik yaklaşımlarla birleştirerek, hem marka değerini hem de yatırım geri dönüşünü maksimize edebilirsiniz.

Unutmayın: Veri konuşur, siz sadece onu doğru dinlemelisiniz.

", "Summary": "blog.posts.digital.excerpt", "ReadTime": "6 dk", "CoverImage": "https://images.pexels.com/photos/7681091/pexels-photo-7681091.jpeg?auto=compress&cs=tinysrgb&w=1920", diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 21db349f..c0a159fa 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -58,8 +58,6 @@ public class PlatformDbContext : public DbSet SkillLevels { get; set; } public DbSet ContactTags { get; set; } public DbSet ContactTitles { get; set; } - - // Blog Entities public DbSet BlogPosts { get; set; } public DbSet BlogCategories { get; set; } diff --git a/company/.env b/company/.env index b75ab81b..005949e1 100644 --- a/company/.env +++ b/company/.env @@ -1,3 +1,4 @@ VITE_APPLICATION_BASEURL='http://localhost:3003/' VITE_API_URL='https://localhost:44344' VITE_KURS_URL='http://localhost:3000/' +VITE_CDN_URL='http://localhost:4005' diff --git a/company/.env.dev b/company/.env.dev index 3cc3786b..aae54283 100644 --- a/company/.env.dev +++ b/company/.env.dev @@ -1,3 +1,4 @@ VITE_APPLICATION_BASEURL='https://sozsoft.com' VITE_API_URL='https://kurs-dev-api.sozsoft.com' VITE_KURS_URL='https://kurs-dev.sozsoft.com' +VITE_CDN_URL='https://kurs-dev-cdn.sozsoft.com' diff --git a/company/.env.production b/company/.env.production index 2c58f138..2c6fe45c 100644 --- a/company/.env.production +++ b/company/.env.production @@ -1,3 +1,4 @@ VITE_APPLICATION_BASEURL='https://sozsoft.com' VITE_API_URL='https://kurs-api.sozsoft.com' VITE_KURS_URL='https://kurs.sozsoft.com' +VITE_CDN_URL='https://kurs-cdn.sozsoft.com' diff --git a/company/package-lock.json b/company/package-lock.json index 523323e7..5d4cbf6a 100644 --- a/company/package-lock.json +++ b/company/package-lock.json @@ -8,6 +8,7 @@ "name": "sozsoft", "version": "1.0.0", "dependencies": { + "@tailwindcss/typography": "^0.5.16", "@tanstack/react-query": "^5.17.9", "axios": "^1.6.5", "date-fns": "^3.6.0", @@ -47,7 +48,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "engines": { "node": ">=10" }, @@ -2093,7 +2093,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2107,7 +2106,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2116,7 +2114,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2135,14 +2132,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2152,7 +2147,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2165,7 +2159,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -2174,7 +2167,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2516,6 +2508,34 @@ "sourcemap-codec": "^1.4.8" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tanstack/query-core": { "version": "5.80.10", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.80.10.tgz", @@ -3163,14 +3183,12 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3182,8 +3200,7 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/argparse": { "version": "2.0.1", @@ -3399,7 +3416,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "engines": { "node": ">=8" }, @@ -3422,7 +3438,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -3533,7 +3548,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "engines": { "node": ">= 6" } @@ -3630,7 +3644,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3654,7 +3667,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -3712,7 +3724,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } @@ -3782,7 +3793,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "bin": { "cssesc": "bin/cssesc" }, @@ -3975,8 +3985,7 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, "node_modules/dir-glob": { "version": "3.0.1", @@ -3994,8 +4003,7 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/doctrine": { "version": "3.0.0", @@ -4487,7 +4495,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4503,7 +4510,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4545,7 +4551,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4600,7 +4605,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4791,7 +4795,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -4935,7 +4938,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -5357,7 +5359,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5399,7 +5400,6 @@ "version": "2.15.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, "dependencies": { "hasown": "^2.0.2" }, @@ -5459,7 +5459,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5511,7 +5510,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -5553,7 +5551,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -5824,7 +5821,6 @@ "version": "1.21.6", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -5974,7 +5970,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "engines": { "node": ">=10" } @@ -5982,8 +5977,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/locate-path": { "version": "6.0.0", @@ -6007,17 +6001,28 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.sortby": { "version": "4.7.0", @@ -6240,7 +6245,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -6691,7 +6695,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6751,7 +6754,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -6762,7 +6764,6 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -6793,7 +6794,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6811,7 +6811,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6820,7 +6819,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "engines": { "node": ">= 6" } @@ -7017,8 +7015,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -7054,14 +7051,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -7073,7 +7068,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7082,7 +7076,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -7101,7 +7094,6 @@ "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7129,7 +7121,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -7146,7 +7137,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -7165,7 +7155,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7200,7 +7189,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, "engines": { "node": ">=14" }, @@ -7212,7 +7200,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7237,7 +7224,6 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7249,8 +7235,7 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -7304,7 +7289,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -7475,7 +7459,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -7484,7 +7467,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -7647,7 +7629,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7674,7 +7655,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -7788,7 +7768,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -8108,7 +8087,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8407,7 +8385,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -8442,7 +8419,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -8454,7 +8430,6 @@ "version": "3.4.13", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", - "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -8566,7 +8541,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -8575,7 +8549,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -8632,7 +8605,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -8685,8 +8657,7 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/type-check": { "version": "0.4.0", @@ -9041,8 +9012,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vfile": { "version": "6.0.3", @@ -9785,7 +9755,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/company/package.json b/company/package.json index 6dfbac03..8361bd00 100644 --- a/company/package.json +++ b/company/package.json @@ -14,6 +14,7 @@ "format": "npm run prettier:fix && npm run lint:fix" }, "dependencies": { + "@tailwindcss/typography": "^0.5.16", "@tanstack/react-query": "^5.17.9", "axios": "^1.6.5", "date-fns": "^3.6.0", diff --git a/company/src/pages/BlogDetail.tsx b/company/src/pages/BlogDetail.tsx index 6a729cc8..04a05596 100644 --- a/company/src/pages/BlogDetail.tsx +++ b/company/src/pages/BlogDetail.tsx @@ -103,9 +103,7 @@ const BlogDetail: React.FC = () => { })} -
-

{blogPost.content}

-
+
); diff --git a/company/src/services/api/auth.service.ts b/company/src/services/api/auth.service.ts index bf590781..a0442690 100644 --- a/company/src/services/api/auth.service.ts +++ b/company/src/services/api/auth.service.ts @@ -1,4 +1,8 @@ import { apiClient } from './config'; +const { VITE_CDN_URL } = import.meta.env + +export const AVATAR_URL = (id?: string, tenantId?: string) => + `${VITE_CDN_URL}/${tenantId ? 'tenants/' + tenantId : 'host'}/Avatar/${id ?? 'default'}.jpg` export interface LoginRequest { username: string; @@ -50,6 +54,7 @@ export interface CurrentUser { phoneNumberVerified: boolean; isAuthenticated: boolean; roles: string[]; + avatar?: string; } class AuthService { @@ -57,6 +62,7 @@ class AuthService { private readonly REFRESH_TOKEN_KEY = 'refresh_token'; private readonly USER_KEY = 'current_user'; private readonly TENANT_KEY = 'tenant_id'; + private readonly AVATAR = 'avatar'; private readonly TOKEN_EXPIRY_KEY = 'token_expiry'; async login(data: LoginRequest): Promise { @@ -137,6 +143,7 @@ class AuthService { lastLoginTime: new Date().toISOString(), creationTime: new Date().toISOString(), roles: currentUser.roles || [], + avatar: AVATAR_URL(currentUser?.id, currentUser.tenantId ?? ''), }; this.setUser(user); @@ -195,6 +202,14 @@ class AuthService { localStorage.setItem(this.TENANT_KEY, tenantId); } + getAvatar(): string | null { + return localStorage.getItem(this.AVATAR); + } + + setAvatar(avatar: string): void { + localStorage.setItem(this.AVATAR, avatar); + } + setTokenExpiry(expiresIn: number): void { const expiryTime = Date.now() + expiresIn * 1000; localStorage.setItem(this.TOKEN_EXPIRY_KEY, expiryTime.toString()); diff --git a/company/src/store/authStore.ts b/company/src/store/authStore.ts index 0b5a9bc8..6a282e8d 100644 --- a/company/src/store/authStore.ts +++ b/company/src/store/authStore.ts @@ -7,7 +7,8 @@ interface AuthState { user: User | null; isAuthenticated: boolean; isLoading: boolean; - tenantId: string | null; + tenantId?: string | null; + avatar: string | null; login: (data: LoginRequest) => Promise; register: (data: RegisterRequest) => Promise; logout: () => void; @@ -15,6 +16,11 @@ interface AuthState { refreshToken: () => Promise; } +const { VITE_CDN_URL } = import.meta.env + +export const AVATAR_URL = (id?: string, tenantId?: string) => + `${VITE_CDN_URL}/${tenantId ? 'tenants/' + tenantId : 'host'}/Avatar/${id ?? 'default'}.jpg` + export const useAuthStore = create()( persist( (set) => ({ @@ -22,6 +28,7 @@ export const useAuthStore = create()( isAuthenticated: false, isLoading: false, tenantId: null, + avatar: null, login: async (data: LoginRequest) => { set({ isLoading: true }); @@ -29,7 +36,9 @@ export const useAuthStore = create()( await authService.login(data); const user = authService.getUser(); const tenantId = authService.getTenantId(); - set({ user, isAuthenticated: true, isLoading: false, tenantId }); + console.log(AVATAR_URL(user?.id, tenantId ?? '')) + set({ user, isAuthenticated: true, isLoading: false, tenantId, avatar: AVATAR_URL(user?.id, tenantId ?? ''), }); + console.log(user) toast.success('Giriş başarılı!', { position:'top-center' }); } catch (error: any) { set({ isLoading: false }); @@ -57,23 +66,23 @@ export const useAuthStore = create()( logout: () => { authService.logout(); - set({ user: null, isAuthenticated: false, tenantId: null }); + set({ user: null, isAuthenticated: false, tenantId: null, avatar: null }); toast.success('Çıkış yapıldı', { position:'top-center' }); }, checkAuth: async () => { if (!authService.isAuthenticated()) { - set({ user: null, isAuthenticated: false, tenantId: null }); + set({ user: null, isAuthenticated: false, tenantId: null, avatar: null }); return; } try { const user = await authService.fetchCurrentUser(); const tenantId = authService.getTenantId(); - set({ user, isAuthenticated: !!user, tenantId }); + set({ user, isAuthenticated: !!user, tenantId, avatar: AVATAR_URL(user?.id, tenantId ?? ''), }); } catch (error) { authService.logout(); - set({ user: null, isAuthenticated: false, tenantId: null }); + set({ user: null, isAuthenticated: false, tenantId: null, avatar: null }); } }, @@ -82,10 +91,10 @@ export const useAuthStore = create()( await authService.refreshToken(); const user = await authService.fetchCurrentUser(); const tenantId = authService.getTenantId(); - set({ user, isAuthenticated: !!user, tenantId }); + set({ user, isAuthenticated: !!user, tenantId, avatar: AVATAR_URL(user?.id, tenantId ?? ''), }); } catch (error) { authService.logout(); - set({ user: null, isAuthenticated: false, tenantId: null }); + set({ user: null, isAuthenticated: false, tenantId: null, avatar: null }); throw error; } }, @@ -95,7 +104,8 @@ export const useAuthStore = create()( partialize: (state) => ({ user: state.user, isAuthenticated: state.isAuthenticated, - tenantId: state.tenantId + tenantId: state.tenantId, + avatar: AVATAR_URL(state.user?.id, state.tenantId ?? ''), }), } ) diff --git a/company/src/vite-env.d.ts b/company/src/vite-env.d.ts index b473e410..f2e93ae9 100644 --- a/company/src/vite-env.d.ts +++ b/company/src/vite-env.d.ts @@ -4,6 +4,7 @@ interface ImportMetaEnv { readonly VITE_APPLICATION_BASEURL: string readonly VITE_API_URL: string readonly VITE_KURS_URL: string + readonly VITE_CDN_URL: string } interface ImportMeta { diff --git a/company/tailwind.config.js b/company/tailwind.config.js index d21f1cda..49c0069c 100644 --- a/company/tailwind.config.js +++ b/company/tailwind.config.js @@ -1,8 +1,10 @@ +import typography from '@tailwindcss/typography'; + /** @type {import('tailwindcss').Config} */ export default { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, - plugins: [], + plugins: [typography], }; diff --git a/ui/src/views/blog/BlogManagement.tsx b/ui/src/views/blog/BlogManagement.tsx index c2329962..569474d9 100644 --- a/ui/src/views/blog/BlogManagement.tsx +++ b/ui/src/views/blog/BlogManagement.tsx @@ -33,6 +33,8 @@ import Td from '@/components/ui/Table/Td' import { SelectBoxOption } from '@/shared/types' import { CheckBox } from 'devextreme-react' import { Checkbox } from '@/components/ui' +import { Helmet } from 'react-helmet' +import { useLocalization } from '@/utils/hooks/useLocalization' const validationSchema = Yup.object().shape({ title: Yup.string().required(), @@ -54,6 +56,7 @@ const categoryValidationSchema = Yup.object().shape({ }) const BlogManagement = () => { + const { translate } = useLocalization() const navigate = useNavigate() const [activeTab, setActiveTab] = useState<'posts' | 'categories'>('posts') const [posts, setPosts] = useState([]) @@ -343,6 +346,11 @@ const BlogManagement = () => { return ( <> +
@@ -374,7 +382,7 @@ const BlogManagement = () => { {' '} @@ -382,7 +390,9 @@ const BlogManagement = () => { {loading ? ( - Yükleniyor... + + Yükleniyor... + ) : ( posts.map((post) => ( @@ -440,7 +450,9 @@ const BlogManagement = () => { {loading ? ( - Yükleniyor... + + Yükleniyor... + ) : ( categories.map((category) => ( diff --git a/ui/src/views/forum/ForumManagement.tsx b/ui/src/views/forum/ForumManagement.tsx index beb83bbb..d0a6fd6f 100644 --- a/ui/src/views/forum/ForumManagement.tsx +++ b/ui/src/views/forum/ForumManagement.tsx @@ -26,6 +26,8 @@ import Tr from '@/components/ui/Table/Tr' import Th from '@/components/ui/Table/Th' import TBody from '@/components/ui/Table/TBody' import Td from '@/components/ui/Table/Td' +import { useLocalization } from '@/utils/hooks/useLocalization' +import { Helmet } from 'react-helmet' const categoryValidationSchema = Yup.object().shape({ name: Yup.string().required('İsim gereklidir'), @@ -34,8 +36,9 @@ const categoryValidationSchema = Yup.object().shape({ }) const ForumManagement = () => { + const { translate } = useLocalization() const navigate = useNavigate() - const [activeTab, setActiveTab] = useState<'categories' | 'topics'>('categories') + const [activeTab, setActiveTab] = useState<'topics' | 'categories'>('topics') const [categories, setCategories] = useState([]) const [topics, setTopics] = useState([]) const [loading, setLoading] = useState(false) @@ -122,9 +125,9 @@ const ForumManagement = () => { Kategori güncellendi , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } else { await forumService.createCategory(data) @@ -132,9 +135,9 @@ const ForumManagement = () => { Kategori oluşturuldu , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } @@ -162,9 +165,9 @@ const ForumManagement = () => { Konu kilidi açıldı , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } else { await forumService.lockTopic(topic.id) @@ -172,9 +175,9 @@ const ForumManagement = () => { Konu kilitlendi , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } loadData() @@ -198,9 +201,9 @@ const ForumManagement = () => { Sabitleme kaldırıldı , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } else { await forumService.pinTopic(topic.id) @@ -208,9 +211,9 @@ const ForumManagement = () => { Konu sabitlendi , - { - placement: 'top-center', - }, + { + placement: 'top-center', + }, ) } loadData() @@ -248,15 +251,11 @@ const ForumManagement = () => { return ( <> -
-

Forum Yönetimi

- {activeTab === 'categories' && ( - - )} -
- +
@@ -264,14 +263,14 @@ const ForumManagement = () => { className={`pb-2 px-1 ${activeTab === 'topics' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-600'}`} onClick={() => setActiveTab('topics')} > - Konular + Konular
@@ -287,13 +286,24 @@ const ForumManagement = () => { Mesaj Sayısı Durum Kilit - İşlemler + + + {loading ? ( - Yükleniyor... + + Yükleniyor... + ) : ( categories.map((category) => ( @@ -363,7 +373,9 @@ const ForumManagement = () => { {loading ? ( - Yükleniyor... + + Yükleniyor... + ) : ( topics.map((topic) => (