Compare commits

..

No commits in common. "main" and "v1.4.1" have entirely different histories.
main ... v1.4.1

708 changed files with 22481 additions and 31211 deletions

View File

@ -1,3 +0,0 @@
{
"appHostPath": "../src/Aspire/src/AppHost/AppHost.csproj"
}

View File

@ -1,30 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-outdated-tool": {
"version": "4.6.9",
"commands": [
"dotnet-outdated"
]
},
"dotnet-ef": {
"version": "10.0.3",
"commands": [
"dotnet-ef"
]
},
"aspire.cli": {
"version": "13.1.1",
"commands": [
"aspire"
]
},
"csharpier": {
"version": "0.30.6",
"commands": [
"dotnet-csharpier"
]
}
}
}

View File

@ -22,9 +22,6 @@
**/.tye/
**/secrets.dev.yaml
**/values.dev.yaml
**/*.jwk
**/keys
LICENSE
README.md
CHANGELOG.md

File diff suppressed because it is too large Load Diff

64
.gitattributes vendored
View File

@ -1,64 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
*.sh text eol=lf
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

View File

@ -1,59 +0,0 @@
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions
# https://doug.sh/posts/using-composite-actions-with-github-actions/
# https://wallis.dev/blog/composite-github-actions
name: "Build-Test"
description: "Build and test service"
# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs
inputs:
project-path:
description: Project path
required: true
tests-path:
description: Test path
required: false
default: ''
reports-path:
description: Test report path
required: true
reports-output-path:
description: Test report output path
required: true
service-name:
description: Service name
required: true
# https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github
token:
description: A Github PAT
required: true
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions
runs:
using: "composite"
steps:
- name: Call Composite Action build
uses: ./.github/actions/build
if: success()
id: build-step
with:
project-path: ${{ inputs.project-path }}
service-name: ${{ inputs.service-name }}
- name: Call Composite Action test
uses: ./.github/actions/test
if: ${{ success() && inputs.tests-path != ''}}
id: test-step
with:
tests-path: ${{ inputs.tests-path }}
# wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
reports-path: ${{ github.workspace }}/**/*.cobertura.xml
reports-output-path: ${{ github.workspace }}/output/test-results
service-name: ${{ inputs.service-name }}
token: ${{ inputs.token }}
no-restore: true

View File

@ -1,69 +0,0 @@
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions
# https://doug.sh/posts/using-composite-actions-with-github-actions/
# https://wallis.dev/blog/composite-github-actions
name: "Build"
description: "Build service"
# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs
inputs:
project-path:
description: Project path
required: true
service-name:
description: Service name
required: true
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions
runs:
using: "composite"
steps:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows
# https://devblogs.microsoft.com/dotnet/dotnet-loves-github-actions/
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net#caching-dependencies
- name: Cache NuGet Packages
uses: actions/cache@v4
if: success()
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-dotnet-nuget
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.x.x'
# https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools
- name: Restore .NET Tools
shell: bash
run: dotnet tool restore
# Note: `Ubuntu` file and folder names are case sensitive, be aware about naming them in solution references. because `Windows` file and folder names as case-insensitive.
# prevent windows case-insensitive for our project with: git config core.ignorecase false; - https://stackoverflow.com/a/27139487/581476
- name: Restore NuGet packages
shell: bash
if: success()
# restore root solution
run: dotnet restore
# npm install, runs `prepare` script automatically in the initialize step
- name: Install NPM Dependencies
shell: bash
if: success()
run: npm install
- name: Format Service
shell: bash
if: ${{ success()}}
run: |
npm run ci-format
- name: Build Service
shell: bash
if: ${{ success()}}
working-directory: ${{ inputs.project-path }}
run: |
dotnet build -c Release --no-restore

View File

@ -34,11 +34,6 @@ runs:
username: ${{ inputs.registry-username }}
password: ${{ inputs.registry-password }}
- name: Docker Tag Info
shell: bash
run:
echo "Docker tag version is:" ${{ inputs.tag-name }}
- name: Build Docker Image
if: ${{ github.ref == 'refs/heads/main' && success() }}
shell: bash

View File

@ -1,85 +0,0 @@
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions
# https://doug.sh/posts/using-composite-actions-with-github-actions/
# https://wallis.dev/blog/composite-github-actions
name: "Test"
description: "Test service"
# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs
inputs:
tests-path:
description: Test path
required: true
reports-path:
description: Test report path
required: true
reports-output-path:
description: Test report output path
required: true
service-name:
description: Service name
required: true
# https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github
token:
description: A Github PAT
required: true
no-restore:
description: No restore nuget packages, but building tests because they don't build in the build composition action
default: 'true'
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions
runs:
using: "composite"
steps:
# see here https://samlearnsazure.blog/2021/01/05/code-coverage-in-github-with-net-core/
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details
# https://josef.codes/dotnet-core-filter-out-specific-test-projects-when-running-dotnet-test/
# https://learn.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=xunit
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
# https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md
# https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md#filters
- name: Tests
shell: bash
id: tests-step
working-directory: ${{ inputs.tests-path }}
# https://stackoverflow.com/questions/3779701/msbuild-error-msb1008-only-one-project-can-be-specified
# https://octopus.com/blog/githubactions-running-unit-tests
# we should not do 'no-build' here, because our tests not build in build phase (build composite action) and should build here
run: |
for file in $(find . -name "*.csproj" -type f); do
echo "Testing $file"
if [ ${{ inputs.no-restore }} == 'true' ]; then
echo "run tests in no-restore mode"
dotnet test "$file" -c Release --no-restore --logger "trx;LogFileName=test-results.trx" || true
else
echo "run tests in restore nuget mode"
dotnet test "$file" -c Release --logger "trx;LogFileName=test-results.trx" || true
fi
done
# GitHub Api call permissions problem here
# https://github.com/dorny/test-reporter/issues/168
# https://octopus.com/blog/githubactions-running-unit-tests
# https://github.com/dorny/test-reporter/issues/67
# https://github.com/phoenix-actions/test-reporting/pull/21
- name: Test Results
uses: phoenix-actions/test-reporting@v10
id: test-report
if: always()
with:
name: ${{ inputs.service-name }} Test Reports
reporter: dotnet-trx
token: ${{ inputs.token }}
# only-summary: 'true'
output-to: "step-summary"
path: "**/test-results.trx"
# Set action as failed if test report contains any failed test
fail-on-error: true
## https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories
## https://github.com/dorny/test-reporter/blob/0d9714ddc7ff86918ec725a527a3a069419d301a/src/utils/github-utils.ts#L44
## artifact name to download trx test result if it is in seperated workflow with github rest call, if it is not in another workflow skip this
# artifact: "'

39
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,39 @@
<!-- Type of change
Please label this PR with one of the existing labels, depending on the scope of your change.
-->
## What does this PR do?
<!-- Mandatory
Explain here the changes you made on the PR. Please explain the WHAT: patterns used, algorithms implemented, design architecture, etc.
-->
## Why is it important?
<!-- Mandatory
Explain here the WHY, or the rationale / motivation for the changes.
-->
## Related issues
<!-- Recommended
Link related issues below. Insert the issue link or reference after the word "Closes" if merging this should automatically close it.
- Closes #123
- Relates #123
- Requires #123
- Supersedes #123
-->
-
<!-- Recommended
## How to test this PR
Explain here how this PR will be tested by the reviewer: commands, dependencies, steps, etc.
-->
<!-- Optional
## Follow-ups
Add here any thought that you consider could be identified as an actionable step once this PR is merged.
-->

View File

@ -28,7 +28,7 @@ categories:
- title: 👷 CI
labels:
- ci
- title: ♻️ Refactor
- title: ♻️ Changes
labels:
- changed
- enhancement
@ -91,7 +91,9 @@ autolabeler:
body:
- '/JIRA-[0-9]{1,4}/'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-template: '- $TITLE (#$NUMBER)'
exclude-contributors:
- 'meysamhadeli'
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
major:

View File

@ -2,83 +2,41 @@ name: CI
on:
push:
branches: [ "main"]
branches: [ "main" , "develop" ]
paths-ignore:
- "README.md"
pull_request:
branches: [ "main"]
branches: [ "main" , "develop" ]
paths-ignore:
- "README.md"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.sha }}
cancel-in-progress: true
jobs:
ci:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Build and Test Flight Microservice
uses: ./.github/actions/build-test
if: success()
id: build-test-flight-step
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
project-path: 'src/Services/Flight/src/Flight.Api'
tests-path: 'src/Services/Flight/tests/'
# wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
reports-path: ${{ github.workspace }}/**/*.cobertura.xml
reports-output-path: ${{ github.workspace }}/output/test-results
service-name: 'Flight'
token: ${{ secrets.GITHUB_TOKEN }}
dotnet-version: 7.0.x
- name: Build and Test Identity Microservice
uses: ./.github/actions/build-test
if: success()
id: build-test-identity-step
- name: Cache NuGet Packages
uses: actions/cache@v3
with:
project-path: 'src/Services/Identity/src/Identity.Api'
tests-path: 'src/Services/Identity/tests/'
# wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
reports-path: ${{ github.workspace }}/**/*.cobertura.xml
reports-output-path: ${{ github.workspace }}/output/test-results
service-name: 'Identity'
token: ${{ secrets.GITHUB_TOKEN }}
key: ${{ runner.os }}-dotnet-nuget
path: ~/.nuget/packages
- name: Build and Test Passenger Microservice
uses: ./.github/actions/build-test
if: success()
id: build-test-passenger-step
with:
project-path: 'src/Services/Passenger/src/Passenger.Api'
tests-path: 'src/Services/Passenger/tests/'
# wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
reports-path: ${{ github.workspace }}/**/*.cobertura.xml
reports-output-path: ${{ github.workspace }}/output/test-results
service-name: 'Passenger'
token: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Test Booking Microservice
uses: ./.github/actions/build-test
if: success()
id: build-test-booking-step
with:
project-path: 'src/Services/Booking/src/Booking.Api'
tests-path: 'src/Services/Booking/tests/'
# wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory
# https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/
# https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not
reports-path: ${{ github.workspace }}/**/*.cobertura.xml
reports-output-path: ${{ github.workspace }}/output/test-results
service-name: 'Booking'
token: ${{ secrets.GITHUB_TOKEN }}
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build -c Release --no-restore
- name: Test
run: dotnet test -c Release --no-restore
- name: Update Release Drafter
if: ${{ github.ref == 'refs/heads/main' && success() }}
@ -87,11 +45,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release Version Info
run:
echo "Release version is:" ${{ steps.last_release.outputs.tag_name }}
- name: Build and Publish Identity Microservice to Docker
- name: Build and Publish Identity to Docker
if: ${{ github.ref == 'refs/heads/main' && success() }}
uses: ./.github/actions/docker-build-publish
with:
@ -101,7 +55,7 @@ jobs:
dockerfile-path: 'src/Services/Identity/Dockerfile'
image-name: 'booking-microservices-identity'
- name: Build and Publish Flight Microservice to Docker
- name: Build and Publish Flight to Docker
if: ${{ github.ref == 'refs/heads/main' && success() }}
uses: ./.github/actions/docker-build-publish
with:
@ -111,7 +65,7 @@ jobs:
dockerfile-path: 'src/Services/Flight/Dockerfile'
image-name: 'booking-microservices-flight'
- name: Build and Publish Passenger Microservice to Docker
- name: Build and Publish Passenger to Docker
if: ${{ github.ref == 'refs/heads/main' && success() }}
uses: ./.github/actions/docker-build-publish
with:
@ -121,7 +75,7 @@ jobs:
dockerfile-path: 'src/Services/Passenger/Dockerfile'
image-name: 'booking-microservices-passenger'
- name: Build and Publish Booking Microservice to Docker
- name: Build and Publish Booking to Docker
if: ${{ github.ref == 'refs/heads/main' && success() }}
uses: ./.github/actions/docker-build-publish
with:

11
.gitignore vendored
View File

@ -226,6 +226,7 @@ ClientBin/
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
@ -431,12 +432,4 @@ fabric.properties
*.sln.iml
# Tye
.tye/
*.jwk
# Monitoring
**/grafana-data
# EventStore
**/eventstore
.tye/

1
.gitpod.Dockerfile vendored Normal file
View File

@ -0,0 +1 @@
FROM gitpod/workspace-dotnet:latest

30
.gitpod.yml Normal file
View File

@ -0,0 +1,30 @@
# https://github.com/gitpod-samples/template-dotnet-core-cli-csharp
# https://www.gitpod.io/docs/introduction/languages/dotnet
# https://github.com/gitpod-samples/template-docker-compose
# https://www.gitpod.io/docs/references/gitpod-yml
# https://www.gitpod.io/docs/configure
# https://www.gitpod.io/docs/configure/workspaces/ports
image:
file: .gitpod.Dockerfile
# https://www.gitpod.io/docs/configure/workspaces/tasks#execution-order
# https://www.gitpod.io/docs/configure/projects/prebuilds
tasks:
- name: Init Docker-Compose
# https://www.gitpod.io/docs/configure/projects/prebuilds
# We load docker on pre-build for increasing speed
init: |
docker-compose pull
docker-compose -f ./deployments/docker-compose/infrastracture.yaml up -d
- name: Setup kubectl
command: bash $GITPOD_REPO_ROOT/scripts/setup_kubectl_gitpod.sh
- name: Restore & Build
init: |
dotnet dev-certs https
dotnet restore
dotnet build
vscode:
extensions:
- muhammad-sammy.csharp

View File

@ -1 +0,0 @@
npx --no -- commitlint --edit ${1}

View File

@ -1,2 +0,0 @@
npm run format
npm run ci-format

View File

