diff --git a/apps/app-client-base/MainPage.xaml b/apps/app-client-base/MainPage.xaml
index 4ecb2106..8f7d8cc2 100644
--- a/apps/app-client-base/MainPage.xaml
+++ b/apps/app-client-base/MainPage.xaml
@@ -16,12 +16,14 @@
diff --git a/apps/app-client-base/Resources/Styles/Colors.xaml b/apps/app-client-base/Resources/Styles/Colors.xaml
index bebe595a..daae3bd9 100644
--- a/apps/app-client-base/Resources/Styles/Colors.xaml
+++ b/apps/app-client-base/Resources/Styles/Colors.xaml
@@ -1,68 +1,23 @@
-
-
+
+
+
+
+
+ #512BD4
+ #ac99ea
+ #242424
+ #DFD8F7
+ #9880e5
+ #2B0B98
-
-
-
- #2196F3
- #1976D2
- #64B5F6
-
-
-
- #FF5722
- #E64A19
-
-
-
-
- #4CAF50
- #FF9800
- #F44336
- #2196F3
-
-
-
-
- #FAFAFA
- #121212
- #FFFFFF
- #1E1E1E
- #00000033
- #FFFFFF33
-
-
-
-
- #212121
- #FFFFFF
- #757575
- #B0B0B0
- #9E9E9E
- #616161
- #FFFFFF
-
-
-
-
- #E0E0E0
- #424242
- #2196F3
-
-
-
-
-
-
-
-
- #2196F3
- #1976D2
- #FF5722
White
Black
+ #D600AA
+ #190649
#1f1f1f
+
#E1E1E1
#C8C8C8
#ACACAC
@@ -71,11 +26,19 @@
#404040
#212121
#141414
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/maui-test/App.xaml b/apps/maui-test/App.xaml
new file mode 100644
index 00000000..f8269a62
--- /dev/null
+++ b/apps/maui-test/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/maui-test/App.xaml.cs b/apps/maui-test/App.xaml.cs
new file mode 100644
index 00000000..287e2aa4
--- /dev/null
+++ b/apps/maui-test/App.xaml.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace TestMauiApp;
+
+public partial class App : Application
+{
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ protected override Window CreateWindow(IActivationState? activationState)
+ {
+ return new Window(new AppShell());
+ }
+}
\ No newline at end of file
diff --git a/apps/maui-test/AppShell.xaml b/apps/maui-test/AppShell.xaml
new file mode 100644
index 00000000..47f65e81
--- /dev/null
+++ b/apps/maui-test/AppShell.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/apps/maui-test/AppShell.xaml.cs b/apps/maui-test/AppShell.xaml.cs
new file mode 100644
index 00000000..377b5fe2
--- /dev/null
+++ b/apps/maui-test/AppShell.xaml.cs
@@ -0,0 +1,9 @@
+namespace TestMauiApp;
+
+public partial class AppShell : Shell
+{
+ public AppShell()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/apps/maui-test/MainPage.xaml b/apps/maui-test/MainPage.xaml
new file mode 100644
index 00000000..3a3e9c0a
--- /dev/null
+++ b/apps/maui-test/MainPage.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/maui-test/MainPage.xaml.cs b/apps/maui-test/MainPage.xaml.cs
new file mode 100644
index 00000000..a19015df
--- /dev/null
+++ b/apps/maui-test/MainPage.xaml.cs
@@ -0,0 +1,23 @@
+namespace TestMauiApp;
+
+public partial class MainPage : ContentPage
+{
+ int count = 0;
+
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+
+ private void OnCounterClicked(object? sender, EventArgs e)
+ {
+ count++;
+
+ if (count == 1)
+ CounterBtn.Text = $"Clicked {count} time";
+ else
+ CounterBtn.Text = $"Clicked {count} times";
+
+ SemanticScreenReader.Announce(CounterBtn.Text);
+ }
+}
diff --git a/apps/maui-test/MauiProgram.cs b/apps/maui-test/MauiProgram.cs
new file mode 100644
index 00000000..88013b6a
--- /dev/null
+++ b/apps/maui-test/MauiProgram.cs
@@ -0,0 +1,24 @@
+using Microsoft.Extensions.Logging;
+
+namespace TestMauiApp;
+
+public static class MauiProgram
+{
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ return builder.Build();
+ }
+}
diff --git a/apps/maui-test/Platforms/Android/AndroidManifest.xml b/apps/maui-test/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 00000000..bdec9b59
--- /dev/null
+++ b/apps/maui-test/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/maui-test/Platforms/Android/MainActivity.cs b/apps/maui-test/Platforms/Android/MainActivity.cs
new file mode 100644
index 00000000..29db1b1b
--- /dev/null
+++ b/apps/maui-test/Platforms/Android/MainActivity.cs
@@ -0,0 +1,10 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+
+namespace TestMauiApp;
+
+[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
+public class MainActivity : MauiAppCompatActivity
+{
+}
diff --git a/apps/maui-test/Platforms/Android/MainApplication.cs b/apps/maui-test/Platforms/Android/MainApplication.cs
new file mode 100644
index 00000000..bf5db886
--- /dev/null
+++ b/apps/maui-test/Platforms/Android/MainApplication.cs
@@ -0,0 +1,15 @@
+using Android.App;
+using Android.Runtime;
+
+namespace TestMauiApp;
+
+[Application]
+public class MainApplication : MauiApplication
+{
+ public MainApplication(IntPtr handle, JniHandleOwnership ownership)
+ : base(handle, ownership)
+ {
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
diff --git a/apps/maui-test/Platforms/Android/Resources/values/colors.xml b/apps/maui-test/Platforms/Android/Resources/values/colors.xml
new file mode 100644
index 00000000..5cd16049
--- /dev/null
+++ b/apps/maui-test/Platforms/Android/Resources/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #512BD4
+ #2B0B98
+ #2B0B98
+
\ No newline at end of file
diff --git a/apps/maui-test/Platforms/MacCatalyst/AppDelegate.cs b/apps/maui-test/Platforms/MacCatalyst/AppDelegate.cs
new file mode 100644
index 00000000..cd1e34b7
--- /dev/null
+++ b/apps/maui-test/Platforms/MacCatalyst/AppDelegate.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+namespace TestMauiApp;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
diff --git a/apps/maui-test/Platforms/MacCatalyst/Entitlements.plist b/apps/maui-test/Platforms/MacCatalyst/Entitlements.plist
new file mode 100644
index 00000000..8e87c0cb
--- /dev/null
+++ b/apps/maui-test/Platforms/MacCatalyst/Entitlements.plist
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ com.apple.security.app-sandbox
+
+
+ com.apple.security.network.client
+
+
+
+
diff --git a/apps/maui-test/Platforms/MacCatalyst/Info.plist b/apps/maui-test/Platforms/MacCatalyst/Info.plist
new file mode 100644
index 00000000..cfd1c83e
--- /dev/null
+++ b/apps/maui-test/Platforms/MacCatalyst/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UIDeviceFamily
+
+ 2
+
+ LSApplicationCategoryType
+ public.app-category.lifestyle
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/apps/maui-test/Platforms/MacCatalyst/Program.cs b/apps/maui-test/Platforms/MacCatalyst/Program.cs
new file mode 100644
index 00000000..da917bf9
--- /dev/null
+++ b/apps/maui-test/Platforms/MacCatalyst/Program.cs
@@ -0,0 +1,15 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace TestMauiApp;
+
+public class Program
+{
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+}
diff --git a/apps/maui-test/Platforms/Windows/App.xaml b/apps/maui-test/Platforms/Windows/App.xaml
new file mode 100644
index 00000000..cc30522d
--- /dev/null
+++ b/apps/maui-test/Platforms/Windows/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/apps/maui-test/Platforms/Windows/App.xaml.cs b/apps/maui-test/Platforms/Windows/App.xaml.cs
new file mode 100644
index 00000000..085f8685
--- /dev/null
+++ b/apps/maui-test/Platforms/Windows/App.xaml.cs
@@ -0,0 +1,24 @@
+using Microsoft.UI.Xaml;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace TestMauiApp.WinUI;
+
+///
+/// Provides application-specific behavior to supplement the default Application class.
+///
+public partial class App : MauiWinUIApplication
+{
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
+
diff --git a/apps/maui-test/Platforms/Windows/Package.appxmanifest b/apps/maui-test/Platforms/Windows/Package.appxmanifest
new file mode 100644
index 00000000..10ccc33c
--- /dev/null
+++ b/apps/maui-test/Platforms/Windows/Package.appxmanifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+ $placeholder$
+ User Name
+ $placeholder$.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/maui-test/Platforms/Windows/app.manifest b/apps/maui-test/Platforms/Windows/app.manifest
new file mode 100644
index 00000000..63816a54
--- /dev/null
+++ b/apps/maui-test/Platforms/Windows/app.manifest
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+ true
+
+
+
diff --git a/apps/maui-test/Platforms/iOS/AppDelegate.cs b/apps/maui-test/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 00000000..cd1e34b7
--- /dev/null
+++ b/apps/maui-test/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+namespace TestMauiApp;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
diff --git a/apps/maui-test/Platforms/iOS/Info.plist b/apps/maui-test/Platforms/iOS/Info.plist
new file mode 100644
index 00000000..358337bb
--- /dev/null
+++ b/apps/maui-test/Platforms/iOS/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/apps/maui-test/Platforms/iOS/Program.cs b/apps/maui-test/Platforms/iOS/Program.cs
new file mode 100644
index 00000000..da917bf9
--- /dev/null
+++ b/apps/maui-test/Platforms/iOS/Program.cs
@@ -0,0 +1,15 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace TestMauiApp;
+
+public class Program
+{
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+}
diff --git a/apps/maui-test/Platforms/iOS/Resources/PrivacyInfo.xcprivacy b/apps/maui-test/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 00000000..1ea3a5d7
--- /dev/null
+++ b/apps/maui-test/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,51 @@
+
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ E174.1
+
+
+
+
+
+
diff --git a/apps/maui-test/Properties/launchSettings.json b/apps/maui-test/Properties/launchSettings.json
new file mode 100644
index 00000000..f4c6c8dd
--- /dev/null
+++ b/apps/maui-test/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Windows Machine": {
+ "commandName": "Project",
+ "nativeDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/maui-test/Resources/AppIcon/appicon.svg b/apps/maui-test/Resources/AppIcon/appicon.svg
new file mode 100644
index 00000000..5f04fcfc
--- /dev/null
+++ b/apps/maui-test/Resources/AppIcon/appicon.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/apps/maui-test/Resources/AppIcon/appiconfg.svg b/apps/maui-test/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 00000000..62d66d7a
--- /dev/null
+++ b/apps/maui-test/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/apps/maui-test/Resources/Fonts/OpenSans-Regular.ttf b/apps/maui-test/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 00000000..6c872c6c
Binary files /dev/null and b/apps/maui-test/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/apps/maui-test/Resources/Fonts/OpenSans-Semibold.ttf b/apps/maui-test/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 00000000..d9ca35e2
Binary files /dev/null and b/apps/maui-test/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/apps/maui-test/Resources/Images/dotnet_bot.png b/apps/maui-test/Resources/Images/dotnet_bot.png
new file mode 100644
index 00000000..054167e5
Binary files /dev/null and b/apps/maui-test/Resources/Images/dotnet_bot.png differ
diff --git a/apps/maui-test/Resources/Raw/AboutAssets.txt b/apps/maui-test/Resources/Raw/AboutAssets.txt
new file mode 100644
index 00000000..f22d3bfa
--- /dev/null
+++ b/apps/maui-test/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,15 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories). Deployment of the asset to your application
+is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
+
+
+
+These files will be deployed with your package and will be accessible using Essentials:
+
+ async Task LoadMauiAsset()
+ {
+ using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+ }
diff --git a/apps/maui-test/Resources/Splash/splash.svg b/apps/maui-test/Resources/Splash/splash.svg
new file mode 100644
index 00000000..62d66d7a
--- /dev/null
+++ b/apps/maui-test/Resources/Splash/splash.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/apps/maui-test/Resources/Styles/Colors.xaml b/apps/maui-test/Resources/Styles/Colors.xaml
new file mode 100644
index 00000000..daae3bd9
--- /dev/null
+++ b/apps/maui-test/Resources/Styles/Colors.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+ #512BD4
+ #ac99ea
+ #242424
+ #DFD8F7
+ #9880e5
+ #2B0B98
+
+ White
+ Black
+ #D600AA
+ #190649
+ #1f1f1f
+
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/maui-test/Resources/Styles/Styles.xaml b/apps/maui-test/Resources/Styles/Styles.xaml
new file mode 100644
index 00000000..0dce3741
--- /dev/null
+++ b/apps/maui-test/Resources/Styles/Styles.xaml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/maui-test/TestMauiApp.csproj b/apps/maui-test/TestMauiApp.csproj
new file mode 100644
index 00000000..8a9d2e43
--- /dev/null
+++ b/apps/maui-test/TestMauiApp.csproj
@@ -0,0 +1,64 @@
+
+
+
+ net10.0-android;net10.0-ios;net10.0-maccatalyst
+ $(TargetFrameworks);net10.0-windows10.0.19041.0
+
+
+
+
+ Exe
+ TestMauiApp
+ true
+ true
+ enable
+ enable
+
+
+ TestMauiApp
+
+
+ com.companyname.testmauiapp
+
+
+ 1.0
+ 1
+
+
+ None
+
+ 15.0
+ 15.0
+ 21.0
+ 10.0.17763.0
+ 10.0.17763.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deployments/local/docker-compose.yml b/deployments/local/docker-compose.yml
index f306bbd3..54233431 100644
--- a/deployments/local/docker-compose.yml
+++ b/deployments/local/docker-compose.yml
@@ -307,10 +307,69 @@ services:
- "traefik.http.services.wallet-service.loadbalancer.healthcheck.path=/health/live"
- "traefik.http.services.wallet-service.loadbalancer.healthcheck.interval=10s"
+ # Chat Service .NET - Real-time Chat with SignalR
+ chat-service-net:
+ build:
+ context: ../../services/chat-service-net
+ dockerfile: Dockerfile
+ image: goodgo/chat-service-net:latest
+ container_name: chat-service-net-local
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_URLS=http://+:8080
+ # EN: Database - Neon PostgreSQL
+ # VI: Cơ sở dữ liệu - Neon PostgreSQL
+ - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=chat_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require
+ # EN: Redis for SignalR Backplane
+ # VI: Redis cho SignalR Backplane
+ - ConnectionStrings__Redis=167.114.174.113:6379,password=Velik@2026
+ # EN: IAM Service Communication
+ # VI: Giao tiếp IAM Service
+ - IamService__BaseUrl=http://iam-service-net:8080
+ - IamService__ServiceName=chat-service
+ # EN: JWT Configuration
+ # VI: Cấu hình JWT
+ - Jwt__Authority=http://iam-service-net:8080
+ - Jwt__Audience=goodgo-api
+ - Jwt__RequireHttpsMetadata=false
+ # EN: SignalR Configuration
+ # VI: Cấu hình SignalR
+ - SignalR__EnableMessagePack=true
+ - SignalR__StatefulReconnectBufferSize=32768
+ ports:
+ - "5010:8080"
+ depends_on:
+ iam-service-net:
+ condition: service_healthy
+ traefik:
+ condition: service_started
+ networks:
+ - microservices-network
+ restart: unless-stopped
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+ labels:
+ - "traefik.enable=true"
+ # EN: HTTP API routes
+ # VI: Routes cho HTTP API
+ - "traefik.http.routers.chat-service.rule=PathPrefix(`/api/v1/conversations`) || PathPrefix(`/api/v1/messages`) || PathPrefix(`/api/v1/chat`)"
+ - "traefik.http.routers.chat-service.entrypoints=web"
+ - "traefik.http.services.chat-service.loadbalancer.server.port=8080"
+ - "traefik.http.services.chat-service.loadbalancer.healthcheck.path=/health/live"
+ - "traefik.http.services.chat-service.loadbalancer.healthcheck.interval=10s"
+ # EN: SignalR Hub route with sticky sessions
+ # VI: Route cho SignalR Hub với sticky sessions
+ - "traefik.http.routers.chat-hub.rule=PathPrefix(`/hubs/chat`)"
+ - "traefik.http.routers.chat-hub.entrypoints=web"
+ - "traefik.http.routers.chat-hub.service=chat-service"
+ - "traefik.http.services.chat-service.loadbalancer.sticky.cookie=true"
+ - "traefik.http.services.chat-service.loadbalancer.sticky.cookie.name=chat_session"
+
- # ===========================================================================
- # OBSERVABILITY (Optional - Uncomment to enable)
- # ===========================================================================
# Jaeger - Distributed Tracing
# jaeger:
diff --git a/services/chat-service-net/Dockerfile b/services/chat-service-net/Dockerfile
index 6f9b52d3..03f13b9a 100644
--- a/services/chat-service-net/Dockerfile
+++ b/services/chat-service-net/Dockerfile
@@ -20,11 +20,11 @@ COPY src/ ./src/
# EN: Build the application
# VI: Build ứng dụng
WORKDIR "/src/src/ChatService.API"
-RUN dotnet build "ChatService.API.csproj" -c Release -o /app/build --no-restore
+RUN dotnet build "ChatService.API.csproj" -c Release -o /app/build
# Publish stage / Giai đoạn publish
FROM build AS publish
-RUN dotnet publish "ChatService.API.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore
+RUN dotnet publish "ChatService.API.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Runtime stage / Giai đoạn runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final