GridLab.Gmss

GridLab.Gmss

GridLab.GMSS

Important

Personal Research & Access Notice

This project is a personal research and technical capability development initiative conducted independently by the author.

  • Independent Initiative: This solution has been developed entirely during personal time. All development overhead, infrastructure costs, and computational resources are personally provided and funded by the author, without utilizing any Siemens assets, hardware, or corporate budget.
  • Exclusive Benefit: While this is a private endeavor, public access is restricted to ensure that the strategic advantages of this research primarily benefit Siemens and its internal community, preventing unauthorized commercial exploitation by third-party entities.
  • Siemens Employees: You can access the full source code and contribute via the internal mirror at code.siemens.com.
  • Inquiries: If you are a partner or an external entity seeking collaboration, please provide your contact information and business case to raif.durmaz@siemens.com.

Microservices Solution

This is a distributed microservices application built on Domain Driven Design (DDD) practices, orchestrated by .NET Aspire.

Pre-requirements

All infrastructure dependencies (PostgreSQL, Valkey, RabbitMQ, Elasticsearch, Prometheus, Grafana, Jaeger, etc.) are containerized and orchestrated via .NET Aspire—no external installation required.


Quick Start

TL;DR — Start Everything

cd aspire\GridLab.Gmss.AppHost
dotnet run

That's it! The Aspire AppHost will:

  1. Start all infrastructure containers (PostgreSQL, Valkey, RabbitMQ, Elasticsearch, etc.)
  2. Start observability stack (Prometheus, Grafana, Jaeger, Kibana)
  3. Start microservices in the correct dependency order
  4. Automatically run database migrations and seed initial data
  5. Wait for each service's health check before starting dependents
  6. Open the Aspire Dashboard

aspire

Default Credentials

After startup, log in with:

  • Username: platon
  • Password: 1q2w3E*

Architecture Overview

System Diagram

system-diagram


Solution Structure

GridLab.Gmss/
├── apps/                           # Web Applications
│   ├── auth-server/                # OAuth 2.0 Authentication Server
│   ├── web/                        # Main Web Application (MVC/Razor Pages)
│   └── public/                     # Public Website / Landing Page

├── gateways/                       # API Gateways
│   ├── web/                        # Web Gateway (internal services)
│   └── public/                     # Public Gateway (external APIs)

├── services/                       # Microservices
│   ├── identity/                   # Users, Roles, OpenIddict
│   ├── administration/             # Permissions, Features, Settings
│   ├── audit-logging/              # Audit Logs
│   ├── tenant-management/          # Tenant definitions and management
│   ├── background-jobs/            # Hangfire Background Jobs
│   ├── data-management/            # Data Import/Export
│   └── .../                        # Business-specific services (e.g. CIM Service)

├── aspire/                         # .NET Aspire Orchestration
│   └── GridLab.Gmss.AppHost/       # Aspire AppHost (startup orchestrator)

├── etc/                            # Infrastructure Configuration Files
│   ├── elastic/                    # Elasticsearch configuration
│   ├── grafana/                    # Grafana dashboards & config
│   ├── otel/                       # OpenTelemetry Collector config
│   ├── prometheus/                 # Prometheus configuration
│   ├── rabbitmq/                   # RabbitMQ configuration
│   └── valkey/                     # Valkey (Redis) configuration

Infrastructure Components

Core Infrastructure

Component Image Port(s) Purpose
PostgreSQL postgres:18 5432 Primary relational database for all microservices
Valkey valkey/valkey:8 6379 Redis-compatible distributed cache (sessions, caching)
RabbitMQ rabbitmq:4-management 5672, 15672 Message broker for async events and distributed messaging
Elasticsearch elasticsearch:8.11.3 9200, 9300 Centralized logging, full-text search, log analytics

Observability Stack

