diff --git a/.gitignore b/.gitignore
index ba1194e..b06b40a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -481,4 +481,9 @@ FodyWeavers.xsd
.fake
.idea
-*.feature.cs
\ No newline at end of file
+*.feature.cs
+
+
+database
+
+.env.*
\ No newline at end of file
diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml
new file mode 100644
index 0000000..eeca7f0
--- /dev/null
+++ b/docker-compose.dev.yaml
@@ -0,0 +1,57 @@
+services:
+ sqlserver:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ platform: linux/amd64
+ container_name: dev-env-sqlserver
+ environment:
+ ACCEPT_EULA: "Y"
+ SA_PASSWORD: "${SA_PASSWORD}"
+ MSSQL_PID: "Developer"
+ ports:
+ - "1433:1433"
+ volumes:
+ - sqlserverdata:/var/opt/mssql
+ healthcheck:
+ test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
+ interval: 10s
+ timeout: 5s
+ retries: 12
+ start_period: 30s
+ networks:
+ - devnet
+
+ api.core:
+ image: api.core
+ container_name: dev-env-api-core
+ depends_on:
+ sqlserver:
+ condition: service_healthy
+ build:
+ context: ./src/Core
+ dockerfile: API/API.Core/Dockerfile
+ args:
+ BUILD_CONFIGURATION: Release
+ APP_UID: 1000
+ ports:
+ - "8080:8080"
+ - "8081:8081"
+ environment:
+ ASPNETCORE_ENVIRONMENT: "Development"
+ ASPNETCORE_URLS: "http://0.0.0.0:8080"
+ DOTNET_RUNNING_IN_CONTAINER: "true"
+ DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
+ restart: unless-stopped
+ networks:
+ - devnet
+ volumes:
+ - nuget-cache:/root/.nuget/packages
+
+volumes:
+ sqlserverdata:
+ driver: local
+ nuget-cache:
+ driver: local
+
+networks:
+ devnet:
+ driver: bridge
\ No newline at end of file
diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml
new file mode 100644
index 0000000..b6b9655
--- /dev/null
+++ b/docker-compose.prod.yaml
@@ -0,0 +1,55 @@
+services:
+ sqlserver:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ platform: linux/amd64
+ container_name: prod-env-sqlserver
+ environment:
+ ACCEPT_EULA: "Y"
+ SA_PASSWORD: "${SA_PASSWORD}"
+ MSSQL_PID: "Developer"
+ volumes:
+ - sqlserverdata:/var/opt/mssql
+ healthcheck:
+ test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
+ interval: 10s
+ timeout: 5s
+ retries: 12
+ start_period: 30s
+ networks:
+ - prodnet
+
+ api.core:
+ image: api.core
+ container_name: prod-env-api-core
+ depends_on:
+ sqlserver:
+ condition: service_healthy
+ build:
+ context: ./src/Core
+ dockerfile: API/API.Core/Dockerfile
+ args:
+ BUILD_CONFIGURATION: Release
+ APP_UID: 1000
+ ports:
+ - "8080:8080"
+ - "8081:8081"
+ environment:
+ ASPNETCORE_ENVIRONMENT: "Production"
+ ASPNETCORE_URLS: "http://0.0.0.0:8080"
+ DOTNET_RUNNING_IN_CONTAINER: "true"
+ DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
+ restart: unless-stopped
+ networks:
+ - prodnet
+ volumes:
+ - nuget-cache:/root/.nuget/packages
+
+volumes:
+ sqlserverdata:
+ driver: local
+ nuget-cache:
+ driver: local
+
+networks:
+ prodnet:
+ driver: bridge
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index e7d8a81..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-services:
- sqlserver:
- image: mcr.microsoft.com/mssql/server:2022-latest
- platform: linux/amd64
- container_name: sqlserver
- env_file:
- - .env
- environment:
- ACCEPT_EULA: "Y"
- SA_PASSWORD: "${SA_PASSWORD}"
- ports:
- - "1433:1433"
- volumes:
- - sqlserverdata:/var/opt/mssql
- healthcheck:
- test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-S", "localhost", "-U", "sa", "-P", "${SA_PASSWORD}", "-Q", "SELECT 1" ]
- interval: 10s
- timeout: 5s
- retries: 12
- networks:
- - devnet
-
-volumes:
- sqlserverdata:
- nuget-cache:
-
-networks:
- devnet:
- driver: bridge
diff --git a/src/Core/.dockerignore b/src/Core/.dockerignore
new file mode 100644
index 0000000..38bece4
--- /dev/null
+++ b/src/Core/.dockerignore
@@ -0,0 +1,25 @@
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.idea
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/src/Core/API/API.Core/API.Core.csproj b/src/Core/API/API.Core/API.Core.csproj
index 1e7ec86..f033c7e 100644
--- a/src/Core/API/API.Core/API.Core.csproj
+++ b/src/Core/API/API.Core/API.Core.csproj
@@ -4,6 +4,7 @@
enable
enable
WebAPI
+ Linux
@@ -19,4 +20,10 @@
+
+
+
+ .dockerignore
+
+
diff --git a/src/Core/API/API.Core/Dockerfile b/src/Core/API/API.Core/Dockerfile
new file mode 100644
index 0000000..7376967
--- /dev/null
+++ b/src/Core/API/API.Core/Dockerfile
@@ -0,0 +1,26 @@
+FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
+ARG APP_UID=1000
+USER $APP_UID
+WORKDIR /app
+EXPOSE 8080
+EXPOSE 8081
+
+FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["API/API.Core/API.Core.csproj", "API/API.Core/"]
+COPY ["Repository/Repository.Core/Repository.Core.csproj", "Repository/Repository.Core/"]
+COPY ["Service/Service.Core/Service.Core.csproj", "Service/Service.Core/"]
+RUN dotnet restore "API/API.Core/API.Core.csproj"
+COPY . .
+WORKDIR "/src/API/API.Core"
+RUN dotnet build "./API.Core.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./API.Core.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "API.Core.dll"]
diff --git a/src/Core/API/API.Core/Program.cs b/src/Core/API/API.Core/Program.cs
index 48ca639..3a44298 100644
--- a/src/Core/API/API.Core/Program.cs
+++ b/src/Core/API/API.Core/Program.cs
@@ -10,6 +10,17 @@ builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOpenApi();
+// Add health checks
+builder.Services.AddHealthChecks();
+
+// Configure logging for container output
+builder.Logging.ClearProviders();
+builder.Logging.AddConsole();
+if (!builder.Environment.IsProduction())
+{
+ builder.Logging.AddDebug();
+}
+
// Dependency Injection
builder.Services.AddSingleton();
builder.Services.AddScoped();
@@ -17,6 +28,7 @@ builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
+
var app = builder.Build();
app.UseSwagger();
@@ -24,6 +36,18 @@ app.UseSwaggerUI();
app.MapOpenApi();
app.UseHttpsRedirection();
+
+// Health check endpoint (used by Docker health checks and orchestrators)
+app.MapHealthChecks("/health");
+
app.MapControllers();
app.MapFallbackToController("Handle404", "NotFound");
+
+// Graceful shutdown handling
+var lifetime = app.Services.GetRequiredService();
+lifetime.ApplicationStopping.Register(() =>
+{
+ app.Logger.LogInformation("Application is shutting down gracefully...");
+});
+
app.Run();
\ No newline at end of file
diff --git a/src/Core/API/API.Core/appsettings.Development.json b/src/Core/API/API.Core/appsettings.Development.json
index ff66ba6..7498bb3 100644
--- a/src/Core/API/API.Core/appsettings.Development.json
+++ b/src/Core/API/API.Core/appsettings.Development.json
@@ -2,7 +2,18 @@
"Logging": {
"LogLevel": {
"Default": "Information",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Information",
+ "Microsoft.EntityFrameworkCore": "Information"
+ },
+ "Console": {
+ "IncludeScopes": true,
+ "TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffZ"
}
+ },
+ "AllowedHosts": "*",
+ "Jwt": {
+ "ExpirationMinutes": 120,
+ "Issuer": "biergarten-api",
+ "Audience": "biergarten-users"
}
}
diff --git a/src/Core/API/API.Core/appsettings.Production.json b/src/Core/API/API.Core/appsettings.Production.json
new file mode 100644
index 0000000..0e455a9
--- /dev/null
+++ b/src/Core/API/API.Core/appsettings.Production.json
@@ -0,0 +1,19 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Warning",
+ "Microsoft.AspNetCore": "Warning",
+ "Microsoft.EntityFrameworkCore": "Error"
+ },
+ "Console": {
+ "IncludeScopes": false,
+ "TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffZ"
+ }
+ },
+ "AllowedHosts": "*",
+ "Jwt": {
+ "ExpirationMinutes": 60,
+ "Issuer": "biergarten-api",
+ "Audience": "biergarten-users"
+ }
+}
diff --git a/src/Core/API/API.Core/appsettings.json b/src/Core/API/API.Core/appsettings.json
index 4d56694..0495346 100644
--- a/src/Core/API/API.Core/appsettings.json
+++ b/src/Core/API/API.Core/appsettings.json
@@ -2,8 +2,23 @@
"Logging": {
"LogLevel": {
"Default": "Information",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Warning",
+ "Microsoft.EntityFrameworkCore": "Information"
+ },
+ "Console": {
+ "IncludeScopes": true,
+ "TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffZ"
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "DefaultConnection": ""
+ },
+ "Jwt": {
+ "SecretKey": "",
+ "ExpirationMinutes": 60,
+ "Issuer": "biergarten-api",
+ "Audience": "biergarten-users"
+ }
}
+
diff --git a/src/Core/API/API.Specs/API.Specs.csproj b/src/Core/API/API.Specs/API.Specs.csproj
index ba032cb..0791bcb 100644
--- a/src/Core/API/API.Specs/API.Specs.csproj
+++ b/src/Core/API/API.Specs/API.Specs.csproj
@@ -12,6 +12,7 @@
+
@@ -33,5 +34,6 @@
+
diff --git a/src/Core/Core.slnx b/src/Core/Core.slnx
index 9fe412a..7687959 100644
--- a/src/Core/Core.slnx
+++ b/src/Core/Core.slnx
@@ -1,17 +1,17 @@
-
-
-
+
+
+
-
-
-
+
+
+
-
+