@ -1,26 +0,0 @@
## Contribution
This is great that you'd like to contribute to this project. All change requests should go through the steps described below.
## Pull Requests
**Please, make sure you open an issue before starting with a Pull Request, unless it's a typo or a really obvious error.** Pull requests are the best way to propose changes.
## Conventional commits
Our repository follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. Releasing to GitHub and NuGet is done with the support of [semantic-release](https://semantic-release.gitbook.io/semantic-release/).
Pull requests should have a title that follows the specification, otherwise, merging is blocked. If you are not familiar with the specification simply ask maintainers to modify. You can also use this cheatsheet if you want:
- `fix: ` prefix in the title indicates that PR is a bug fix and PATCH release must be triggered.
- `feat: ` prefix in the title indicates that PR is a feature and MINOR release must be triggered.
- `docs: ` prefix in the title indicates that PR is only related to the documentation and there is no need to trigger release.
- `chore: ` prefix in the title indicates that PR is only related to cleanup in the project and there is no need to trigger release.
- `test: ` prefix in the title indicates that PR is only related to tests and there is no need to trigger release.
- `refactor: ` prefix in the title indicates that PR is only related to refactoring and there is no need to trigger release.
## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
- [GitHub Help](https://help.github.com)

View File

@ -1,48 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="all" Version="1.1.118">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" Version="2.0.299">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" PrivateAssets="all" Version="4.15.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" PrivateAssets="all" Version="4.15.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Formatting.Analyzers" PrivateAssets="all" Version="4.15.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" PrivateAssets="all" Version="17.14.15">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AsyncAwaitBestPractices" PrivateAssets="all" Version="10.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CSharpGuidelinesAnalyzer" PrivateAssets="all" Version="3.8.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<GlobalPackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.0" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<GlobalPackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" />
</ItemGroup>
<PropertyGroup>
<RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<AnalysisMode>Recommended</AnalysisMode>
</PropertyGroup>
</Project>

241
README.md
View File

@ -2,128 +2,90 @@
<img src="assets/logo.png" alt="booking-microservices" />
<div align="center">
<a href="https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml"><img alt="ci-status" src="https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml/badge.svg?branch=main&style=flat-square"/></a>
<a href="https://gitpod.io/#https://github.com/meysamhadeli/booking-microservices"><img src="https://img.shields.io/badge/Gitpod-live--code-blue?logo=gitpod&style=flat-square&color=ff69b4"/></a>
<a href="https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE"><img alt="build-status" src="https://img.shields.io/github/license/meysamhadeli/booking-microservices?color=%234275f5&style=flat-square"/></a>
</div>
</div>
> 🚀 **A practical microservices with the latest technologies and architectures like Vertical Slice Architecture, Event Sourcing, CQRS, DDD, gRpc, MongoDB, RabbitMq, Masstransit, and Aspire in .Net 10.**
## You can find other version of this project here:
- [Booking with Modular Monolith Architecture](https://github.com/meysamhadeli/booking-modular-monolith)
- [Booking with Monolith Architecture](https://github.com/meysamhadeli/booking-monolith)
<div>
<a href='https://codespaces.new/meysamhadeli/booking-microservices?quickstart=1'><img alt='Open in GitHub Codespaces' src='https://github.com/codespaces/badge.svg'></a>
</div>
> **The main idea of creating this project is implementing an infrastructure for up and running distributed system with the latest technology and architecture like Vertical Slice Architecture, Event Sourcing, CQRS, DDD, gRpc, MongoDB, RabbitMq, Masstransit in .Net, and we will not deal mainly with business.** 🚀
# Table of Contents
- [The Goals of This Project](#the-goals-of-this-project)
- [Plan](#plan)
- [Technologies - Libraries](#technologies---libraries)
- [Key Features](#key-features)
- [When to Use](#when-to-use)
- [Challenges](#challenges)
- [The Domain and Bounded Context - Service Boundary](#the-domain-and-bounded-context---service-boundary)
- [Structure of Project](#structure-of-project)
- [Development Setup](#development-setup)
- [Dotnet Tools Packages](#dotnet-tools-packages)
- [Husky](#husky)
- [Upgrade Nuget Packages](#upgrade-nuget-packages)
- [How to Run](#how-to-run)
- [Config Certificate](#config-certificate)
- [Aspire](#aspire)
- [Docker Compose](#docker-compose)
- [Kubernetes](#kubernetes)
- [Build](#build)
- [Run](#run)
- [Test](#test)
- [Documentation Apis](#documentation-apis)
- [Support](#support)
- [Contribution](#contribution)
## The Goals of This Project
- :sparkle: Using `Vertical Slice Architecture` for `architecture` level.
- :sparkle: Using `Domain Driven Design (DDD)` to implement all `business logic`.
- :sparkle: Using `Rabbitmq` on top of `Masstransit` for `Event Driven Architecture`.
- :sparkle: Using `gRPC` for `internal communication`.
- :sparkle: Using `Vertical Slice Architecture` for architecture level.
- :sparkle: Using `Domain Driven Design (DDD)` to implement all business processes in microservices.
- :sparkle: Using `Rabbitmq` on top of `Masstransit` for `Event Driven Architecture` between our microservices.
- :sparkle: Using `gRPC` for internal communication between our microservices.
- :sparkle: Using `CQRS` implementation with `MediatR` library.
- :sparkle: Using `Postgres` for `write side` database.
- :sparkle: Using `MongoDB` for `read side` database.
- :sparkle: Using `Event Store` for `write side` of Booking Microservice/Module to store all `historical change` of aggregate.
- :sparkle: Using `Inbox Pattern` for ensuring message idempotency for receiver and `Exactly once Delivery`.
- :sparkle: Using `Outbox Pattern` for ensuring no message is lost and there is at `At Least One Delivery`.
- :sparkle: Using `Unit Testing` for testing small units and mocking our dependencies with `Nsubstitute`.
- :sparkle: Using `End-To-End Testing` and `Integration Testing` for testing `features` with all dependencies using `testcontainers`.
- :sparkle: Using `Postgres` for `write side` of some microservices.
- :sparkle: Using `MongoDB` for `read side` of some microservices.
- :sparkle: Using `Event Store` for `write side` of Booking-Microservice to store all `historical state` of aggregate.
- :sparkle: Using `Inbox Pattern` for ensuring message idempotency for receiver and `Exactly once Delivery`.
- :sparkle: Using `Outbox Pattern` for ensuring no message is lost and there is at `Least One Delivery`.
- :sparkle: Using `Unit Testing`, `Integration Testing`, `End To End Testing` for testing level.
- :sparkle: Using `Fluent Validation` and a `Validation Pipeline Behaviour` on top of `MediatR`.
- :sparkle: Using `Minimal API` for all endpoints.
- :sparkle: Using `AspNetCore OpenApi` for `generating` built-in support `OpenAPI documentation` in ASP.NET Core.
- :sparkle: Using `Health Check` for `reporting` the `health` of app infrastructure components.
- :sparkle: Using `Health Check` for reporting the health of app infrastructure components.
- :sparkle: Using `Docker-Compose` and `Kubernetes` for our deployment mechanism.
- :sparkle: Using `Kibana` on top of `Serilog` for `logging`.
- :sparkle: Using `OpenTelemetry` for distributed tracing on top of `Jaeger`.
- :sparkle: Using `OpenTelemetry` for monitoring on top of `Prometheus` and `Grafana`.
- :sparkle: Using `OpenTelemetry` for distributed tracing.
- :sparkle: Using `IdentityServer` for authentication and authorization base on `OpenID-Connect` and `OAuth2`.
- :sparkle: Using `Yarp` as a microservices `gateway`.
- :sparkle: Using `Kubernetes` to achieve efficient `scaling` and ensure `high availability` for each of our microservices.
- :sparkle: Using `Nginx Ingress Controller` for `load balancing` between our microservices top of `Kubernetes`.
- :sparkle: Using `cert-manager` to Configure `TLS` in `kubernetes cluster`.
- :sparkle: Using `Aspire` for `service discovery`, `observability`, and `local orchestration` of microservices.
- :sparkle: Using `Yarp` as a microservices gateway.
## Plan
## Technologies - Libraries
> 🌀This project is a work in progress, new features will be added over time.🌀
- ✔️ **[`.NET 10`](https://github.com/dotnet/aspnetcore)** - .NET Framework and .NET Core, including ASP.NET and ASP.NET Core.
- ✔️ **[`MVC Versioning API`](https://github.com/microsoft/aspnet-api-versioning)** - Set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET Core.
- ✔️ **[`EF Core`](https://github.com/dotnet/efcore)** - Modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
- ✔️ **[`AspNetCore OpenApi`](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/aspnetcore-openapi)** - Provides built-in support for OpenAPI document generation in ASP.NET Core.
I will try to register future goals and additions in the [Issues](https://github.com/meysamhadeli/booking-microservices/issues) section of this repository.
High-level plan is represented in the table
| Feature | Status |
| ----------------- | -------------- |
| API Gateway | Completed ✔️ |
| Identity Service | Completed ✔️ |
| Flight Service | Completed ✔️ |
| Passenger Service | Completed ✔️ |
| Booking Service | Completed ✔️ |
| Building Blocks | Completed ✔️ |
## :heart: Technologies - Libraries
- ✔️ **[`.NET 7`](https://dotnet.microsoft.com/download)** - .NET Framework and .NET Core, including ASP.NET and ASP.NET Core
- ✔️ **[`MVC Versioning API`](https://github.com/microsoft/aspnet-api-versioning)** - Set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET Core
- ✔️ **[`EF Core`](https://github.com/dotnet/efcore)** - Modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations
- ✔️ **[`Masstransit`](https://github.com/MassTransit/MassTransit)** - Distributed Application Framework for .NET.
- ✔️ **[`MediatR`](https://github.com/jbogard/MediatR)** - Simple, unambitious mediator implementation in .NET.
- ✔️ **[`FluentValidation`](https://github.com/FluentValidation/FluentValidation)** - Popular .NET validation library for building strongly-typed validation rules.
- ✔️ **[`Scalar`](https://github.com/scalar/scalar/tree/main/packages/scalar.aspnetcore)** - Scalar provides an easy way to render beautiful API references based on OpenAPI/Swagger documents.
- ✔️ **[`Swagger UI`](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)** - Swagger tools for documenting API's built on ASP.NET Core.
- ✔️ **[`FluentValidation`](https://github.com/FluentValidation/FluentValidation)** - Popular .NET validation library for building strongly-typed validation rules
- ✔️ **[`Swagger & Swagger UI`](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)** - Swagger tools for documenting API's built on ASP.NET Core
- ✔️ **[`Serilog`](https://github.com/serilog/serilog)** - Simple .NET logging with fully-structured events
- ✔️ **[`Polly`](https://github.com/App-vNext/Polly)** - Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.
- ✔️ **[`Polly`](https://github.com/App-vNext/Polly)** - Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner
- ✔️ **[`Scrutor`](https://github.com/khellang/Scrutor)** - Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
- ✔️ **[`Opentelemetry-dotnet`](https://github.com/open-telemetry/opentelemetry-dotnet)** - The OpenTelemetry .NET Client
- ✔️ **[`DuendeSoftware IdentityServer`](https://github.com/DuendeSoftware/IdentityServer)** - The most flexible and standards-compliant OpenID Connect and OAuth 2.x framework for ASP.NET Core.
- ✔️ **[`DuendeSoftware IdentityServer`](https://github.com/DuendeSoftware/IdentityServer)** - The most flexible and standards-compliant OpenID Connect and OAuth 2.x framework for ASP.NET Core
- ✔️ **[`EasyCaching`](https://github.com/dotnetcore/EasyCaching)** - Open source caching library that contains basic usages and some advanced usages of caching which can help us to handle caching more easier.
- ✔️ **[`Mapster`](https://github.com/MapsterMapper/Mapster)** - Convention-based object-object mapper in .NET.
- ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core.
- ✔️ **[`NewId`](https://github.com/phatboyg/NewId)** - NewId can be used as an embedded unique ID generator that produces 128 bit (16 bytes) sequential IDs.
- ✔️ **[`Yarp`](https://github.com/microsoft/reverse-proxy)** - Reverse proxy toolkit for building fast proxy servers in .NET.
- ✔️ **[`Tye`](https://github.com/dotnet/tye)** - Developer tool that makes developing, testing, and deploying microservices and distributed applications easier.
- ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core
- ✔️ **[`IdGen`](https://github.com/RobThree/IdGen)** - Twitter Snowflake-alike ID generator for .Net
- ✔️ **[`Yarp`](https://github.com/microsoft/reverse-proxy)** - Reverse proxy toolkit for building fast proxy servers in .NET
- ✔️ **[`Tye`](https://github.com/dotnet/tye)** - Developer tool that makes developing, testing, and deploying microservices and distributed applications easier
- ✔️ **[`gRPC-dotnet`](https://github.com/grpc/grpc-dotnet)** - gRPC functionality for .NET.
- ✔️ **[`EventStore`](https://github.com/EventStore/EventStore)** - The open-source, functional database with Complex Event Processing.
- ✔️ **[`MongoDB.Driver`](https://github.com/mongodb/mongo-csharp-driver)** - .NET Driver for MongoDB.
- ✔️ **[`xUnit.net`](https://github.com/xunit/xunit)** - A free, open source, community-focused unit testing tool for the .NET Framework.
- ✔️ **[`Respawn`](https://github.com/jbogard/Respawn)** - Respawn is a small utility to help in resetting test databases to a clean state.
- ✔️ **[`Testcontainers`](https://github.com/testcontainers/testcontainers-dotnet)** - Testcontainers for .NET is a library to support tests with throwaway instances of Docker containers.
- ✔️ **[`K6`](https://github.com/grafana/k6)** - Modern load testing for developers and testers in the DevOps era.
- ✔️ **[`Aspire`](https://github.com/dotnet/aspire)** - .NET stack for building and orchestrating observable, distributed cloud-native applications.
## Key Features
1. **Independent Services**: Each service is a separate project with its own database and deployment pipeline, enabling independent development and deployment.
2. **Decentralized Communication**: Services communicate via APIs (REST, gRPC) or message brokers (RabbitMQ, Kafka), ensuring loose coupling and resilience.
3. **Scalability**: Services can be scaled independently based on demand, allowing efficient resource utilization.
4. **Fault Tolerance**: Failures are isolated, preventing cascading failures and ensuring high availability.
5. **Technology Agnostic**: Services can use different technologies, frameworks, or databases, providing flexibility.
## When to Use
1. **Large and Complex Projects**: Ideal for applications with complex business logic that can be broken into smaller, manageable services.
2. **High Scalability Needs**: Suitable for applications requiring independent scaling of components.
3. **Fault Tolerance and High Availability**: Perfect for systems where failure isolation and uptime are critical.
4. **Distributed Teams**: Enables teams to work independently on different services.
5. **Frequent Updates**: Supports continuous deployment and A/B testing for individual services.
6. **Technology Diversity**: Allows the use of different technologies for different services.
## Challenges
- Increased complexity in management, DevOps overhead, data consistency, latency, and higher costs.
## The Domain And Bounded Context - Service Boundary
@ -137,19 +99,26 @@
![](./assets/booking-microservices.png)
## Structure of Project
In this project, I used [vertical slice architecture](https://jimmybogard.com/vertical-slice-architecture/) at the architectural level and [feature folder structure](http://www.kamilgrzybek.com/design/feature-folders/) to structure my files.
In this project I used a mix of [clean architecture](https://jasontaylor.dev/clean-architecture-getting-started/), [vertical slice architecture](https://jimmybogard.com/vertical-slice-architecture/) and I used [feature folder structure](http://www.kamilgrzybek.com/design/feature-folders/) to structure my files.
I used [yarp reverse proxy](https://microsoft.github.io/reverse-proxy/articles/index.html) to route synchronous and asynchronous requests to the corresponding microservice. Each microservice has its dependencies such as databases, files etc. Each microservice is decoupled from other microservices and developed and deployed separately. Microservices talk to each other with Rest or gRPC for synchronous calls and use RabbitMq or Kafka for asynchronous calls.
We have a separate microservice ([IdentityServer](https://github.com/DuendeSoftware/IdentityServer)) for authentication and authorization of each request. Once signed-in users are issued a JWT token. This token is used by other microservices to validate the user, read claims and allow access to authorized/role specific endpoints.
I used [RabbitMQ](https://github.com/rabbitmq) as my MessageBroker for async communication between microservices using the eventual consistency mechanism. Each microservice uses [MassTransit](https://github.com/MassTransit/MassTransit) to interface with [RabbitMQ](https://github.com/rabbitmq) providing, messaging, availability, reliability, etc.
Microservices are `event based` which means they can publish and/or subscribe to any events occurring in the setup. By using this approach for communicating between services, each microservice does not need to know about the other services or handle errors occurred in other microservices.
After saving data in write side, I save a [Internal Command](https://github.com/kgrzybek/modular-monolith-with-ddd#38-internal-processing) record in my Persist Messages storage (like something we do in outbox pattern) and after committing transaction in write side, trigger our command handler in read side and this handler could save their read models in our MongoDB database.
I treat each request as a distinct use case or slice, encapsulating and grouping all concerns from front-end to back.
When adding or changing a feature in an application in n-tire architecture, we are typically touching many "layers" in an application. We are changing the user interface, adding fields to models, modifying validation, and so on. Instead of coupling across a layer, we couple vertically along a slice. We `minimize coupling` `between slices`, and `maximize coupling` `in a slice`.
With this approach, each of our vertical slices can decide for itself how to best fulfill the request. New features only add code, we're not changing shared code and worrying about side effects.
<div align="center">
<img src="./assets/vertical-slice-architecture.png" />
</div>
![](./assets/Vertical-Slice-Architecture.jpg)
Instead of grouping related action methods in one controller, as found in traditional ASP.net controllers, I used the [REPR pattern](https://deviq.com/design-patterns/repr-design-pattern). Each action gets its own small endpoint, consisting of a route, the action, and an `IMediator` instance (see [MediatR](https://github.com/jbogard/MediatR)). The request is passed to the `IMediator` instance, routed through a [`Mediatr pipeline`](https://lostechies.com/jimmybogard/2014/09/09/tackling-cross-cutting-concerns-with-a-mediator-pipeline/) where custom [middleware](https://github.com/jbogard/MediatR/wiki/Behaviors) can log, validate and intercept requests. The request is then handled by a request specific `IRequestHandler` which performs business logic before returning the result.
@ -163,111 +132,43 @@ I used CQRS to decompose my features into small parts that makes our application
Using the CQRS pattern, we cut each business functionality into vertical slices, for each of these slices we group classes (see [technical folders structure](http://www.kamilgrzybek.com/design/feature-folders)) specific to that feature together (command, handlers, infrastructure, repository, controllers, etc). In our CQRS pattern each command/query handler is a separate slice. This is where you can reduce coupling between layers. Each handler can be a separated code unit, even copy/pasted. Thanks to that, we can tune down the specific method to not follow general conventions (e.g. use custom SQL query or even different storage). In a traditional layered architecture, when we change the core generic mechanism in one layer, it can impact all methods.
## Development Setup
### Dotnet Tools Packages
For installing our requirement packages with .NET cli tools, we need to install `dotnet tool manifest`.
```bash
dotnet new tool-manifest
```
And after that we can restore our dotnet tools packages with .NET cli tools from `.config` folder and `dotnet-tools.json` file.
```
dotnet tool restore
```
### Husky
Here we use `husky` to handel some pre commit rules and we used `conventional commits` rules and `formatting` as pre commit rules, here in [package.json](.././package.json). of course, we can add more rules for pre commit in future. (find more about husky in the [documentation](https://typicode.github.io/husky/get-started.html))
We need to install `husky` package for `manage` `pre commits hooks` and also I add two packages `@commitlint/cli` and `@commitlint/config-conventional` for handling conventional commits rules in [package.json](.././package.json).
Run the command bellow in the root of project to install all npm dependencies related to husky:
```bash
npm install
```
> Note: In the root of project we have `.husky` folder and it has `commit-msg` file for handling conventional commits rules with provide user friendly message and `pre-commit` file that we can run our `scripts` as a `pre-commit` hooks. that here we call `format` script from [package.json](./package.json) for formatting purpose.
### Upgrade Nuget Packages
For upgrading our nuget packages to last version, we use the great package [dotnet-outdated](https://github.com/dotnet-outdated/dotnet-outdated).
Run the command below in the root of project to upgrade all of packages to last version:
```bash
dotnet outdated -u
```
## How to Run
> ### Config Certificate
Run the following commands to [Config SSL](https://docs.microsoft.com/en-us/aspnet/core/security/docker-compose-https?view=aspnetcore-6.0) in your system:
### Config Certificate
Run the following commands for [Config SSL](https://docs.microsoft.com/en-us/aspnet/core/security/docker-compose-https?view=aspnetcore-6.0) in your system
#### Windows using Linux containers
```bash
dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p password
dotnet dev-certs https --trust
```
> Note: for running this command in `powershell` use `$env:USERPROFILE` instead of `%USERPROFILE%`*
> Note: for running this command in `powershell` use `$env:USERPROFILE` instead of `%USERPROFILE%`
#### macOS or Linux
```bash
dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p $CREDENTIAL_PLACEHOLDER$
dotnet dev-certs https --trust
```
### Docker Compose
### Aspire
To run the application using the `Aspire App Host`, execute the following command from the solution root:
```bash
aspire run
```
> Note:The `Aspire dashboard` will be available at `http://localhost:18888`
> ### Docker Compose
To run this app in `Docker`, use the [docker-compose.yaml](./deployments/docker-compose/docker-compose.yaml) and execute the below command at the `root` of the application:
Run this app in docker using the [docker-compose.yaml](./deployments/docker-compose/docker-compose.yaml) file with the below command at the root of the application:
```bash
docker-compose -f ./deployments/docker-compose/docker-compose.yaml up -d
```
> ### Kubernetes
To `configure TLS` in the `Kubernetes cluster`, we need to install `cert-manager` based on the [docs](https://cert-manager.io/docs/installation) and run the following commands to apply TLS in our application. Here, we use [Let's Encrypt](https://letsencrypt.org/) to encrypt our certificate.
Also we have a seprate docker file for up and running [infrastracture.yaml](./deployments/docker-compose/infrastracture.yaml) independently:
```bash
kubectl apply -f ./deployments/kubernetes/booking-cert-manager.yml
docker-compose -f ./deployments/docker-compose/infrastracture.yaml up -d
```
To apply all necessary `deployments`, `pods`, `services`, `ingress`, and `config maps`, please run the following command:
### Kubernetes - TODO
```bash
kubectl apply -f ./deployments/kubernetes/booking-microservices.yml
```
### Documentation Apis
> ### Build
To `build` all microservices, run this command in the `root` of the project:
```bash
dotnet build
```
> ### Run
To `run` each microservice, run this command in the root of the `Api` folder of each microservice where the `csproj` file is located:
```bash
dotnet run
```
> ### Test
To `test` all microservices, run this command in the `root` of the project:
```bash
dotnet test
```
> ### Documentation Apis
Each microservice provides `API documentation` and navigate to `/swagger` for `Swagger OpenAPI` or `/scalar/v1` for `Scalar OpenAPI` to visit list of endpoints.
As part of API testing, I created the [booking.rest](./booking.rest) file which can be run with the [REST Client](https://github.com/Huachao/vscode-restclient) `VSCode plugin`.
Each microservice uses swagger open api, navigate to /swagger for a list of every endpoint.
For testing apis I used the [REST Client](https://github.com/Huachao/vscode-restclient) plugin for VSCode running this file [booking.rest](./booking.rest).
# Support
@ -279,9 +180,7 @@ Thanks a bunch for supporting me!
## Contribution
Thanks to all [contributors](https://github.com/meysamhadeli/booking-microservices/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized, community-driven collection of very well-known resources.
Please follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull request or create the issue.
Thanks to all [contributors](https://github.com/meysamhadeli/booking-microservices/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized community-driven collection of very well-known resources.
## Project References & Credits
@ -289,7 +188,9 @@ Please follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull
- [https://github.com/kgrzybek/modular-monolith-with-ddd](https://github.com/kgrzybek/modular-monolith-with-ddd)
- [https://github.com/oskardudycz/EventSourcing.NetCore](https://github.com/oskardudycz/EventSourcing.NetCore)
- [https://github.com/thangchung/clean-architecture-dotnet](https://github.com/thangchung/clean-architecture-dotnet)
- [https://github.com/jasontaylordev/CleanArchitecture](https://github.com/jasontaylordev/CleanArchitecture)
- [https://github.com/pdevito3/MessageBusTestingInMemHarness](https://github.com/pdevito3/MessageBusTestingInMemHarness)
- [https://github.com/devmentors/FeedR](https://github.com/devmentors/FeedR)
## License
This project is made available under the MIT license. See [LICENSE](https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE) for details.

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -1,431 +0,0 @@
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [
{
"type": "rectangle",
"version": 242,
"versionNonce": 1509780320,
"isDeleted": false,
"id": "80OGzNPG6Gk8NAvbV3XaF",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 648,
"y": 187,
"strokeColor": "#000000",
"backgroundColor": "#a8bffe",
"width": 538,
"height": 62,
"seed": 246982778,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [
{
"type": "text",
"id": "46GLDhDwmnc8RGy3v8OK8"
}
],
"updated": 1679316672934,
"link": null,
"locked": false
},
{
"type": "text",
"version": 137,
"versionNonce": 703919968,
"isDeleted": false,
"id": "46GLDhDwmnc8RGy3v8OK8",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 897.848014831543,
"y": 201.2,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 38.30397033691406,
"height": 33.6,
"seed": 2080176422,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949309,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Api",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": "80OGzNPG6Gk8NAvbV3XaF",
"originalText": "Api"
},
{
"type": "rectangle",
"version": 358,
"versionNonce": 356515488,
"isDeleted": false,
"id": "nZuYK7wbLObwRvpRRLHay",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 648,
"y": 263,
"strokeColor": "#000000",
"backgroundColor": "#fea8d5",
"width": 538,
"height": 62,
"seed": 287502970,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [
{
"type": "text",
"id": "OALII-DXtatRPgn_EkHfp"
}
],
"updated": 1679316735759,
"link": null,
"locked": false
},
{
"type": "text",
"version": 246,
"versionNonce": 1126108000,
"isDeleted": false,
"id": "OALII-DXtatRPgn_EkHfp",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 845.628044128418,
"y": 277.2,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 142.74391174316406,
"height": 33.6,
"seed": 1016531494,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949309,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Application",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": "nZuYK7wbLObwRvpRRLHay",
"originalText": "Application"
},
{
"type": "rectangle",
"version": 282,
"versionNonce": 787808928,
"isDeleted": false,
"id": "za_4vz64MSfPF5TWmD7wj",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 650,
"y": 338,
"strokeColor": "#000000",
"backgroundColor": "#f30358",
"width": 538,
"height": 62,
"seed": 676018342,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [
{
"type": "text",
"id": "6CqYCSOKHqhqJ8nf4b-Sv"
}
],
"updated": 1679316783390,
"link": null,
"locked": false
},
{
"type": "text",
"version": 189,
"versionNonce": 1441177440,
"isDeleted": false,
"id": "6CqYCSOKHqhqJ8nf4b-Sv",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 816.618049621582,
"y": 352.2,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 204.76390075683594,
"height": 33.6,
"seed": 1067355322,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949309,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Infrastructure",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": "za_4vz64MSfPF5TWmD7wj",
"originalText": "Infrastructure"
},
{
"type": "rectangle",
"version": 326,
"versionNonce": 1669046112,
"isDeleted": false,
"id": "t2sZwLLvmq3y2ndIbEomB",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 70,
"angle": 0,
"x": 648,
"y": 413,
"strokeColor": "#000000",
"backgroundColor": "#9d9ca2",
"width": 538,
"height": 62,
"seed": 1173221990,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [
{
"type": "text",
"id": "b3wdaWjaVmgHpzMD26uKD"
}
],
"updated": 1679316844215,
"link": null,
"locked": false
},
{
"type": "text",
"version": 224,
"versionNonce": 1385935712,
"isDeleted": false,
"id": "b3wdaWjaVmgHpzMD26uKD",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 70,
"angle": 0,
"x": 886.5500106811523,
"y": 427.2,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 60.89997863769531,
"height": 33.6,
"seed": 1307397882,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949310,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Core",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": "t2sZwLLvmq3y2ndIbEomB",
"originalText": "Core"
},
{
"type": "rectangle",
"version": 202,
"versionNonce": 1461187232,
"isDeleted": false,
"id": "FQZImjU2-VUOATU9Yeyly",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 678,
"y": 154,
"strokeColor": "#000000",
"backgroundColor": "#fefda8",
"width": 48,
"height": 361,
"seed": 1254939642,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [],
"updated": 1679316609154,
"link": null,
"locked": false
},
{
"type": "rectangle",
"version": 249,
"versionNonce": 1540775776,
"isDeleted": false,
"id": "_Vw9EnXAyzxRDEzXCTfeL",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 742,
"y": 153.5,
"strokeColor": "#000000",
"backgroundColor": "#fefda8",
"width": 48,
"height": 361,
"seed": 523058342,
"groupIds": [],
"roundness": {
"type": 3
},
"boundElements": [],
"updated": 1679316594766,
"link": null,
"locked": false
},
{
"type": "text",
"version": 249,
"versionNonce": 871687840,
"isDeleted": false,
"id": "hyJiOwPt7LFndn5R0xgfL",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 4.707547804955119,
"x": 637.1248451774691,
"y": 317.9455509364301,
"strokeColor": "#000000",
"backgroundColor": "#f9e79f",
"width": 130.73194885253906,
"height": 33.6,
"seed": 678740006,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315961675,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Feature 1",
"textAlign": "left",
"verticalAlign": "top",
"containerId": null,
"originalText": "Feature 1"
},
{
"type": "text",
"version": 182,
"versionNonce": 1494113120,
"isDeleted": false,
"id": "7KOHd5JA_wVMmwXPVT1N3",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 80,
"angle": 4.7123889803846915,
"x": 695.6880416870117,
"y": 313.20000000000005,
"strokeColor": "#000000",
"backgroundColor": "#f9e79f",
"width": 143.07994079589844,
"height": 33.6,
"seed": 1387191482,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949310,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Feature 2",
"textAlign": "left",
"verticalAlign": "top",
"containerId": null,
"originalText": "Feature 2"
},
{
"type": "text",
"version": 163,
"versionNonce": 1243581088,
"isDeleted": false,
"id": "SuFNrbzZGowiIybusnadN",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 70,
"angle": 0,
"x": 748,
"y": 96,
"strokeColor": "#000000",
"backgroundColor": "#f9e79f",
"width": 360.47186279296875,
"height": 33.6,
"seed": 2006173690,
"groupIds": [],
"roundness": null,
"boundElements": [],
"updated": 1679315949310,
"link": null,
"locked": false,
"fontSize": 28,
"fontFamily": 1,
"text": "Vertical Slice Architecture",
"textAlign": "left",
"verticalAlign": "top",
"containerId": null,
"originalText": "Vertical Slice Architecture"
}
],
"appState": {
"gridSize": null,
"viewBackgroundColor": "#ffffff"
},
"files": {}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,175 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{5B69EDFD-4B09-457A-AAAF-D816D402D595}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{9010E0B5-9C42-4256-ADE4-E290434F2CEF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateway", "ApiGateway", "{3E38DD17-9EEE-4815-9D5B-BEB5549020A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{776BDF43-0DEA-44A3-AF72-99408CE544EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "src\ApiGateway\src\ApiGateway.csproj", "{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingBlocks", "src\BuildingBlocks\BuildingBlocks.csproj", "{E42BB533-4144-4D78-BCCE-50BA00BCADBE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flight", "Flight", "{5F0996AB-F8DB-4240-BD4A-DFDD70638A73}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Passenger", "Passenger", "{1A2ABCD9-493B-4848-9C69-919CDBCA61F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Booking", "Booking", "{22447274-717D-4321-87F3-868BAF93CBEC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{55BE6759-95AA-434D-925D-A8D32F274E66}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E2637D6D-04A5-4DE4-8AAF-E015C65DE8E1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{5185D5C5-0EAD-49D5-B405-93B939F3639B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{53D0AA09-F5FA-4721-8C1B-375CBD15B4E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C6EE337B-91EA-472A-87C7-E9528408CE59}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F39D8F09-6233-4495-ACD0-F98904993B7E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{295284BA-D4E4-40AA-A2C2-BE36343F7DE6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{85DA00E5-CC11-463C-8577-C34967C328F7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C1EBE17D-BFAD-47DA-88EB-BB073B84593E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Booking", "src\Services\Booking\src\Booking\Booking.csproj", "{B2BAA061-C005-409F-9D3E-BDCBE5B1B136}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Booking.Api", "src\Services\Booking\src\Booking.Api\Booking.Api.csproj", "{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flight", "src\Services\Flight\src\Flight\Flight.csproj", "{574222F8-9C26-4015-8F35-C1E5D41A505F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flight.Api", "src\Services\Flight\src\Flight.Api\Flight.Api.csproj", "{B8F734F5-873C-4367-9EBD-38EA420CD868}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "src\Services\Identity\src\Identity\Identity.csproj", "{65C1BB58-2A2E-44FF-B15D-2B023CF088D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Api", "src\Services\Identity\src\Identity.Api\Identity.Api.csproj", "{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger", "src\Services\Passenger\src\Passenger\Passenger.csproj", "{6D7BCECE-D77D-4C57-A296-CA6E728E94B7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger.Api", "src\Services\Passenger\src\Passenger.Api\Passenger.Api.csproj", "{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Flight\tests\IntegrationTest\Integration.Test.csproj", "{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Identity\tests\IntegrationTest\Integration.Test.csproj", "{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Passenger\tests\IntegrationTest\Integration.Test.csproj", "{539364C8-88B1-48A3-8406-D0B19FF30509}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Booking\tests\IntegrationTest\Integration.Test.csproj", "{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "src\Services\Flight\tests\UnitTest\Unit.Test.csproj", "{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndToEnd.Test", "src\Services\Flight\tests\EndToEndTest\EndToEnd.Test.csproj", "{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{776BDF43-0DEA-44A3-AF72-99408CE544EE} = {3E38DD17-9EEE-4815-9D5B-BEB5549020A0}
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5} = {776BDF43-0DEA-44A3-AF72-99408CE544EE}
{E42BB533-4144-4D78-BCCE-50BA00BCADBE} = {5B69EDFD-4B09-457A-AAAF-D816D402D595}
{5F0996AB-F8DB-4240-BD4A-DFDD70638A73} = {9010E0B5-9C42-4256-ADE4-E290434F2CEF}
{1A2ABCD9-493B-4848-9C69-919CDBCA61F3} = {9010E0B5-9C42-4256-ADE4-E290434F2CEF}
{22447274-717D-4321-87F3-868BAF93CBEC} = {9010E0B5-9C42-4256-ADE4-E290434F2CEF}
{55BE6759-95AA-434D-925D-A8D32F274E66} = {9010E0B5-9C42-4256-ADE4-E290434F2CEF}
{E2637D6D-04A5-4DE4-8AAF-E015C65DE8E1} = {22447274-717D-4321-87F3-868BAF93CBEC}
{5185D5C5-0EAD-49D5-B405-93B939F3639B} = {22447274-717D-4321-87F3-868BAF93CBEC}
{53D0AA09-F5FA-4721-8C1B-375CBD15B4E8} = {5F0996AB-F8DB-4240-BD4A-DFDD70638A73}
{C6EE337B-91EA-472A-87C7-E9528408CE59} = {5F0996AB-F8DB-4240-BD4A-DFDD70638A73}
{F39D8F09-6233-4495-ACD0-F98904993B7E} = {55BE6759-95AA-434D-925D-A8D32F274E66}
{295284BA-D4E4-40AA-A2C2-BE36343F7DE6} = {55BE6759-95AA-434D-925D-A8D32F274E66}
{85DA00E5-CC11-463C-8577-C34967C328F7} = {1A2ABCD9-493B-4848-9C69-919CDBCA61F3}
{C1EBE17D-BFAD-47DA-88EB-BB073B84593E} = {1A2ABCD9-493B-4848-9C69-919CDBCA61F3}
{B2BAA061-C005-409F-9D3E-BDCBE5B1B136} = {E2637D6D-04A5-4DE4-8AAF-E015C65DE8E1}
{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C} = {E2637D6D-04A5-4DE4-8AAF-E015C65DE8E1}
{574222F8-9C26-4015-8F35-C1E5D41A505F} = {53D0AA09-F5FA-4721-8C1B-375CBD15B4E8}
{B8F734F5-873C-4367-9EBD-38EA420CD868} = {53D0AA09-F5FA-4721-8C1B-375CBD15B4E8}
{65C1BB58-2A2E-44FF-B15D-2B023CF088D4} = {F39D8F09-6233-4495-ACD0-F98904993B7E}
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA} = {F39D8F09-6233-4495-ACD0-F98904993B7E}
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7} = {85DA00E5-CC11-463C-8577-C34967C328F7}
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837} = {85DA00E5-CC11-463C-8577-C34967C328F7}
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2} = {295284BA-D4E4-40AA-A2C2-BE36343F7DE6}
{539364C8-88B1-48A3-8406-D0B19FF30509} = {C1EBE17D-BFAD-47DA-88EB-BB073B84593E}
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC} = {5185D5C5-0EAD-49D5-B405-93B939F3639B}
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Release|Any CPU.Build.0 = Release|Any CPU
{E42BB533-4144-4D78-BCCE-50BA00BCADBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E42BB533-4144-4D78-BCCE-50BA00BCADBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E42BB533-4144-4D78-BCCE-50BA00BCADBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E42BB533-4144-4D78-BCCE-50BA00BCADBE}.Release|Any CPU.Build.0 = Release|Any CPU
{B2BAA061-C005-409F-9D3E-BDCBE5B1B136}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2BAA061-C005-409F-9D3E-BDCBE5B1B136}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2BAA061-C005-409F-9D3E-BDCBE5B1B136}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2BAA061-C005-409F-9D3E-BDCBE5B1B136}.Release|Any CPU.Build.0 = Release|Any CPU
{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E8FB852-4317-43D2-8EFC-14E3ECCFDA2C}.Release|Any CPU.Build.0 = Release|Any CPU
{574222F8-9C26-4015-8F35-C1E5D41A505F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{574222F8-9C26-4015-8F35-C1E5D41A505F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{574222F8-9C26-4015-8F35-C1E5D41A505F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{574222F8-9C26-4015-8F35-C1E5D41A505F}.Release|Any CPU.Build.0 = Release|Any CPU
{B8F734F5-873C-4367-9EBD-38EA420CD868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8F734F5-873C-4367-9EBD-38EA420CD868}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8F734F5-873C-4367-9EBD-38EA420CD868}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8F734F5-873C-4367-9EBD-38EA420CD868}.Release|Any CPU.Build.0 = Release|Any CPU
{65C1BB58-2A2E-44FF-B15D-2B023CF088D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65C1BB58-2A2E-44FF-B15D-2B023CF088D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65C1BB58-2A2E-44FF-B15D-2B023CF088D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65C1BB58-2A2E-44FF-B15D-2B023CF088D4}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA}.Release|Any CPU.Build.0 = Release|Any CPU
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7}.Release|Any CPU.Build.0 = Release|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Release|Any CPU.Build.0 = Release|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Release|Any CPU.Build.0 = Release|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Release|Any CPU.Build.0 = Release|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Debug|Any CPU.Build.0 = Debug|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Release|Any CPU.ActiveCfg = Release|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Release|Any CPU.Build.0 = Release|Any CPU
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Release|Any CPU.Build.0 = Release|Any CPU
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Release|Any CPU.Build.0 = Release|Any CPU
{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8561089E-9FB9-4ACD-A1F5-EAAF213E1DDB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -1,348 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CD4A4407-C3B0-422D-BB8C-2A810CED9938}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateway", "ApiGateway", "{CDFA86FA-BBBA-4A5B-A833-3BE219E373E5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{C734CEF7-A2AC-3076-84D8-694B7490AA9D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flight", "Flight", "{A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Booking", "Booking", "{C6034A5C-F49A-5FA4-86A6-65B2CB19613F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Passenger", "Passenger", "{9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{B465D535-05D9-3A0A-08BF-35A1C18CEC46}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A2834164-BF04-BF13-ADC5-A97145852861}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1B4FBE3A-43F5-1B1E-2877-3036AC5431EF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{773BFBD8-04CD-79F8-8301-C81308C3ED45}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4B043475-1AFA-C467-FE09-A46D09CD6936}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CED3889-AECF-A6CD-55DC-F680D3C18861}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Booking.Api", "src\Services\Booking\src\Booking.Api\Booking.Api.csproj", "{D3BF565A-C413-4185-9528-BE1B4F46993C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Booking", "src\Services\Booking\src\Booking\Booking.csproj", "{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flight", "src\Services\Flight\src\Flight\Flight.csproj", "{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flight.Api", "src\Services\Flight\src\Flight.Api\Flight.Api.csproj", "{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "src\Services\Identity\src\Identity\Identity.csproj", "{BCDEAB10-6373-46E7-B408-846A3B0B508B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Api", "src\Services\Identity\src\Identity.Api\Identity.Api.csproj", "{B0EC74C5-9B2D-492C-ABAE-3E868397B122}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger", "src\Services\Passenger\src\Passenger\Passenger.csproj", "{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger.Api", "src\Services\Passenger\src\Passenger.Api\Passenger.Api.csproj", "{101FFD12-17A4-4615-9438-F347BBF4CC85}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingBlocks", "src\BuildingBlocks\BuildingBlocks.csproj", "{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{427BE8BE-DA7B-FC74-412B-547671E05463}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "src\ApiGateway\src\ApiGateway.csproj", "{C015BF35-6977-407B-8948-636A9C81C5BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Booking\tests\IntegrationTest\Integration.Test.csproj", "{19A89F36-FD3A-448D-90D1-04A1B67BB255}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndToEnd.Test", "src\Services\Flight\tests\EndToEndTest\EndToEnd.Test.csproj", "{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Flight\tests\IntegrationTest\Integration.Test.csproj", "{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "src\Services\Flight\tests\UnitTest\Unit.Test.csproj", "{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Identity\tests\IntegrationTest\Integration.Test.csproj", "{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Passenger\tests\IntegrationTest\Integration.Test.csproj", "{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C4287034-6833-4505-A6EB-704A86392ECB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppHost", "src\Aspire\src\AppHost\AppHost.csproj", "{490BCB11-314C-473C-9B85-A32164783507}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "src\Aspire\src\ServiceDefaults\ServiceDefaults.csproj", "{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x64.ActiveCfg = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x64.Build.0 = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x86.ActiveCfg = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x86.Build.0 = Debug|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|Any CPU.Build.0 = Release|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x64.ActiveCfg = Release|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x64.Build.0 = Release|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x86.ActiveCfg = Release|Any CPU
{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x86.Build.0 = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x64.ActiveCfg = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x64.Build.0 = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x86.ActiveCfg = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x86.Build.0 = Debug|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|Any CPU.Build.0 = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x64.ActiveCfg = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x64.Build.0 = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x86.ActiveCfg = Release|Any CPU
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x86.Build.0 = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x64.ActiveCfg = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x64.Build.0 = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x86.ActiveCfg = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x86.Build.0 = Debug|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|Any CPU.Build.0 = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x64.ActiveCfg = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x64.Build.0 = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x86.ActiveCfg = Release|Any CPU
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x86.Build.0 = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x64.ActiveCfg = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x64.Build.0 = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x86.ActiveCfg = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x86.Build.0 = Debug|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|Any CPU.Build.0 = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x64.ActiveCfg = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x64.Build.0 = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x86.ActiveCfg = Release|Any CPU
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x86.Build.0 = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x64.ActiveCfg = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x64.Build.0 = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x86.ActiveCfg = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x86.Build.0 = Debug|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|Any CPU.Build.0 = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x64.ActiveCfg = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x64.Build.0 = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x86.ActiveCfg = Release|Any CPU
{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x86.Build.0 = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x64.ActiveCfg = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x64.Build.0 = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x86.ActiveCfg = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x86.Build.0 = Debug|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|Any CPU.Build.0 = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x64.ActiveCfg = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x64.Build.0 = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x86.ActiveCfg = Release|Any CPU
{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x86.Build.0 = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x64.ActiveCfg = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x64.Build.0 = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x86.ActiveCfg = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x86.Build.0 = Debug|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|Any CPU.Build.0 = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x64.ActiveCfg = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x64.Build.0 = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x86.ActiveCfg = Release|Any CPU
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x86.Build.0 = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x64.ActiveCfg = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x64.Build.0 = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x86.ActiveCfg = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x86.Build.0 = Debug|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|Any CPU.Build.0 = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x64.ActiveCfg = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x64.Build.0 = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x86.ActiveCfg = Release|Any CPU
{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x86.Build.0 = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x64.ActiveCfg = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x64.Build.0 = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x86.ActiveCfg = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x86.Build.0 = Debug|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|Any CPU.Build.0 = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x64.ActiveCfg = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x64.Build.0 = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x86.ActiveCfg = Release|Any CPU
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x86.Build.0 = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x64.ActiveCfg = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x64.Build.0 = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x86.ActiveCfg = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x86.Build.0 = Debug|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|Any CPU.Build.0 = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x64.ActiveCfg = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x64.Build.0 = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x86.ActiveCfg = Release|Any CPU
{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x86.Build.0 = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x64.ActiveCfg = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x64.Build.0 = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x86.ActiveCfg = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x86.Build.0 = Debug|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|Any CPU.Build.0 = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x64.ActiveCfg = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x64.Build.0 = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x86.ActiveCfg = Release|Any CPU
{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x86.Build.0 = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x64.ActiveCfg = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x64.Build.0 = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x86.ActiveCfg = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x86.Build.0 = Debug|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|Any CPU.Build.0 = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x64.ActiveCfg = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x64.Build.0 = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x86.ActiveCfg = Release|Any CPU
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x86.Build.0 = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x64.ActiveCfg = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x64.Build.0 = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x86.ActiveCfg = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x86.Build.0 = Debug|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|Any CPU.Build.0 = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x64.ActiveCfg = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x64.Build.0 = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x86.ActiveCfg = Release|Any CPU
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x86.Build.0 = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x64.ActiveCfg = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x64.Build.0 = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x86.ActiveCfg = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x86.Build.0 = Debug|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|Any CPU.Build.0 = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x64.ActiveCfg = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x64.Build.0 = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x86.ActiveCfg = Release|Any CPU
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x86.Build.0 = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x64.ActiveCfg = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x64.Build.0 = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x86.ActiveCfg = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x86.Build.0 = Debug|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|Any CPU.Build.0 = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x64.ActiveCfg = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x64.Build.0 = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x86.ActiveCfg = Release|Any CPU
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x86.Build.0 = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x64.ActiveCfg = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x64.Build.0 = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x86.ActiveCfg = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x86.Build.0 = Debug|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|Any CPU.Build.0 = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x64.ActiveCfg = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x64.Build.0 = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x86.ActiveCfg = Release|Any CPU
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x86.Build.0 = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|Any CPU.Build.0 = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|x64.ActiveCfg = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|x64.Build.0 = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|x86.ActiveCfg = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Debug|x86.Build.0 = Debug|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|Any CPU.ActiveCfg = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|Any CPU.Build.0 = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|x64.ActiveCfg = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|x64.Build.0 = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|x86.ActiveCfg = Release|Any CPU
{490BCB11-314C-473C-9B85-A32164783507}.Release|x86.Build.0 = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x64.ActiveCfg = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x64.Build.0 = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x86.ActiveCfg = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x86.Build.0 = Debug|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|Any CPU.Build.0 = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x64.ActiveCfg = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x64.Build.0 = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x86.ActiveCfg = Release|Any CPU
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CDFA86FA-BBBA-4A5B-A833-3BE219E373E5} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}
{B19FD14B-4DFE-26B6-646B-3D5D94CC4D36} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}
{C734CEF7-A2AC-3076-84D8-694B7490AA9D} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}
{A3579DE0-F7C5-67E8-3CF8-3AC89B64E059} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}
{C6034A5C-F49A-5FA4-86A6-65B2CB19613F} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}
{9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}
{B465D535-05D9-3A0A-08BF-35A1C18CEC46} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}
{A2834164-BF04-BF13-ADC5-A97145852861} = {C6034A5C-F49A-5FA4-86A6-65B2CB19613F}
{1B4FBE3A-43F5-1B1E-2877-3036AC5431EF} = {C6034A5C-F49A-5FA4-86A6-65B2CB19613F}
{DDEDC5E0-5D13-A45C-2393-A774DD4A1A07} = {A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}
{51D8F471-B8EB-AD1C-0E89-AA84C5D0C759} = {A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}
{773BFBD8-04CD-79F8-8301-C81308C3ED45} = {B465D535-05D9-3A0A-08BF-35A1C18CEC46}
{4B043475-1AFA-C467-FE09-A46D09CD6936} = {B465D535-05D9-3A0A-08BF-35A1C18CEC46}
{5CED3889-AECF-A6CD-55DC-F680D3C18861} = {9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}
{54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352} = {9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}
{D3BF565A-C413-4185-9528-BE1B4F46993C} = {A2834164-BF04-BF13-ADC5-A97145852861}
{3EA375C7-2900-4927-B1E5-C9D31E67F4A8} = {A2834164-BF04-BF13-ADC5-A97145852861}
{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279} = {DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}
{836D1466-3C20-4D74-B54A-FA09C0EE0FA2} = {DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}
{BCDEAB10-6373-46E7-B408-846A3B0B508B} = {773BFBD8-04CD-79F8-8301-C81308C3ED45}
{B0EC74C5-9B2D-492C-ABAE-3E868397B122} = {773BFBD8-04CD-79F8-8301-C81308C3ED45}
{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538} = {5CED3889-AECF-A6CD-55DC-F680D3C18861}
{101FFD12-17A4-4615-9438-F347BBF4CC85} = {5CED3889-AECF-A6CD-55DC-F680D3C18861}
{AEDB3219-5E1D-4716-8DE2-F5F9391913A2} = {C734CEF7-A2AC-3076-84D8-694B7490AA9D}
{427BE8BE-DA7B-FC74-412B-547671E05463} = {CDFA86FA-BBBA-4A5B-A833-3BE219E373E5}
{C015BF35-6977-407B-8948-636A9C81C5BE} = {427BE8BE-DA7B-FC74-412B-547671E05463}
{19A89F36-FD3A-448D-90D1-04A1B67BB255} = {1B4FBE3A-43F5-1B1E-2877-3036AC5431EF}
{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}
{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}
{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}
{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01} = {4B043475-1AFA-C467-FE09-A46D09CD6936}
{A85AE27D-81ED-485A-BA4B-161B25BEB8A5} = {54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352}
{D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}
{C4287034-6833-4505-A6EB-704A86392ECB} = {D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA}
{490BCB11-314C-473C-9B85-A32164783507} = {C4287034-6833-4505-A6EB-704A86392ECB}
{5B7BF918-E47F-4932-B5C5-E8C2C35890E4} = {C4287034-6833-4505-A6EB-704A86392ECB}
EndGlobalSection
EndGlobal

View File

@ -1,15 +1,12 @@
## uncommnet this line for use kubernetes ingress controller instead of Yarp
//@api-gateway=https://booking-microservices.com
# https://github.com/Huachao/vscode-restclient
@api-gateway=https://localhost:5000
@identity-api=http://localhost:6005
@flight-api=http://localhost:5004
@passenger-api=http://localhost:6012
@booking-api=http://localhost:6010
@identity-api=https://localhost:5005
@flight-api=https://localhost:5003
@passenger-api=https://localhost:5012
@booking-api=https://localhost:5010
@contentType = application/json
@flightid = "3c5c0000-97c6-fc34-2eb9-08db322230c9"
@passengerId = "8c9c0000-97c6-fc34-2eb9-66db322230c9"
@flightid = 1
@passengerId = 1
################################# Identity API #################################
@ -21,7 +18,7 @@ GET {{identity-api}}
###
# @name Authenticate
POST {{api-gateway}}/identity/connect/token
POST {{api-gateway}}/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=password
@ -29,16 +26,14 @@ grant_type=password
&client_secret=secret
&username=samh
&password=Admin@123456
&scope=flight-api role
### change scope base on microservices scope (eg. passenger-api, ...)
&scope=flight-api
###
###
# @name Register_New_User
POST {{api-gateway}}/identity/api/v1/identity/register-user
POST {{api-gateway}}/api/v1/identity/register-user
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -47,7 +42,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
"firstName": "John",
"lastName": "Do",
"username": "admin",
"passportNumber": "41290000",
"passportNumber": "412900000000",
"email": "admin@admin.com",
"password": "Admin@12345",
"confirmPassword": "Admin@12345"
@ -63,7 +58,7 @@ GET {{flight-api}}
###
# @name Create_Seat
Post {{api-gateway}}/flight/api/v1/flight/seat
Post {{api-gateway}}/api/v1/flight/seat
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -72,20 +67,20 @@ authorization: bearer {{Authenticate.response.body.access_token}}
"seatNumber": "1255",
"type": 1,
"class": 1,
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9"
"flightId": 1
}
###
###
# @name Reserve_Seat
Post {{api-gateway}}/flight/api/v1/flight/reserve-seat
Post {{api-gateway}}/api/v1/flight/reserve-seat
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"flightId": 1,
"seatNumber": "1255"
}
###
@ -93,7 +88,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Get_Available_Seats
GET {{api-gateway}}/flight/api/v1/flight/get-available-seats/{{flightid}}
GET {{api-gateway}}/api/v1/flight/get-available-seats/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -102,7 +97,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Get_Flight_By_Id
GET {{api-gateway}}/flight/api/v1/flight/{{flightid}}
GET {{api-gateway}}/api/v1/flight/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -111,7 +106,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Get_Available_Flights
GET {{api-gateway}}/flight/api/v1/flight/get-available-flights
GET {{api-gateway}}/api/v1/flight/get-available-flights
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -120,18 +115,18 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Create_Flights
POST {{api-gateway}}/flight/api/v1/flight
POST {{api-gateway}}/api/v1/flight
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightNumber": "12BB",
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"aircraftId": 1,
"departureAirportId": 1,
"departureDate": "2022-03-01T14:55:41.255Z",
"arriveDate": "2022-03-01T14:55:41.255Z",
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"arriveAirportId": 2,
"durationMinutes": 120,
"flightDate": "2022-03-01T14:55:41.255Z",
"status": 1,
@ -142,7 +137,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Update_Flights
PUT {{api-gateway}}/flight/api/v1/flight
PUT {{api-gateway}}/api/v1/flight
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -150,11 +145,11 @@ authorization: bearer {{Authenticate.response.body.access_token}}
{
"id": 1,
"flightNumber": "BD467",
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"aircraftId": 1,
"departureAirportId": 1,
"departureDate": "2022-04-23T12:17:45.140Z",
"arriveDate": "2022-04-23T12:17:45.140Z",
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"arriveAirportId": 2,
"durationMinutes": 120,
"flightDate": "2022-04-23T12:17:45.140Z",
"status": 4,
@ -166,7 +161,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Delete_Flights
DELETE {{api-gateway}}/flight/api/v1/flight/{{flightid}}
DELETE {{api-gateway}}/api/v1/flight/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -175,7 +170,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Create_Airport
POST {{api-gateway}}/flight/api/v1/flight/airport
POST {{api-gateway}}/api/v1/flight/airport
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -191,7 +186,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Create_Aircraft
POST {{api-gateway}}/flight/api/v1/flight/aircraft
POST {{api-gateway}}/api/v1/flight/aircraft
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -214,13 +209,13 @@ GET {{passenger-api}}
###
# @name Complete_Registration_Passenger
POST {{api-gateway}}/passenger/api/v1/passenger/complete-registration
POST {{api-gateway}}/api/v1/passenger/complete-registration
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passportNumber": "41290000",
"passportNumber": "412900000000",
"passengerType": 1,
"age": 30
}
@ -229,7 +224,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
###
# @name Get_Passenger_By_Id
GET {{api-gateway}}/passenger/api/v1/passenger/{{passengerId}}
GET {{api-gateway}}/api/v1/passenger/{{passengerId}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
@ -246,14 +241,14 @@ GET {{booking-api}}
###
# @name Create_Booking
POST {{api-gateway}}/booking/api/v1/booking
POST {{api-gateway}}/api/v1/booking
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passengerId": "8c9c0000-97c6-fc34-2eb9-66db322230c9",
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"passengerId": 8765596234940416,
"flightId": 1,
"description": "I want to fly to iran"
}
###

View File

@ -1,3 +0,0 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
}

0
current-version.txt Normal file
View File

View File

@ -1,8 +0,0 @@
# Dashboards
- [Introducing ASP.NET Core metrics and Grafana dashboards in .NET 8](https://devblogs.microsoft.com/dotnet/introducing-aspnetcore-metrics-and-grafana-dashboards-in-dotnet-8/)
- [ASP.NET Core](https://grafana.com/grafana/dashboards/19924-asp-net-core/)
- [ASP.NET Core Endpoint](https://grafana.com/grafana/dashboards/19925-asp-net-core-endpoint/)
- [Node Exporter Quickstart and Dashboard](https://grafana.com/grafana/dashboards/13978-node-exporter-quickstart-and-dashboard/)
- [PostgreSQL Exporter Quickstart and Dashboard](https://grafana.com/grafana/dashboards/14114-postgres-overview/)
- [RabbitMQ-Overview](https://grafana.com/grafana/dashboards/10991-rabbitmq-overview/)

View File

@ -1,908 +0,0 @@
{
"__inputs": [
{
"name": "DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY",
"label": "Managed_Prometheus_jamesnk-telemetry",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": {},
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "9.4.8"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [
{
"asDropdown": false,
"icon": "dashboard",
"includeVars": false,
"keepTime": true,
"tags": [],
"targetBlank": false,
"title": " ASP.NET Core",
"tooltip": "",
"type": "link",
"url": "/d/KdDACDp4z/asp-net-core-metrics"
}
],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "dark-green",
"mode": "continuous-GrYlRd",
"seriesBy": "max"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"axisSoftMin": 0,
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 50,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "s"
},
"overrides": [
{
"__systemRef": "hideSeriesFrom",
"matcher": {
"id": "byNames",
"options": {
"mode": "exclude",
"names": [
"p50"
],
"prefix": "All except:",
"readOnly": true
}
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"legend": false,
"tooltip": false,
"viz": false
}
}
]
}
]
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"id": 40,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"min",
"max"
],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.50, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"legendFormat": "p50",
"range": true,
"refId": "p50"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.75, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p75",
"range": true,
"refId": "p75"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.90, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p90",
"range": true,
"refId": "p90"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.95, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p95",
"range": true,
"refId": "p95"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.98, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p98",
"range": true,
"refId": "p98"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.99, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p99",
"range": true,
"refId": "p99"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.999, sum(rate(http_server_request_duration_s_bucket{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m])) by (le))",
"hide": false,
"legendFormat": "p99.9",
"range": true,
"refId": "p99.9"
}
],
"title": "Requests Duration - $method $route",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic",
"seriesBy": "max"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 50,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "percentunit"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "All"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "dark-orange",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "4XX"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "yellow",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "5XX"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "dark-red",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 0
},
"id": 46,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"min",
"max"
],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\", status_code=~\"4..|5..\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m]))",
"legendFormat": "All",
"range": true,
"refId": "All"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\", status_code=~\"4..\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m]))",
"hide": false,
"legendFormat": "4XX",
"range": true,
"refId": "4XX"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\", status_code=~\"5..\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[5m]))",
"hide": false,
"legendFormat": "5XX",
"range": true,
"refId": "5XX"
}
],
"title": "Errors Rate - $method $route",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Requests"
},
"properties": [
{
"id": "custom.width",
"value": 300
},
{
"id": "custom.cellOptions",
"value": {
"mode": "gradient",
"type": "gauge"
}
},
{
"id": "color",
"value": {
"mode": "continuous-YlRd"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Route"
},
"properties": [
{
"id": "links",
"value": [
{
"title": "",
"url": "/d/NagEsjE4z/asp-net-core-endpoint-details?var-route=${__data.fields.Route}&var-method=${__data.fields.Method}&${__url_time_range}"
}
]
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 9
},
"hideTimeOverride": false,
"id": 44,
"options": {
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": [
{
"desc": true,
"displayName": "Value"
}
]
},
"pluginVersion": "9.4.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum by (exception_name) (\r\n max_over_time(http_server_request_duration_s_count{route=\"$route\", method=\"$method\", exception_name!=\"\"}[$__rate_interval])\r\n)",
"format": "table",
"instant": true,
"interval": "",
"legendFormat": "{{route}}",
"range": false,
"refId": "A"
}
],
"title": "Unhandled Exceptions",
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"method": false
},
"indexByName": {
"Time": 0,
"Value": 2,
"exception_name": 1
},
"renameByName": {
"Value": "Requests",
"exception_name": "Exception",
"method": "Method",
"route": "Route"
}
}
}
],
"type": "table"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "blue",
"mode": "fixed"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 12,
"x": 12,
"y": 9
},
"id": 42,
"options": {
"colorMode": "background",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"max"
],
"fields": "",
"values": false
},
"textMode": "value_and_name"
},
"pluginVersion": "9.4.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum by (status_code) (\r\n max_over_time(http_server_request_duration_s_count{route=\"$route\", method=\"$method\"}[$__rate_interval])\r\n )",
"legendFormat": "Status {{status_code}}",
"range": true,
"refId": "A"
}
],
"title": "Requests HTTP Status Code",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "green",
"mode": "fixed"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 12,
"y": 13
},
"id": 48,
"options": {
"colorMode": "background",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"max"
],
"fields": "",
"values": false
},
"textMode": "value_and_name"
},
"pluginVersion": "9.4.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum by (scheme) (\r\n max_over_time(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[$__rate_interval])\r\n )",
"legendFormat": "{{scheme}}",
"range": true,
"refId": "A"
}
],
"title": "Requests Secured",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "purple",
"mode": "fixed"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 18,
"y": 13
},
"id": 50,
"options": {
"colorMode": "background",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"max"
],
"fields": "",
"values": false
},
"textMode": "value_and_name"
},
"pluginVersion": "9.4.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"editorMode": "code",
"expr": "sum by (protocol) (\r\n max_over_time(http_server_request_duration_s_count{job=\"$job\", instance=\"$instance\", route=\"$route\", method=\"$method\"}[$__rate_interval])\r\n )",
"legendFormat": "{{protocol}}",
"range": true,
"refId": "A"
}
],
"title": "Requests HTTP Protocol",
"type": "stat"
}
],
"refresh": "",
"revision": 1,
"schemaVersion": 38,
"style": "dark",
"tags": [
"dotnet",
"prometheus",
"aspnetcore"
],
"templating": {
"list": [
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"definition": "label_values(http_server_current_requests, job)",
"hide": 0,
"includeAll": false,
"label": "Job",
"multi": false,
"name": "job",
"options": [],
"query": {
"query": "label_values(http_server_current_requests, job)",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"definition": "label_values(http_server_current_requests{job=~\"$job\"}, instance)",
"hide": 0,
"includeAll": false,
"label": "Instance",
"multi": false,
"name": "instance",
"options": [],
"query": {
"query": "label_values(http_server_current_requests{job=~\"$job\"}, instance)",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"definition": "label_values(http_server_request_duration_s_count, route)",
"description": "Route",
"hide": 0,
"includeAll": false,
"label": "Route",
"multi": false,
"name": "route",
"options": [],
"query": {
"query": "label_values(http_server_request_duration_s_count, route)",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}"
},
"definition": "label_values(http_server_request_duration_s_count{route=~\"$route\"}, method)",
"hide": 0,
"includeAll": false,
"label": "Method",
"multi": false,
"name": "method",
"options": [],
"query": {
"query": "label_values(http_server_request_duration_s_count{route=~\"$route\"}, method)",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ASP.NET Core Endpoint",
"uid": "NagEsjE4z",
"version": 10,
"weekStart": ""
}

File diff suppressed because it is too large Load Diff

View File

@ -1,892 +0,0 @@
{
"__inputs": [],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "7.4.3"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
}
],
"annotations": {
"list": []
},
"editable": false,
"gnetId": 13978,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"refresh": "",
"rows": [
{
"collapse": false,
"collapsed": false,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {},
"id": 2,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": true,
"steppedLine": false,
"targets": [
{
"expr": "(\n (1 - rate(node_cpu_seconds_total{job=\"node\", mode=\"idle\", instance=\"$instance\"}[$__interval]))\n/ ignoring(cpu) group_left\n count without (cpu)( node_cpu_seconds_total{job=\"node\", mode=\"idle\", instance=\"$instance\"})\n)\n",
"format": "time_series",
"interval": "1m",
"intervalFactor": 5,
"legendFormat": "{{cpu}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "CPU Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percentunit",
"label": null,
"logBase": 1,
"max": 1,
"min": 0,
"show": true
},
{
"format": "percentunit",
"label": null,
"logBase": 1,
"max": 1,
"min": 0,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 0,
"fillGradient": 0,
"gridPos": {},
"id": 3,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "node_load1{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "1m load average",
"refId": "A"
},
{
"expr": "node_load5{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "5m load average",
"refId": "B"
},
{
"expr": "node_load15{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "15m load average",
"refId": "C"
},
{
"expr": "count(node_cpu_seconds_total{job=\"node\", instance=\"$instance\", mode=\"idle\"})",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "logical cores",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Load Average",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
}
]
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6",
"type": "row"
},
{
"collapse": false,
"collapsed": false,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {},
"id": 4,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"span": 9,
"stack": true,
"steppedLine": false,
"targets": [
{
"expr": "(\n node_memory_MemTotal_bytes{job=\"node\", instance=\"$instance\"}\n-\n node_memory_MemFree_bytes{job=\"node\", instance=\"$instance\"}\n-\n node_memory_Buffers_bytes{job=\"node\", instance=\"$instance\"}\n-\n node_memory_Cached_bytes{job=\"node\", instance=\"$instance\"}\n)\n",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "memory used",
"refId": "A"
},
{
"expr": "node_memory_Buffers_bytes{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "memory buffers",
"refId": "B"
},
{
"expr": "node_memory_Cached_bytes{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "memory cached",
"refId": "C"
},
{
"expr": "node_memory_MemFree_bytes{job=\"node\", instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "memory free",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Memory Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
}
]
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(237, 129, 40, 0.89)",
"rgba(245, 54, 54, 0.9)"
],
"datasource": "$datasource",
"format": "percent",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": true,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {},
"id": 5,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 3,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "100 -\n(\n avg(node_memory_MemAvailable_bytes{job=\"node\", instance=\"$instance\"})\n/\n avg(node_memory_MemTotal_bytes{job=\"node\", instance=\"$instance\"})\n* 100\n)\n",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "80, 90",
"title": "Memory Usage",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6",
"type": "row"
},
{
"collapse": false,
"collapsed": false,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 0,
"fillGradient": 0,
"gridPos": {},
"id": 6,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [
{
"alias": "/ read| written/",
"yaxis": 1
},
{
"alias": "/ io time/",
"yaxis": 2
}
],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(node_disk_read_bytes_total{job=\"node\", instance=\"$instance\", device!=\"\"}[$__interval])",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{device}} read",
"refId": "A"
},
{
"expr": "rate(node_disk_written_bytes_total{job=\"node\", instance=\"$instance\", device!=\"\"}[$__interval])",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{device}} written",
"refId": "B"
},
{
"expr": "rate(node_disk_io_time_seconds_total{job=\"node\", instance=\"$instance\", device!=\"\"}[$__interval])",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{device}} io time",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Disk I/O",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "s",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {},
"id": 7,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [
{
"alias": "used",
"color": "#E0B400"
},
{
"alias": "available",
"color": "#73BF69"
}
],
"spaceLength": 10,
"span": 6,
"stack": true,
"steppedLine": false,
"targets": [
{
"expr": "sum(\n max by (device) (\n node_filesystem_size_bytes{job=\"node\", instance=\"$instance\", fstype!=\"\"}\n -\n node_filesystem_avail_bytes{job=\"node\", instance=\"$instance\", fstype!=\"\"}\n )\n)\n",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "used",
"refId": "A"
},
{
"expr": "sum(\n max by (device) (\n node_filesystem_avail_bytes{job=\"node\", instance=\"$instance\", fstype!=\"\"}\n )\n)\n",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "available",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Disk Space Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
}
]
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6",
"type": "row"
},
{
"collapse": false,
"collapsed": false,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 0,
"fillGradient": 0,
"gridPos": {},
"id": 8,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(node_network_receive_bytes_total{job=\"node\", instance=\"$instance\", device!=\"lo\"}[$__interval])",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{device}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Network Received",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 0,
"fillGradient": 0,
"gridPos": {},
"id": 9,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"sideWidth": null,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(node_network_transmit_bytes_total{job=\"node\", instance=\"$instance\", device!=\"lo\"}[$__interval])",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{device}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Network Transmitted",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": 0,
"show": true
}
]
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "Dashboard Row",
"titleSize": "h6",
"type": "row"
}
],
"schemaVersion": 14,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"text": "Prometheus",
"value": "Prometheus"
},
"hide": 0,
"label": null,
"name": "datasource",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"type": "datasource"
},
{
"allValue": null,
"current": {},
"datasource": "$datasource",
"hide": 0,
"includeAll": false,
"label": null,
"multi": false,
"name": "instance",
"options": [],
"query": "label_values(node_exporter_build_info{job=\"node\"}, instance)",
"refresh": 2,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "browser",
"title": "Node Exporter Quickstart and Dashboard",
"version": 0,
"description": "A quickstart to setup Prometheus Node Exporter with preconfigured dashboards, alerting rules, and recording rules."
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
# https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards
apiVersion: 1
providers:
- name: "default"
orgId: 1
folder: ""
type: file
disableDeletion: false
editable: true
allowUiUpdates: true
updateIntervalSeconds: 5 # how often Grafana will scan for changed dashboards
options:
path: /var/lib/grafana/dashboards # path to dashboards on disk

View File

@ -1,88 +0,0 @@
# https://grafana.com/docs/grafana/latest/administration/provisioning/
# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml
# https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml
apiVersion: 1
datasources:
# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml
- name: Prometheus
type: prometheus
typeName: Prometheus
uid: prometheus-uid
access: proxy
orgId: 1
url: http://prometheus:9090
basicAuth: false
isDefault: true
readOnly: false
user: ''
database: ''
version: 1
editable: false
jsonData:
httpMethod: GET
- name: Jaeger
type: jaeger
access: proxy
url: http://jaeger-all-in-one:16686
editable: false
uid: jaeger-uid
- name: Zipkin
type: zipkin
access: proxy
url: http://zipkin-all-in-one:9411
editable: false
uid: zipkin-uid
# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml
- name: Tempo
type: tempo
access: proxy
orgId: 1
url: http://tempo:3200
basicAuth: false
isDefault: false
version: 1
editable: false
apiVersion: 1
uid: tempo-uid
jsonData:
httpMethod: GET
serviceMap:
datasourceUid: prometheus-uid
streamingEnabled:
search: true
#https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml
- name: Loki
type: loki
access: proxy
uid: loki-uid
url: http://loki:3100
user: ''
database: ''
readOnly: false
jsonData:
derivedFields:
- datasourceUid: tempo-uid
matcherRegex: "^.*?traceI[d|D]=(\\w+).*$"
name: traceId
url: '$${__value.raw}'
- name: Kibana
type: elasticsearch
url: http://elasticsearch:9200
access: proxy
isDefault: false
uid: kibana-uid
jsonData:
esVersion: 7
timeField: "@timestamp"
maxConcurrentShardRequests: 256
interval: Daily
logMessageField: "message" # Optional: Field for log messages
logLevelField: "level" # Optional: Field for log levels
editable: true

View File

@ -1,44 +0,0 @@
# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/
# https://github.com/grafana/loki/issues/2018#issuecomment-970789233
# https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/
# https://github.com/grafana/loki/blob/main/examples/getting-started/loki-config.yaml
# https://github.com/grafana/loki/blob/main/cmd/loki/loki-local-config.yaml
# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/#1-local-configuration-exampleyaml
---
# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/#1-local-configuration-exampleyaml
auth_enabled: false
# This is a complete configuration to deploy Loki backed by the filesystem.
# The index will be shipped to the storage via tsdb-shipper.
server:
http_listen_port: 3100
common:
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
replication_factor: 1
path_prefix: /tmp/loki
schema_config:
configs:
- from: 2020-05-15
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
filesystem:
directory: /tmp/loki/chunks
# https://grafana.com/docs/loki/latest/send-data/otel/
# https://grafana.com/docs/loki/latest/send-data/otel/#changing-the-default-mapping-of-otlp-to-loki-format
limits_config:
# this attribute should be `true` when we use `otlphttp/loki`, but if we want to use `loki component` from `opentelemetry-collector-contrib` it should be false.
allow_structured_metadata: true

View File

@ -1,131 +0,0 @@
# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/otel-collector-config.yaml
# https://opentelemetry.io/docs/collector/configuration/
# https://opentelemetry.io/docs/collector/architecture/
# https://betterstack.com/community/guides/observability/opentelemetry-collector/
# https://signoz.io/blog/opentelemetry-collector-complete-guide/
# This configuration sets up an OpenTelemetry Collector that receives trace data via the OTLP protocol over HTTP on port 4318, applies batch processing, and then exports the processed traces
# to exporter components like `Jaeger` endpoint located at `jaeger-all-in-one:4317`. It also includes a health_check extension for monitoring the collector's status.
# Receivers in the OpenTelemetry Collector are components that collect telemetry data (traces, metrics, and logs) from various sources, such as instrumented applications or agents.
# They act as entry points, converting incoming data into OpenTelemetry's internal format for processing and export.
# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components
# https://opentelemetry.io/docs/collector/architecture/#receivers
# https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md
# https://opentelemetry.io/docs/collector/configuration/#receivers
receivers:
# supported receivers
# https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver
# instead of specifying details explicitly we can just use `otlp` and it uses both grpc and http
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
# prometheus:
# config:
# scrape_configs:
# - job_name: 'node-exporter'
# scrape_interval: 10s
# static_configs:
# - targets: [ 'node-exporter:9100' ]
# Processors in the OpenTelemetry Collector modify and enhance telemetry data by filtering, transforming, enriching, or batching it to prepare it for export.
# https://github.com/open-telemetry/opentelemetry-collector/tree/main/processor
processors:
batch: # Batches logs for better performance
# - Exporters in the OpenTelemetry Collector send processed telemetry data to backend systems like observability platforms, databases, or cloud services for storage, visualization, and analysis.
# - The `key` follows the `type/name` format, where `type` specifies the exporter `type` (e.g., otlp, kafka, prometheus), and `name` (optional) can be appended to provide a unique name for multiple instance of the same type
# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components
# https://opentelemetry.io/docs/collector/architecture/#exporters
# https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter
# https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter
# https://opentelemetry.io/docs/collector/configuration/#exporters
exporters:
# valid values: [prometheusremotewrite zipkin otlphttp file kafka prometheus debug nop otlp opencensus]
# Prometheus exporter metrics
prometheus:
endpoint: "0.0.0.0:8889"
prometheusremotewrite:
endpoint: "http://prometheus:9090/api/v1/write"
# https://grafana.com/docs/loki/latest/send-data/otel/
# https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/lokiexporter/README.md
otlphttp/loki:
endpoint: "http://loki:3100/otlp"
tls:
insecure: true
# # we can also use `loki component` from `opentelemetry-collector-contrib` if we don't want to use builtin `otlphttp` exporter type and `http://loki:3100/otlp` loki endpoint
# loki:
# endpoint: "http://loki:3100/loki/api/v1/push"
# tls:
# insecure: true
debug:
# https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/elasticsearchexporter
# using `elasticsearch` from `opentelemetry-collector-contrib` components because it doesn't exist in `opentelemetry-collector`
elasticsearch:
endpoint: "http://elasticsearch:9200"
zipkin:
endpoint: "http://zipkin-all-in-one:9411/api/v2/spans"
format: proto
# export collected telemetry traces to jaeger OTLP grpc port, we can send data to other available endpoints and ports on jaeger as well
otlp/jaeger:
endpoint: "http://jaeger-all-in-one:4317"
tls:
insecure: true
otlp/tempo:
endpoint: "http://tempo:4317"
tls:
insecure: true
# seq-otlp:
# endpoint: "http://seq:5341/ingest/otlp"
# https://opentelemetry.io/docs/collector/configuration/#extensions
# https://github.com/open-telemetry/opentelemetry-collector/blob/main/extension/README.md
extensions:
pprof:
endpoint: 0.0.0.0:1888
zpages:
endpoint: 0.0.0.0:55679
health_check:
endpoint: 0.0.0.0:13133
# - The service section is used to configure what components are enabled in the Collector based on the configuration found in the receivers, processors, exporters, and extensions sections.
# - If a component is configured, but not defined within the service section, then its not enabled.
# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components
# https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md
# https://opentelemetry.io/docs/collector/architecture/
# https://opentelemetry.io/docs/collector/configuration/#service
service:
# The `service.extensions` subsection determines which of the configured extensions will be enabled
extensions: [pprof, zpages, health_check]
# The `service.pipeline` Each pipeline starts with one or more receivers collecting data, which is then processed sequentially by processors (applying transformations, filtering, or sampling).
# The processed data is finally sent to all configured exporters, ensuring each receives a copy. Components must be pre-configured in their respective sections before being used in a pipeline.
# pipeline activate predefined components, defined components are disabled by default
pipelines:
traces:
receivers: [otlp]
processors: [batch]
# https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-selection
exporters: [debug, zipkin, otlp/jaeger, otlp/tempo]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [debug, prometheusremotewrite, prometheus]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp/loki, elasticsearch]

View File

@ -1,48 +0,0 @@
# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/prometheus.yaml
# https://prometheus.io/docs/introduction/first_steps/
# https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
global:
scrape_interval: 5s
scrape_configs:
# when we use otel-collector we should comment other jobs in prometheus config, and we read configs from `otel-collector-config`
- job_name: "otel-collector"
scrape_interval: 10s
static_configs:
# otel-collector Prometheus exporter metrics
- targets: [ 'otel-collector:8889' ]
- targets: [ 'otel-collector:8888' ]
- job_name: "prometheus"
static_configs:
- targets: ["prometheus:9090"]
# # https://prometheus.io/docs/guides/node-exporter/
# # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
# - job_name: "node-exporter"
# static_configs:
# - targets: [ 'node-exporter:9100' ]
# # if we don't use otel collector we should uncomment this
# # scrap application metrics
# # http://localhost:4000/metrics by AddPrometheusExporter()
# - job_name: vertical-slice-template-api
# scrape_interval: 10s
# metrics_path: /metrics
# static_configs:
# - targets: ['host.docker.internal:4000']
#
# # if we don't use otel collector we should uncomment this
# # scrap application health metrics
# # http://localhost:4000/health/metrics by AddPrometheusExporter()
# - job_name: vertical-slice-template-api-healthchecks
# scrape_interval: 10s
# metrics_path: /health/metrics
# static_configs:
# - targets: ['host.docker.internal:4000']
## https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/prometheus.yaml
# - job_name: 'tempo'
# static_configs:
# - targets: [ 'tempo:3200' ]

View File

@ -1,49 +0,0 @@
# https://grafana.com/docs/tempo/latest/configuration/
# https://github.com/grafana/tempo/blob/main/example/docker-compose/local/tempo.yaml
# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/tempo.yaml
stream_over_http_enabled: true
server:
http_listen_port: 3200
log_level: info
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: "tempo:4317"
ingester:
max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally
compactor:
compaction:
block_retention: 1h # overall Tempo trace retention. set for demo purposes
metrics_generator:
registry:
external_labels:
source: tempo
cluster: docker-compose
storage:
path: /var/tempo/generator/wal
remote_write:
- url: http://prometheus:9090/api/v1/write
send_exemplars: true
traces_storage:
path: /var/tempo/generator/traces
storage:
trace:
backend: local # backend configuration to use
wal:
path: /var/tempo/wal # where to store the wal locally
local:
path: /var/tempo/blocks
overrides:
defaults:
metrics_generator:
processors: [service-graphs, span-metrics, local-blocks] # enables metrics generator
generate_native_histograms: both

View File

@ -1,362 +0,0 @@
# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/docker-compose.yaml
# ref: https://github.com/joaofbantunes/DotNetMicroservicesObservabilitySample/blob/main/docker-compose.yml
# ref: https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/docker-compose.yml
# https://github.com/grafana/intro-to-mltp
# https://stackoverflow.com/questions/65272764/ports-are-not-available-listen-tcp-0-0-0-0-50070-bind-an-attempt-was-made-to
name: booking-microservices-infrastructure
services:
#######################################################
# rabbitmq
#######################################################
rabbitmq:
image: rabbitmq:management
container_name: rabbitmq
restart: unless-stopped
ports:
- "5672:5672"
- "15672:15672"
# volumes:
# - rabbitmq:/var/lib/rabbitmq
networks:
- infrastructure
#######################################################
# postgres
#######################################################
postgres:
image: postgres:latest
container_name: postgres
restart: unless-stopped
ports:
- '5432:5432'
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
command:
- "postgres"
- "-c"
- "wal_level=logical"
- "-c"
- "max_prepared_transactions=10"
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- infrastructure
#######################################################
# EventStoreDB
#######################################################
eventstore:
container_name: eventstore
image: eventstore/eventstore:latest
restart: unless-stopped
environment:
- EVENTSTORE_CLUSTER_SIZE=1
- EVENTSTORE_RUN_PROJECTIONS=All
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
- EVENTSTORE_HTTP_PORT=2113
- EVENTSTORE_INSECURE=True
- EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=True
ports:
- "2113:2113"
networks:
- infrastructure
# #######################################################
# # Mongo
# #######################################################
mongo:
image: mongo:latest
container_name: mongo
restart: unless-stopped
# environment:
# - MONGO_INITDB_ROOT_USERNAME=root
# - MONGO_INITDB_ROOT_PASSWORD=secret
ports:
- 27017:27017
networks:
- infrastructure
# #######################################################
# # Redis
# #######################################################
redis:
image: redis
container_name: redis
restart: unless-stopped
ports:
- 6379:6379
networks:
- infrastructure
# #######################################################
# # jaeger
# # https://www.jaegertracing.io/docs/1.64/deployment/
# # https://www.jaegertracing.io/docs/1.6/deployment/
# #######################################################
jaeger-all-in-one:
image: jaegertracing/all-in-one:latest
container_name: jaeger-all-in-one
restart: unless-stopped
ports:
- "6831:6831/udp" # UDP port for Jaeger agent
- "16686:16686" # endpoints and Jaeger UI
- "14268:14268" # HTTP port for accept trace spans directly from clients
- "14317:4317" # OTLP gRPC receiver for jaeger
- "14318:4318" # OTLP http receiver for jaeger
# - "9411" # Accepts Zipkin spans - /api/v2/spans
networks:
- infrastructure
# #######################################################
# # zipkin
# # https://zipkin.io/pages/quickstart
# #######################################################
zipkin-all-in-one:
image: openzipkin/zipkin:latest
container_name: zipkin-all-in-one
restart: unless-stopped
ports:
- "9411:9411"
networks:
- infrastructure
# #######################################################
# # otel-collector
# # https://opentelemetry.io/docs/collector/installation/
# # https://github.com/open-telemetry/opentelemetry-collector
# # https://github.com/open-telemetry/opentelemetry-collector-contrib
# # we can use none contrib docker `otel/opentelemetry-collector` version from `https://github.com/open-telemetry/opentelemetry-collector` repository but,
# # if we need more components like `elasticsearch` we should use `otel/opentelemetry-collector-contrib` image of `https://github.com/open-telemetry/opentelemetry-collector-contrib` repository.
# #######################################################
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
container_name: otel-collector
restart: unless-stopped
command: ["--config=/etc/otelcol-contrib/config.yaml"]
volumes:
- ./../configs/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
ports:
- "11888:1888" # pprof extension
- "8888:8888" # Prometheus metrics exposed by the Collector
- "8889:8889" # Prometheus exporter metrics
- "13133:13133" # health_check extension
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP http receiver
- "55679:55679" # zpages extension
networks:
- infrastructure
# #######################################################
# # prometheus
# # https://prometheus.io/docs/introduction/first_steps/
# # https://prometheus.io/docs/prometheus/3.1/installation/
# # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
# #######################################################
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./../configs/prometheus.yaml:/etc/prometheus/prometheus.yml
# to passe one flag, such as "--log.level=debug" or "--web.enable-remote-write-receiver", we need to override the whole command, as we can't just pass one extra argument
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.console.libraries=/usr/share/prometheus/console_libraries"
- "--web.console.templates=/usr/share/prometheus/consoles"
# need this for the OpenTelemetry collector to be able to put metrics into Prometheus
- "--web.enable-remote-write-receiver"
# - "--log.level=debug"
networks:
- infrastructure
# #######################################################
# # node-exporter
# # https://prometheus.io/docs/guides/node-exporter/
# # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
# #######################################################
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
ports:
- "9101:9100"
networks:
- infrastructure
# #######################################################
# # grafana
# # https://grafana.com/docs/grafana/latest/administration/provisioning/
# # https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/
# # https://grafana.com/docs/grafana/latest/setup-grafana/configure-docker/
# # https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml
# #######################################################
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
environment:
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_FEATURE_TOGGLES_ENABLE=traceqlEditor
# - GF_AUTH_ANONYMOUS_ENABLED=true
# - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
# - GF_AUTH_DISABLE_LOGIN_FORM=true
depends_on:
- prometheus
ports:
- "3000:3000"
volumes:
- ./../configs/grafana/provisioning:/etc/grafana/provisioning
- ./../configs/grafana/dashboards:/var/lib/grafana/dashboards
## https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/
# - ./../configs/grafana/grafana.ini:/etc/grafana/grafana.ini
networks:
- infrastructure
# #######################################################
# # tempo
# # https://github.com/grafana/tempo/blob/main/example/docker-compose/otel-collector/docker-compose.yaml
# # https://github.com/grafana/tempo/blob/main/example/docker-compose/shared
# # https://github.com/grafana/tempo/blob/main/example/docker-compose/local
# # https://github.com/grafana/tempo/tree/main/example/docker-compose
# #######################################################
tempo:
image: grafana/tempo:latest
container_name: tempo
restart: unless-stopped
command: [ "-config.file=/etc/tempo.yaml" ]
volumes:
- ./../configs/tempo.yaml:/etc/tempo.yaml
ports:
- "3200" # tempo
- "24317:4317" # otlp grpc
- "24318:4318" # otlp http
networks:
- infrastructure
# #######################################################
# # loki
# # https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/
# # https://github.com/grafana/loki/blob/main/production/docker-compose.yaml
# # https://github.com/grafana/loki/blob/main/examples/getting-started/docker-compose.yaml
# #######################################################
loki:
image: grafana/loki:latest
hostname: loki
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./../configs/loki-config.yaml:/etc/loki/local-config.yaml
networks:
- infrastructure
# #######################################################
# # elasticsearch
# # https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docker.html#docker-compose-file
# #######################################################
elasticsearch:
container_name: elasticsearch
restart: unless-stopped
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
environment:
- discovery.type=single-node
- cluster.name=docker-cluster
- node.name=docker-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=false
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- network.host=0.0.0.0
- http.port=9200
- transport.host=localhost
- bootstrap.memory_lock=true
- cluster.routing.allocation.disk.threshold_enabled=false
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- elastic-data:/usr/share/elasticsearch/data
ports:
- ${ELASTIC_HOST_PORT:-9200}:${ELASTIC_PORT:-9200}
- 9300:9300
networks:
- infrastructure
# #######################################################
# # kibana
# # https://www.elastic.co/guide/en/kibana/current/docker.html
# #######################################################
kibana:
image: docker.elastic.co/kibana/kibana:8.17.0
container_name: kibana
restart: unless-stopped
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- ${KIBANA_HOST_PORT:-5601}:${KIBANA_PORT:-5601}
depends_on:
- elasticsearch
networks:
- infrastructure
# #######################################################
# # cadvisor
# #######################################################
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
devices:
- /dev/kmsg
networks:
- infrastructure
networks:
infrastructure:
name: infrastructure
driver: bridge
volumes:
elastic-data:
postgres-data:

View File

@ -1,372 +1,31 @@
name: booking-microservices
version: "3.3"
services:
#######################################################
# rabbitmq
# Gateway
#######################################################
rabbitmq:
image: rabbitmq:management
container_name: rabbitmq
restart: unless-stopped
ports:
- "5672:5672"
- "15672:15672"
# volumes:
# - rabbitmq:/var/lib/rabbitmq
networks:
- booking
#######################################################
# postgres
#######################################################
postgres:
image: postgres:latest
container_name: postgres
restart: unless-stopped
ports:
- '5432:5432'
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
command:
- "postgres"
- "-c"
- "wal_level=logical"
- "-c"
- "max_prepared_transactions=10"
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- booking
#######################################################
# EventStoreDB
#######################################################
eventstore:
container_name: eventstore
image: eventstore/eventstore:latest
restart: unless-stopped
environment:
- EVENTSTORE_CLUSTER_SIZE=1
- EVENTSTORE_RUN_PROJECTIONS=All
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
- EVENTSTORE_HTTP_PORT=2113
- EVENTSTORE_INSECURE=True
- EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=True
ports:
- "2113:2113"
networks:
- booking
#######################################################
# Mongo
#######################################################
mongo:
image: mongo:latest
container_name: mongo
restart: unless-stopped
# environment:
# - MONGO_INITDB_ROOT_USERNAME=root
# - MONGO_INITDB_ROOT_PASSWORD=secret
ports:
- 27017:27017
networks:
- booking
#######################################################
# Redis
#######################################################
redis:
image: redis
container_name: redis
restart: unless-stopped
ports:
- 6379:6379
networks:
- booking
#######################################################
# jaeger
# https://www.jaegertracing.io/docs/1.64/deployment/
# https://www.jaegertracing.io/docs/1.6/deployment/
#######################################################
jaeger-all-in-one:
image: jaegertracing/all-in-one:latest
container_name: jaeger-all-in-one
restart: unless-stopped
ports:
- "6831:6831/udp" # UDP port for Jaeger agent
- "16686:16686" # endpoints and Jaeger UI
- "14268:14268" # HTTP port for accept trace spans directly from clients
- "14317:4317" # OTLP gRPC receiver for jaeger
- "14318:4318" # OTLP http receiver for jaeger
# - "9411" # Accepts Zipkin spans - /api/v2/spans
networks:
- booking
#######################################################
# zipkin
# https://zipkin.io/pages/quickstart
#######################################################
zipkin-all-in-one:
image: openzipkin/zipkin:latest
container_name: zipkin-all-in-one
restart: unless-stopped
ports:
- "9411:9411"
networks:
- booking
#######################################################
# otel-collector
# https://opentelemetry.io/docs/collector/installation/
# https://github.com/open-telemetry/opentelemetry-collector
# https://github.com/open-telemetry/opentelemetry-collector-contrib
# we can use none contrib docker `otel/opentelemetry-collector` version from `https://github.com/open-telemetry/opentelemetry-collector` repository but,
# if we need more components like `elasticsearch` we should use `otel/opentelemetry-collector-contrib` image of `https://github.com/open-telemetry/opentelemetry-collector-contrib` repository.
#######################################################
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
container_name: otel-collector
restart: unless-stopped
command: ["--config=/etc/otelcol-contrib/config.yaml"]
volumes:
- ./../configs/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
ports:
- "11888:1888" # pprof extension
- "8888:8888" # Prometheus metrics exposed by the Collector
- "8889:8889" # Prometheus exporter metrics
- "13133:13133" # health_check extension
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP http receiver
- "55679:55679" # zpages extension
networks:
- booking
#######################################################
# prometheus
# https://prometheus.io/docs/introduction/first_steps/
# https://prometheus.io/docs/prometheus/3.1/installation/
# https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
#######################################################
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./../configs/prometheus.yaml:/etc/prometheus/prometheus.yml
# to passe one flag, such as "--log.level=debug" or "--web.enable-remote-write-receiver", we need to override the whole command, as we can't just pass one extra argument
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.console.libraries=/usr/share/prometheus/console_libraries"
- "--web.console.templates=/usr/share/prometheus/consoles"
# need this for the OpenTelemetry collector to be able to put metrics into Prometheus
- "--web.enable-remote-write-receiver"
# - "--log.level=debug"
networks:
- booking
#######################################################
# node-exporter
# https://prometheus.io/docs/guides/node-exporter/
# https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/
#######################################################
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
ports:
- "9101:9100"
networks:
- booking
#######################################################
# grafana
# https://grafana.com/docs/grafana/latest/administration/provisioning/
# https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/
# https://grafana.com/docs/grafana/latest/setup-grafana/configure-docker/
# https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml
#######################################################
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
environment:
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_FEATURE_TOGGLES_ENABLE=traceqlEditor
# - GF_AUTH_ANONYMOUS_ENABLED=true
# - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
# - GF_AUTH_DISABLE_LOGIN_FORM=true
depends_on:
- prometheus
ports:
- "3000:3000"
volumes:
- ./../configs/grafana/provisioning:/etc/grafana/provisioning
- ./../configs/grafana/dashboards:/var/lib/grafana/dashboards
## https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/
# - ./../configs/grafana/grafana.ini:/etc/grafana/grafana.ini
networks:
- booking
#######################################################
# tempo
# https://github.com/grafana/tempo/blob/main/example/docker-compose/otel-collector/docker-compose.yaml
# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared
# https://github.com/grafana/tempo/blob/main/example/docker-compose/local
# https://github.com/grafana/tempo/tree/main/example/docker-compose
#######################################################
tempo:
image: grafana/tempo:latest
container_name: tempo
restart: unless-stopped
command: [ "-config.file=/etc/tempo.yaml" ]
volumes:
- ./../configs/tempo.yaml:/etc/tempo.yaml
ports:
- "3200" # tempo
- "24317:4317" # otlp grpc
- "24318:4318" # otlp http
networks:
- booking
#######################################################
# loki
# https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/
# https://github.com/grafana/loki/blob/main/production/docker-compose.yaml
# https://github.com/grafana/loki/blob/main/examples/getting-started/docker-compose.yaml
#######################################################
loki:
image: grafana/loki:latest
hostname: loki
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./../configs/loki-config.yaml:/etc/loki/local-config.yaml
networks:
- booking
#######################################################
# elasticsearch
# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docker.html#docker-compose-file
#######################################################
elasticsearch:
container_name: elasticsearch
restart: unless-stopped
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
environment:
- discovery.type=single-node
- cluster.name=docker-cluster
- node.name=docker-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=false
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- network.host=0.0.0.0
- http.port=9200
- transport.host=localhost
- bootstrap.memory_lock=true
- cluster.routing.allocation.disk.threshold_enabled=false
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- elastic-data:/usr/share/elasticsearch/data
ports:
- ${ELASTIC_HOST_PORT:-9200}:${ELASTIC_PORT:-9200}
- 9300:9300
networks:
- booking
#######################################################
# kibana
# https://www.elastic.co/guide/en/kibana/current/docker.html
#######################################################
kibana:
image: docker.elastic.co/kibana/kibana:8.17.0
container_name: kibana
restart: unless-stopped
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- ${KIBANA_HOST_PORT:-5601}:${KIBANA_PORT:-5601}
depends_on:
- elasticsearch
networks:
- booking
#######################################################
# cadvisor
#######################################################
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
devices:
- /dev/kmsg
networks:
- booking
######################################################
# Api-Gateway
######################################################
api-gateway:
image: api-gateway
gateway:
image: gateway
build:
args:
Version: "1"
context: ../../
dockerfile: src/ApiGateway/Dockerfile
container_name: api-gateway
container_name: booking-gateway
ports:
- "5001:80"
- "5000:443"
depends_on:
- postgres
- rabbitmq
- jaeger
- elasticsearch
- kibana
volumes:
- ~/.aspnet/https:/https:ro
environment:
- ASPNETCORE_ENVIRONMENT=docker
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=5000
- ASPNETCORE_HTTP_PORT=5001
- 'ASPNETCORE_URLS=https://+;http://+'
- ASPNETCORE_HTTPS_PORT=5001
- ASPNETCORE_Kestrel__Certificates__Default__Password=password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
networks:
@ -387,18 +46,24 @@ services:
ports:
- 5004:80
- 5003:443
depends_on:
- postgres
- rabbitmq
- jaeger
- elasticsearch
- kibana
- mongo
volumes:
- ~/.aspnet/https:/https:ro
environment:
- ASPNETCORE_ENVIRONMENT=docker
- ASPNETCORE_URLS=https://+;http://+
- 'ASPNETCORE_URLS=https://+;http://+'
- ASPNETCORE_HTTPS_PORT=5003
- ASPNETCORE_HTTP_PORT=5004
- ASPNETCORE_Kestrel__Certificates__Default__Password=password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
networks:
- booking
#######################################################
# Identity
#######################################################
@ -413,13 +78,17 @@ services:
ports:
- 6005:80
- 5005:443
depends_on:
- postgres
- rabbitmq
- jaeger
- elasticsearch
- kibana
volumes:
- ~/.aspnet/https:/https:ro
environment:
- ASPNETCORE_ENVIRONMENT=docker
- ASPNETCORE_URLS=https://+;http://+
- 'ASPNETCORE_URLS=https://+;http://+'
- ASPNETCORE_HTTPS_PORT=5005
- ASPNETCORE_HTTP_PORT=6005
- ASPNETCORE_Kestrel__Certificates__Default__Password=password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
networks:
@ -440,13 +109,18 @@ services:
ports:
- 6012:80
- 5012:443
depends_on:
- postgres
- rabbitmq
- jaeger
- elasticsearch
- kibana
- mongo
volumes:
- ~/.aspnet/https:/https:ro
environment:
- ASPNETCORE_ENVIRONMENT=docker
- ASPNETCORE_URLS=https://+;http://+
- 'ASPNETCORE_URLS=https://+;http://+'
- ASPNETCORE_HTTPS_PORT=5012
- ASPNETCORE_HTTP_PORT=6012
- ASPNETCORE_Kestrel__Certificates__Default__Password=password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
networks:
@ -467,26 +141,154 @@ services:
ports:
- 6010:80
- 5010:443
depends_on:
- postgres
- rabbitmq
- jaeger
- eventstore
- elasticsearch
- kibana
- mongo
volumes:
- ~/.aspnet/https:/https:ro
environment:
- ASPNETCORE_ENVIRONMENT=docker
- ASPNETCORE_URLS=https://+;http://+
- 'ASPNETCORE_URLS=https://+;http://+'
- ASPNETCORE_HTTPS_PORT=5010
- ASPNETCORE_HTTP_PORT=6010
- ASPNETCORE_Kestrel__Certificates__Default__Password=password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
networks:
- booking
######################################################
# Postgres
######################################################
postgres:
image: postgres:latest
container_name: postgres
restart: on-failure
ports:
- '5432:5432'
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
networks:
- booking
#######################################################
# Rabbitmq
#######################################################
rabbitmq:
container_name: rabbitmq
image: rabbitmq:3-management
restart: unless-stopped
ports:
- 5672:5672
- 15672:15672
networks:
- booking
#######################################################
# Jaeger
#######################################################
jaeger:
image: jaegertracing/all-in-one
container_name: jaeger
restart: unless-stopped
networks:
- booking
ports:
- 5775:5775/udp
- 5778:5778
- 6831:6831/udp
- 6832:6832/udp
- 9411:9411
- 14268:14268
- 16686:16686
#######################################################
# EventStoreDB
#######################################################
eventstore:
container_name: eventstore
image: eventstore/eventstore:21.2.0-buster-slim
restart: on-failure
environment:
- EVENTSTORE_CLUSTER_SIZE=1
- EVENTSTORE_RUN_PROJECTIONS=All
- EVENTSTORE_START_STANDARD_PROJECTIONS=true
- EVENTSTORE_EXT_TCP_PORT=1113
- EVENTSTORE_EXT_HTTP_PORT=2113
- EVENTSTORE_INSECURE=true
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
- EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
ports:
- '1113:1113'
- '2113:2113'
networks:
- booking
#######################################################
# Mongo
#######################################################
mongo:
image: mongo:5
container_name: mongo
restart: unless-stopped
# environment:
# - MONGO_INITDB_ROOT_USERNAME=root
# - MONGO_INITDB_ROOT_PASSWORD=secret
networks:
- booking
ports:
- 27017:27017
#######################################################
# Elastic Search
#######################################################
elasticsearch:
container_name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.9.2
restart: unless-stopped
ports:
- 9200:9200
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
environment:
- xpack.monitoring.enabled=true
- xpack.watcher.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.type=single-node
networks:
- booking
#######################################################
# Kibana
#######################################################
kibana:
container_name: kibana
image: docker.elastic.co/kibana/kibana:7.9.2
restart: unless-stopped
ports:
- 5601:5601
depends_on:
- elasticsearch
environment:
- ELASTICSEARCH_URL=http://localhost:9200
networks:
- booking
networks:
booking:
name: booking
driver: bridge
volumes:
elastic-data:
postgres-data:
elasticsearch-data:

View File

@ -0,0 +1,152 @@
version: "3.3"
services:
# #######################################################
# # Rabbitmq
# #######################################################
rabbitmq:
container_name: rabbitmq
image: rabbitmq:3-management
restart: unless-stopped
ports:
- 5672:5672
- 15672:15672
networks:
- booking
#######################################################
# Postgres
######################################################
postgres:
image: postgres:latest
container_name: postgres
restart: on-failure
ports:
- '5432:5432'
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
networks:
- booking
#######################################################
# Jaeger
#######################################################
jaeger:
container_name: jaeger
image: jaegertracing/all-in-one
restart: unless-stopped
networks:
- booking
ports:
- 5775:5775/udp
- 5778:5778
- 6831:6831/udp
- 6832:6832/udp
- 9411:9411
- 14268:14268
- 16686:16686
#######################################################
# EventStoreDB
#######################################################
#https://stackoverflow.com/questions/65272764/ports-are-not-available-listen-tcp-0-0-0-0-50070-bind-an-attempt-was-made-to
eventstore:
container_name: eventstore
image: eventstore/eventstore:21.2.0-buster-slim
restart: on-failure
environment:
- EVENTSTORE_CLUSTER_SIZE=1
- EVENTSTORE_RUN_PROJECTIONS=All
- EVENTSTORE_START_STANDARD_PROJECTIONS=true
- EVENTSTORE_EXT_TCP_PORT=1113
- EVENTSTORE_EXT_HTTP_PORT=2113
- EVENTSTORE_INSECURE=true
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
- EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
ports:
- '1113:1113'
- '2113:2113'
networks:
- booking
#######################################################
# Mongo
#######################################################
mongo:
image: mongo:5
container_name: mongo
restart: unless-stopped
# environment:
# - MONGO_INITDB_ROOT_USERNAME=root
# - MONGO_INITDB_ROOT_PASSWORD=secret
networks:
- booking
ports:
- 27017:27017
#######################################################
# Elastic Search
#######################################################
elasticsearch:
container_name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9
restart: unless-stopped
ports:
- 9200:9200
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
environment:
- xpack.monitoring.enabled=true
- xpack.watcher.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.type=single-node
networks:
- booking
#######################################################
# Kibana
#######################################################
kibana:
container_name: kibana
image: docker.elastic.co/kibana/kibana:7.17.9
restart: unless-stopped
ports:
- 5601:5601
depends_on:
- elasticsearch
environment:
- ELASTICSEARCH_URL=http://localhost:9200
networks:
- booking
#######################################################
# Redis
#######################################################
redis:
image: redis
container_name: redis
restart: unless-stopped
networks:
- booking
ports:
- 6379:6379
networks:
booking:
name: booking
volumes:
elasticsearch-data:

View File

@ -1,16 +0,0 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# Staging API
server: https://acme-staging-v02.api.letsencrypt.org/directory
# server: https://acme-v02.api.letsencrypt.org/directory
email: test@email.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
class: nginx

File diff suppressed because it is too large Load Diff

45
deployments/tye/tye.yml Normal file
View File

@ -0,0 +1,45 @@
name: Booking
services:
- name: booking-gateway
project: ./../../src/ApiGateway/src/ApiGateway.csproj
bindings:
- port: 5001
env:
- name: ASPNETCORE_ENVIRONMENT
value: development
- name: flight
project: ./../../src/Services/Flight/src/Flight.Api/Flight.Api.csproj
bindings:
- port: 5003
env:
- name: ASPNETCORE_ENVIRONMENT
value: development
- name: identity
project: ./../../src/Services/Identity/src/Identity.Api/Identity.Api.csproj
bindings:
- port: 5005
env:
- name: ASPNETCORE_ENVIRONMENT
value: development
- name: passenger
project: ./../../src/Services/Passenger/src/Passenger.Api/Passenger.Api.csproj
bindings:
- port: 5012
env:
- name: ASPNETCORE_ENVIRONMENT
value: development
- name: booking
project: ./../../src/Services/Booking/src/Booking.Api/Booking.Api.csproj
bindings:
- port: 5010
env:
- name: ASPNETCORE_ENVIRONMENT
value: development

View File

@ -1,6 +0,0 @@
{
"sdk": {
"version": "10.0.103",
"rollForward": "latestFeature"
}
}

1346
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,3 @@
{
"name": "booking-microservices",
"version": "1.0.0",
"description": "booking-microservices",
"author": "Meysam Hadeli",
"license": "MIT",
"main": "index.js",
"scripts": {
"prepare": "husky && dotnet tool restore",
"format": "dotnet tool run dotnet-csharpier booking-microservices.sln",
"ci-format": "dotnet tool run dotnet-csharpier booking-microservices.sln --check",
"upgrade-packages": "dotnet outdated --upgrade"
},
"devDependencies": {
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"husky": "^9.1.6"
}
{
"version": "0.0.0"
}

View File

@ -1,38 +1,37 @@
# ---------- Build Stage ----------
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS builder
WORKDIR /src
# Copy solution-level files
COPY .editorconfig .
COPY global.json .
COPY Directory.Build.props .
# Setup working directory for the project
WORKDIR /src
COPY ./src/BuildingBlocks/BuildingBlocks.csproj ./BuildingBlocks/
COPY ./src/ApiGateway/src/ApiGateway.csproj ./ApiGateway/src/
# Copy project files first (better Docker caching)
COPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/
COPY src/ApiGateway/src/ApiGateway.csproj src/ApiGateway/src/
COPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/
# Restore dependencies
RUN dotnet restore src/ApiGateway/src/ApiGateway.csproj
# Restore nuget packages
RUN dotnet restore ./ApiGateway/src/ApiGateway.csproj
# Copy the rest of the source code
COPY src ./src
# Copy project files
COPY ./src/BuildingBlocks ./BuildingBlocks/
COPY ./src/ApiGateway/src ./ApiGateway/src/
# Publish (build included)
RUN dotnet publish src/ApiGateway/src/ApiGateway.csproj \
-c Release \
-o /app/publish \
--no-restore
# Build project with Release configuration
# and no restore, as we did it already
# ---------- Runtime Stage ----------
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
RUN ls
RUN dotnet build -c Release --no-restore ./ApiGateway/src/ApiGateway.csproj
WORKDIR /src/ApiGateway/src
# Publish project to output folder
# and no build, as we did it already
RUN dotnet publish -c Release --no-build -o out
FROM mcr.microsoft.com/dotnet/aspnet:7.0
# Setup working directory for the project
WORKDIR /app
COPY --from=build /app/publish .
ENV ASPNETCORE_URLS=http://+:80
ENV ASPNETCORE_ENVIRONMENT=docker
COPY --from=builder /src/ApiGateway/src/out .
EXPOSE 80
EXPOSE 443
ENTRYPOINT ["dotnet", "ApiGateway.dll"]
ENTRYPOINT ["dotnet", "ApiGateway.dll"]

View File

@ -1,5 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\BuildingBlocks.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0" />
<PackageReference Update="Meziantou.Analyzer" Version="1.0.747" />
<PackageReference Update="Microsoft.VisualStudio.Threading.Analyzers" Version="17.4.27" />
<PackageReference Update="Roslynator.Analyzers" Version="4.1.2" />
<PackageReference Update="Roslynator.Formatting.Analyzers" Version="4.2.0" />
<PackageReference Update="Roslynator.CodeAnalysis.Analyzers" Version="4.1.2" />
</ItemGroup>
</Project>

View File

@ -1,6 +1,9 @@
using BuildingBlocks.Jwt;
using BuildingBlocks.Logging;
using BuildingBlocks.Web;
using Figgle;
using Figgle.Fonts;
using Microsoft.AspNetCore.Authentication;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
var env = builder.Environment;
@ -8,6 +11,9 @@ var appOptions = builder.Services.GetOptions<AppOptions>("AppOptions");
Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));
builder.AddCustomSerilog(env);
builder.Services.AddJwt();
builder.Services.AddControllers();
builder.Services.AddHttpContextAccessor();
@ -15,6 +21,7 @@ builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSecti
var app = builder.Build();
app.UseSerilogRequestLogging();
app.UseCorrelationId();
app.UseRouting();
app.UseHttpsRedirection();
@ -24,9 +31,18 @@ app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapReverseProxy();
endpoints.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var token = await context.GetTokenAsync("access_token");
context.Request.Headers["Authorization"] = $"Bearer {token}";
await next().ConfigureAwait(false);
});
});
});
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));
app.Run();
app.Run();

View File

@ -1,5 +1,13 @@
{
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17191",
"sslPort": 44352
}
},
"profiles": {
"ApiGateway": {
"commandName": "Project",
@ -9,6 +17,14 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,36 +1,24 @@
{
"LogOptions": {
"Level": "Information",
"LogTemplate": "{Timestamp:HH:mm:ss} [{Level:u4}] {Message:lj}{NewLine}{Exception}",
"ElasticUri": "elasticsearch:9200"
},
"Yarp": {
"clusters": {
"flight": {
"destinations": {
"destination1": {
"address": "http://flight:80"
}
}
},
"identity": {
"destinations": {
"destination1": {
"address": "http://identity:80"
"address": "http://flight"
}
}
},
"passenger": {
"destinations": {
"destination1": {
"address": "http://passenger:80"
"address": "http://passenger"
}
}
},
"booking": {
"destinations": {
"destination1": {
"address": "http://booking:80"
"address": "http://booking"
}
}
}

View File

@ -15,78 +15,61 @@
"identity": {
"clusterId": "identity",
"match": {
"path": "identity/{**catch-all}"
},
"Transforms": [
{
"PathRemovePrefix": "identity"
"path": "/{**catch-all}"
}
]
},
"flight": {
"clusterId": "flight",
"match": {
"path": "flight/{**catch-all}"
},
"Transforms": [
{
"PathRemovePrefix": "flight"
}
]
"path": "api/{version}/flight/{**catch-all}"
}
},
"passenger": {
"clusterId": "passenger",
"match": {
"path": "passenger/{**catch-all}"
},
"Transforms": [
{
"PathRemovePrefix": "passenger"
}
]
"path": "api/{version}/passenger/{**catch-all}"
}
},
"booking": {
"clusterId": "booking",
"match": {
"path": "booking/{**catch-all}"
},
"Transforms": [
{
"PathRemovePrefix": "booking"
}
]
"path": "api/{version}/booking/{**catch-all}"
}
}
},
"clusters": {
"flight": {
"destinations": {
"destination1": {
"address": "http://localhost:5004"
"address": "https://localhost:5003"
}
}
},
"identity": {
"destinations": {
"destination1": {
"address": "http://localhost:6005"
"address": "https://localhost:5005"
}
}
},
"passenger": {
"destinations": {
"destination1": {
"address": "http://localhost:6012"
"address": "https://localhost:5012"
}
}
},
"booking": {
"destinations": {
"destination1": {
"address": "http://localhost:6010"
"address": "https://localhost:5010"
}
}
}
}
},
"Jwt": {
"Authority": "https://localhost:5005"
},
"AllowedHosts": "*"
}

View File

@ -1,33 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.SDK" Version="13.1.1"/>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>bde28db3-85ba-4201-b889-0f3faba24169</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.1" />
<PackageReference Include="Aspire.Hosting.Docker" Version="13.1.1-preview.1.26105.8" />
<PackageReference Include="Aspire.Hosting.MongoDB" Version="13.1.1" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="13.1.1" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" Version="13.1.1" />
<PackageReference Include="Aspire.Hosting.Redis" Version="13.1.1" />
<PackageReference Include="CommunityToolkit.Aspire.Hosting.EventStore" Version="9.9.0" />
<PackageReference Include="Elastic.Aspire.Hosting.Elasticsearch" Version="9.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\ApiGateway\src\ApiGateway.csproj" />
<ProjectReference Include="..\..\..\Services\Booking\src\Booking.Api\Booking.Api.csproj" />
<ProjectReference Include="..\..\..\Services\Flight\src\Flight.Api\Flight.Api.csproj" />
<ProjectReference Include="..\..\..\Services\Identity\src\Identity.Api\Identity.Api.csproj" />
<ProjectReference Include="..\..\..\Services\Passenger\src\Passenger.Api\Passenger.Api.csproj" />
</ItemGroup>
</Project>

View File

@ -1,366 +0,0 @@
using System.Net.Sockets;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddDockerComposeEnvironment("docker-compose");
// 1. Database Services
var pgUsername = builder.AddParameter("pg-username", "postgres", secret: true);
var pgPassword = builder.AddParameter("pg-password", "postgres", secret: true);
var postgres = builder.AddPostgres("postgres", pgUsername, pgPassword)
.WithImage("postgres:latest")
.WithEndpoint(
"tcp",
e =>
{
e.Port = 5432;
e.TargetPort = 5432;
e.IsProxied = true;
e.IsExternal = false;
})
.WithArgs(
"-c",
"wal_level=logical",
"-c",
"max_prepared_transactions=10");
if (builder.ExecutionContext.IsPublishMode)
{
postgres.WithDataVolume("postgres-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var flightDb = postgres.AddDatabase("flight");
var passengerDb = postgres.AddDatabase("passenger");
var identityDb = postgres.AddDatabase("identity");
var persistMessageDb = postgres.AddDatabase("persist-message");
var mongoUsername = builder.AddParameter("mongo-username", "root", secret: true);
var mongoPassword = builder.AddParameter("mongo-password", "secret", secret: true);
var mongo = builder.AddMongoDB("mongo", userName: mongoUsername, password: mongoPassword)
.WithImage("mongo")
.WithImageTag("latest")
.WithEndpoint(
"tcp",
e =>
{
e.Port = 27017;
e.TargetPort = 27017;
e.IsProxied = true;
e.IsExternal = false;
});
if (builder.ExecutionContext.IsPublishMode)
{
mongo.WithDataVolume("mongo-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var redis = builder.AddRedis("redis")
.WithImage("redis:latest")
.WithEndpoint(
"tcp",
e =>
{
e.Port = 6379;
e.TargetPort = 6379;
e.IsProxied = true;
e.IsExternal = false;
});
if (builder.ExecutionContext.IsPublishMode)
{
redis.WithDataVolume("redis-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var eventstore = builder.AddEventStore("eventstore")
.WithImage("eventstore/eventstore")
.WithEnvironment("EVENTSTORE_CLUSTER_SIZE", "1")
.WithEnvironment("EVENTSTORE_RUN_PROJECTIONS", "All")
.WithEnvironment("EVENTSTORE_START_STANDARD_PROJECTIONS", "True")
.WithEnvironment("EVENTSTORE_INSECURE", "True")
.WithEnvironment("EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP", "True")
.WithEndpoint(
"http",
e =>
{
e.TargetPort = 2113;
e.Port = 2113;
e.IsProxied = true;
e.IsExternal = true;
})
.WithEndpoint(
port: 1113,
targetPort: 1113,
name: "tcp",
isProxied: true,
isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
eventstore.WithDataVolume("eventstore-data")
.WithLifetime(ContainerLifetime.Persistent);
}
// 2. Messaging Services
var rabbitmqUsername = builder.AddParameter("rabbitmq-username", "guest", secret: true);
var rabbitmqPassword = builder.AddParameter("rabbitmq-password", "guest", secret: true);
var rabbitmq = builder.AddRabbitMQ("rabbitmq", rabbitmqUsername, rabbitmqPassword)
.WithManagementPlugin()
.WithEndpoint(
"tcp",
e =>
{
e.TargetPort = 5672;
e.Port = 5672;
e.IsProxied = true;
e.IsExternal = false;
})
.WithEndpoint(
"management",
e =>
{
e.TargetPort = 15672;
e.Port = 15672;
e.IsProxied = true;
e.IsExternal = true;
});
if (builder.ExecutionContext.IsPublishMode)
{
rabbitmq.WithLifetime(ContainerLifetime.Persistent);
}
// // 3. Observability Services
var jaeger = builder.AddContainer("jaeger-all-in-one", "jaegertracing/all-in-one")
.WithEndpoint(
port: 6831,
targetPort: 6831,
name: "agent",
protocol: ProtocolType.Udp,
isProxied: true,
isExternal: false)
.WithEndpoint(port: 16686, targetPort: 16686, name: "http", isProxied: true, isExternal: true)
.WithEndpoint(port: 14268, targetPort: 14268, name: "collector", isProxied: true, isExternal: false)
.WithEndpoint(port: 14317, targetPort: 4317, name: "otlp-grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 14318, targetPort: 4318, name: "otlp-http", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
jaeger.WithLifetime(ContainerLifetime.Persistent);
}
var zipkin = builder.AddContainer("zipkin-all-in-one", "openzipkin/zipkin")
.WithEndpoint(port: 9411, targetPort: 9411, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
zipkin.WithLifetime(ContainerLifetime.Persistent);
}
var otelCollector = builder.AddContainer("otel-collector", "otel/opentelemetry-collector-contrib")
.WithBindMount(
"../../../../deployments/configs/otel-collector-config.yaml",
"/etc/otelcol-contrib/config.yaml",
isReadOnly: true)
.WithArgs("--config=/etc/otelcol-contrib/config.yaml")
.WithEndpoint(port: 11888, targetPort: 1888, name: "otel-pprof", isProxied: true, isExternal: true)
.WithEndpoint(port: 8888, targetPort: 8888, name: "otel-metrics", isProxied: true, isExternal: true)
.WithEndpoint(port: 8889, targetPort: 8889, name: "otel-exporter-metrics", isProxied: true, isExternal: true)
.WithEndpoint(port: 13133, targetPort: 13133, name: "otel-health", isProxied: true, isExternal: true)
.WithEndpoint(port: 4317, targetPort: 4317, name: "otel-grpc", isProxied: true, isExternal: true)
.WithEndpoint(port: 4318, targetPort: 4318, name: "otel-http", isProxied: true, isExternal: true)
.WithEndpoint(port: 55679, targetPort: 55679, name: "otel-zpages", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
otelCollector.WithLifetime(ContainerLifetime.Persistent);
}
var prometheus = builder.AddContainer("prometheus", "prom/prometheus")
.WithBindMount("../../../../deployments/configs/prometheus.yaml", "/etc/prometheus/prometheus.yml")
.WithArgs(
"--config.file=/etc/prometheus/prometheus.yml",
"--storage.tsdb.path=/prometheus",
"--web.console.libraries=/usr/share/prometheus/console_libraries",
"--web.console.templates=/usr/share/prometheus/consoles",
"--web.enable-remote-write-receiver")
.WithEndpoint(port: 9090, targetPort: 9090, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
prometheus.WithLifetime(ContainerLifetime.Persistent);
}
var grafana = builder.AddContainer("grafana", "grafana/grafana")
.WithEnvironment("GF_INSTALL_PLUGINS", "grafana-clock-panel,grafana-simple-json-datasource")
.WithEnvironment("GF_SECURITY_ADMIN_USER", "admin")
.WithEnvironment("GF_SECURITY_ADMIN_PASSWORD", "admin")
.WithEnvironment("GF_FEATURE_TOGGLES_ENABLE", "traceqlEditor")
.WithBindMount("../../../../deployments/configs/grafana/provisioning", "/etc/grafana/provisioning")
.WithBindMount("../../../../deployments/configs/grafana/dashboards", "/var/lib/grafana/dashboards")
.WithEndpoint(port: 3000, targetPort: 3000, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
grafana.WithLifetime(ContainerLifetime.Persistent);
}
var nodeExporter = builder.AddContainer("node-exporter", "prom/node-exporter")
.WithBindMount("/proc", "/host/proc", isReadOnly: true)
.WithBindMount("/sys", "/host/sys", isReadOnly: true)
.WithBindMount("/", "/rootfs", isReadOnly: true)
.WithArgs(
"--path.procfs=/host/proc",
"--path.rootfs=/rootfs",
"--path.sysfs=/host/sys")
.WithEndpoint(port: 9101, targetPort: 9100, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
nodeExporter.WithLifetime(ContainerLifetime.Persistent);
}
var tempo = builder.AddContainer("tempo", "grafana/tempo")
.WithBindMount("../../../../deployments/configs/tempo.yaml", "/etc/tempo.yaml", isReadOnly: true)
.WithArgs("--config.file=/etc/tempo.yaml")
.WithEndpoint(port: 3200, targetPort: 3200, name: "http", isProxied: true, isExternal: false)
.WithEndpoint(port: 9095, targetPort: 9095, name: "grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 4317, targetPort: 4317, name: "otlp-grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 4318, targetPort: 4318, name: "otlp-http", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
tempo.WithLifetime(ContainerLifetime.Persistent);
}
var loki = builder.AddContainer("loki", "grafana/loki")
.WithBindMount("../../../../deployments/configs/loki-config.yaml", "/etc/loki/local-config.yaml", isReadOnly: true)
.WithArgs("-config.file=/etc/loki/local-config.yaml")
.WithEndpoint(port: 3100, targetPort: 3100, name: "http", isProxied: true, isExternal: false)
.WithEndpoint(port: 9096, targetPort: 9096, name: "grpc", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
loki.WithLifetime(ContainerLifetime.Persistent);
}
var elasticsearch = builder.AddElasticsearch("elasticsearch")
.WithImage("docker.elastic.co/elasticsearch/elasticsearch:8.17.0")
.WithEnvironment("discovery.type", "single-node")
.WithEnvironment("cluster.name", "docker-cluster")
.WithEnvironment("node.name", "docker-node")
.WithEnvironment("ES_JAVA_OPTS", "-Xms512m -Xmx512m")
.WithEnvironment("xpack.security.enabled", "false")
.WithEnvironment("xpack.security.http.ssl.enabled", "false")
.WithEnvironment("xpack.security.transport.ssl.enabled", "false")
.WithEnvironment("network.host", "0.0.0.0")
.WithEnvironment("http.port", "9200")
.WithEnvironment("transport.host", "localhost")
.WithEnvironment("bootstrap.memory_lock", "true")
.WithEnvironment("cluster.routing.allocation.disk.threshold_enabled", "false")
.WithEndpoint(
"http",
e =>
{
e.TargetPort = 9200;
e.Port = 9200;
e.IsProxied = true;
e.IsExternal = false;
})
.WithEndpoint(
"internal",
e =>
{
e.TargetPort = 9300;
e.Port = 9300;
e.IsProxied = true;
e.IsExternal = false;
})
.WithDataVolume("elastic-data");
if (builder.ExecutionContext.IsPublishMode)
{
elasticsearch.WithLifetime(ContainerLifetime.Persistent);
}
var kibana = builder.AddContainer("kibana", "docker.elastic.co/kibana/kibana:8.17.0")
.WithEnvironment("ELASTICSEARCH_HOSTS", "http://elasticsearch:9200")
.WithEndpoint(port: 5601, targetPort: 5601, name: "http", isProxied: true, isExternal: true)
.WithReference(elasticsearch)
.WaitFor(elasticsearch);
if (builder.ExecutionContext.IsPublishMode)
{
kibana.WithLifetime(ContainerLifetime.Persistent);
}
// 5. Application Services
var identity = builder.AddProject<Projects.Identity_Api>("identity-service")
.WithReference(persistMessageDb)
.WaitFor(persistMessageDb)
.WithReference(identityDb)
.WaitFor(identityDb)
.WithReference(mongo)
.WaitFor(mongo)
.WithReference(rabbitmq)
.WaitFor(rabbitmq)
.WithHttpEndpoint(port: 6005, name: "identity-http")
.WithHttpsEndpoint(port: 5005, name: "identity-https");
var passenger = builder.AddProject<Projects.Passenger_Api>("passenger-service")
.WithReference(persistMessageDb)
.WaitFor(persistMessageDb)
.WithReference(passengerDb)
.WaitFor(passengerDb)
.WithReference(mongo)
.WaitFor(mongo)
.WithReference(rabbitmq)
.WaitFor(rabbitmq)
.WithHttpEndpoint(port: 6012, name: "passenger-http")
.WithHttpsEndpoint(port: 5012, name: "passenger-https");
var flight = builder.AddProject<Projects.Flight_Api>("flight-service")
.WithReference(persistMessageDb)
.WaitFor(persistMessageDb)
.WithReference(flightDb)
.WaitFor(flightDb)
.WithReference(mongo)
.WaitFor(mongo)
.WithReference(rabbitmq)
.WaitFor(rabbitmq)
.WithHttpEndpoint(port: 5004, name: "flight-http")
.WithHttpsEndpoint(port: 5003, name: "flight-https");
var booking = builder.AddProject<Projects.Booking_Api>("booking-service")
.WithReference(persistMessageDb)
.WaitFor(persistMessageDb)
.WithReference(eventstore)
.WaitFor(eventstore)
.WithReference(mongo)
.WaitFor(mongo)
.WithReference(rabbitmq)
.WaitFor(rabbitmq)
.WithHttpEndpoint(port: 6010, name: "booking-http")
.WithHttpsEndpoint(port: 5010, name: "booking-https");
var gateway = builder.AddProject<Projects.ApiGateway>("api-gateway")
.WithReference(flight)
.WaitFor(flight)
.WithReference(passenger)
.WaitFor(passenger)
.WithReference(identity)
.WaitFor(identity)
.WithReference(booking)
.WaitFor(booking)
.WithHttpEndpoint(port: 5001, name: "gateway-http")
.WithHttpsEndpoint(port: 5000, name: "gateway-https");
builder.Build().Run();

View File

@ -1,18 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"AppHost": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:18888",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://otel-collector:4317",
"ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL": "http://otel-collector:4318"
}
}
}
}

View File

@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -1,41 +0,0 @@
using BuildingBlocks.HealthCheck;
using BuildingBlocks.OpenTelemetryCollector;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ServiceDefaults;
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(this WebApplicationBuilder builder)
{
builder.Services.AddCustomHealthCheck();
builder.AddCustomObservability();
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler(options =>
{
var timeSpan = TimeSpan.FromMinutes(1);
options.CircuitBreaker.SamplingDuration = timeSpan * 2;
options.TotalRequestTimeout.Timeout = timeSpan * 3;
options.Retry.MaxRetryAttempts = 3;
});
// Turn on service discovery by default
http.AddServiceDiscovery();
});
return builder;
}
public static WebApplication UseServiceDefaults(this WebApplication app)
{
app.UseCustomHealthCheck();
app.UseCustomObservability();
return app;
}
}

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\BuildingBlocks.csproj" IsAspireProjectResource="false" />
</ItemGroup>
</Project>

View File

@ -1,110 +1,160 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="5.0.0" />
<PackageReference Include="Asp.Versioning.Abstractions" Version="8.1.0" />
<PackageReference Include="Asp.Versioning.Http" Version="8.1.1" />
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.1" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.1" />
<PackageReference Include="Figgle.Fonts" Version="0.6.5" />
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
<PackageReference Include="Asp.Versioning.Abstractions" Version="7.0.0" />
<PackageReference Include="Asp.Versioning.Http" Version="7.0.0" />
<PackageReference Include="Asp.Versioning.Mvc" Version="7.0.0" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="7.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Elasticsearch" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.EventStore" Version="6.0.3" />
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="6.0.5" />
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
<PackageReference Include="EasyCaching.Core" Version="1.8.0" />
<PackageReference Include="EasyCaching.InMemory" Version="1.8.0" />
<PackageReference Include="EasyNetQ.Management.Client" Version="1.4.2" />
<PackageReference Include="EFCore.NamingConventions" Version="7.0.2" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.2" />
<PackageReference Include="Figgle" Version="0.5.1" />
<PackageReference Include="FluentValidation" Version="11.4.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Grpc.Core.Testing" Version="2.46.6" />
<PackageReference Include="EasyCaching.Core" Version="1.9.2" />
<PackageReference Include="EasyCaching.InMemory" Version="1.9.2" />
<PackageReference Include="EasyNetQ.Management.Client" Version="3.0.1" />
<PackageReference Include="EFCore.NamingConventions" Version="10.0.1" />
<PackageReference Include="Figgle" Version="0.6.5" />
<PackageReference Include="FluentValidation" Version="12.1.1" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.3.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="10.3.0" />
<PackageReference Include="Npgsql" Version="10.0.1" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="Polly" Version="8.6.5" />
<PackageReference Include="Humanizer.Core" Version="3.0.1" />
<PackageReference Include="IdGen" Version="3.0.7" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.1" />
<PackageReference Include="MediatR" Version="14.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
<PackageReference Include="MongoDB.Driver" Version="3.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="Scalar.AspNetCore" Version="2.12.38" />
<PackageReference Include="Scrutor" Version="7.0.0" />
<PackageReference Include="Sieve" Version="2.5.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.2" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="10.1.2" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.2" />
<PackageReference Include="MassTransit" Version="8.5.8" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.5.8" />
<PackageReference Include="Duende.IdentityServer" Version="7.4.5" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="7.4.5" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="7.4.5" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="7.4.5" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="System.Linq.Async" Version="7.0.0" />
<PackageReference Include="System.Linq.Async.Queryable" Version="7.0.0" />
<PackageReference Include="Testcontainers" Version="4.9.0" />
<PackageReference Include="Testcontainers.EventStoreDb" Version="4.9.0" />
<PackageReference Include="Testcontainers.MongoDb" Version="4.9.0" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.9.0" />
<PackageReference Include="Testcontainers.RabbitMq" Version="4.9.0" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
<PackageReference Include="Xunit.Extensions.Logging" Version="1.1.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.3" />
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.EventStore" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="9.0.0" />
<PackageReference Include="Npgsql.OpenTelemetry" Version="10.0.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.15.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.15.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.15.0-beta.1" />
<PackageReference Include="Grafana.OpenTelemetry" Version="1.5.2" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.15.0" />
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="23.3.9" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<PackageReference Include="AutoBogus" Version="2.13.1" />
<PackageReference Include="Bogus" Version="35.6.5" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Respawn" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="10.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.3" />
<PackageReference Include="WebMotions.Fake.Authentication.JwtBearer" Version="10.0.0" />
<PackageReference Include="Google.Protobuf" Version="3.33.5" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.76.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.3">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Mongo2Go" Version="3.1.3" />
<PackageReference Include="Npgsql" Version="7.0.1" />
<PackageReference Include="NSubstitute" Version="4.4.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.0.0-rc9.7" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="protobuf-net.BuildTools" Version="3.1.25">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.5.1" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="IdGen" Version="3.0.3" />
<PackageReference Include="Mapster" Version="7.3.0" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
<PackageReference Include="MediatR" Version="11.1.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
<PackageReference Include="MongoDB.Driver" Version="2.18.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="OpenTelemetry.Contrib.Instrumentation.MassTransit" Version="1.0.0-beta2" />
<PackageReference Include="Scrutor" Version="4.2.0" />
<PackageReference Include="Scrutor.AspNetCore" Version="3.3.0" />
<PackageReference Include="Sentry.Serilog" Version="3.25.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0" />
<PackageReference Include="Serilog.Enrichers.Span" Version="3.1.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="8.4.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.2" />
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.3.3" />
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.5" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.2" />
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
<PackageReference Include="MassTransit" Version="8.0.12" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.12" />
<PackageReference Include="DotNetCore.CAP" Version="7.0.2" />
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="7.0.2" />
<PackageReference Include="DotNetCore.CAP.MongoDB" Version="7.0.2" />
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="7.0.2" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="7.0.2" />
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="7.0.2" />
<PackageReference Include="Duende.IdentityServer" Version="6.2.2" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.2" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.2" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Testcontainers" Version="2.3.0" />
<PackageReference Include="Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.7.1" />
<PackageReference Include="WebMotions.Fake.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.1" />
<PackageReference Include="Microsoft.Identity.Web" Version="2.0.5-preview" />
<PackageReference Include="Jaeger" Version="1.0.3" />
<PackageReference Include="OpenTracing" Version="0.12.1" />
<PackageReference Include="prometheus-net" Version="7.0.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="7.0.0" />
<PackageReference Include="OpenTelemetry" Version="1.4.0-beta.1" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.4.0-beta.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9.7" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.7" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.7" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.0.64">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.1" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="AutoBogus" Version="2.13.1" />
<PackageReference Include="Bogus" Version="34.0.2" />
<PackageReference Include="FluentAssertions" Version="6.9.0" />
<PackageReference Include="Respawn" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.2" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="Google.Protobuf" Version="3.21.12" />
<PackageReference Include="Grpc.Net.Client" Version="2.51.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.51.0" />
<PackageReference Update="AsyncFixer" Version="1.6.0" />
<PackageReference Update="Meziantou.Analyzer" Version="1.0.758" />
<PackageReference Remove="Microsoft.VisualStudio.Threading.Analyzers" />
<PackageReference Update="Microsoft.VisualStudio.Threading.Analyzers" Version="17.4.27" />
<PackageReference Update="Roslynator.Analyzers" Version="4.2.0" />
<PackageReference Update="Roslynator.CodeAnalysis.Analyzers" Version="4.2.0" />
<PackageReference Update="Roslynator.Formatting.Analyzers" Version="4.2.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Contracts" />
<Folder Include="EventStoreDB\BackgroundWorkers" />
<Folder Include="PersistMessageProcessor\Data\Configurations" />
<Folder Include="PersistMessageProcessor\Data\Migrations" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,55 @@
using System.Text.Encodings.Web;
using System.Text.Unicode;
using BuildingBlocks.Utils;
using BuildingBlocks.Web;
using DotNetCore.CAP;
using DotNetCore.CAP.Messages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace BuildingBlocks.CAP;
public static class Extensions
{
public static IServiceCollection AddCustomCap<TDbContext>(this IServiceCollection services)
where TDbContext : DbContext
{
var rabbitMqOptions = services.GetOptions<RabbitMQOptions>("RabbitMq");
services.AddCap(x =>
{
x.UseEntityFramework<TDbContext>();
x.UseRabbitMQ(o =>
{
o.HostName = rabbitMqOptions.HostName;
o.UserName = rabbitMqOptions.UserName;
o.Password = rabbitMqOptions.Password;
});
x.UseDashboard();
x.FailedRetryCount = 5;
x.FailedThresholdCallback = failed =>
{
var logger = failed.ServiceProvider.GetService<ILogger>();
logger?.LogError(
$@"A message of type {failed.MessageType} failed after executing {x.FailedRetryCount} several times,
requiring manual troubleshooting. Message name: {failed.Message.GetName()}");
};
x.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
// services.AddOpenTelemetryTracing((builder) => builder
// .AddAspNetCoreInstrumentation()
// .AddCapInstrumentation()
// .AddZipkinExporter()
// );
services.Scan(s =>
s.FromAssemblies(AppDomain.CurrentDomain.GetAssemblies())
.AddClasses(c => c.AssignableTo(typeof(ICapSubscribe)))
.AsImplementedInterfaces()
.WithScopedLifetime());
return services;
}
}

View File

@ -1,4 +1,4 @@
using EasyCaching.Core;
using EasyCaching.Core;
using MediatR;
using Microsoft.Extensions.Logging;
@ -47,4 +47,4 @@ public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
return response;
}
}
}

View File

@ -4,4 +4,4 @@ public interface ICacheRequest
{
string CacheKey { get; }
DateTime? AbsoluteExpirationRelativeToNow { get; }
}
}

View File

@ -4,4 +4,4 @@ namespace BuildingBlocks.Caching
{
string CacheKey { get; }
}
}
}

View File

@ -36,4 +36,4 @@ namespace BuildingBlocks.Caching
return response;
}
}
}
}

View File

@ -1,10 +0,0 @@
namespace BuildingBlocks.Constants;
public static class IdentityConstant
{
public static class Role
{
public const string Admin = "admin";
public const string User = "user";
}
}

View File

@ -2,10 +2,10 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record FlightCreated(Guid Id) : IIntegrationEvent;
public record FlightUpdated(Guid Id) : IIntegrationEvent;
public record FlightDeleted(Guid Id) : IIntegrationEvent;
public record AircraftCreated(Guid Id) : IIntegrationEvent;
public record AirportCreated(Guid Id) : IIntegrationEvent;
public record SeatCreated(Guid Id) : IIntegrationEvent;
public record SeatReserved(Guid Id) : IIntegrationEvent;
public record FlightCreated(long Id) : IIntegrationEvent;
public record FlightUpdated(long Id) : IIntegrationEvent;
public record FlightDeleted(long Id) : IIntegrationEvent;
public record AircraftCreated(long Id) : IIntegrationEvent;
public record AirportCreated(long Id) : IIntegrationEvent;
public record SeatCreated(long Id) : IIntegrationEvent;
public record SeatReserved(long Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record UserCreated(Guid Id, string Name, string PassportNumber) : IIntegrationEvent;
public record UserCreated(long Id, string Name, string PassportNumber) : IIntegrationEvent;

View File

@ -2,5 +2,5 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record PassengerRegistrationCompleted(Guid Id) : IIntegrationEvent;
public record PassengerCreated(Guid Id) : IIntegrationEvent;
public record PassengerRegistrationCompleted(long Id) : IIntegrationEvent;
public record PassengerCreated(long Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record BookingCreated(Guid Id) : IIntegrationEvent;
public record BookingCreated(long Id) : IIntegrationEvent;

View File

@ -1,4 +1,4 @@
using MediatR;
using MediatR;
namespace BuildingBlocks.Core.CQRS;
@ -9,4 +9,4 @@ public interface ICommand : ICommand<Unit>
public interface ICommand<out T> : IRequest<T>
where T : notnull
{
}
}

View File

@ -1,4 +1,4 @@
using MediatR;
using MediatR;
namespace BuildingBlocks.Core.CQRS;
@ -11,4 +11,4 @@ public interface ICommandHandler<in TCommand, TResponse> : IRequestHandler<TComm
where TCommand : ICommand<TResponse>
where TResponse : notnull
{
}
}

View File

@ -1,8 +1,8 @@
using MediatR;
using MediatR;
namespace BuildingBlocks.Core.CQRS;
public interface IQuery<out T> : IRequest<T>
where T : notnull
{
}
}

View File

@ -1,4 +1,4 @@
using MediatR;
using MediatR;
namespace BuildingBlocks.Core.CQRS;
@ -6,4 +6,4 @@ public interface IQueryHandler<in TQuery, TResponse> : IRequestHandler<TQuery, T
where TQuery : IQuery<TResponse>
where TResponse : notnull
{
}
}

View File

@ -1,37 +0,0 @@
using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core;
public class CompositeEventMapper : IEventMapper
{
private readonly IEnumerable<IEventMapper> _mappers;
public CompositeEventMapper(IEnumerable<IEventMapper> mappers)
{
_mappers = mappers;
}
public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)
{
foreach (var mapper in _mappers)
{
var integrationEvent = mapper.MapToIntegrationEvent(@event);
if (integrationEvent is not null)
return integrationEvent;
}
return null;
}
public IInternalCommand? MapToInternalCommand(IDomainEvent @event)
{
foreach (var mapper in _mappers)
{
var internalCommand = mapper.MapToInternalCommand(@event);
if (internalCommand is not null)
return internalCommand;
}
return null;
}
}

View File

@ -6,4 +6,4 @@ public enum EventType
DomainEvent = 1,
IntegrationEvent = 2,
InternalCommand = 4
}
}

View File

@ -2,4 +2,4 @@ namespace BuildingBlocks.Core.Event;
public interface IDomainEvent : IEvent
{
}
}

View File

@ -1,12 +1,11 @@
using BuildingBlocks.IdsGenerator;
using MediatR;
namespace BuildingBlocks.Core.Event;
using global::MassTransit;
public interface IEvent : INotification
{
Guid EventId => NewId.NextGuid();
long EventId => SnowFlakIdGenerator.NewId();
public DateTime OccurredOn => DateTime.Now;
public string EventType => GetType().AssemblyQualifiedName;
}
}

View File

@ -5,4 +5,4 @@ namespace BuildingBlocks.Core.Event;
[ExcludeFromTopology]
public interface IIntegrationEvent : IEvent
{
}
}

View File

@ -1,5 +1,5 @@
namespace BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core.Event;
public interface IInternalCommand : IEvent
{
}
}

View File

@ -1,5 +1,6 @@
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.IdsGenerator;
namespace BuildingBlocks.Core.Event;
public record InternalCommand : IInternalCommand, ICommand;
public record InternalCommand : IInternalCommand, ICommand;

View File

@ -1,4 +1,4 @@
using Google.Protobuf;
using Google.Protobuf;
namespace BuildingBlocks.Core.Event;
@ -23,4 +23,4 @@ public class MessageEnvelope<TMessage> : MessageEnvelope
}
public new TMessage? Message { get; }
}
}

View File

@ -9,17 +9,30 @@ using MessageEnvelope = BuildingBlocks.Core.Event.MessageEnvelope;
namespace BuildingBlocks.Core;
public sealed class EventDispatcher(
IServiceScopeFactory serviceScopeFactory,
IEventMapper eventMapper,
ILogger<EventDispatcher> logger,
IPersistMessageProcessor persistMessageProcessor,
IHttpContextAccessor httpContextAccessor
)
: IEventDispatcher
public sealed class EventDispatcher : IEventDispatcher
{
private readonly IEventMapper _eventMapper;
private readonly ILogger<EventDispatcher> _logger;
private readonly IPersistMessageProcessor _persistMessageProcessor;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IServiceScopeFactory _serviceScopeFactory;
public EventDispatcher(IServiceScopeFactory serviceScopeFactory,
IEventMapper eventMapper,
ILogger<EventDispatcher> logger,
IPersistMessageProcessor persistMessageProcessor,
IHttpContextAccessor httpContextAccessor)
{
_serviceScopeFactory = serviceScopeFactory;
_eventMapper = eventMapper;
_logger = logger;
_persistMessageProcessor = persistMessageProcessor;
_httpContextAccessor = httpContextAccessor;
}
public async Task SendAsync<T>(IReadOnlyList<T> events, Type type = null,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default)
where T : IEvent
{
if (events.Count > 0)
@ -32,7 +45,7 @@ public sealed class EventDispatcher(
{
foreach (var integrationEvent in integrationEvents)
{
await persistMessageProcessor.PublishMessageAsync(
await _persistMessageProcessor.PublishMessageAsync(
new MessageEnvelope(integrationEvent, SetHeaders()),
cancellationToken);
}
@ -41,13 +54,13 @@ public sealed class EventDispatcher(
switch (events)
{
case IReadOnlyList<IDomainEvent> domainEvents:
{
var integrationEvents = await MapDomainEventToIntegrationEventAsync(domainEvents)
{
var integrationEvents = await MapDomainEventToIntegrationEventAsync(domainEvents)
.ConfigureAwait(false);
await PublishIntegrationEvent(integrationEvents);
break;
}
await PublishIntegrationEvent(integrationEvents);
break;
}
case IReadOnlyList<IIntegrationEvent> integrationEvents:
await PublishIntegrationEvent(integrationEvents);
@ -61,7 +74,7 @@ public sealed class EventDispatcher(
foreach (var internalMessage in internalMessages)
{
await persistMessageProcessor.AddInternalMessageAsync(internalMessage, cancellationToken);
await _persistMessageProcessor.AddInternalMessageAsync(internalMessage, cancellationToken);
}
}
}
@ -70,34 +83,33 @@ public sealed class EventDispatcher(
public async Task SendAsync<T>(T @event, Type type = null,
CancellationToken cancellationToken = default)
where T : IEvent =>
await SendAsync(new[] { @event }, type, cancellationToken);
await SendAsync(new[] {@event}, type, cancellationToken);
private Task<IReadOnlyList<IIntegrationEvent>> MapDomainEventToIntegrationEventAsync(
IReadOnlyList<IDomainEvent> events)
{
logger.LogTrace("Processing integration events start...");
_logger.LogTrace("Processing integration events start...");
var wrappedIntegrationEvents = GetWrappedIntegrationEvents(events.ToList())?.ToList();
if (wrappedIntegrationEvents?.Count > 0)
return Task.FromResult<IReadOnlyList<IIntegrationEvent>>(wrappedIntegrationEvents);
var integrationEvents = new List<IIntegrationEvent>();
using var scope = serviceScopeFactory.CreateScope();
using var scope = _serviceScopeFactory.CreateScope();
foreach (var @event in events)
{
var eventType = @event.GetType();
logger.LogTrace($"Handling domain event: {eventType.Name}");
_logger.LogTrace($"Handling domain event: {eventType.Name}");
var integrationEvent = eventMapper.MapToIntegrationEvent(@event);
var integrationEvent = _eventMapper.MapToIntegrationEvent(@event);
if (integrationEvent is null)
continue;
if (integrationEvent is null) continue;
integrationEvents.Add(integrationEvent);
}
logger.LogTrace("Processing integration events done...");
_logger.LogTrace("Processing integration events done...");
return Task.FromResult<IReadOnlyList<IIntegrationEvent>>(integrationEvents);
}
@ -106,24 +118,23 @@ public sealed class EventDispatcher(
private Task<IReadOnlyList<IInternalCommand>> MapDomainEventToInternalCommandAsync(
IReadOnlyList<IDomainEvent> events)
{
logger.LogTrace("Processing internal message start...");
_logger.LogTrace("Processing internal message start...");
var internalCommands = new List<IInternalCommand>();
using var scope = serviceScopeFactory.CreateScope();
using var scope = _serviceScopeFactory.CreateScope();
foreach (var @event in events)
{
var eventType = @event.GetType();
logger.LogTrace($"Handling domain event: {eventType.Name}");
_logger.LogTrace($"Handling domain event: {eventType.Name}");
var integrationEvent = eventMapper.MapToInternalCommand(@event);
var integrationEvent = _eventMapper.MapToInternalCommand(@event);
if (integrationEvent is null)
continue;
if (integrationEvent is null) continue;
internalCommands.Add(integrationEvent);
}
logger.LogTrace("Processing internal message done...");
_logger.LogTrace("Processing internal message done...");
return Task.FromResult<IReadOnlyList<IInternalCommand>>(internalCommands);
}
@ -146,10 +157,10 @@ public sealed class EventDispatcher(
private IDictionary<string, object> SetHeaders()
{
var headers = new Dictionary<string, object>();
headers.Add("CorrelationId", httpContextAccessor?.HttpContext?.GetCorrelationId());
headers.Add("UserId", httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier));
headers.Add("UserName", httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.Name));
headers.Add("CorrelationId", _httpContextAccessor?.HttpContext?.GetCorrelationId());
headers.Add("UserId", _httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier));
headers.Add("UserName", _httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.Name));
return headers;
}
}
}

View File

@ -8,4 +8,4 @@ public interface IEventDispatcher
where T : IEvent;
public Task SendAsync<T>(T @event, Type type = null, CancellationToken cancellationToken = default)
where T : IEvent;
}
}

View File

@ -4,6 +4,6 @@ namespace BuildingBlocks.Core;
public interface IEventMapper
{
IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event);
IInternalCommand? MapToInternalCommand(IDomainEvent @event);
}
IIntegrationEvent MapToIntegrationEvent(IDomainEvent @event);
IInternalCommand MapToInternalCommand(IDomainEvent @event);
}

View File

@ -3,4 +3,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core;
public record IntegrationEventWrapper<TDomainEventType>(TDomainEventType DomainEvent) : IIntegrationEvent
where TDomainEventType : IDomainEvent;
where TDomainEventType : IDomainEvent;

View File

@ -1,23 +1,32 @@
using BuildingBlocks.Core.Event;
using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core.Model;
public abstract record Aggregate<TId> : Entity<TId>, IAggregate<TId>
namespace BuildingBlocks.Core.Model
{
private readonly List<IDomainEvent> _domainEvents = new();
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
public void AddDomainEvent(IDomainEvent domainEvent)
public abstract record Aggregate : Aggregate<long>
{
_domainEvents.Add(domainEvent);
}
public IEvent[] ClearDomainEvents()
public abstract record Aggregate<TId> : Audit, IAggregate<TId>
{
IEvent[] dequeuedEvents = _domainEvents.ToArray();
private readonly List<IDomainEvent> _domainEvents = new();
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
_domainEvents.Clear();
public void AddDomainEvent(IDomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
return dequeuedEvents;
public IEvent[] ClearDomainEvents()
{
IEvent[] dequeuedEvents = _domainEvents.ToArray();
_domainEvents.Clear();
return dequeuedEvents;
}
public long Version { get; set; }
public TId Id { get; set; }
}
}
}

View File

@ -1,15 +1,10 @@
namespace BuildingBlocks.Core.Model;
public interface IEntity<T> : IEntity
{
public T Id { get; set; }
}
public interface IEntity : IVersion
public abstract record Audit : IAudit
{
public DateTime? CreatedAt { get; set; }
public long? CreatedBy { get; set; }
public DateTime? LastModified { get; set; }
public long? LastModifiedBy { get; set; }
public bool IsDeleted { get; set; }
}
}

View File

@ -1,13 +1,19 @@
using BuildingBlocks.Core.Event;
using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core.Model;
public interface IAggregate<T> : IAggregate, IEntity<T>
{
}
public interface IAggregate : IEntity
public interface IAggregate : IAudit, IVersion
{
IReadOnlyList<IDomainEvent> DomainEvents { get; }
IEvent[] ClearDomainEvents();
}
}
public interface IAggregate<out T> : IAggregate
{
T Id { get; }
}
public interface IVersion
{
long Version { get; set; }
}

View File

@ -1,12 +1,10 @@
namespace BuildingBlocks.Core.Model;
public abstract record Entity<T> : IEntity<T>
public interface IAudit
{
public T Id { get; set; }
public DateTime? CreatedAt { get; set; }
public long? CreatedBy { get; set; }
public DateTime? LastModified { get; set; }
public long? LastModifiedBy { get; set; }
public bool IsDeleted { get; set; }
public long Version { get; set; }
}
}

View File

@ -1,7 +0,0 @@
namespace BuildingBlocks.Core.Model;
// For handling optimistic concurrency
public interface IVersion
{
long Version { get; set; }
}

View File

@ -1,36 +0,0 @@
namespace BuildingBlocks.Core.Pagination;
using Sieve.Models;
using Sieve.Services;
public static class Extensions
{
public static async Task<IPageList<TEntity>> ApplyPagingAsync<TEntity>(
this IQueryable<TEntity> queryable,
IPageRequest pageRequest,
ISieveProcessor sieveProcessor,
CancellationToken cancellationToken = default
)
where TEntity : class
{
var sieveModel = new SieveModel
{
PageSize = pageRequest.PageSize,
Page = pageRequest.PageNumber,
Sorts = pageRequest.SortOrder,
Filters = pageRequest.Filters
};
// https://github.com/Biarity/Sieve/issues/34#issuecomment-403817573
var result = sieveProcessor.Apply(sieveModel, queryable, applyPagination: false);
var total = result.Count();
result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false,
applySorting: false); // Only applies pagination
var items = await result
.ToAsyncEnumerable()
.ToListAsync(cancellationToken: cancellationToken);
return PageList<TEntity>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total);
}
}

View File

@ -1,16 +0,0 @@
namespace BuildingBlocks.Core.Pagination;
public interface IPageList<T>
where T : class
{
int CurrentPageSize { get; }
int CurrentStartIndex { get; }
int CurrentEndIndex { get; }
int TotalPages { get; }
bool HasPrevious { get; }
bool HasNext { get; }
IReadOnlyList<T> Items { get; init; }
int TotalCount { get; init; }
int PageNumber { get; init; }
int PageSize { get; init; }
}

View File

@ -1,7 +0,0 @@
namespace BuildingBlocks.Core.Pagination;
using MediatR;
public interface IPageQuery<out TResponse> : IPageRequest, IRequest<TResponse>
where TResponse : class
{ }

Some files were not shown because too many files have changed in this diff Show More