Component Image Port(s) Purpose
Prometheus prom/prometheus:v3 9090 Metrics collection, alerting, and time-series database
Grafana grafana/grafana:12.0 3001 Metrics visualization, dashboards, and alerting UI
Jaeger jaegertracing/jaeger:2.17.0 16686, 4317, 4318 Distributed tracing for request flow visualization
Kibana kibana:8.11.3 5601 Elasticsearch UI for log exploration and visualization
OTel Collector OpenTelemetry Collector 4317, 4318 Unified telemetry collection and export pipeline

Configuration files are located in the etc/ directory:

etc/
├── elastic/           # Elasticsearch configuration
├── grafana/
│   ├── config/        # Grafana settings
│   └── dashboards/    # Pre-configured dashboards
├── otel/              # OpenTelemetry Collector configuration
│   └── otel-collector-config.yaml
├── prometheus/        # Prometheus configuration
│   └── prometheus.yml
├── rabbitmq/          # RabbitMQ configuration
│   ├── rabbitmq.conf
│   └── enabled_plugins
├── valkey/            # Valkey (Redis) configuration
│   └── valkey.conf
└── secrets/           # Secret management

Database Schema

Each microservice owns its own database following the Database-per-Service pattern:

Service Database Description
Identity Service Gmss_Identity Users, Roles, Claims, OpenIddict clients/scopes
Administration Service Gmss_Administration Permissions, Features, Settings definitions
Administration Service Gmss_AbpBlobStoring Binary Large Object (BLOB) storage
Audit Logging Service Gmss_AuditLogging Security audit logs, entity change logs
Tenant Management Service Gmss_TenantManagement Tenant definitions, tenant-specific features
Data Management Service Gmss_DataManagement Data import/export and processing
Background Jobs Service Gmss_BackgroundJobs Hangfire job storage and scheduling

AuthServer Role

Important: The AuthServer does NOT create any databases. It only:

  • Reads from databases created by the services above
  • Handles authentication/authorization
  • Issues tokens using OpenIddict

How Automatic Migration Works

Each service has a RuntimeDatabaseMigrator that runs during OnPreApplicationInitializationAsync:

// Example from IdentityService
public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
{
    using var scope = context.ServiceProvider.CreateScope();
    await scope.ServiceProvider
        .GetRequiredService<IdentityServiceRuntimeDatabaseMigrator>()
        .CheckAndApplyDatabaseMigrationsAsync();
}

The migrator:

  1. Acquires a distributed lock (prevents concurrent migrations)
  2. Checks if database exists (creates if not)
  3. Applies EF Core migrations (creates/updates tables)
  4. Runs data seeders (creates initial data)
  5. Releases lock

.NET Aspire is the recommended way to run the solution locally. It orchestrates all services, databases, and infrastructure dependencies with a single launch.

Pre-requirements (Aspire)

  • Docker Desktop must be running (Aspire uses containers for infrastructure)
  • .NET 10+ SDK installed

Authenticate with Docker Registry

Before running, authenticate with the container registry:

docker login
docker pull postgres:18
docker pull valkey/valkey:8
docker pull rabbitmq:4-management
docker pull docker.elastic.co/elasticsearch/elasticsearch:8.11.3
docker pull docker.elastic.co/kibana/kibana:8.11.3
docker pull prom/prometheus:v3
docker pull grafana/grafana:12.0
docker pull jaegertracing/jaeger:2.17.0
docker pull ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.123.0

Running with Aspire

  1. Ensure Docker Desktop is running

  2. Set GridLab.Gmss.AppHost as the startup project in Visual Studio

  3. Press F5 (or Ctrl+F5), or from the command line:

    dotnet run --project aspire/GridLab.Gmss.AppHost
  4. The Aspire Dashboard opens automatically at http://localhost:15888, providing:

    • Resources — all running projects and containers with endpoints and status
    • Console Logs — aggregated, searchable logs from every service
    • Structured Logs — filterable structured/semantic log entries
    • Traces — distributed traces showing request flow across services
    • Metrics — runtime and application-level metrics

Viewing Logs

Service Startup Order

Aspire enforces the following startup order to ensure proper database migrations:

