diff --git a/Dockerfile.service b/Dockerfile.service
new file mode 100644
index 0000000..a84bde7
--- /dev/null
+++ b/Dockerfile.service
@@ -0,0 +1,33 @@
+ARG DOTNET_VERSION=9.0
+
+FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} AS build
+ARG PROJECT_PATH
+WORKDIR /src
+
+COPY . .
+RUN dotnet publish "${PROJECT_PATH}" -c Release -o /app/publish
+
+FROM mcr.microsoft.com/dotnet/aspnet:${DOTNET_VERSION} AS runtime
+ARG APP_DLL
+WORKDIR /app
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends curl \
+ && rm -rf /var/lib/apt/lists/*
+
+USER app
+
+COPY --from=build --chown=app:app /app/publish .
+
+ENV ASPNETCORE_ENVIRONMENT=Production \
+ ASPNETCORE_URLS=http://0.0.0.0:8080 \
+ DOTNET_RUNNING_IN_CONTAINER=true \
+ DOTNET_PRINT_TELEMETRY_MESSAGE=false \
+ APP_DLL=${APP_DLL}
+
+EXPOSE 8080
+
+HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=3 \
+ CMD curl --fail --silent http://localhost:8080/healthz || exit 1
+
+ENTRYPOINT ["sh", "-c", "dotnet \"$APP_DLL\""]
diff --git a/DorkNet.Contracts/DorkNet.Contracts.csproj b/DorkNet.Contracts/DorkNet.Contracts.csproj
new file mode 100644
index 0000000..9623deb
--- /dev/null
+++ b/DorkNet.Contracts/DorkNet.Contracts.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
diff --git a/DorkNet.Contracts/DorkNetServiceMapOptions.cs b/DorkNet.Contracts/DorkNetServiceMapOptions.cs
new file mode 100644
index 0000000..cfb2244
--- /dev/null
+++ b/DorkNet.Contracts/DorkNetServiceMapOptions.cs
@@ -0,0 +1,26 @@
+namespace DorkNet.Contracts;
+
+public sealed class DorkNetServiceMapOptions
+{
+ public string Identity { get; set; } = "http://localhost:8081";
+ public string Rooms { get; set; } = "http://localhost:8082";
+ public string Notify { get; set; } = "http://localhost:8083";
+ public string Monolith { get; set; } = "http://localhost:8084";
+
+ public IReadOnlyList Endpoints()
+ {
+ DorkNetServiceEndpoint[] endpoints =
+ [
+ new(ServiceNames.Identity, Identity),
+ new(ServiceNames.Rooms, Rooms),
+ new(ServiceNames.Notify, Notify),
+ new(ServiceNames.Monolith, Monolith),
+ ];
+
+ return endpoints
+ .Where(endpoint => !string.IsNullOrWhiteSpace(endpoint.BaseUrl))
+ .ToArray();
+ }
+}
+
+public sealed record DorkNetServiceEndpoint(string Name, string BaseUrl);
diff --git a/DorkNet.Contracts/ServiceContracts.cs b/DorkNet.Contracts/ServiceContracts.cs
new file mode 100644
index 0000000..216e6a2
--- /dev/null
+++ b/DorkNet.Contracts/ServiceContracts.cs
@@ -0,0 +1,19 @@
+namespace DorkNet.Contracts;
+
+public sealed record ServiceHealthResponse(
+ string Service,
+ string Status,
+ DateTimeOffset CheckedAtUtc);
+
+public sealed record ServiceCapabilityResponse(
+ string Service,
+ string[] Owns,
+ string[] PlannedPublicRoutes);
+
+public sealed record ServiceProbeResponse(
+ string Service,
+ string BaseUrl,
+ string Status,
+ int? StatusCode,
+ string? Error,
+ DateTimeOffset CheckedAtUtc);
diff --git a/DorkNet.Contracts/ServiceNames.cs b/DorkNet.Contracts/ServiceNames.cs
new file mode 100644
index 0000000..12dae24
--- /dev/null
+++ b/DorkNet.Contracts/ServiceNames.cs
@@ -0,0 +1,10 @@
+namespace DorkNet.Contracts;
+
+public static class ServiceNames
+{
+ public const string Gateway = "gateway";
+ public const string Identity = "identity";
+ public const string Rooms = "rooms";
+ public const string Notify = "notify";
+ public const string Monolith = "monolith";
+}
diff --git a/DorkNet.Gateway/DorkNet.Gateway.csproj b/DorkNet.Gateway/DorkNet.Gateway.csproj
new file mode 100644
index 0000000..8e34531
--- /dev/null
+++ b/DorkNet.Gateway/DorkNet.Gateway.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/DorkNet.Gateway/Program.cs b/DorkNet.Gateway/Program.cs
new file mode 100644
index 0000000..b0b2808
--- /dev/null
+++ b/DorkNet.Gateway/Program.cs
@@ -0,0 +1,68 @@
+using DorkNet.Contracts;
+using DorkNet.ServiceDefaults;
+using Microsoft.Extensions.Options;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Configuration.AddJsonFile("appsettings.Local.json",
+ optional: true, reloadOnChange: true);
+
+builder.AddDorkNetServiceDefaults(ServiceNames.Gateway);
+builder.Services.Configure(
+ builder.Configuration.GetSection("DorkNet:Services"));
+
+var app = builder.Build();
+
+app.MapDorkNetServiceDefaults();
+
+app.MapGet("/", () => Results.Redirect("/healthz"));
+app.MapGet("/internal/services", (IOptions options) =>
+ Results.Ok(options.Value.Endpoints()));
+
+app.MapGet("/internal/services/health", async (
+ IOptions options,
+ IHttpClientFactory httpClientFactory,
+ CancellationToken ct) =>
+{
+ var client = httpClientFactory.CreateClient();
+ var probes = new List();
+
+ foreach (var endpoint in options.Value.Endpoints())
+ {
+ probes.Add(await ProbeServiceAsync(client, endpoint, ct));
+ }
+
+ return Results.Ok(probes);
+});
+
+app.Run();
+
+static async Task ProbeServiceAsync(
+ HttpClient client,
+ DorkNetServiceEndpoint endpoint,
+ CancellationToken ct)
+{
+ var checkedAt = DateTimeOffset.UtcNow;
+ var baseUrl = endpoint.BaseUrl.TrimEnd('/');
+
+ try
+ {
+ using var response = await client.GetAsync($"{baseUrl}/internal/healthz", ct);
+ return new ServiceProbeResponse(
+ endpoint.Name,
+ endpoint.BaseUrl,
+ response.IsSuccessStatusCode ? "ok" : "unhealthy",
+ (int)response.StatusCode,
+ null,
+ checkedAt);
+ }
+ catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException)
+ {
+ return new ServiceProbeResponse(
+ endpoint.Name,
+ endpoint.BaseUrl,
+ "unreachable",
+ null,
+ ex.Message,
+ checkedAt);
+ }
+}
diff --git a/DorkNet.Gateway/appsettings.json b/DorkNet.Gateway/appsettings.json
new file mode 100644
index 0000000..3daa59e
--- /dev/null
+++ b/DorkNet.Gateway/appsettings.json
@@ -0,0 +1,17 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "System.Net.Http.HttpClient": "Warning"
+ }
+ },
+ "DorkNet": {
+ "Services": {
+ "Identity": "http://localhost:8081",
+ "Rooms": "http://localhost:8082",
+ "Notify": "http://localhost:8083",
+ "Monolith": "http://localhost:8084"
+ }
+ }
+}
diff --git a/DorkNet.ServiceDefaults/DorkNet.ServiceDefaults.csproj b/DorkNet.ServiceDefaults/DorkNet.ServiceDefaults.csproj
new file mode 100644
index 0000000..7ce055b
--- /dev/null
+++ b/DorkNet.ServiceDefaults/DorkNet.ServiceDefaults.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/DorkNet.ServiceDefaults/DorkNetServiceDefaultsExtensions.cs b/DorkNet.ServiceDefaults/DorkNetServiceDefaultsExtensions.cs
new file mode 100644
index 0000000..19ae748
--- /dev/null
+++ b/DorkNet.ServiceDefaults/DorkNetServiceDefaultsExtensions.cs
@@ -0,0 +1,37 @@
+using DorkNet.Contracts;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace DorkNet.ServiceDefaults;
+
+public static class DorkNetServiceDefaultsExtensions
+{
+ public static WebApplicationBuilder AddDorkNetServiceDefaults(
+ this WebApplicationBuilder builder,
+ string serviceName)
+ {
+ builder.Services.AddSingleton(new DorkNetServiceInfo(serviceName));
+ builder.Services.AddHealthChecks();
+ builder.Services.AddHttpClient();
+ builder.Services.ConfigureHttpJsonOptions(opt =>
+ opt.SerializerOptions.PropertyNamingPolicy = null);
+
+ return builder;
+ }
+
+ public static WebApplication MapDorkNetServiceDefaults(this WebApplication app)
+ {
+ app.MapHealthChecks("/healthz");
+ app.MapGet("/internal/healthz", (DorkNetServiceInfo info) =>
+ {
+ return Results.Ok(new ServiceHealthResponse(
+ info.Name,
+ "ok",
+ DateTimeOffset.UtcNow));
+ });
+
+ return app;
+ }
+}
diff --git a/DorkNet.ServiceDefaults/DorkNetServiceInfo.cs b/DorkNet.ServiceDefaults/DorkNetServiceInfo.cs
new file mode 100644
index 0000000..6e7f7c6
--- /dev/null
+++ b/DorkNet.ServiceDefaults/DorkNetServiceInfo.cs
@@ -0,0 +1,3 @@
+namespace DorkNet.ServiceDefaults;
+
+public sealed record DorkNetServiceInfo(string Name);
diff --git a/DorkNet.Services.Identity/DorkNet.Services.Identity.csproj b/DorkNet.Services.Identity/DorkNet.Services.Identity.csproj
new file mode 100644
index 0000000..8e34531
--- /dev/null
+++ b/DorkNet.Services.Identity/DorkNet.Services.Identity.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/DorkNet.Services.Identity/Program.cs b/DorkNet.Services.Identity/Program.cs
new file mode 100644
index 0000000..1697272
--- /dev/null
+++ b/DorkNet.Services.Identity/Program.cs
@@ -0,0 +1,29 @@
+using DorkNet.Contracts;
+using DorkNet.ServiceDefaults;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Configuration.AddJsonFile("appsettings.Local.json",
+ optional: true, reloadOnChange: true);
+
+builder.AddDorkNetServiceDefaults(ServiceNames.Identity);
+
+var app = builder.Build();
+
+app.MapDorkNetServiceDefaults();
+app.MapGet("/internal/identity/capabilities", () =>
+ Results.Ok(new ServiceCapabilityResponse(
+ ServiceNames.Identity,
+ [
+ "accounts",
+ "auth",
+ "platform-login",
+ "jwt-issuance",
+ ],
+ [
+ "/account/*",
+ "/api/account/*",
+ "/api/platformlogin/*",
+ "/api/auth/*",
+ ])));
+
+app.Run();
diff --git a/DorkNet.Services.Identity/appsettings.json b/DorkNet.Services.Identity/appsettings.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/DorkNet.Services.Identity/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/DorkNet.Services.Notify/DorkNet.Services.Notify.csproj b/DorkNet.Services.Notify/DorkNet.Services.Notify.csproj
new file mode 100644
index 0000000..8e34531
--- /dev/null
+++ b/DorkNet.Services.Notify/DorkNet.Services.Notify.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/DorkNet.Services.Notify/Program.cs b/DorkNet.Services.Notify/Program.cs
new file mode 100644
index 0000000..4e2f842
--- /dev/null
+++ b/DorkNet.Services.Notify/Program.cs
@@ -0,0 +1,28 @@
+using DorkNet.Contracts;
+using DorkNet.ServiceDefaults;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Configuration.AddJsonFile("appsettings.Local.json",
+ optional: true, reloadOnChange: true);
+
+builder.AddDorkNetServiceDefaults(ServiceNames.Notify);
+
+var app = builder.Build();
+
+app.MapDorkNetServiceDefaults();
+app.MapGet("/internal/notify/capabilities", () =>
+ Results.Ok(new ServiceCapabilityResponse(
+ ServiceNames.Notify,
+ [
+ "signalr-edge",
+ "notification-fanout",
+ "presence",
+ "player-request-logs",
+ ],
+ [
+ "/hub/v1",
+ "/api/notification/*",
+ "/player/*presence*",
+ ])));
+
+app.Run();
diff --git a/DorkNet.Services.Notify/appsettings.json b/DorkNet.Services.Notify/appsettings.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/DorkNet.Services.Notify/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/DorkNet.Services.Rooms/DorkNet.Services.Rooms.csproj b/DorkNet.Services.Rooms/DorkNet.Services.Rooms.csproj
new file mode 100644
index 0000000..8e34531
--- /dev/null
+++ b/DorkNet.Services.Rooms/DorkNet.Services.Rooms.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/DorkNet.Services.Rooms/Program.cs b/DorkNet.Services.Rooms/Program.cs
new file mode 100644
index 0000000..ed11f71
--- /dev/null
+++ b/DorkNet.Services.Rooms/Program.cs
@@ -0,0 +1,31 @@
+using DorkNet.Contracts;
+using DorkNet.ServiceDefaults;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Configuration.AddJsonFile("appsettings.Local.json",
+ optional: true, reloadOnChange: true);
+
+builder.AddDorkNetServiceDefaults(ServiceNames.Rooms);
+
+var app = builder.Build();
+
+app.MapDorkNetServiceDefaults();
+app.MapGet("/internal/rooms/capabilities", () =>
+ Results.Ok(new ServiceCapabilityResponse(
+ ServiceNames.Rooms,
+ [
+ "rooms",
+ "subrooms",
+ "room-keys",
+ "matchmaking",
+ "discovery",
+ ],
+ [
+ "/rooms/*",
+ "/api/rooms/*",
+ "/roomserver/*",
+ "/v1/find",
+ "/v1/join/*",
+ ])));
+
+app.Run();
diff --git a/DorkNet.Services.Rooms/appsettings.json b/DorkNet.Services.Rooms/appsettings.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/DorkNet.Services.Rooms/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/DorkNet.sln b/DorkNet.sln
index 01601e1..dfcd048 100644
--- a/DorkNet.sln
+++ b/DorkNet.sln
@@ -13,6 +13,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrateSqliteToPostgres", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.AdminMobile", "DorkNet.AdminMobile\DorkNet.AdminMobile.csproj", "{C2265F00-DFC5-4352-A94C-B887E3C0E5CA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.Contracts", "DorkNet.Contracts\DorkNet.Contracts.csproj", "{7D9E995E-5333-43B2-848B-3522C6C3D893}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.ServiceDefaults", "DorkNet.ServiceDefaults\DorkNet.ServiceDefaults.csproj", "{0A66087B-37DF-401D-AFAC-01E7324C2460}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.Gateway", "DorkNet.Gateway\DorkNet.Gateway.csproj", "{1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.Services.Identity", "DorkNet.Services.Identity\DorkNet.Services.Identity.csproj", "{E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.Services.Rooms", "DorkNet.Services.Rooms\DorkNet.Services.Rooms.csproj", "{3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DorkNet.Services.Notify", "DorkNet.Services.Notify\DorkNet.Services.Notify.csproj", "{5A6D7277-0974-4F12-AD9D-C705F5CFE19C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -71,6 +83,78 @@ Global
{C2265F00-DFC5-4352-A94C-B887E3C0E5CA}.Release|x64.Build.0 = Release|Any CPU
{C2265F00-DFC5-4352-A94C-B887E3C0E5CA}.Release|x86.ActiveCfg = Release|Any CPU
{C2265F00-DFC5-4352-A94C-B887E3C0E5CA}.Release|x86.Build.0 = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|x64.Build.0 = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Debug|x86.Build.0 = Debug|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|x64.ActiveCfg = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|x64.Build.0 = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|x86.ActiveCfg = Release|Any CPU
+ {7D9E995E-5333-43B2-848B-3522C6C3D893}.Release|x86.Build.0 = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|x64.Build.0 = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Debug|x86.Build.0 = Debug|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|x64.ActiveCfg = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|x64.Build.0 = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|x86.ActiveCfg = Release|Any CPU
+ {0A66087B-37DF-401D-AFAC-01E7324C2460}.Release|x86.Build.0 = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|x64.Build.0 = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Debug|x86.Build.0 = Debug|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|x64.ActiveCfg = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|x64.Build.0 = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|x86.ActiveCfg = Release|Any CPU
+ {1A7D03D5-DAC5-474C-9A21-8F2EEF82396F}.Release|x86.Build.0 = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|x64.Build.0 = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Debug|x86.Build.0 = Debug|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|x64.ActiveCfg = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|x64.Build.0 = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|x86.ActiveCfg = Release|Any CPU
+ {E85B21BA-ED08-4CED-ADB5-6B5E5ADEEBD1}.Release|x86.Build.0 = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|x64.Build.0 = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Debug|x86.Build.0 = Debug|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|x64.ActiveCfg = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|x64.Build.0 = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|x86.ActiveCfg = Release|Any CPU
+ {3F01BA71-BD1E-461B-BCD0-F2E9CC92B640}.Release|x86.Build.0 = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|x64.Build.0 = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Debug|x86.Build.0 = Debug|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|x64.ActiveCfg = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|x64.Build.0 = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|x86.ActiveCfg = Release|Any CPU
+ {5A6D7277-0974-4F12-AD9D-C705F5CFE19C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/docker-compose.microservices.yml b/docker-compose.microservices.yml
new file mode 100644
index 0000000..d502099
--- /dev/null
+++ b/docker-compose.microservices.yml
@@ -0,0 +1,71 @@
+services:
+ gateway:
+ build:
+ context: .
+ dockerfile: Dockerfile.service
+ args:
+ PROJECT_PATH: DorkNet.Gateway/DorkNet.Gateway.csproj
+ APP_DLL: DorkNet.Gateway.dll
+ environment:
+ DorkNet__Services__Identity: http://identity:8080
+ DorkNet__Services__Rooms: http://rooms:8080
+ DorkNet__Services__Notify: http://notify:8080
+ DorkNet__Services__Monolith: ""
+ ports:
+ - "8080:8080"
+ depends_on:
+ - identity
+ - rooms
+ - notify
+
+ identity:
+ build:
+ context: .
+ dockerfile: Dockerfile.service
+ args:
+ PROJECT_PATH: DorkNet.Services.Identity/DorkNet.Services.Identity.csproj
+ APP_DLL: DorkNet.Services.Identity.dll
+ depends_on:
+ - postgres
+ - redis
+
+ rooms:
+ build:
+ context: .
+ dockerfile: Dockerfile.service
+ args:
+ PROJECT_PATH: DorkNet.Services.Rooms/DorkNet.Services.Rooms.csproj
+ APP_DLL: DorkNet.Services.Rooms.dll
+ environment:
+ S3__Endpoint: ${DORKNET_S3_ENDPOINT:-}
+ S3__AccessKey: ${DORKNET_S3_ACCESS_KEY:-}
+ S3__SecretKey: ${DORKNET_S3_SECRET_KEY:-}
+ S3__Region: ${DORKNET_S3_REGION:-garage}
+ depends_on:
+ - postgres
+ - redis
+
+ notify:
+ build:
+ context: .
+ dockerfile: Dockerfile.service
+ args:
+ PROJECT_PATH: DorkNet.Services.Notify/DorkNet.Services.Notify.csproj
+ APP_DLL: DorkNet.Services.Notify.dll
+ depends_on:
+ - redis
+
+ postgres:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_DB: dorknet
+ POSTGRES_USER: dorknet
+ POSTGRES_PASSWORD: dorknet_dev
+ volumes:
+ - microservices-postgres:/var/lib/postgresql/data
+
+ redis:
+ image: redis:7-alpine
+
+volumes:
+ microservices-postgres: