From c28b248b7fe262bf0f98b67085678dc563a65223 Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Mon, 27 Apr 2026 02:54:46 +0300
Subject: [PATCH 01/16] feat: add CI for backend, fix tests
---
.dockerignore | 9 ++
.github/workflows/pr-validation.yml | 33 +++++
.gitignore | 2 +-
SmartEventBooking.slnx | 8 +-
src/api/SmartEventBooking.Web/Dockerfile | 27 ++++
src/client/angular.json | 3 +-
src/client/package-lock.json | 140 +++---------------
.../Persistence/IdentitySeederTests.cs | 0
...ing.Infrastructure.IntegrationTests.csproj | 8 +-
.../Helpers/MockHelpers.cs | 0
.../Identity/AuthServiceTests.cs | 0
...entBooking.Infrastructure.UnitTests.csproj | 10 +-
.../Controllers/AuthControllerTests.cs | 116 +++++----------
.../Controllers/HomeControllerTests.cs | 43 +++---
.../SmartEventBooking.Web.Tests.csproj | 3 +-
15 files changed, 162 insertions(+), 240 deletions(-)
create mode 100644 .dockerignore
create mode 100644 .github/workflows/pr-validation.yml
create mode 100644 src/api/SmartEventBooking.Web/Dockerfile
rename {SmartEventBooking.Infrastructure.IntegrationTests => tests/SmartEventBooking.Infrastructure.IntegrationTests}/Persistence/IdentitySeederTests.cs (100%)
rename {SmartEventBooking.Infrastructure.IntegrationTests => tests/SmartEventBooking.Infrastructure.IntegrationTests}/SmartEventBooking.Infrastructure.IntegrationTests.csproj (65%)
rename {SmartEventBooking.Infrastructure.UnitTests => tests/SmartEventBooking.Infrastructure.UnitTests}/Helpers/MockHelpers.cs (100%)
rename {SmartEventBooking.Infrastructure.UnitTests => tests/SmartEventBooking.Infrastructure.UnitTests}/Identity/AuthServiceTests.cs (100%)
rename {SmartEventBooking.Infrastructure.UnitTests => tests/SmartEventBooking.Infrastructure.UnitTests}/SmartEventBooking.Infrastructure.UnitTests.csproj (65%)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..e031e1f
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,9 @@
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.vs
+**/.vscode
+**/bin
+**/obj
+**/Dockerfile
\ No newline at end of file
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
new file mode 100644
index 0000000..495b94c
--- /dev/null
+++ b/.github/workflows/pr-validation.yml
@@ -0,0 +1,33 @@
+name: PR Validation
+
+on:
+ pull_request:
+ branches:
+ - develop
+ - main
+
+jobs:
+ build-and-test:
+ name: Build and Test
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Restore dependencies
+ run: dotnet restore -p:Configuration=Release
+
+ - name: Build project
+ run: dotnet build --no-restore --configuration Release
+
+ - name: Run Unit & Integration Tests
+ run: dotnet test --no-build --configuration Release --verbosity normal
+
+ - name: Verify Dockerfile builds successfully
+ run: docker build -t smarteventbooking:test -f src/api/SmartEventBooking.Web/Dockerfile .
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3101c45..bb85a2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -418,4 +418,4 @@ FodyWeavers.xsd
*.msp
docker-compose.yml
-Dockerfile
\ No newline at end of file
+#Dockerfile
\ No newline at end of file
diff --git a/SmartEventBooking.slnx b/SmartEventBooking.slnx
index 4537440..1669172 100644
--- a/SmartEventBooking.slnx
+++ b/SmartEventBooking.slnx
@@ -8,12 +8,8 @@
-
-
-
-
-
-
+
+
diff --git a/src/api/SmartEventBooking.Web/Dockerfile b/src/api/SmartEventBooking.Web/Dockerfile
new file mode 100644
index 0000000..93cb69a
--- /dev/null
+++ b/src/api/SmartEventBooking.Web/Dockerfile
@@ -0,0 +1,27 @@
+FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
+WORKDIR /app
+EXPOSE 8080
+
+FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+WORKDIR /src
+
+COPY ["src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj", "src/api/SmartEventBooking.Web/"]
+COPY ["src/api/SmartEventBooking.Application/SmartEventBooking.Application.csproj", "src/api/SmartEventBooking.Application/"]
+COPY ["src/api/SmartEventBooking.Domain/SmartEventBooking.Domain.csproj", "src/api/SmartEventBooking.Domain/"]
+COPY ["src/api/SmartEventBooking.Infrastructure/SmartEventBooking.Infrastructure.csproj", "src/api/SmartEventBooking.Infrastructure/"]
+COPY ["src/api/SmartEventBooking.Shared/SmartEventBooking.Shared.csproj", "src/api/SmartEventBooking.Shared/"]
+
+RUN dotnet restore "src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj"
+
+COPY . .
+WORKDIR "/src/src/api/SmartEventBooking.Web"
+
+RUN dotnet build "SmartEventBooking.Web.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "SmartEventBooking.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "SmartEventBooking.Web.dll"]
\ No newline at end of file
diff --git a/src/client/angular.json b/src/client/angular.json
index c71771d..d14c691 100644
--- a/src/client/angular.json
+++ b/src/client/angular.json
@@ -2,7 +2,8 @@
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
- "packageManager": "npm"
+ "packageManager": "npm",
+ "analytics": false
},
"newProjectRoot": "projects",
"projects": {
diff --git a/src/client/package-lock.json b/src/client/package-lock.json
index d2902e5..bc1d9ce 100644
--- a/src/client/package-lock.json
+++ b/src/client/package-lock.json
@@ -463,6 +463,7 @@
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.9.tgz",
"integrity": "sha512-7spQcF3hPN/fjTx6Pwa32KRRdO0NcixnRuPV4lo50ejtXesjiLVR+fkaX38sawAyGoq89IuuYvUDrbLwCMypmQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -479,6 +480,7 @@
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.9.tgz",
"integrity": "sha512-clsK1EsSPtAuqlRl4CciA/gsvsW7xe0eWcvHxtrMW6DYaUJ6X4AAuDxEEJ5cf/3Mpw4s8KssjIUPPtbrUIGLSQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -492,6 +494,7 @@
"integrity": "sha512-hTTW/OiqTXrwTneS18CMp47OX0XSbLYl2rIomLS3nXVJniSETH6S/k+LqQtGWWgLbzsd3PzUOOckHnvzpTBTsA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/core": "7.29.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
@@ -524,6 +527,7 @@
"resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.9.tgz",
"integrity": "sha512-uZLq2aedJ+0uEZxyf6a1Nc7y1aZ7akAW7K1Kon8JUDZOvI2IDbk0i00MzkELt8q9uSmSSqg9zNKuhjspFf0Pyw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -568,6 +572,7 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.9.tgz",
"integrity": "sha512-MjEtFvoFtsjsAeu2yzauqGgwwEHV4ml25c9vGFmw4OmSoNme4yp41f2DegwOkn1TTHL3OF3GE65ng2U2feJU4Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -692,6 +697,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -1055,6 +1061,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.19.0"
},
@@ -1103,35 +1110,11 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.19.0"
}
},
- "node_modules/@emnapi/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
- "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.2.1",
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@emnapi/runtime": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -1139,7 +1122,6 @@
"dev": true,
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"tslib": "^2.4.0"
}
@@ -1871,6 +1853,7 @@
"integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@inquirer/checkbox": "^4.3.2",
"@inquirer/confirm": "^5.1.21",
@@ -2442,9 +2425,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2462,9 +2442,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2482,9 +2459,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2502,9 +2476,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2522,9 +2493,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2542,9 +2510,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -2562,9 +2527,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3008,9 +2970,6 @@
"arm"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3032,9 +2991,6 @@
"arm"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3056,9 +3012,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3080,9 +3033,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3104,9 +3054,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3128,9 +3075,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3308,9 +3252,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3328,9 +3269,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3348,9 +3286,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3368,9 +3303,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3547,9 +3479,6 @@
"arm"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3564,9 +3493,6 @@
"arm"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3581,9 +3507,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3598,9 +3521,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3615,9 +3535,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3632,9 +3549,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3649,9 +3563,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3666,9 +3577,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3683,9 +3591,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3700,9 +3605,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3717,9 +3619,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3734,9 +3633,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3751,9 +3647,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4413,6 +4306,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782",
@@ -4564,6 +4458,7 @@
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"readdirp": "^5.0.0"
},
@@ -5252,6 +5147,7 @@
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
@@ -5580,6 +5476,7 @@
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -5921,6 +5818,7 @@
"integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.31",
"@asamuzakjp/dom-selector": "^6.8.1",
@@ -6029,6 +5927,7 @@
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"cli-truncate": "^5.0.0",
"colorette": "^2.0.20",
@@ -7126,6 +7025,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -7439,6 +7339,7 @@
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -8063,7 +7964,8 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD"
+ "license": "0BSD",
+ "peer": true
},
"node_modules/tuf-js": {
"version": "4.1.0",
@@ -8101,6 +8003,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -8186,6 +8089,7 @@
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -8261,6 +8165,7 @@
"integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vitest/expect": "4.1.5",
"@vitest/mocker": "4.1.5",
@@ -8653,6 +8558,7 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/SmartEventBooking.Infrastructure.IntegrationTests/Persistence/IdentitySeederTests.cs b/tests/SmartEventBooking.Infrastructure.IntegrationTests/Persistence/IdentitySeederTests.cs
similarity index 100%
rename from SmartEventBooking.Infrastructure.IntegrationTests/Persistence/IdentitySeederTests.cs
rename to tests/SmartEventBooking.Infrastructure.IntegrationTests/Persistence/IdentitySeederTests.cs
diff --git a/SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj b/tests/SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj
similarity index 65%
rename from SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj
rename to tests/SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj
index a7d6e10..dfadfa3 100644
--- a/SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj
+++ b/tests/SmartEventBooking.Infrastructure.IntegrationTests/SmartEventBooking.Infrastructure.IntegrationTests.csproj
@@ -22,10 +22,10 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/SmartEventBooking.Infrastructure.UnitTests/Helpers/MockHelpers.cs b/tests/SmartEventBooking.Infrastructure.UnitTests/Helpers/MockHelpers.cs
similarity index 100%
rename from SmartEventBooking.Infrastructure.UnitTests/Helpers/MockHelpers.cs
rename to tests/SmartEventBooking.Infrastructure.UnitTests/Helpers/MockHelpers.cs
diff --git a/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs b/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
similarity index 100%
rename from SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
rename to tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
diff --git a/SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj b/tests/SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj
similarity index 65%
rename from SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj
rename to tests/SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj
index 31f2528..8bc9eae 100644
--- a/SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj
+++ b/tests/SmartEventBooking.Infrastructure.UnitTests/SmartEventBooking.Infrastructure.UnitTests.csproj
@@ -1,7 +1,7 @@
- net9.0
+ net10.0
enable
enable
false
@@ -10,7 +10,7 @@
-
+
@@ -18,9 +18,9 @@
-
-
-
+
+
+
diff --git a/tests/SmartEventBooking.Web.Tests/Controllers/AuthControllerTests.cs b/tests/SmartEventBooking.Web.Tests/Controllers/AuthControllerTests.cs
index 3a963c6..70b253c 100644
--- a/tests/SmartEventBooking.Web.Tests/Controllers/AuthControllerTests.cs
+++ b/tests/SmartEventBooking.Web.Tests/Controllers/AuthControllerTests.cs
@@ -1,101 +1,53 @@
+using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Moq;
-using FluentAssertions;
-using SmartEventBooking.Web.Controllers;
using SmartEventBooking.Application.Abstractions.Identity;
using SmartEventBooking.Application.DTOs.Auth;
-using Microsoft.AspNetCore.Http;
-using System.Security.Claims;
-
-namespace SmartEventBooking.Web.Tests.Controllers
-{
- public class AuthControllerTests
- {
- private readonly Mock _authServiceMock;
- private readonly AuthController _controller;
-
- public AuthControllerTests()
- {
- _authServiceMock = new Mock();
- _controller = new AuthController(_authServiceMock.Object);
-
- var user = new ClaimsPrincipal(new ClaimsIdentity());
- _controller.ControllerContext = new ControllerContext
- {
- HttpContext = new DefaultHttpContext { User = user }
- };
- }
-
- [Fact]
- public void Register_ReturnsViewResult_WhenNotAuthenticated()
- {
- var result = _controller.Register();
-
- result.Should().BeOfType();
- }
+using SmartEventBooking.Web.Controllers;
- [Fact]
- public async Task Register_Post_ReturnsViewResult_WhenModelStateIsInvalid()
- {
- _controller.ModelState.AddModelError("Email", "Required");
- var dto = new RegisterDto
- {
- Email = "",
- Password = "123",
- ConfirmPassword = "123",
- FirstName = "Test"
- };
+namespace SmartEventBooking.Web.Tests.Controllers;
- var result = await _controller.Register(dto);
+public class AuthControllerTests
+{
+ private readonly Mock _authServiceMock = new();
- result.Should().BeOfType();
- var viewResult = result as ViewResult;
- viewResult?.Model.Should().Be(dto);
- }
+ private AuthController CreateController() => new(_authServiceMock.Object);
- [Fact]
- public async Task Register_Post_RedirectsToHome_WhenRegistrationSucceeds()
+ [Fact]
+ public async Task Register_ReturnsOk_WhenRegistrationSucceeds()
+ {
+ var dto = new RegisterDto
{
- var dto = new RegisterDto
- {
- Email = "test@test.com",
- Password = "Password123!",
- ConfirmPassword = "Password123!",
- FirstName = "Ivan"
- };
+ Email = "test@example.com",
+ Password = "Password123!",
+ ConfirmPassword = "Password123!",
+ FirstName = "Ivan"
+ };
- _authServiceMock.Setup(x => x.RegisterAsync(dto))
- .ReturnsAsync(new AuthResultDto { Succeeded = true });
+ _authServiceMock.Setup(x => x.RegisterAsync(dto))
+ .ReturnsAsync(new AuthResultDto { Succeeded = true });
- var result = await _controller.Register(dto);
+ var result = await CreateController().Register(dto);
- result.Should().BeOfType();
- var redirectResult = result as RedirectToActionResult;
- redirectResult?.ActionName.Should().Be("Index");
- redirectResult?.ControllerName.Should().Be("Home");
- }
+ result.Should().BeOfType();
+ }
- [Fact]
- public async Task Register_Post_ReturnsViewWithErrors_WhenRegistrationFails()
+ [Fact]
+ public async Task Register_ReturnsBadRequest_WhenRegistrationFails()
+ {
+ var dto = new RegisterDto
{
- var dto = new RegisterDto
- {
- Email = "test@test.com",
- Password = "Password123!",
- ConfirmPassword = "Password123!",
- FirstName = "Ivan"
- };
+ Email = "test@example.com",
+ Password = "Password123!",
+ ConfirmPassword = "Password123!",
+ FirstName = "Ivan"
+ };
- _authServiceMock.Setup(x => x.RegisterAsync(dto))
- .ReturnsAsync(new AuthResultDto { Succeeded = false, Errors = new[] { "Error 1" } });
+ _authServiceMock.Setup(x => x.RegisterAsync(dto))
+ .ReturnsAsync(new AuthResultDto { Succeeded = false, Errors = ["Email already taken"] });
- var result = await _controller.Register(dto);
+ var result = await CreateController().Register(dto);
- result.Should().BeOfType();
- _controller.ModelState.IsValid.Should().BeFalse();
- _controller.ModelState.Values.SelectMany(v => v.Errors)
- .Should().ContainSingle()
- .Which.ErrorMessage.Should().Be("Error 1");
- }
+ result.Should().BeOfType();
}
}
diff --git a/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs b/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
index c83573b..0c534ed 100644
--- a/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
+++ b/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
@@ -3,46 +3,43 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using SmartEventBooking.Web.Controllers;
-using SmartEventBooking.Web.Models;
namespace SmartEventBooking.Web.Tests.Controllers;
public class HomeControllerTests
{
+ private static HomeController CreateController() =>
+ new(NullLogger.Instance)
+ {
+ ControllerContext = new ControllerContext
+ {
+ HttpContext = new DefaultHttpContext()
+ }
+ };
+
[Fact]
- public void Index_ReturnsViewResult()
+ public void Index_ReturnsOk()
{
- var controller = new HomeController(NullLogger.Instance);
-
- var result = controller.Index();
+ var result = CreateController().Index();
- result.Should().BeOfType();
+ result.Should().BeOfType();
}
[Fact]
- public void Privacy_ReturnsViewResult()
+ public void Privacy_ReturnsOk()
{
- var controller = new HomeController(NullLogger.Instance);
+ var result = CreateController().Privacy();
- var result = controller.Privacy();
-
- result.Should().BeOfType();
+ result.Should().BeOfType();
}
[Fact]
- public void Error_ReturnsViewWithErrorViewModel()
+ public void Error_ReturnsObjectResult_WithProblemDetails()
{
- var controller = new HomeController(NullLogger.Instance)
- {
- ControllerContext = new ControllerContext
- {
- HttpContext = new DefaultHttpContext()
- }
- };
-
- var result = controller.Error();
+ var result = CreateController().Error();
- var viewResult = result.Should().BeOfType().Subject;
- viewResult.Model.Should().BeOfType();
+ var objectResult = result.Should().BeOfType().Subject;
+ objectResult.StatusCode.Should().Be(500);
+ objectResult.Value.Should().BeOfType();
}
}
diff --git a/tests/SmartEventBooking.Web.Tests/SmartEventBooking.Web.Tests.csproj b/tests/SmartEventBooking.Web.Tests/SmartEventBooking.Web.Tests.csproj
index cf01b78..a5a993d 100644
--- a/tests/SmartEventBooking.Web.Tests/SmartEventBooking.Web.Tests.csproj
+++ b/tests/SmartEventBooking.Web.Tests/SmartEventBooking.Web.Tests.csproj
@@ -21,7 +21,8 @@
-
+
+
From 50b44297beeea9afdd86670ca381e35aac10c231 Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Mon, 27 Apr 2026 14:49:21 +0300
Subject: [PATCH 02/16] feat: add frontend CI, add dockerfile for frontend and
docker-compose and configure nginx
---
.github/workflows/pr-validation.yml | 38 ++++++++++++--
.gitignore | 2 +-
docker-compose.yml | 50 +++++++++++++++++++
.../DependencyInjection.cs | 5 +-
src/api/SmartEventBooking.Web/Program.cs | 3 +-
src/client/.nvmrc | 1 +
src/client/Dockerfile | 22 ++++++++
src/client/config.json.template | 3 ++
src/client/docker-entrypoint.sh | 5 ++
src/client/nginx.custom.conf | 21 ++++++++
src/client/package-lock.json | 50 ++++++++++---------
src/client/src/app/app.config.ts | 9 +++-
.../src/app/core/services/category.service.ts | 7 ++-
.../src/app/core/services/config.service.ts | 23 +++++++++
.../src/app/core/services/event.service.ts | 8 ++-
src/client/src/assets/config.json | 3 ++
.../environments/environment.development.ts | 3 +-
src/client/src/environments/environment.ts | 3 +-
18 files changed, 216 insertions(+), 40 deletions(-)
create mode 100644 docker-compose.yml
create mode 100644 src/client/.nvmrc
create mode 100644 src/client/Dockerfile
create mode 100644 src/client/config.json.template
create mode 100644 src/client/docker-entrypoint.sh
create mode 100644 src/client/nginx.custom.conf
create mode 100644 src/client/src/app/core/services/config.service.ts
create mode 100644 src/client/src/assets/config.json
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index 495b94c..8615baa 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -7,8 +7,8 @@ on:
- main
jobs:
- build-and-test:
- name: Build and Test
+ build-and-test-api:
+ name: API Validation
runs-on: ubuntu-latest
steps:
@@ -29,5 +29,35 @@ jobs:
- name: Run Unit & Integration Tests
run: dotnet test --no-build --configuration Release --verbosity normal
- - name: Verify Dockerfile builds successfully
- run: docker build -t smarteventbooking:test -f src/api/SmartEventBooking.Web/Dockerfile .
\ No newline at end of file
+ - name: Verify API Dockerfile builds
+ run: docker build -t smarteventbooking-api:test -f src/api/SmartEventBooking.Web/Dockerfile .
+
+
+ build-and-test-client:
+ name: Client UI Validation
+ runs-on: ubuntu-latest
+
+ defaults:
+ run:
+ working-directory: ./src/client
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: src/client/.nvmrc
+ cache: 'npm'
+ cache-dependency-path: ./src/client/package-lock.json
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build Angular project
+ run: npm run build -- --configuration production
+
+ - name: Verify Client Dockerfile builds
+ working-directory: .
+ run: docker build -t smarteventbooking-client:test src/client/
diff --git a/.gitignore b/.gitignore
index bb85a2a..2daa04b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -417,5 +417,5 @@ FodyWeavers.xsd
*.msm
*.msp
-docker-compose.yml
+#docker-compose.yml
#Dockerfile
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..6815a43
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,50 @@
+
+services:
+ db:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ container_name: smart-event-booking-sql-db
+ environment:
+ - ACCEPT_EULA=Y
+ - MSSQL_SA_PASSWORD=${Database__Password}
+ ports:
+ - "1433:1433"
+ volumes:
+ - sql_data:/var/opt/mssql
+ healthcheck:
+ test: ["CMD", "/opt/mssql-tools18/bin/sqlcmd", "-S", "localhost", "-U", "sa", "-P", "${Database__Password}", "-Q", "SELECT 1", "-No"]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+ start_period: 10s
+
+ api:
+ image: smart-event-api:latest
+ build:
+ context: .
+ dockerfile: src/api/SmartEventBooking.Web/Dockerfile
+ container_name: smart-event-booking-api-app
+ ports:
+ - "5270:8080"
+ env_file:
+ - .env
+ environment:
+ - Database__Server=db
+ depends_on:
+ db:
+ condition: service_healthy
+
+ client:
+ image: smart-event-booking-client:latest
+ build:
+ context: ./src/client
+ dockerfile: Dockerfile
+ container_name: smart-event-booking-client-app
+ ports:
+ - "4200:80"
+ environment:
+ - API_BASE_URL=http://localhost:5270
+ depends_on:
+ - api
+
+volumes:
+ sql_data:
\ No newline at end of file
diff --git a/src/api/SmartEventBooking.Infrastructure/DependencyInjection.cs b/src/api/SmartEventBooking.Infrastructure/DependencyInjection.cs
index bb40337..3515b6d 100644
--- a/src/api/SmartEventBooking.Infrastructure/DependencyInjection.cs
+++ b/src/api/SmartEventBooking.Infrastructure/DependencyInjection.cs
@@ -40,8 +40,9 @@ public static IServiceCollection AddInfrastructure(
options.UseSqlServer(connectionString, sqlOptions =>
{
- sqlOptions.EnableRetryOnFailure(maxRetryCount: 3,
- maxRetryDelay: TimeSpan.FromSeconds(5),
+ sqlOptions.EnableRetryOnFailure(
+ maxRetryCount: 3,
+ maxRetryDelay: TimeSpan.FromSeconds(10),
errorNumbersToAdd: null);
});
});
diff --git a/src/api/SmartEventBooking.Web/Program.cs b/src/api/SmartEventBooking.Web/Program.cs
index 8c276b2..4a0ce89 100644
--- a/src/api/SmartEventBooking.Web/Program.cs
+++ b/src/api/SmartEventBooking.Web/Program.cs
@@ -39,7 +39,8 @@
{
builder.WithOrigins("http://localhost:4200", "https://localhost:4200")
.AllowAnyMethod()
- .AllowAnyHeader();
+ .AllowAnyHeader()
+ .AllowCredentials();
});
});
diff --git a/src/client/.nvmrc b/src/client/.nvmrc
new file mode 100644
index 0000000..a45fd52
--- /dev/null
+++ b/src/client/.nvmrc
@@ -0,0 +1 @@
+24
diff --git a/src/client/Dockerfile b/src/client/Dockerfile
new file mode 100644
index 0000000..f1dabea
--- /dev/null
+++ b/src/client/Dockerfile
@@ -0,0 +1,22 @@
+FROM node:24-alpine AS build
+WORKDIR /app
+
+COPY package.json package-lock.json ./
+RUN npm ci
+
+COPY . .
+
+RUN npm run build -- --configuration production
+
+FROM nginx:stable-alpine
+
+RUN apk add --no-cache gettext
+
+COPY --from=build /app/dist/client/browser /usr/share/nginx/html
+COPY nginx.custom.conf /etc/nginx/conf.d/default.conf
+COPY config.json.template /usr/share/nginx/html/assets/config.json.template
+COPY docker-entrypoint.sh /docker-entrypoint.sh
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 80
+CMD ["/docker-entrypoint.sh"]
\ No newline at end of file
diff --git a/src/client/config.json.template b/src/client/config.json.template
new file mode 100644
index 0000000..7553824
--- /dev/null
+++ b/src/client/config.json.template
@@ -0,0 +1,3 @@
+{
+ "apiBaseUrl": "${API_BASE_URL}"
+}
diff --git a/src/client/docker-entrypoint.sh b/src/client/docker-entrypoint.sh
new file mode 100644
index 0000000..beaf0cb
--- /dev/null
+++ b/src/client/docker-entrypoint.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+envsubst '${API_BASE_URL}' \
+ < /usr/share/nginx/html/assets/config.json.template \
+ > /usr/share/nginx/html/assets/config.json
+exec nginx -g 'daemon off;'
diff --git a/src/client/nginx.custom.conf b/src/client/nginx.custom.conf
new file mode 100644
index 0000000..681e1a6
--- /dev/null
+++ b/src/client/nginx.custom.conf
@@ -0,0 +1,21 @@
+server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ try_files $uri $uri/ /index.html;
+ }
+
+ location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|eot|ttf|otf)$ {
+ root /usr/share/nginx/html;
+ expires 1y;
+ add_header Cache-Control "public, no-transform";
+ }
+
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root /usr/share/nginx/html;
+ }
+}
\ No newline at end of file
diff --git a/src/client/package-lock.json b/src/client/package-lock.json
index bc1d9ce..ee0d0c8 100644
--- a/src/client/package-lock.json
+++ b/src/client/package-lock.json
@@ -463,7 +463,6 @@
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.9.tgz",
"integrity": "sha512-7spQcF3hPN/fjTx6Pwa32KRRdO0NcixnRuPV4lo50ejtXesjiLVR+fkaX38sawAyGoq89IuuYvUDrbLwCMypmQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -480,7 +479,6 @@
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.9.tgz",
"integrity": "sha512-clsK1EsSPtAuqlRl4CciA/gsvsW7xe0eWcvHxtrMW6DYaUJ6X4AAuDxEEJ5cf/3Mpw4s8KssjIUPPtbrUIGLSQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -494,7 +492,6 @@
"integrity": "sha512-hTTW/OiqTXrwTneS18CMp47OX0XSbLYl2rIomLS3nXVJniSETH6S/k+LqQtGWWgLbzsd3PzUOOckHnvzpTBTsA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/core": "7.29.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
@@ -527,7 +524,6 @@
"resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.9.tgz",
"integrity": "sha512-uZLq2aedJ+0uEZxyf6a1Nc7y1aZ7akAW7K1Kon8JUDZOvI2IDbk0i00MzkELt8q9uSmSSqg9zNKuhjspFf0Pyw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -572,7 +568,6 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.9.tgz",
"integrity": "sha512-MjEtFvoFtsjsAeu2yzauqGgwwEHV4ml25c9vGFmw4OmSoNme4yp41f2DegwOkn1TTHL3OF3GE65ng2U2feJU4Q==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -697,7 +692,6 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -1061,7 +1055,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
},
@@ -1110,11 +1103,35 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
}
},
+ "node_modules/@emnapi/core": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -1122,6 +1139,7 @@
"dev": true,
"license": "MIT",
"optional": true,
+ "peer": true,
"dependencies": {
"tslib": "^2.4.0"
}
@@ -1853,7 +1871,6 @@
"integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@inquirer/checkbox": "^4.3.2",
"@inquirer/confirm": "^5.1.21",
@@ -4306,7 +4323,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782",
@@ -4458,7 +4474,6 @@
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"readdirp": "^5.0.0"
},
@@ -5147,7 +5162,6 @@
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
@@ -5476,7 +5490,6 @@
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -5818,7 +5831,6 @@
"integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.31",
"@asamuzakjp/dom-selector": "^6.8.1",
@@ -5927,7 +5939,6 @@
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"cli-truncate": "^5.0.0",
"colorette": "^2.0.20",
@@ -7025,7 +7036,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -7339,7 +7349,6 @@
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -7964,8 +7973,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD",
- "peer": true
+ "license": "0BSD"
},
"node_modules/tuf-js": {
"version": "4.1.0",
@@ -8003,7 +8011,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -8089,7 +8096,6 @@
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -8165,7 +8171,6 @@
"integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@vitest/expect": "4.1.5",
"@vitest/mocker": "4.1.5",
@@ -8558,7 +8563,6 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/src/client/src/app/app.config.ts b/src/client/src/app/app.config.ts
index 4451829..6b83381 100644
--- a/src/client/src/app/app.config.ts
+++ b/src/client/src/app/app.config.ts
@@ -1,13 +1,18 @@
-import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
+import { ApplicationConfig, inject, provideBrowserGlobalErrorListeners, provideAppInitializer } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
+import { ConfigService } from './core/services/config.service';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideRouter(routes),
- provideHttpClient()
+ provideHttpClient(),
+ provideAppInitializer(() => {
+ const configService = inject(ConfigService);
+ return configService.load();
+ })
]
};
diff --git a/src/client/src/app/core/services/category.service.ts b/src/client/src/app/core/services/category.service.ts
index 6377cbc..2cf49a2 100644
--- a/src/client/src/app/core/services/category.service.ts
+++ b/src/client/src/app/core/services/category.service.ts
@@ -2,13 +2,18 @@ import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Category } from '../models/category.model';
+import { ConfigService } from './config.service';
@Injectable({
providedIn: 'root'
})
export class CategoryService {
private http = inject(HttpClient);
- private apiUrl = 'https://localhost:7134/api/categories';
+ private config = inject(ConfigService);
+
+ private get apiUrl(): string {
+ return `${this.config.apiBaseUrl}/api/categories`;
+ }
getCategories(): Observable {
return this.http.get(this.apiUrl);
diff --git a/src/client/src/app/core/services/config.service.ts b/src/client/src/app/core/services/config.service.ts
new file mode 100644
index 0000000..de9ba89
--- /dev/null
+++ b/src/client/src/app/core/services/config.service.ts
@@ -0,0 +1,23 @@
+import { Injectable, inject } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { firstValueFrom } from 'rxjs';
+
+interface AppConfig {
+ apiBaseUrl: string;
+}
+
+@Injectable({ providedIn: 'root' })
+export class ConfigService {
+ private readonly http = inject(HttpClient);
+ private config: AppConfig = { apiBaseUrl: '' };
+
+ async load(): Promise {
+ this.config = await firstValueFrom(
+ this.http.get('/assets/config.json')
+ );
+ }
+
+ get apiBaseUrl(): string {
+ return this.config.apiBaseUrl;
+ }
+}
diff --git a/src/client/src/app/core/services/event.service.ts b/src/client/src/app/core/services/event.service.ts
index c8a0a8a..5b53807 100644
--- a/src/client/src/app/core/services/event.service.ts
+++ b/src/client/src/app/core/services/event.service.ts
@@ -4,14 +4,18 @@ import { Observable } from 'rxjs';
import { Event } from '../models/event.model';
import { PaginatedList } from '../models/paginated-list.model';
import { EventSearchDto } from '../models/event-search.model';
-import { environment } from '../../../environments/environment';
+import { ConfigService } from './config.service';
@Injectable({
providedIn: 'root'
})
export class EventService {
private http = inject(HttpClient);
- private apiUrl = environment.apiUrl;
+ private config = inject(ConfigService);
+
+ private get apiUrl(): string {
+ return `${this.config.apiBaseUrl}/api/events`;
+ }
getUpcomingEvents(page: number = 1, pageSize: number = 5, search?: EventSearchDto): Observable> {
let params = new HttpParams()
diff --git a/src/client/src/assets/config.json b/src/client/src/assets/config.json
new file mode 100644
index 0000000..31c6818
--- /dev/null
+++ b/src/client/src/assets/config.json
@@ -0,0 +1,3 @@
+{
+ "apiBaseUrl": "https://localhost:7134"
+}
diff --git a/src/client/src/environments/environment.development.ts b/src/client/src/environments/environment.development.ts
index 49a1bc0..ffe8aed 100644
--- a/src/client/src/environments/environment.development.ts
+++ b/src/client/src/environments/environment.development.ts
@@ -1,4 +1,3 @@
export const environment = {
- production: false,
- apiUrl: 'https://localhost:7134/api/events'
+ production: false
};
diff --git a/src/client/src/environments/environment.ts b/src/client/src/environments/environment.ts
index 2a66107..3612073 100644
--- a/src/client/src/environments/environment.ts
+++ b/src/client/src/environments/environment.ts
@@ -1,4 +1,3 @@
export const environment = {
- production: true,
- apiUrl: 'https://localhost:7134/api/events'
+ production: true
};
From c0373ba5d56231bae65acfbae82564dda194cd35 Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Mon, 27 Apr 2026 15:36:58 +0300
Subject: [PATCH 03/16] add swagger for api, fix node.js error for local run
and update readme
---
README.md | 100 ++++++++++++++++--
src/api/SmartEventBooking.Web/Program.cs | 11 +-
.../Properties/launchSettings.json | 2 +
.../SmartEventBooking.Web.csproj | 1 +
src/client/{src => public}/assets/config.json | 0
src/client/tsconfig.app.json | 1 +
6 files changed, 106 insertions(+), 9 deletions(-)
rename src/client/{src => public}/assets/config.json (100%)
diff --git a/README.md b/README.md
index 7f21047..3201d47 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,56 @@
# Smart Event Booking
-ASP.NET Core MVC application for event discovery and ticket booking.
+Full-stack event discovery and ticket booking platform — ASP.NET Core 10 API + Angular client.
For product vision, scope, and contribution workflow, see `PROJECT_SCOPE.md`.
## Prerequisites
+**To run with Docker Compose:**
+- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
+
+**To run locally:**
- .NET SDK 10.0
+- Node.js 24 LTS (see [Node version setup](#node-version-setup))
- SQL Server (local instance or Docker)
+## Running with Docker Compose
+
+The quickest way to run the full stack (API + client + database) without any local tooling beyond Docker.
+
+1. Copy the env file and fill in your credentials:
+ ```bash
+ cp .env.example .env
+ ```
+
+2. Start everything:
+ ```bash
+ docker compose up -d --build
+ ```
+
+ | Service | URL |
+ |---|---|
+ | Client (Angular) | http://localhost:4200 |
+ | API (ASP.NET Core) | http://localhost:5270 |
+ | SQL Server | localhost:1433 |
+
+ Migrations run automatically on API startup — no manual `dotnet ef` step needed.
+
+3. Stop everything:
+ ```bash
+ docker compose down
+ ```
+ Add `-v` to also wipe the database volume.
+
+---
+
+## Running locally
+
+Follow the numbered steps below to run the API and client separately.
+
## 1) Configure the database settings
-This app reads database values from environment variables (`Database__Server`, `Database__Name`, `Database__User`, `Database__Password`, `Database__TrustServerCertificate`) and falls back to `src/SmartEventBooking.Web/appsettings.json`.
+This app reads database values from environment variables (`Database__Server`, `Database__Name`, `Database__User`, `Database__Password`, `Database__TrustServerCertificate`) and falls back to `src/api/SmartEventBooking.Web/appsettings.json`.
Admin seeding credentials are also read from environment variables:
@@ -43,19 +82,20 @@ From the repository root:
```bash
dotnet restore
-dotnet ef database update --project src/SmartEventBooking.Infrastructure/SmartEventBooking.Infrastructure.csproj --startup-project src/SmartEventBooking.Web/SmartEventBooking.Web.csproj --context ApplicationDbContext
+dotnet ef database update --project src/api/SmartEventBooking.Infrastructure/SmartEventBooking.Infrastructure.csproj --startup-project src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj --context ApplicationDbContext
```
-## 4) Run the app
+## 4) Run the API
```bash
-dotnet run --project src/SmartEventBooking.Web/SmartEventBooking.Web.csproj --launch-profile https
+dotnet run --project src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj --launch-profile https
```
Default URLs (development):
- `https://localhost:7134`
- `http://localhost:5270`
+- Swagger UI: `https://localhost:7134/swagger`
If you run without the `https` launch profile, you may see:
@@ -63,7 +103,17 @@ If you run without the `https` launch profile, you may see:
Use `--launch-profile https` (shown above), or set `ASPNETCORE_URLS` to include an HTTPS URL.
-## 5) Verify connectivity
+## 5) Run the client
+
+```bash
+cd src/client
+npm ci
+ng serve
+```
+
+Client runs at `http://localhost:4200`. The API URL it connects to is configured in `src/client/public/assets/config.json`.
+
+## 6) Verify connectivity
Health endpoint:
@@ -81,3 +131,41 @@ Expected result:
dotnet build
dotnet test
```
+
+---
+
+## Node version setup
+
+The client requires **Node.js 24 LTS**, pinned in `src/client/.nvmrc`.
+
+### Option A — Install Node 24 directly (simplest)
+
+Download and install Node 24 LTS from [nodejs.org](https://nodejs.org/en/download). No version manager needed if you only work on this project.
+
+### Option B — Use fnm (if you work on multiple projects with different Node versions)
+
+**Windows:**
+```powershell
+winget install Schniz.fnm
+```
+Add to your PowerShell profile (run once):
+```powershell
+Add-Content $PROFILE "fnm env --use-on-cd --shell power-shell | Out-String | Invoke-Expression"
+```
+Restart PowerShell, then inside `src/client/`:
+```powershell
+fnm install
+fnm use
+```
+
+**macOS / Linux:**
+```bash
+curl -fsSL https://fnm.vercel.app/install | bash
+```
+Then inside `src/client/`:
+```bash
+fnm install
+fnm use
+```
+
+> **Switching versions and seeing native module errors?** Delete `node_modules` and run `npm ci` again — native binaries are version-specific.
diff --git a/src/api/SmartEventBooking.Web/Program.cs b/src/api/SmartEventBooking.Web/Program.cs
index 4a0ce89..0bfb7a5 100644
--- a/src/api/SmartEventBooking.Web/Program.cs
+++ b/src/api/SmartEventBooking.Web/Program.cs
@@ -13,6 +13,8 @@
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped();
builder.Services.AddValidatorsFromAssemblyContaining();
@@ -48,11 +50,14 @@
await app.InitialiseDatabaseAsync();
-// Configure the HTTP request pipeline.
-if (!app.Environment.IsDevelopment())
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+}
+else
{
app.UseExceptionHandler("/Home/Error");
- // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
diff --git a/src/api/SmartEventBooking.Web/Properties/launchSettings.json b/src/api/SmartEventBooking.Web/Properties/launchSettings.json
index 695f794..b84c5ba 100644
--- a/src/api/SmartEventBooking.Web/Properties/launchSettings.json
+++ b/src/api/SmartEventBooking.Web/Properties/launchSettings.json
@@ -5,6 +5,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
+ "launchUrl": "swagger",
"applicationUrl": "http://localhost:5270",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
@@ -14,6 +15,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
+ "launchUrl": "swagger",
"applicationUrl": "https://localhost:7134;http://localhost:5270",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
diff --git a/src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj b/src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj
index 48af957..e51df86 100644
--- a/src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj
+++ b/src/api/SmartEventBooking.Web/SmartEventBooking.Web.csproj
@@ -12,6 +12,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
+
diff --git a/src/client/src/assets/config.json b/src/client/public/assets/config.json
similarity index 100%
rename from src/client/src/assets/config.json
rename to src/client/public/assets/config.json
diff --git a/src/client/tsconfig.app.json b/src/client/tsconfig.app.json
index 264f459..e4dd97c 100644
--- a/src/client/tsconfig.app.json
+++ b/src/client/tsconfig.app.json
@@ -4,6 +4,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
+ "rootDir": "./src",
"types": []
},
"include": [
From 7ebee97635ccf759d46b0a567077cfa968101d8c Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Tue, 28 Apr 2026 16:46:24 +0300
Subject: [PATCH 04/16] feat: testing new workflow for deploy
---
.dockerignore | 5 +-
.gitattributes | 2 +
.github/workflows/release-to-prod.yml | 55 +++++++++++++++++++
docker-compose.yml | 2 +-
src/api/SmartEventBooking.Web/Program.cs | 7 ++-
.../appsettings.Development.json | 4 ++
.../SmartEventBooking.Web/appsettings.json | 5 +-
src/api/SmartEventBooking.Web/temp.txt | 0
src/client/Dockerfile | 2 +-
9 files changed, 75 insertions(+), 7 deletions(-)
create mode 100644 .gitattributes
create mode 100644 .github/workflows/release-to-prod.yml
delete mode 100644 src/api/SmartEventBooking.Web/temp.txt
diff --git a/.dockerignore b/.dockerignore
index e031e1f..03fc0eb 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -6,4 +6,7 @@
**/.vscode
**/bin
**/obj
-**/Dockerfile
\ No newline at end of file
+**/Dockerfile
+**/node_modules
+**/dist
+**/.angular
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..efdba87
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto
+*.sh text eol=lf
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
new file mode 100644
index 0000000..d6d778e
--- /dev/null
+++ b/.github/workflows/release-to-prod.yml
@@ -0,0 +1,55 @@
+name: Release to Production
+
+#on:
+# push:
+# branches: [ main ]
+
+on:
+ pull_request:
+ branches:
+ - develop
+
+
+env:
+ BACKEND_IMAGE: smart-event-api-app
+ FRONTEND_IMAGE: smart-event-client-app
+
+jobs:
+ build-and-push:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_ACCESSTOKEN }}
+
+ - name: Build and push Backend
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: src/api/SmartEventBooking.Web/Dockerfile
+ push: true
+ tags: |
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.BACKEND_IMAGE }}:latest
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.BACKEND_IMAGE }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Build and push Frontend
+ uses: docker/build-push-action@v5
+ with:
+ context: ./src/client
+ push: true
+ tags: |
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.FRONTEND_IMAGE }}:latest
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.FRONTEND_IMAGE }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ # ---------------------- Don't forget to write job for deploy
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 6815a43..514e7dd 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -18,7 +18,7 @@ services:
start_period: 10s
api:
- image: smart-event-api:latest
+ image: smart-event-booking-api:latest
build:
context: .
dockerfile: src/api/SmartEventBooking.Web/Dockerfile
diff --git a/src/api/SmartEventBooking.Web/Program.cs b/src/api/SmartEventBooking.Web/Program.cs
index 0bfb7a5..8951f31 100644
--- a/src/api/SmartEventBooking.Web/Program.cs
+++ b/src/api/SmartEventBooking.Web/Program.cs
@@ -35,11 +35,14 @@
options.ExpireTimeSpan = TimeSpan.FromDays(7);
});
+var allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get()
+ ?? new[] { "http://localhost:4200", "https://localhost:4200" };
+
builder.Services.AddCors(options =>
{
- options.AddDefaultPolicy(builder =>
+ options.AddDefaultPolicy(corsBuilder =>
{
- builder.WithOrigins("http://localhost:4200", "https://localhost:4200")
+ corsBuilder.WithOrigins(allowedOrigins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
diff --git a/src/api/SmartEventBooking.Web/appsettings.Development.json b/src/api/SmartEventBooking.Web/appsettings.Development.json
index 7568bef..a23a2ec 100644
--- a/src/api/SmartEventBooking.Web/appsettings.Development.json
+++ b/src/api/SmartEventBooking.Web/appsettings.Development.json
@@ -1,4 +1,8 @@
{
+ "AllowedOrigins": [
+ "http://localhost:4200",
+ "https://localhost:4200"
+ ],
"ConnectionStrings": {
"DefaultConnection": ""
},
diff --git a/src/api/SmartEventBooking.Web/appsettings.json b/src/api/SmartEventBooking.Web/appsettings.json
index a796e57..6ad1def 100644
--- a/src/api/SmartEventBooking.Web/appsettings.json
+++ b/src/api/SmartEventBooking.Web/appsettings.json
@@ -1,11 +1,12 @@
{
+ "AllowedOrigins": [],
"ConnectionStrings": {
"DefaultConnection": ""
},
"Database": {
- "Server": "localhost,1433",
+ "Server": "",
"Name": "SmartEventBookingDb",
- "User": "sa",
+ "User": "",
"Password": "",
"TrustServerCertificate": true
},
diff --git a/src/api/SmartEventBooking.Web/temp.txt b/src/api/SmartEventBooking.Web/temp.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/src/client/Dockerfile b/src/client/Dockerfile
index f1dabea..cae194d 100644
--- a/src/client/Dockerfile
+++ b/src/client/Dockerfile
@@ -16,7 +16,7 @@ COPY --from=build /app/dist/client/browser /usr/share/nginx/html
COPY nginx.custom.conf /etc/nginx/conf.d/default.conf
COPY config.json.template /usr/share/nginx/html/assets/config.json.template
COPY docker-entrypoint.sh /docker-entrypoint.sh
-RUN chmod +x /docker-entrypoint.sh
+RUN sed -i 's/\r//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh
EXPOSE 80
CMD ["/docker-entrypoint.sh"]
\ No newline at end of file
From bed1cf3188b4f13c8e895f313a34ac1c2db4b561 Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Tue, 28 Apr 2026 17:00:49 +0300
Subject: [PATCH 05/16] fix: change dockerhub image name
---
.github/workflows/release-to-prod.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index d6d778e..979b241 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -11,8 +11,8 @@ on:
env:
- BACKEND_IMAGE: smart-event-api-app
- FRONTEND_IMAGE: smart-event-client-app
+ BACKEND_IMAGE: smart-event-booking-api-app
+ FRONTEND_IMAGE: smart-event-booking-client-app
jobs:
build-and-push:
From 6135ac9ba793c6a61459ee315800f7dee271cdff Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 00:38:17 +0300
Subject: [PATCH 06/16] feat: add deploy to azure to workflow
---
.github/workflows/release-to-prod.yml | 40 +++++++++++++++++++++------
src/client/Dockerfile | 7 +++--
2 files changed, 36 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index 979b241..7d06b9e 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -11,8 +11,10 @@ on:
env:
- BACKEND_IMAGE: smart-event-booking-api-app
- FRONTEND_IMAGE: smart-event-booking-client-app
+ API_IMAGE: smart-event-booking-api-app
+ CLIENT_IMAGE: smart-event-booking-client-app
+ AZURE_WEBAPP_API_NAME: app-smarteventbooking-api
+ AZURE_WEBAPP_CLIENT_NAME: app-smarteventbooking-client
jobs:
build-and-push:
@@ -29,27 +31,47 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESSTOKEN }}
- - name: Build and push Backend
+ - name: Build and push API
uses: docker/build-push-action@v5
with:
context: .
file: src/api/SmartEventBooking.Web/Dockerfile
push: true
tags: |
- ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.BACKEND_IMAGE }}:latest
- ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.BACKEND_IMAGE }}:${{ github.sha }}
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.API_IMAGE }}:latest
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.API_IMAGE }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- - name: Build and push Frontend
+ - name: Build and push Client
uses: docker/build-push-action@v5
with:
context: ./src/client
push: true
tags: |
- ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.FRONTEND_IMAGE }}:latest
- ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.FRONTEND_IMAGE }}:${{ github.sha }}
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.CLIENT_IMAGE }}:latest
+ ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.CLIENT_IMAGE }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- # ---------------------- Don't forget to write job for deploy
\ No newline at end of file
+ deploy-api:
+ needs: build-and-push
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy API to Azure Web App
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: ${{ env.AZURE_WEBAPP_API_NAME }}
+ publish-profile: ${{ secrets.AZURE_API_PUBLISH_PROFILE }}
+ images: '${{ secrets.DOCKERHUB_USERNAME }}/${{ env.API_IMAGE }}:${{ github.sha }}'
+
+ deploy-client:
+ needs: build-and-push
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy Client to Azure Web App
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: ${{ env.AZURE_WEBAPP_CLIENT_NAME }}
+ publish-profile: ${{ secrets.AZURE_CLIENT_PUBLISH_PROFILE }}
+ images: '${{ secrets.DOCKERHUB_USERNAME }}/${{ env.CLIENT_IMAGE }}:${{ github.sha }}'
diff --git a/src/client/Dockerfile b/src/client/Dockerfile
index cae194d..f858451 100644
--- a/src/client/Dockerfile
+++ b/src/client/Dockerfile
@@ -5,7 +5,6 @@ COPY package.json package-lock.json ./
RUN npm ci
COPY . .
-
RUN npm run build -- --configuration production
FROM nginx:stable-alpine
@@ -14,9 +13,13 @@ RUN apk add --no-cache gettext
COPY --from=build /app/dist/client/browser /usr/share/nginx/html
COPY nginx.custom.conf /etc/nginx/conf.d/default.conf
+
COPY config.json.template /usr/share/nginx/html/assets/config.json.template
+
COPY docker-entrypoint.sh /docker-entrypoint.sh
+
RUN sed -i 's/\r//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh
EXPOSE 80
-CMD ["/docker-entrypoint.sh"]
\ No newline at end of file
+
+ENTRYPOINT ["/docker-entrypoint.sh"]
\ No newline at end of file
From e59649bcf388986dd363e5302815fbecaa8e0abf Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 01:05:33 +0300
Subject: [PATCH 07/16] fix: fix tests after merge
---
.../Controllers/HomeControllerTests.cs | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs b/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
index 73302cd..8abd23f 100644
--- a/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
+++ b/tests/SmartEventBooking.Web.Tests/Controllers/HomeControllerTests.cs
@@ -1,4 +1,5 @@
using FluentAssertions;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using SmartEventBooking.Web.Controllers;
@@ -31,14 +32,4 @@ public void Privacy_ReturnsOkResult()
result.Should().BeOfType();
}
-
- [Fact]
- public void Error_ReturnsObjectResult_WithProblemDetails()
- {
- var result = CreateController().Error();
-
- var objectResult = result.Should().BeOfType().Subject;
- objectResult.StatusCode.Should().Be(500);
- objectResult.Value.Should().BeOfType();
- }
}
\ No newline at end of file
From d488a579ca5afa39d32aed621483117c3d1af80c Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 01:10:33 +0300
Subject: [PATCH 08/16] change deploy worflow to deploy only on merge with main
---
.github/workflows/release-to-prod.yml | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index 7d06b9e..b146ef3 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -1,14 +1,8 @@
name: Release to Production
-#on:
-# push:
-# branches: [ main ]
-
on:
- pull_request:
- branches:
- - develop
-
+ push:
+ branches: [ main ]
env:
API_IMAGE: smart-event-booking-api-app
From d07429787e52dae42f5b37477179c59f825feaad Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 01:43:30 +0300
Subject: [PATCH 09/16] fix comments and test
---
.github/workflows/pr-validation.yml | 6 ++---
.github/workflows/release-to-prod.yml | 35 +++++++++++++++++++++++++--
2 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index 8615baa..37ee133 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -54,9 +54,9 @@ jobs:
- name: Install dependencies
run: npm ci
-
- - name: Build Angular project
- run: npm run build -- --configuration production
+
+ - name: Run client tests
+ run: npm test -- --watch=false --browsers=ChromeHeadless
- name: Verify Client Dockerfile builds
working-directory: .
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index b146ef3..a6e502f 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -1,8 +1,14 @@
name: Release to Production
+# on:
+# push:
+# branches: [ main ]
+
on:
- push:
- branches: [ main ]
+ pull_request:
+ branches:
+ - develop
+ - main
env:
API_IMAGE: smart-event-booking-api-app
@@ -11,7 +17,22 @@ env:
AZURE_WEBAPP_CLIENT_NAME: app-smarteventbooking-client
jobs:
+ run-tests:
+ name: Run Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Run API tests
+ run: dotnet test --configuration Release --verbosity normal
+
build-and-push:
+ needs: run-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -59,6 +80,11 @@ jobs:
publish-profile: ${{ secrets.AZURE_API_PUBLISH_PROFILE }}
images: '${{ secrets.DOCKERHUB_USERNAME }}/${{ env.API_IMAGE }}:${{ github.sha }}'
+ - name: Smoke test API
+ run: |
+ curl --retry 10 --retry-delay 10 --retry-connrefused --fail \
+ https://${{ env.AZURE_WEBAPP_API_NAME }}.azurewebsites.net/health/db
+
deploy-client:
needs: build-and-push
runs-on: ubuntu-latest
@@ -69,3 +95,8 @@ jobs:
app-name: ${{ env.AZURE_WEBAPP_CLIENT_NAME }}
publish-profile: ${{ secrets.AZURE_CLIENT_PUBLISH_PROFILE }}
images: '${{ secrets.DOCKERHUB_USERNAME }}/${{ env.CLIENT_IMAGE }}:${{ github.sha }}'
+
+ - name: Smoke test Client
+ run: |
+ curl --retry 10 --retry-delay 10 --retry-connrefused --fail \
+ https://${{ env.AZURE_WEBAPP_CLIENT_NAME }}.azurewebsites.net
From d51e4b08fa181a1cc307b66e3fb37adf7399b32e Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 01:45:59 +0300
Subject: [PATCH 10/16] fix for failing client test job in pr-validation
---
.github/workflows/pr-validation.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index 37ee133..660b167 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -56,7 +56,7 @@ jobs:
run: npm ci
- name: Run client tests
- run: npm test -- --watch=false --browsers=ChromeHeadless
+ run: npm test -- --watch=false
- name: Verify Client Dockerfile builds
working-directory: .
From 54246bc2a59ff2212a7c723ec7fb2b17cfbfca3f Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 02:02:57 +0300
Subject: [PATCH 11/16] fix deployed apps testing
---
.github/workflows/release-to-prod.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index a6e502f..12abe3b 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -83,7 +83,7 @@ jobs:
- name: Smoke test API
run: |
curl --retry 10 --retry-delay 10 --retry-connrefused --fail \
- https://${{ env.AZURE_WEBAPP_API_NAME }}.azurewebsites.net/health/db
+ ${{ vars.AZURE_WEBAPP_API_URL }}/health/db
deploy-client:
needs: build-and-push
@@ -99,4 +99,4 @@ jobs:
- name: Smoke test Client
run: |
curl --retry 10 --retry-delay 10 --retry-connrefused --fail \
- https://${{ env.AZURE_WEBAPP_CLIENT_NAME }}.azurewebsites.net
+ ${{ vars.AZURE_WEBAPP_CLIENT_URL }}
From 18fb0d1d4176da9e50690fc0163084a980c831cc Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 02:08:22 +0300
Subject: [PATCH 12/16] add caching to pr-validation and remove "on pr" from
release workflow
---
.github/workflows/pr-validation.yml | 23 ++++++++++++++++++-----
.github/workflows/release-to-prod.yml | 10 ++--------
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index 660b167..bd8f87a 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -14,7 +14,10 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v4
-
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
@@ -22,7 +25,7 @@ jobs:
- name: Restore dependencies
run: dotnet restore -p:Configuration=Release
-
+
- name: Build project
run: dotnet build --no-restore --configuration Release
@@ -30,7 +33,13 @@ jobs:
run: dotnet test --no-build --configuration Release --verbosity normal
- name: Verify API Dockerfile builds
- run: docker build -t smarteventbooking-api:test -f src/api/SmartEventBooking.Web/Dockerfile .
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: src/api/SmartEventBooking.Web/Dockerfile
+ push: false
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
build-and-test-client:
@@ -59,5 +68,9 @@ jobs:
run: npm test -- --watch=false
- name: Verify Client Dockerfile builds
- working-directory: .
- run: docker build -t smarteventbooking-client:test src/client/
+ uses: docker/build-push-action@v5
+ with:
+ context: ./src/client
+ push: false
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/.github/workflows/release-to-prod.yml b/.github/workflows/release-to-prod.yml
index 12abe3b..680c3d7 100644
--- a/.github/workflows/release-to-prod.yml
+++ b/.github/workflows/release-to-prod.yml
@@ -1,14 +1,8 @@
name: Release to Production
-# on:
-# push:
-# branches: [ main ]
-
on:
- pull_request:
- branches:
- - develop
- - main
+ push:
+ branches: [ main ]
env:
API_IMAGE: smart-event-booking-api-app
From 19c2cc6798ceecbde7552409bdb0e03dadaf9109 Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 02:10:17 +0300
Subject: [PATCH 13/16] minor fix
---
.github/workflows/pr-validation.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml
index bd8f87a..da47953 100644
--- a/.github/workflows/pr-validation.yml
+++ b/.github/workflows/pr-validation.yml
@@ -54,6 +54,9 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
From 2f57ded1f1629e6c4a4786d0c59ef7360b62effa Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 17:43:25 +0300
Subject: [PATCH 14/16] fix: fix ci tests failure
---
src/client/src/app/core/services/auth.service.ts | 9 +++++----
.../Identity/AuthServiceTests.cs | 4 ++--
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/client/src/app/core/services/auth.service.ts b/src/client/src/app/core/services/auth.service.ts
index 9cb87c8..4d0f4d0 100644
--- a/src/client/src/app/core/services/auth.service.ts
+++ b/src/client/src/app/core/services/auth.service.ts
@@ -1,7 +1,7 @@
import { Injectable, computed, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, tap } from 'rxjs';
-import { environment } from '../../../environments/environment';
+import { ConfigService } from './config.service';
export interface LoginRequest {
email: string;
@@ -35,15 +35,16 @@ export class AuthService {
private static readonly AUTH_SESSION_STORAGE_KEY = 'auth.session';
private readonly http = inject(HttpClient);
+ private readonly config = inject(ConfigService);
private readonly authSessionSignal = signal(this.readStoredAuthSession());
readonly authSession = computed(() => this.authSessionSignal());
readonly userEmail = computed(() => this.authSessionSignal()?.email ?? null);
readonly isLoggedIn = computed(() => this.authSessionSignal() !== null);
- private readonly authApiUrl = environment.apiUrl.endsWith('/events')
- ? environment.apiUrl.replace('/events', '/auth')
- : `${environment.apiUrl}/auth`;
+ private get authApiUrl(): string {
+ return `${this.config.apiBaseUrl}/api/auth`;
+ }
register(request: RegisterRequest): Observable {
return this.http.post(`${this.authApiUrl}/register`, request);
diff --git a/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs b/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
index d7a1d74..9e3e877 100644
--- a/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
+++ b/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
@@ -240,7 +240,7 @@ public async Task LoginAsync_ShouldReturnErrors_WhenUserIsLockedOut()
var result = await _authService.LoginAsync(dto);
result.Succeeded.Should().BeFalse();
- result.Errors.Should().ContainSingle().Which.Should().Be("Login failed.");
+ result.Errors.Should().ContainSingle().Which.Should().Be("Login failed: Rate limited.");
}
[Fact]
@@ -298,7 +298,7 @@ public async Task LoginAsync_ShouldReturnErrors_WhenPasswordIsInvalid()
var result = await _authService.LoginAsync(dto);
result.Succeeded.Should().BeFalse();
- result.Errors.Should().ContainSingle().Which.Should().Be("Login failed.");
+ result.Errors.Should().ContainSingle().Which.Should().Be("Login failed: Please verify your email (should never happen for now).");
}
[Theory]
From 763f9e290e292c871eb71bcc4e81a54252009e1c Mon Sep 17 00:00:00 2001
From: viktorpekhun <129255792+viktorpekhun@users.noreply.github.com>
Date: Wed, 29 Apr 2026 17:49:01 +0300
Subject: [PATCH 15/16] minor fix
---
.../Identity/AuthServiceTests.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs b/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
index 9e3e877..1dec78b 100644
--- a/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
+++ b/tests/SmartEventBooking.Infrastructure.UnitTests/Identity/AuthServiceTests.cs
@@ -269,7 +269,7 @@ public async Task LoginAsync_ShouldReturnErrors_WhenUserIsNotAllowed()
var result = await _authService.LoginAsync(dto);
result.Succeeded.Should().BeFalse();
- result.Errors.Should().ContainSingle().Which.Should().Be("Login failed.");
+ result.Errors.Should().ContainSingle().Which.Should().Be("Login failed: Please verify your email (should never happen for now).");
}
[Fact]
@@ -298,7 +298,7 @@ public async Task LoginAsync_ShouldReturnErrors_WhenPasswordIsInvalid()
var result = await _authService.LoginAsync(dto);
result.Succeeded.Should().BeFalse();
- result.Errors.Should().ContainSingle().Which.Should().Be("Login failed: Please verify your email (should never happen for now).");
+ result.Errors.Should().ContainSingle().Which.Should().Be("Login failed.");
}
[Theory]
From 4731e4de3ee304f49670deefc7e76cbef592900f Mon Sep 17 00:00:00 2001
From: Ivan Lutsenko <108870263+eevatsen@users.noreply.github.com>
Date: Thu, 30 Apr 2026 14:51:13 +0300
Subject: [PATCH 16/16] Update package-lock.json
---
src/client/package-lock.json | 50 +++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/src/client/package-lock.json b/src/client/package-lock.json
index bc1d9ce..ee0d0c8 100644
--- a/src/client/package-lock.json
+++ b/src/client/package-lock.json
@@ -463,7 +463,6 @@
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.9.tgz",
"integrity": "sha512-7spQcF3hPN/fjTx6Pwa32KRRdO0NcixnRuPV4lo50ejtXesjiLVR+fkaX38sawAyGoq89IuuYvUDrbLwCMypmQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -480,7 +479,6 @@
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.9.tgz",
"integrity": "sha512-clsK1EsSPtAuqlRl4CciA/gsvsW7xe0eWcvHxtrMW6DYaUJ6X4AAuDxEEJ5cf/3Mpw4s8KssjIUPPtbrUIGLSQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -494,7 +492,6 @@
"integrity": "sha512-hTTW/OiqTXrwTneS18CMp47OX0XSbLYl2rIomLS3nXVJniSETH6S/k+LqQtGWWgLbzsd3PzUOOckHnvzpTBTsA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/core": "7.29.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
@@ -527,7 +524,6 @@
"resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.9.tgz",
"integrity": "sha512-uZLq2aedJ+0uEZxyf6a1Nc7y1aZ7akAW7K1Kon8JUDZOvI2IDbk0i00MzkELt8q9uSmSSqg9zNKuhjspFf0Pyw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -572,7 +568,6 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.9.tgz",
"integrity": "sha512-MjEtFvoFtsjsAeu2yzauqGgwwEHV4ml25c9vGFmw4OmSoNme4yp41f2DegwOkn1TTHL3OF3GE65ng2U2feJU4Q==",
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -697,7 +692,6 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -1061,7 +1055,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
},
@@ -1110,11 +1103,35 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
}
},
+ "node_modules/@emnapi/core": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -1122,6 +1139,7 @@
"dev": true,
"license": "MIT",
"optional": true,
+ "peer": true,
"dependencies": {
"tslib": "^2.4.0"
}
@@ -1853,7 +1871,6 @@
"integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@inquirer/checkbox": "^4.3.2",
"@inquirer/confirm": "^5.1.21",
@@ -4306,7 +4323,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782",
@@ -4458,7 +4474,6 @@
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"readdirp": "^5.0.0"
},
@@ -5147,7 +5162,6 @@
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
@@ -5476,7 +5490,6 @@
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -5818,7 +5831,6 @@
"integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.31",
"@asamuzakjp/dom-selector": "^6.8.1",
@@ -5927,7 +5939,6 @@
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"cli-truncate": "^5.0.0",
"colorette": "^2.0.20",
@@ -7025,7 +7036,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -7339,7 +7349,6 @@
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -7964,8 +7973,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD",
- "peer": true
+ "license": "0BSD"
},
"node_modules/tuf-js": {
"version": "4.1.0",
@@ -8003,7 +8011,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -8089,7 +8096,6 @@
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -8165,7 +8171,6 @@
"integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@vitest/expect": "4.1.5",
"@vitest/mocker": "4.1.5",
@@ -8558,7 +8563,6 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}