startup-order

This order is enforced in aspire/GridLab.Gmss.AppHost/Program.cs using .WaitFor() dependencies.

Configure User Secrets (Optional)

Override default credentials using .NET User Secrets:

cd aspire/GridLab.Gmss.AppHost

# PostgreSQL credentials
dotnet user-secrets set "Parameters:postgres-user" "postgres"
dotnet user-secrets set "Parameters:postgres-password" "your-secure-password"

# RabbitMQ credentials
dotnet user-secrets set "Parameters:rabbitMQ-user" "user"
dotnet user-secrets set "Parameters:rabbitMQ-user-password" "your-secure-password"

Application Endpoints

Web Applications

Application URL Description
Aspire Dashboard http://localhost:15888 Orchestration dashboard
Auth Server http://localhost:44346 OAuth 2.0 / OpenIddict server
Web Application http://localhost:44304 Main Web UI
Public Website http://localhost:44354 Public landing page

API Gateways

Gateway URL Description
Web Gateway http://localhost:44310 Internal API gateway
Public Gateway http://localhost:44369 External API gateway

Microservices

Service URL Description
Identity Service http://localhost:44321 User & role management
Administration Service http://localhost:44355 Permissions, features, settings
Tenant Management Service http://localhost:44348 Tenant management
Audit Logging Service http://localhost:44328 Audit logging
Data Management Service http://localhost:44378 Data management
Background Jobs Service http://localhost:44393 Hangfire background jobs

Observability

Tool URL Description
Grafana http://localhost:3001 Metrics dashboards
Prometheus http://localhost:9090 Metrics & alerting
Jaeger http://localhost:16686 Distributed tracing
Kibana http://localhost:5601 Log exploration
RabbitMQ Management http://localhost:15672 Message broker UI

Building the Solution

This workspace uses the .slnx solution format (supported in .NET SDK 9.0.200+ and .NET 10).

Build with Graph

dotnet build GridLab.Gmss.slnx /graph

The /graph switch constructs a Directed Acyclic Graph (DAG) of all project dependencies:

  • Improves parallel scheduling for faster builds
  • Avoids double-building projects referenced by multiple entry points
  • Detects circular or missing dependency issues upfront

Useful Commands

Task Command
Build with graph dotnet build GridLab.Gmss.slnx /graph
Build with graph + isolation dotnet build GridLab.Gmss.slnx /graph /isolate
List projects in solution dotnet sln GridLab.Gmss.slnx list
Restore packages dotnet restore GridLab.Gmss.slnx

Configuration

Configuration Check

Review these configurations before running:

  • appsettings.json files in each application/service project
  • Connection strings for PostgreSQL
  • Redis/Valkey connection settings
  • RabbitMQ credentials
  • Elasticsearch URLs

Key Configuration Files

