Project Structure
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
| Attribute | Value |
|---|---|
| Type | ASP.NET Core Web Application |
| Framework | .NET 10.0 |
| Entry Point | Program.cs → Startup.cs |
| Responsibilities | HTTP 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:
| Directory | Purpose |
|---|---|
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
| Attribute | Value |
|---|---|
| Type | Class Library |
| Framework | .NET 10.0 |
| Dependencies | Ampra.Core, FluentValidation |
| Responsibilities | Service 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:
| Directory | Contents |
|---|---|
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
| Attribute | Value |
|---|---|
| Type | Class Library |
| Framework | .NET 10.0 |
| Dependencies | Ampra.Application, Ampra.Core, EF Core, MongoDB.Driver, StackExchange.Redis, MimeKit, SendGrid, MinIO SDK |
| Responsibilities | All 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:
| Directory | Contents |
|---|---|
Services/ | 18 service implementations |
Data/ | ApplicationDbContext, EF Core migrations, seed data |
Ampra.Core
| Attribute | Value |
|---|---|
| Type | Class Library |
| Framework | .NET 10.0 |
| Dependencies | None (leaf module) |
| Responsibilities | Shared 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:
| Directory | Contents |
|---|---|
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
| Attribute | Value |
|---|---|
| Type | .NET Worker Service |
| Framework | .NET 10.0 |
| Dependencies | Ampra.Core, MQTTnet, MongoDB.Driver, Npgsql |
| Responsibilities | Real-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:
| File | Purpose |
|---|---|
Worker.cs | BackgroundService — connect, subscribe, message dispatch loop |
Services/DataNormalizer.cs | Field alias resolution, value range validation, JSON → NormalizedSunSourceData |
Services/MongoIngestionService.cs | Insert with throttling, deduplication, and index management |
Services/SourceValidator.cs | PostgreSQL lookup with 5-minute TTL cache |
Configuration/MqttSettings.cs | Broker host, port, client ID, credentials, topic filter |
Configuration/IngestionSettings.cs | Throttle seconds, dedup window, max payload bytes |
Ampra.ML
| Attribute | Value |
|---|---|
| Type | Python Flask microservice |
| Runtime | Python 3.12, Gunicorn |
| Dependencies | Flask, XGBoost, scikit-learn, pandas, NumPy, pymongo, requests |
| Responsibilities | Model 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.
| File | Purpose |
|---|---|
app.py | Flask application, API routes, Redis job status reporting |
trainer.py | Data fetching, feature engineering, XGBoost model training |
predictor.py | Model loading, weather integration, physics-aware prediction |
constants.py | Shared string constants |
Ampra.UI
| Attribute | Value |
|---|---|
| Type | React 19 SPA |
| Build | Vite, TypeScript |
| Dependencies | TanStack Router, TanStack Query, Tailwind CSS v4, Recharts, Leaflet |
| Responsibilities | End-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
| Attribute | Value |
|---|---|
| Type | Docusaurus 3.9.2 |
| Build | Node.js, TypeScript |
| Responsibilities | Platform 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.
| Exception | HTTP Status | Usage Example |
|---|---|---|
NotFoundException | 404 | Sun source, power group, user, or price record not found |
UnauthorizedAccessException | 403 | Ownership check failure |
ArgumentException | 400 | Invalid request parameters |
| Unhandled exceptions | 500 | Logged 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:
| Token | Value |
|---|---|
{{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:
| Token | Value |
|---|---|
{{firstName}} | User's first name |