20 KiB
ADAS Core Backend API
ADAS Core — Backend platform developed by Epigram Technologies.
Implements Clean Architecture with a Modular Monolith pattern, built on .NET 8 and designed for scalability, maintainability, and flexible deployment in industrial and institutional environments.
Table of Contents
- Overview
- Architecture
- Solution Structure
- Functional Modules
- Getting Started
- Configuration
- Authentication
- Logging
- Testing
- Technologies & Dependencies
- Conventions & Best Practices
Overview
ADAS Core is the main backend API for the ADAS platform. It follows a modular monolith architecture where business domains are organized into independent modules while sharing a common infrastructure and application core.
Key characteristics:
- Clean Architecture: Clear separation between Domain, Application, Infrastructure, and Presentation layers.
- Modular Monolith: Business modules are self-contained and can be extracted into microservices if needed.
- Pluggable Authentication: Supports multiple authentication strategies via a common abstraction layer.
- Structured Logging: Full observability through Serilog with multiple sinks and enrichers.
- Production Ready: Multi-configuration builds, Docker support, Prometheus metrics, and comprehensive test coverage.
Architecture
The architecture follows the principles of Clean Architecture (Onion Architecture), ensuring that business rules remain independent of frameworks, UI, and infrastructure concerns.
Design Principles
| Principle | Description |
|---|---|
| Dependency Rule | Dependencies always point inward. The Domain layer has zero external dependencies. |
| Separation of Concerns | Each layer has a single responsibility (Domain, Application, Infrastructure, Authentication, Modules). |
| Framework Independence | The Domain layer contains pure business logic without references to ASP.NET Core, databases, or external libraries. |
| Testability | Business rules can be unit-tested in isolation without infrastructure concerns. |
| Modularity | Functional domains are encapsulated in independent modules with minimal shared surface. |
Layer Responsibilities
| Layer | Projects | Responsibility |
|---|---|---|
| Domain | adas-core.Domain |
Entities, value objects, domain events, business rules, and repository interfaces. |
| Application | adas-core.Application |
Use cases, application services, DTOs, and orchestration logic. |
| Infrastructure | adas-core.Infrastructure |
Persistence, messaging, caching, external APIs, and technical concerns. |
| Authentication | adas-core.Authentication |
Authentication abstractions, JWT handling, and security middleware. |
| Presentation | adas-core (Host) |
ASP.NET Core Web API, controllers, dependency injection composition, and module registration. |
| Modules | adas-core.module.* |
Independent business domains with their own entities, services, and controllers. |
Architecture Diagram
flowchart TB
subgraph Presentation["Presentation Layer"]
H[adas-core Host<br/>ASP.NET Core Web API]
end
subgraph Auth["Authentication Layer"]
A[adas-core.Authentication<br/>JWT / Middleware / Abstractions]
L[adas-core.LdapLogin]
Lo[adas-core.LocalLogin]
end
subgraph Application["Application Layer"]
AP[adas-core.Application<br/>Use Cases / Services / DTOs]
end
subgraph Domain["Domain Layer"]
D[adas-core.Domain<br/>Entities / Rules / Interfaces]
end
subgraph Infrastructure["Infrastructure Layer"]
I[adas-core.Infrastructure<br/>Persistence / Messaging / Cache]
end
subgraph Modules["Business Modules"]
M1[module.LightBeacons]
M2[module.ProxyDevices]
M3[module.Relays]
end
H --> A
H --> AP
AP --> D
A --> AP
A --> D
L --> A
Lo --> A
Lo --> I
I --> AP
I --> M1
I --> M3
M1 --> D
M2 --> D
M3 --> D
Request Flow Example
sequenceDiagram
participant Client
participant Host as adas-core (Host)
participant Auth as Authentication
participant App as Application
participant Mod as Module
participant Inf as Infrastructure
participant DB as Database
Client->>Host: HTTP Request
Host->>Auth: Validate JWT / Authenticate
Auth-->>Host: ClaimsPrincipal
Host->>App: Invoke Use Case
App->>Mod: Execute Business Logic
Mod->>Inf: Persist / Query
Inf->>DB: Database Operation
DB-->>Inf: Result
Inf-->>Mod: Data
Mod-->>App: Domain Result
App-->>Host: DTO / Response
Host-->>Client: HTTP Response
Note on Dependencies: The
Infrastructureproject references theApplicationand specific modules it supports. Modules referenceDomain(preferentially) orApplicationfor shared abstractions. The Host references all layers and wires them together via the dependency injection container.
Solution Structure
adas-core/
├── adas-core.sln # Main solution file
├── Dockerfile # Multi-stage Linux image
├── .dockerignore # Docker build exclusions
├── .gitignore / .gitattributes # Version control
│
├── adas-core/ # API Host (ASP.NET Core Web)
│ ├── Program.cs # Application bootstrap
│ ├── appsettings.json # Base configuration
│ ├── appsettings.Local.json # Local overrides
│ └── Properties/
│ └── launchSettings.json # Launch profiles
│
├── adas-core.Domain/ # Pure Domain layer
│ ├── Entities/
│ ├── ValueObjects/
│ ├── Interfaces/ # Repository contracts
│ └── Events/ # Domain events
│
├── adas-core.Application/ # Use Case layer
│ ├── Services/ # Application services
│ ├── DTOs/ # Data transfer objects
│ └── Interfaces/ # Service contracts
│
├── adas-core.Infrastructure/ # Technical Infrastructure
│ ├── Persistence/ # Data access implementations
│ ├── Messaging/ # RabbitMQ / EasyNetQ wrappers
│ └── Cache/ # Redis abstractions
│
├── adas-core.Authentication/ # Security abstractions
│ ├── TokenService.cs # JWT generation / validation
│ └── Middleware/ # Auth middleware
│
├── adas-core.LdapLogin/ # LDAP / Active Directory strategy
│ └── LdapAuthenticationService.cs
│
├── adas-core.LocalLogin/ # Local database strategy
│ └── LocalAuthenticationService.cs
│
├── adas-core.module.LightBeacons/ # Functional module: Light Beacons
│
├── adas-core.module.ProxyDevices/ # Functional module: Proxy Devices
│
├── adas-core.module.Relays/ # Functional module: Relays
│
└── adas-core.Test/ # Automated test suite (NUnit)
Cross-Project Reference Rules
adas-core.Host → references → Domain, Application, Infrastructure, Authentication, Modules
adas-core.Application → references → Domain
adas-core.Infrastructure → references → Application, Modules
adas-core.Authentication → references → Application, Domain
adas-core.LdapLogin → references → Authentication
adas-core.LocalLogin → references → Authentication, Infrastructure
Modules → references → Domain (preferentially)
adas-core.Test → references → Domain, Infrastructure, Host
Functional Modules
Each module is an autonomous functional domain encapsulating its own business logic, entities, and services.
| Module | Project | Description |
|---|---|---|
| LightBeacons | adas-core.module.LightBeacons |
Management and control of light beacons: state, lighting patterns, visual alerts, and synchronization. |
| ProxyDevices | adas-core.module.ProxyDevices |
Administration of intermediary devices: registration, heartbeat, remote configuration, and telemetry. |
| Relays | adas-core.module.Relays |
Control of electromechanical/electronic relays: ON/OFF commands, time scheduling, and real-time status. |
Modules communicate with each other preferentially through domain events published via
EasyNetQ(RabbitMQ). This ensures loose coupling and allows future extraction into independent microservices.
Module Interaction Diagram
flowchart LR
subgraph Core["Application Core"]
A[Application Layer]
D[Domain Layer]
I[Infrastructure Layer]
end
subgraph Modules["Business Modules"]
M1[LightBeacons]
M2[ProxyDevices]
M3[Relays]
end
subgraph Bus["Message Bus"]
R[(RabbitMQ\nvia EasyNetQ)]
end
M1 -->|reads/writes| I
M2 -->|reads/writes| I
M3 -->|reads/writes| I
M1 -->|depends on| D
M2 -->|depends on| D
M3 -->|depends on| D
M1 -.->|publishes events| R
M2 -.->|publishes events| R
M3 -.->|publishes events| R
R -.->|consumes events| M1
R -.->|consumes events| M2
R -.->|consumes events| M3
Getting Started
Prerequisites
| Requirement | Min. Version | Verification |
|---|---|---|
| .NET SDK | 8.0.x | dotnet --version |
| Docker (optional) | 24.x+ | docker --version |
| MongoDB (if not using Docker) | 6.0+ | mongod --version |
| Redis (if not using Docker) | 7.0+ | redis-cli --version |
| RabbitMQ (optional, for messaging) | 3.12+ | rabbitmqctl status |
Quick Start
# 1. Clone the repository
git clone <repository-url>
cd adas-core
# 2. Restore dependencies
dotnet restore adas-core.sln
# 3. Build the solution
dotnet build adas-core.sln --configuration Release
# 4. Run the API in development mode
cd adas-core
dotnet run --launch-profile "Development"
The API will be available by default at:
- HTTP:
http://localhost:5000 - HTTPS:
https://localhost:5001
(Ports are configurable in Properties/launchSettings.json.)
Docker Deployment
# Build the image
docker build -t adas-core:latest .
# Run the container
docker run -p 8080:80 \
-e ASPNETCORE_ENVIRONMENT=Production \
adas-core:latest
The
Dockerfileuses a multi-stage Linux-based build optimized for production deployment.
Build Configurations
The solution supports multiple build configurations for different environments:
| Configuration | Purpose |
|---|---|
Debug |
Local development with full debug symbols. |
DebugNoMedia |
Debug without embedded media resources (faster compilation). |
Release |
Optimized build for general production. |
ReleaseNoMedia |
Release without media resources (smaller artifact). |
H12O-Release |
Release profile for the H12O product line. |
HRYC-Release |
Release profile for the HRYC product line. |
SmacsServer |
Release profile for the SMACS server environment. |
# Example: build a specific profile
dotnet build adas-core.sln --configuration H12O-Release
All
ReleaseandH*-Releaseconfigurations enforceTreatWarningsAsErrors, ensuring production-quality code.
Configuration
appsettings.json
The application uses the standard ASP.NET Core configuration hierarchy:
{
"ConnectionStrings": {
"MongoDb": "mongodb://localhost:27017/adas-core",
"Redis": "localhost:6379"
},
"Authentication": {
"Scheme": "Local",
"Jwt": {
"Secret": "your-secret-key-min-32-characters-long",
"Issuer": "ADAS-Core",
"Audience": "ADAS-Clients",
"ExpirationMinutes": 60
}
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
}
}
}
Environment Variables
| Variable | Purpose | Example |
|---|---|---|
ASPNETCORE_ENVIRONMENT |
Runtime environment | Development, Staging, Production |
ASPNETCORE_URLS |
Binding URLs | http://+:80;https://+:443 |
ConnectionStrings__MongoDb |
MongoDB connection string | mongodb://... |
Authentication__Jwt__Secret |
JWT signing key | (use secrets manager in production) |
User Secrets
In development, store sensitive values using the .NET User Secrets manager:
cd adas-core
dotnet user-secrets set "Authentication:Jwt:Secret" "your-dev-secret-key"
Authentication
The system implements a multi-strategy authentication model using a provider pattern. The host application registers the appropriate strategy at runtime based on configuration.
Available Strategies
| Strategy | Project | Description |
|---|---|---|
| LDAP / Active Directory | adas-core.LdapLogin |
Corporate authentication against LDAP directories. Uses Novell.Directory.Ldap.NETStandard. |
| Local Database | adas-core.LocalLogin |
Internal authentication with users stored in MongoDB. Passwords hashed with BCrypt. |
Architecture
flowchart LR
subgraph AuthLayer["Authentication Abstraction"]
A[adas-core.Authentication\nJWT / Claims / Middleware]
end
subgraph Strategies["Concrete Strategies"]
L[adas-core.LdapLogin]
Lo[adas-core.LocalLogin]
end
subgraph Stores["Identity Stores"]
LDAP[(LDAP / AD Server)]
DB[(MongoDB)]
end
Client -->|HTTP Request| A
A -->|resolve strategy| L
A -->|resolve strategy| Lo
L -->|bind| LDAP
Lo -->|query| DB
Configuration Example
{
"Authentication": {
"Scheme": "Local",
"Jwt": {
"Secret": "<32-char-secret-key-here>",
"Issuer": "ADAS-Core",
"Audience": "ADAS-Clients",
"ExpirationMinutes": 60
},
"Ldap": {
"Server": "ldap.corp.local",
"Port": 636,
"UseSSL": true,
"BindDN": "CN=service,OU=Users,DC=corp,DC=local"
}
}
}
To switch strategies, change the Authentication:Scheme value to "Ldap" or "Local".
Logging
The application uses Serilog for structured logging, integrated natively with ASP.NET Core.
Features
- Structured JSON output for machine parsing and aggregation.
- Automatic enrichment with thread identifiers, exception details, and dynamic context properties.
- Multiple sinks: Console for containers, rolling files for persistence.
- Compact format for efficient storage and transmission.
Configured Sinks
| Sink | Output | Format |
|---|---|---|
| Console | Standard output / Docker logs | Compact JSON |
| File | ./Logs/log-.txt (daily rotation) |
Compact JSON |
Enrichers
| Enricher | Source | Purpose |
|---|---|---|
ThreadId |
Serilog.Enrichers.Thread |
Track request thread correlation. |
ExceptionDetails |
Serilog.Exceptions |
Capture full exception object graphs. |
DynamicProperties |
Serilog.Enrichers.Dynamic |
Add runtime context properties. |
Prometheus Metrics
The /metrics endpoint exposes application and runtime metrics in Prometheus-compatible format:
curl http://localhost:5000/metrics
Testing
The adas-core.Test project provides comprehensive test coverage using NUnit as the test framework.
Running Tests
# Full test suite
dotnet test adas-core.sln
# With code coverage
dotnet test adas-core.sln --collect:"XPlat Code Coverage"
# Verbose output
dotnet test adas-core.sln --logger "console;verbosity=detailed"
Test Types
| Type | Description | Tools |
|---|---|---|
| Unit | Isolated tests of domain rules and application services. | NUnit, Moq |
| Integration | End-to-end tests with embedded MongoDB (Mongo2Go). |
NUnit, Mongo2Go |
| Fakes | Isolated tests of external dependencies using assembly shims. | Microsoft Fakes |
Code Quality Gates
TreatWarningsAsErrors = True(Debug / Release)- Nullable reference types enabled across all projects
- NUnit static analysis via
NUnit.Analyzers - Coverlet code coverage collection
Technologies & Dependencies
Framework & Runtime
| Technology | Version |
|---|---|
| .NET / ASP.NET Core | 8.0 |
| C# Language | 12 |
Key Libraries
| Category | Package | Version | Purpose |
|---|---|---|---|
| ORM | Microsoft.EntityFrameworkCore |
8.0.27 | Relational data access |
| NoSQL | MongoDB.Driver / MongoDB.Bson |
3.9.0 | MongoDB access and serialization |
| Migrations | MongoMigrations.Core |
4.0.15 | MongoDB schema migrations |
| Cache | StackExchange.Redis |
2.13.17 | Distributed caching |
| Messaging | EasyNetQ |
8.1.4 | RabbitMQ async messaging |
| Push | WebPush |
1.0.13 | Browser push notifications |
| Auth | Microsoft.AspNetCore.Authentication.JwtBearer |
8.0.8 | JWT Bearer authentication |
| Auth | System.IdentityModel.Tokens.Jwt |
8.18.0 | JWT token handling |
| Security | BCrypt.Net-Next |
4.2.0 | Password hashing |
| Security | Novell.Directory.Ldap.NETStandard |
4.0.0 | LDAP integration |
| Validation | FluentValidation |
12.1.1 | Input validation rules |
| Mapping | AutoMapper |
16.1.1 | Entity <-> DTO mapping |
| Scheduling | Quartz |
3.18.1 | Background job scheduling |
| Scripts | Microsoft.CodeAnalysis.CSharp.Scripting |
5.3.0 | Dynamic C# evaluation |
| Logging | Serilog + sinks + enrichers |
4.x | Structured logging pipeline |
| Metrics | prometheus-net.AspNetCore |
8.2.1 | Prometheus metrics endpoint |
| Testing | NUnit / NUnit3TestAdapter |
4.6.1 / 6.2.0 | Unit testing framework |
| Testing | Moq |
4.20.72 | Dependency mocking |
| Testing | Mongo2Go |
4.1.0 | Embedded MongoDB for tests |
| Testing | coverlet.collector |
10.0.1 | Code coverage |
Conventions & Best Practices
Code Style
- Naming:
PascalCasefor types, methods, and properties;camelCasefor parameters and locals. - Namespaces: Must match the physical file path (e.g.,
adas_core.Domain.Entities). - Nullables: Explicit nullable reference types are enforced (
nullable enable). - Interfaces: Prefixed with
I(e.g.,IRepository<T>,ITokenService). - Async: Asynchronous method names must end with
Asyncsuffix. - XML Docs: All public APIs must include XML documentation comments.
Dependency Direction
- The Domain layer must never reference any other project.
- Application depends only on Domain.
- Infrastructure depends on Application and modules it supports.
- Authentication depends on Application and Domain.
- Concrete login strategies depend on Authentication.
- Modules depend on Domain (preferentially) or Application for shared abstractions.
- Tests reference the layers under test; use mocking for external dependencies.
Commit Messages
Use descriptive English commit messages following conventional commits:
feat(beacon): add color pattern validation
fix(auth): resolve JWT expiration drift
refactor(infra): extract Redis connection factory
docs(readme): update build instructions
Scalability Notes
- Modules are designed to be extracted as independent microservices with minimal changes.
- Domain events enable asynchronous inter-module communication without tight coupling.
- Message bus (RabbitMQ via EasyNetQ) supports horizontal scaling of consumers.
- Redis caching layer reduces database load for frequently accessed data.
- Prometheus metrics allow monitoring and alerting in container orchestration environments.
License
Copyright (c) Epigram Technologies — All rights reserved.
This software is proprietary and confidential. Reproduction, distribution, or modification without express written authorization from Epigram Technologies is prohibited.
ADAS Core v2.1 | Built with .NET 8