File Purpose
aspire/GridLab.Gmss.AppHost/Program.cs Service orchestration and dependencies
aspire/GridLab.Gmss.AppHost/InfrastructureExtensions.cs Infrastructure container definitions
etc/*/ Infrastructure configuration files
appsettings.json (per service) Service-specific configuration
services/*/Data/*RuntimeDatabaseMigrator.cs Migration logic
services/*/Data/*DataSeeder.cs Data seeding logic

Generating a Signing Certificate

For production environments:

dotnet dev-certs https -v -ep openiddict.pfx -p 17bd45f0-e7c8-4350-a745-66c4d501ed8b

Client-Side Dependencies Setup

If client-side packages are missing:

# Install ABP CLI
dotnet tool install --global Volo.Abp.Studio.CLI --version X.Y.Z

# Or restore from local tool manifest
dotnet tool restore

# Install client-side libraries
abp install-libs

Health Checks

Each service exposes health checks at /health-status:

http://localhost:{port}/health-status

Use these to verify services are fully initialized before making requests.


Observability Guide

Metrics (Prometheus + Grafana)

  1. Access Grafana at http://localhost:3001

  2. Default credentials: admin / admin

  3. Pre-configured dashboards available in etc/grafana/dashboards/

  4. Prometheus data source auto-configured

    grafana-dashboards

Adding a New Service to Prometheus

To enable metrics scraping for a new microservice, add a job entry to etc/prometheus/prometheus.yml:

scrape_configs:
  # ... existing jobs ...

  - job_name: 'your-new-service'
    scheme: http
    metrics_path: 'metrics'
    static_configs:
      - targets: ['host.docker.internal:<PORT>']

Example: Adding a new reporting service on port 44399:

  - job_name: 'reporting'
    scheme: http
    metrics_path: 'metrics'
    static_configs:
      - targets: ['host.docker.internal:44399']

Note: Use host.docker.internal to access services running on the host from within Docker containers.

After updating, restart the Aspire AppHost to apply changes.

Current configured services:

Job Name Port Service
identity 44321 Identity Service
administration 44355 Administration Service
tenantmanagement 44348 Tenant Management Service
auditlogging 44328 Audit Logging Service
datamanagement 44378 Data Management Service
authserver 44346 Auth Server
web 44304 Web Application

Tracing (Jaeger)

  1. Access Jaeger at http://localhost:16686

  2. Select a service from the dropdown

  3. View distributed traces across microservices

  4. Analyze request latency and bottlenecks

    jaeger

Logging (Elasticsearch + Kibana)

  1. Access Kibana at http://localhost:5601

  2. Create index pattern for logs-*

  3. Explore logs in Discover tab

  4. Build visualizations and dashboards

    kibana-create-dataview

OpenTelemetry Collector

The OTel Collector receives telemetry from all services and exports to:

  • Metrics → Prometheus
  • Traces → Jaeger
  • Logs → Elasticsearch

Configuration: etc/otel/otel-collector-config.yaml


Troubleshooting

Problem Solution
Cannot connect to PostgreSQL Ensure Docker Desktop is running: docker ps
Port already in use Stop other services using same ports
OpenIddict client not found IdentityService didn't seed — check logs
Infrastructure containers not starting Run docker system prune and retry

Manual Database Reset (Development Only)

# Connect to PostgreSQL
docker exec -it <postgres-container-id> psql -U postgres

# Drop databases (they will be recreated on service startup)
DROP DATABASE "Gmss_Identity";
DROP DATABASE "Gmss_Administration";
DROP DATABASE "Gmss_AuditLogging";
DROP DATABASE "Gmss_TenantManagement";
DROP DATABASE "Gmss_BackgroundJobs";
DROP DATABASE "Gmss_AbpBlobStoring";
DROP DATABASE "Gmss_Cim";
\q

# Restart Aspire AppHost
cd aspire\GridLab.Gmss.AppHost
dotnet run

Helpful Commands

# Check running containers
docker ps

# View container logs
docker logs <container-id>

# Reset all databases (development only)
docker exec -it <postgres-container> psql -U postgres -c "DROP DATABASE \"Gmss_Identity\";"
# ... repeat for other databases

# Restart the entire stack
cd aspire\GridLab.Gmss.AppHost
dotnet run

Production Deployment

For production environments:

  1. Pre-create databases on your PostgreSQL server
  2. Run migrations manually using CI/CD pipeline
  3. Configure connection strings via environment variables or secrets
  4. Disable auto-migration in production configuration
  5. Use proper SSL certificates (not dev-certs)
  6. Configure external observability (cloud-based monitoring)

Example migration command:

dotnet ef database update --project services/identity/GridLab.Gmss.IdentityService
dotnet ef database update --project services/administration/GridLab.Gmss.AdministrationService
# ... repeat for other services

Summary

Do Don't
Use Aspire AppHost for development Start AuthServer before other services
Wait for health checks before testing Manually create database tables
Check service logs if migrations fail Run multiple instances during first startup
Use docker ps to verify containers Modify infrastructure configs without testing

Need Help? Check the logs in each service's output or the Aspire Dashboard for detailed migration progress and errors