Skip to main content

Project Structure

Solution Architecture & Module Inventory

Solution Overview

The Ampra platform is organised as a multi-project .NET solution augmented by three non-.NET modules — a React SPA, a Python ML microservice, and a Docusaurus documentation site. Every module lives under the src/ directory.


Module Dependency Graph


Module Details

Ampra.Web

AttributeValue
TypeASP.NET Core Web Application
Framework.NET 10.0
Entry PointProgram.csStartup.cs
ResponsibilitiesHTTP routing, authentication, middleware, background jobs

Houses all 16 controllers, the GlobalExceptionMiddleware, the OwnershipFilter, and three Quartz.NET background jobs. Configures Identity, cookie authentication, CORS, Redis, PostgreSQL, MongoDB, MinIO, and SendGrid integrations in Startup.cs.

Key directories:

DirectoryPurpose
Controllers/16 API controllers including AuthenticatedControllerBase
Middleware/GlobalExceptionMiddleware — maps exceptions to HTTP status codes
Filters/OwnershipFilter — enforces resource-level access control
Jobs/UpdateWeatherDataJob, DailyPredictionJob, DownsampleDataJob
Properties/Launch settings for local development

Ampra.Application

AttributeValue
TypeClass Library
Framework.NET 10.0
DependenciesAmpra.Core, FluentValidation
ResponsibilitiesService contracts, request/response models, input validation

Defines the 18 service interfaces that Ampra.Infrastructure implements. All DTOs, request models, and response models live here, keeping the contract layer decoupled from implementation details.

Key directories:

DirectoryContents
Interfaces/18 service interfaces (IAuthService, ISunSourceService, etc.)
Models/Request/response DTOs grouped by domain (Auth, Admin, SunSource, etc.)
Validators/10 FluentValidation validators for all write operations

Ampra.Infrastructure

AttributeValue
TypeClass Library
Framework.NET 10.0
DependenciesAmpra.Application, Ampra.Core, EF Core, MongoDB.Driver, StackExchange.Redis, MimeKit, SendGrid, MinIO SDK
ResponsibilitiesAll service implementations, database contexts, external API calls

Every interface defined in Ampra.Application has its implementation here. This module owns the ApplicationDbContext (PostgreSQL via EF Core), MongoDB data access, Redis caching, MinIO file storage, ML microservice HTTP client, Open-Meteo integration, and SendGrid email dispatch.

Key directories:

DirectoryContents
Services/18 service implementations
Data/ApplicationDbContext, EF Core migrations, seed data

Ampra.Core

AttributeValue
TypeClass Library
Framework.NET 10.0
DependenciesNone (leaf module)
ResponsibilitiesShared types referenced by all other .NET modules

The dependency-free foundation of the solution. Contains entities, constants, configuration POCOs, email templates, and custom exceptions. Both the main API and the MQTT worker reference this module.

Key directories:

DirectoryContents
Entities/EF Core entity classes (ApplicationUser, SunSource, PowerGroup, etc.)
Constants/14 static constant classes and enums
Configuration/MinIOSettings, MqttBrokerSettings
Templates/HTML + plaintext email templates
Exceptions/NotFoundException

Ampra.MQTT

AttributeValue
Type.NET Worker Service
Framework.NET 10.0
DependenciesAmpra.Core, MQTTnet, MongoDB.Driver, Npgsql
ResponsibilitiesReal-time MQTT telemetry ingestion

A standalone background worker that connects to the EMQX broker, subscribes to device telemetry topics, normalises incoming JSON, and inserts documents into MongoDB. Runs as its own Docker container independent of the web API.

Key components:

FilePurpose
Worker.csBackgroundService — connect, subscribe, message dispatch loop
Services/DataNormalizer.csField alias resolution, value range validation, JSON → NormalizedSunSourceData
Services/MongoIngestionService.csInsert with throttling, deduplication, and index management
Services/SourceValidator.csPostgreSQL lookup with 5-minute TTL cache
Configuration/MqttSettings.csBroker host, port, client ID, credentials, topic filter
Configuration/IngestionSettings.csThrottle seconds, dedup window, max payload bytes

Ampra.ML

AttributeValue
TypePython Flask microservice
RuntimePython 3.12, Gunicorn
DependenciesFlask, XGBoost, scikit-learn, pandas, NumPy, pymongo, requests
ResponsibilitiesModel training and physics-aware solar production prediction

Exposes two HTTP endpoints (/train, /predict) consumed by the .NET API. Uses XGBoost for regression, incorporates physical solar parameters (panel tilt, azimuth, capacity, atmospheric attenuation), and stores model artefacts in MongoDB GridFS.

FilePurpose
app.pyFlask application, API routes, Redis job status reporting
trainer.pyData fetching, feature engineering, XGBoost model training
predictor.pyModel loading, weather integration, physics-aware prediction
constants.pyShared string constants

Ampra.UI

AttributeValue
TypeReact 19 SPA
BuildVite, TypeScript
DependenciesTanStack Router, TanStack Query, Tailwind CSS v4, Recharts, Leaflet
ResponsibilitiesEnd-user web interface

Single-page application served via nginx. Uses file-based routing (TanStack Router), server-state management (TanStack Query), and cookie authentication against the API.


Ampra.Docs

AttributeValue
TypeDocusaurus 3.9.2
BuildNode.js, TypeScript
ResponsibilitiesPlatform documentation

This documentation site. Auto-generated sidebar from the docs/ directory structure. Deployed behind Traefik at docs.ampra.solar.


Configuration Models

MinIOSettings

public class MinIOSettings
{
public string Endpoint { get; set; }
public string PublicUrl { get; set; }
public string AccessKey { get; set; }
public string SecretKey { get; set; }
public string BucketName { get; set; } // "ampra-assets"
public bool UseSSL { get; set; }
public bool PublicUseSSL { get; set; }
}

Bound from the MinIO configuration section. Endpoint is the internal Docker network address, PublicUrl is the public-facing URL used when constructing file download links returned to clients.

MqttBrokerSettings

public class MqttBrokerSettings
{
public string Host { get; set; }
public int Port { get; set; }
public string InternalHost { get; set; }
public string SuperUser { get; set; }
public string SuperPassword { get; set; }
public string InternalApiKey { get; set; }
}

Bound from the MqttBroker configuration section. Host / Port are the public-facing values used for client connection strings. InternalHost is the Docker-internal hostname. InternalApiKey secures internal-only MQTT auth callbacks.


Custom Exceptions

NotFoundException

public class NotFoundException : Exception
{
public NotFoundException(string message) : base(message) { }
}

Thrown by any service when a requested resource does not exist. The GlobalExceptionMiddleware catches this and returns 404 Not Found with the message as the response body.

ExceptionHTTP StatusUsage Example
NotFoundException404Sun source, power group, user, or price record not found
UnauthorizedAccessException403Ownership check failure
ArgumentException400Invalid request parameters
Unhandled exceptions500Logged and returned as generic error

Email Templates

The platform sends two categories of transactional email, each with an HTML and plaintext variant:

Verification Code Email

Template: Templates/VerificationCode.html + VerificationCode.txt

Sent immediately after user registration. Contains a 6-digit numeric code with a 10-minute expiry. The HTML variant uses luxury-grade styling with the Ampra brand palette.

Placeholders:

TokenValue
{{firstName}}User's first name
{{code}}6-digit verification code

Welcome Email

Template: Templates/Welcome.html + Welcome.txt

Sent after successful email verification. Confirms the account is active and provides a link to the platform dashboard.

Placeholders:

TokenValue
{{firstName}}User's first name