Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,21 @@ The documentation sources are located in the `docs` directory. See the [docs rea

## Development

This section describes how to set up the development environment. First, you need to install the following tools:
This section describes how to set up the development environment. First, you need to install the following tools installed on your machine:

- Docker
- .NET 10.0 SDK
- node.js v24.x and npm
- your favourite IDE
- Node.js v24.x and npm
- Your preferred IDE such as [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio](https://visualstudio.microsoft.com/vs/)

To run the application from source, follow these steps:

1. Open the `src/Turnierplan.slnx` solution and navigate to the docker compose file located under `Solution Items`. Run the `turnierplan.database` docker compose service. This will start up the PostgreSQL database for local development.
2. Navigate to the `Turnierplan.App` project and run the `Turnierplan.App` launch configuration. This will start the backend using port `45000`.
3. Open a terminal and navigate to the `src/Turnierplan.App/Client` directory. Run `npm install` to install the node dependencies. Next, you can start the client application by typing `npm run start`.
4. Access the client application using [http://localhost:45001](http://localhost:45001) and log in using default credentials. The user name is `admin` and the password is `P@ssw0rd`.
1. Open the `src/Turnierplan.slnx` solution.
2. Run the `Turnierplan.AppHost` project. Make sure to use the configuration *with client*. This will start the Aspire AppHost which will do the following steps:
- Download the postgres container image and run a local database
- Install npm dependencies and run the client app
- Run the backend `Turnierplan.App`
3. The Aspire dashboard will open up from which you can navigate to the client application ([http://localhost:45001](http://localhost:45001)).
4. Now you can log in using default credentials: The username is `admin` and the password is `P@ssw0rd`.

When running locally, the API documentation can be viewed by opening [http://localhost:45000/scalar](http://localhost:45000/scalar).

> [!NOTE]
> The solution must be built first before the client application can be started. This is because the client application startup depends on OpenAPI files generated during the solution build.
50 changes: 41 additions & 9 deletions src/Turnierplan.App/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Azure.Monitor.OpenTelemetry.AspNetCore;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Npgsql;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Turnierplan.App.Security;
using Turnierplan.Core.ApiKey;
using Turnierplan.Core.User;
Expand All @@ -14,17 +18,45 @@ internal static class ServiceCollectionExtensions
{
public static void AddTurnierplanMonitoring(this IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetSection("ApplicationInsights").GetValue<string>("ConnectionString");
var applicationInsightsConnectionString = configuration.GetSection("ApplicationInsights").GetValue<string>("ConnectionString");
var hasApplicationInsights = !string.IsNullOrEmpty(applicationInsightsConnectionString);
var hasOltpExporter = !string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

if (!string.IsNullOrWhiteSpace(connectionString))
if (!hasApplicationInsights && !hasOltpExporter)
{
services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.AddTurnierplanDataAccessLayer();
tracing.AddTurnierplanDocumentRendering();
})
.UseAzureMonitor(opt => opt.ConnectionString = connectionString);
return;
}

var openTelemetryBuilder = services.AddOpenTelemetry();

openTelemetryBuilder.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation();
metrics.AddHttpClientInstrumentation();
metrics.AddRuntimeInstrumentation();
metrics.AddNpgsqlInstrumentation();
});

openTelemetryBuilder.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation(options =>
{
// Exclude health check requests from tracing
options.Filter = context => !context.Request.Path.StartsWithSegments("/health");
});
tracing.AddHttpClientInstrumentation();
tracing.AddTurnierplanDataAccessLayer();
tracing.AddTurnierplanDocumentRendering();
});

if (hasApplicationInsights)
{
openTelemetryBuilder.UseAzureMonitor(opt => opt.ConnectionString = applicationInsightsConnectionString);
}

if (hasOltpExporter)
{
openTelemetryBuilder.UseOtlpExporter();
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/Turnierplan.App/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"Turnierplan.App": {
"postgres": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:45000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Turnierplan.App (in-memory)": {
"in-memory": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:45000",
Expand Down
2 changes: 2 additions & 0 deletions src/Turnierplan.App/Turnierplan.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.0"/>
<PackageReference Include="Scalar.AspNetCore" Version="2.12.17" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
</ItemGroup>
Expand Down
3 changes: 0 additions & 3 deletions src/Turnierplan.App/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
"Default": "Information"
}
},
"Database": {
"ConnectionString": "Host=localhost;Database=turnierplan;Username=postgres;Password=P@ssw0rd"
},
"Turnierplan": {
"ApplicationUrl": "http://localhost:45000",
"InitialUserPassword": "P@ssw0rd"
Expand Down
32 changes: 32 additions & 0 deletions src/Turnierplan.AppHost/AppHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.Extensions.Configuration;
using Projects;

var builder = DistributedApplication.CreateBuilder(args);

var database = builder.AddPostgres("turnierplan-postgres")
.WithDataVolume()
.WithLifetime(ContainerLifetime.Persistent)
.AddDatabase("turnierplan-database");

builder.AddProject<Turnierplan_App>("turnierplan-backend")
.WaitFor(database)
.WithHttpHealthCheck("/health")
.WithEnvironment("Database__ConnectionString", database.Resource.ConnectionStringExpression);

if (builder.Configuration.GetValue("TURNIERPLAN_ASPIRE_RUN_CLIENT", defaultValue: false))
{
builder.AddJavaScriptApp("turnierplan-client", "../Turnierplan.App/Client")
.WithRunScript("start")
.WithHttpEndpoint(45001, isProxied: false)
.WithHttpHealthCheck("/index.html")
.WithNpm(install: true, installCommand: "ci");
}
else
{
// When starting locally without client app, add an external resource with the client app URL
// and health check so that the client app is still visible and accessible in the dashboard.
builder.AddExternalService("turnierplan-client", "http://localhost:45001")
.WithHttpHealthCheck("/index.html");
}

builder.Build().Run();
30 changes: 30 additions & 0 deletions src/Turnierplan.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"with client": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:15285",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19065",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18247",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20277",
"TURNIERPLAN_ASPIRE_RUN_CLIENT": "true"
}
},
"without client": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:15285",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19065",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18247",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20277"
}
}
}
}
20 changes: 20 additions & 0 deletions src/Turnierplan.AppHost/Turnierplan.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Aspire.AppHost.Sdk/13.1.0">
<Import Project="../version.xml" />

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Exe</OutputType>
<UserSecretsId>523f324d-1695-4d45-a000-a79765a1468a</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.JavaScript" Version="13.1.0" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="13.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Turnierplan.App\Turnierplan.App.csproj" />
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions src/Turnierplan.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions src/Turnierplan.AppHost/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
15 changes: 0 additions & 15 deletions src/docker-compose.yml

This file was deleted.

2 changes: 1 addition & 1 deletion src/turnierplan.NET.slnx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Solution>
<Folder Name="/Solution Files/">
<File Path="docker-compose.yml" />
<File Path="version.xml" />
</Folder>
<Folder Name="/Test/">
Expand All @@ -15,6 +14,7 @@
</Folder>
<Project Path="Turnierplan.Adapter/Turnierplan.Adapter.csproj" />
<Project Path="Turnierplan.App/Turnierplan.App.csproj" />
<Project Path="Turnierplan.AppHost/Turnierplan.AppHost.csproj" />
<Project Path="Turnierplan.Core/Turnierplan.Core.csproj" />
<Project Path="Turnierplan.Dal/Turnierplan.Dal.csproj" />
<Project Path="Turnierplan.ImageStorage/Turnierplan.ImageStorage.csproj" />
Expand Down
Loading