From 9bfbed9b92fd154cbdbc159304b884a0504f9100 Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Tue, 3 Feb 2026 23:02:07 -0500 Subject: [PATCH 1/2] add docker config --- .gitignore | 7 ++- docker-compose.dev.yaml | 57 +++++++++++++++++++ docker-compose.prod.yaml | 55 ++++++++++++++++++ docker-compose.yml | 29 ---------- src/Core/.dockerignore | 25 ++++++++ src/Core/API/API.Core/API.Core.csproj | 7 +++ src/Core/API/API.Core/Dockerfile | 26 +++++++++ src/Core/API/API.Core/Program.cs | 24 ++++++++ .../API/API.Core/appsettings.Development.json | 13 ++++- .../API/API.Core/appsettings.Production.json | 19 +++++++ src/Core/API/API.Core/appsettings.json | 19 ++++++- src/Core/API/API.Specs/API.Specs.csproj | 2 + src/Core/Core.slnx | 14 ++--- 13 files changed, 257 insertions(+), 40 deletions(-) create mode 100644 docker-compose.dev.yaml create mode 100644 docker-compose.prod.yaml delete mode 100644 docker-compose.yml create mode 100644 src/Core/.dockerignore create mode 100644 src/Core/API/API.Core/Dockerfile create mode 100644 src/Core/API/API.Core/appsettings.Production.json 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 @@ - - - + + + - - - + + + - + From e0af25f17c261bb17a69a95c2482ca72cf332247 Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Sat, 7 Feb 2026 13:21:28 -0500 Subject: [PATCH 2/2] Change dir name for migrations, update docker config to seed db --- .csharpierrc.json | 1 - docker-compose.dev.yaml | 32 ++++++-- docker-compose.prod.yaml | 33 ++++++-- src/Core/Core.slnx | 2 +- src/Core/Database/Database.Core/Program.cs | 32 -------- .../Database.Migrations.csproj} | 6 ++ .../Database/Database.Migrations/Dockerfile | 17 ++++ .../Database/Database.Migrations/Program.cs | 82 +++++++++++++++++++ .../scripts/01-schema/schema.sql | 0 .../02-functions/UDF_GetCountryIdByCode.sql | 0 .../UDF_GetStateProvinceIdByCode.sql | 0 .../01-UserAccount/USP_CreateUserAccount.sql | 0 .../01-UserAccount/USP_DeleteUserAccount.sql | 0 .../01-UserAccount/USP_GetAllUserAccounts.sql | 0 .../USP_GetUserAccountByEmail.sql | 0 .../01-UserAccount/USP_GetUserAccountById.sql | 0 .../USP_GetUserAccountByUsername.sql | 0 .../01-UserAccount/USP_UpdateUserAccount.sql | 0 .../USP_GetUserCredentialByUserAccountId.sql | 0 .../02-Auth/USP_InvalidateUserCredential.sql | 0 .../03-crud/02-Auth/USP_RegisterUser.sql | 0 .../02-Auth/USP_RotateUserCredential.sql | 0 .../USP_AddUserVerification.sql | 0 .../03-crud/04-Location/USP_CreateCity.sql | 0 .../03-crud/04-Location/USP_CreateCountry.sql | 0 .../04-Location/USP_CreateStateProvince.sql | 0 .../Database.Seed/Database.Seed.csproj | 4 +- src/Core/Database/Database.Seed/Program.cs | 16 ++-- 28 files changed, 168 insertions(+), 57 deletions(-) delete mode 100644 src/Core/Database/Database.Core/Program.cs rename src/Core/Database/{Database.Core/Database.Core.csproj => Database.Migrations/Database.Migrations.csproj} (74%) create mode 100644 src/Core/Database/Database.Migrations/Dockerfile create mode 100644 src/Core/Database/Database.Migrations/Program.cs rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/01-schema/schema.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/02-functions/UDF_GetCountryIdByCode.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/02-Auth/USP_RegisterUser.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/04-Location/USP_CreateCity.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/04-Location/USP_CreateCountry.sql (100%) rename src/Core/Database/{Database.Core => Database.Migrations}/scripts/03-crud/04-Location/USP_CreateStateProvince.sql (100%) diff --git a/.csharpierrc.json b/.csharpierrc.json index 1073d01..0e17843 100644 --- a/.csharpierrc.json +++ b/.csharpierrc.json @@ -1,5 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/belav/csharpier/main/src/CSharpier.Cli/schema.json", "printWidth": 80, "useTabs": false, "tabWidth": 4, diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index eeca7f0..6fff877 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -6,11 +6,11 @@ services: environment: ACCEPT_EULA: "Y" SA_PASSWORD: "${SA_PASSWORD}" - MSSQL_PID: "Developer" + MSSQL_PID: "Express" ports: - "1433:1433" volumes: - - sqlserverdata:/var/opt/mssql + - sqlserverdata-dev:/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 @@ -19,7 +19,25 @@ services: start_period: 30s networks: - devnet - + database.migrations: + image: database.migrations + container_name: dev-env-database-migrations + depends_on: + sqlserver: + condition: service_healthy + build: + context: ./src/Core/Database + dockerfile: Database.Migrations/Dockerfile + args: + BUILD_CONFIGURATION: Release + APP_UID: 1000 + environment: + DOTNET_RUNNING_IN_CONTAINER: "true" + DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" + restart: "no" + networks: + - devnet api.core: image: api.core container_name: dev-env-api-core @@ -44,14 +62,14 @@ services: networks: - devnet volumes: - - nuget-cache:/root/.nuget/packages + - nuget-cache-dev:/root/.nuget/packages volumes: - sqlserverdata: + sqlserverdata-dev: driver: local - nuget-cache: + nuget-cache-dev: driver: local networks: devnet: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index b6b9655..7efaaba 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -6,9 +6,9 @@ services: environment: ACCEPT_EULA: "Y" SA_PASSWORD: "${SA_PASSWORD}" - MSSQL_PID: "Developer" + MSSQL_PID: "Express" volumes: - - sqlserverdata:/var/opt/mssql + - sqlserverdata-prod:/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 @@ -18,6 +18,26 @@ services: networks: - prodnet + database.migrations: + image: database.migrations + container_name: prod-env-database-migrations + depends_on: + sqlserver: + condition: service_healthy + build: + context: ./src/Core/Database + dockerfile: Database.Migrations/Dockerfile + args: + BUILD_CONFIGURATION: Release + APP_UID: 1000 + environment: + DOTNET_RUNNING_IN_CONTAINER: "true" + DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" + restart: "no" + networks: + - prodnet + api.core: image: api.core container_name: prod-env-api-core @@ -37,19 +57,20 @@ services: ASPNETCORE_ENVIRONMENT: "Production" ASPNETCORE_URLS: "http://0.0.0.0:8080" DOTNET_RUNNING_IN_CONTAINER: "true" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" restart: unless-stopped networks: - prodnet volumes: - - nuget-cache:/root/.nuget/packages + - nuget-cache-prod:/root/.nuget/packages volumes: - sqlserverdata: + sqlserverdata-prod: driver: local - nuget-cache: + nuget-cache-prod: driver: local networks: prodnet: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/src/Core/Core.slnx b/src/Core/Core.slnx index 7687959..b2f3ee2 100644 --- a/src/Core/Core.slnx +++ b/src/Core/Core.slnx @@ -4,7 +4,7 @@ - + diff --git a/src/Core/Database/Database.Core/Program.cs b/src/Core/Database/Database.Core/Program.cs deleted file mode 100644 index d3405e9..0000000 --- a/src/Core/Database/Database.Core/Program.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Get connection string from environment variable - -using System.Reflection; -using DbUp; - -var connectionString = Environment.GetEnvironmentVariable( - "DB_CONNECTION_STRING" -); - -var upgrader = DeployChanges - .To.SqlDatabase(connectionString) - .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()) - .LogToConsole() - .Build(); - -var result = upgrader.PerformUpgrade(); - -if (!result.Successful) -{ - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(result.Error); - Console.ResetColor(); -#if DEBUG - Console.ReadLine(); -#endif - return -1; -} - -Console.ForegroundColor = ConsoleColor.Green; -Console.WriteLine("Success!"); -Console.ResetColor(); -return 0; diff --git a/src/Core/Database/Database.Core/Database.Core.csproj b/src/Core/Database/Database.Migrations/Database.Migrations.csproj similarity index 74% rename from src/Core/Database/Database.Core/Database.Core.csproj rename to src/Core/Database/Database.Migrations/Database.Migrations.csproj index 00a74a3..3488889 100644 --- a/src/Core/Database/Database.Core/Database.Core.csproj +++ b/src/Core/Database/Database.Migrations/Database.Migrations.csproj @@ -5,6 +5,7 @@ enable enable DataLayer + Linux @@ -14,4 +15,9 @@ + + + .dockerignore + + diff --git a/src/Core/Database/Database.Migrations/Dockerfile b/src/Core/Database/Database.Migrations/Dockerfile new file mode 100644 index 0000000..2fc184d --- /dev/null +++ b/src/Core/Database/Database.Migrations/Dockerfile @@ -0,0 +1,17 @@ + +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +# Copy everything from the context (src/Core/Database) +COPY . . +RUN dotnet restore "./Database.Migrations/Database.Migrations.csproj" +RUN dotnet build "./Database.Migrations/Database.Migrations.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Database.Migrations/Database.Migrations.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM mcr.microsoft.com/dotnet/runtime:10.0 AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Database.Migrations.dll"] diff --git a/src/Core/Database/Database.Migrations/Program.cs b/src/Core/Database/Database.Migrations/Program.cs new file mode 100644 index 0000000..1fa4b3a --- /dev/null +++ b/src/Core/Database/Database.Migrations/Program.cs @@ -0,0 +1,82 @@ +using System.Data; +using System.Reflection; +using DbUp; +using Microsoft.Data.SqlClient; + +namespace DataLayer; + +public static class Program +{ + private static readonly string? connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"); + private static readonly string? masterConnectionString = Environment.GetEnvironmentVariable("MASTER_DB_CONNECTION_STRING"); + + private static bool DeployMigrations() + { + var upgrader = DeployChanges + .To.SqlDatabase(connectionString) + .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()) + .LogToConsole() + .Build(); + + var result = upgrader.PerformUpgrade(); + return result.Successful; + } + + private static bool CreateDatabaseIfNotExists() + { + var myConn = new SqlConnection(masterConnectionString); + + const string str = """ + IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name = 'Biergarten') + CREATE DATABASE [Biergarten] + """; + + var myCommand = new SqlCommand(str, myConn); + try + { + myConn.Open(); + myCommand.ExecuteNonQuery(); + Console.WriteLine("Database creation command executed successfully."); + } + catch (System.Exception ex) + { + Console.WriteLine($"Error creating database: {ex}"); + } + finally + { + if (myConn.State == ConnectionState.Open) + { + myConn.Close(); + } + } + return true; + } + + public static int Main(string[] args) + { + Console.WriteLine("Starting database migrations..."); + + try + { + CreateDatabaseIfNotExists(); + var success = DeployMigrations(); + + if (success) + { + Console.WriteLine("Database migrations completed successfully."); + return 0; + } + else + { + Console.WriteLine("Database migrations failed."); + return 1; + } + } + catch (Exception ex) + { + Console.WriteLine("An error occurred during database migrations:"); + Console.WriteLine(ex.Message); + return 1; + } + } +} diff --git a/src/Core/Database/Database.Core/scripts/01-schema/schema.sql b/src/Core/Database/Database.Migrations/scripts/01-schema/schema.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/01-schema/schema.sql rename to src/Core/Database/Database.Migrations/scripts/01-schema/schema.sql diff --git a/src/Core/Database/Database.Core/scripts/02-functions/UDF_GetCountryIdByCode.sql b/src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetCountryIdByCode.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/02-functions/UDF_GetCountryIdByCode.sql rename to src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetCountryIdByCode.sql diff --git a/src/Core/Database/Database.Core/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql b/src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql rename to src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RegisterUser.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RegisterUser.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RegisterUser.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RegisterUser.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCity.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCity.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCity.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCity.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCountry.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCountry.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCountry.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCountry.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateStateProvince.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateStateProvince.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateStateProvince.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateStateProvince.sql diff --git a/src/Core/Database/Database.Seed/Database.Seed.csproj b/src/Core/Database/Database.Seed/Database.Seed.csproj index e9b8521..656d3be 100644 --- a/src/Core/Database/Database.Seed/Database.Seed.csproj +++ b/src/Core/Database/Database.Seed/Database.Seed.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/src/Core/Database/Database.Seed/Program.cs b/src/Core/Database/Database.Seed/Program.cs index 8612f2e..720005b 100644 --- a/src/Core/Database/Database.Seed/Program.cs +++ b/src/Core/Database/Database.Seed/Program.cs @@ -22,14 +22,14 @@ try await useMaster.ExecuteNonQueryAsync(); var dbName = "Biergarten"; - var dropDb = connection.CreateCommand(); - dropDb.CommandText = $@" - IF DB_ID(N'{dbName}') IS NOT NULL - BEGIN - ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; - DROP DATABASE [{dbName}]; - END"; - await dropDb.ExecuteNonQueryAsync(); + var dropDb = connection.CreateCommand(); + dropDb.CommandText = $@" + IF DB_ID(N'{dbName}') IS NOT NULL + BEGIN + ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [{dbName}]; + END"; + await dropDb.ExecuteNonQueryAsync(); var createDb = connection.CreateCommand(); createDb.CommandText = $@"CREATE DATABASE [{dbName}];";