TECHNICAL REPORT

The Architectural
Blueprint

A comprehensive deconstruction of the enterprise architecture powering our applications. From the "Smart Orchestrator" frontend to the In-Database AI vector engine.

1. The "Smart Orchestrator" Pattern

We strictly decouple UI (`.razor`) from Logic using the Orchestrator Pattern. The view is intentionally "dumb"—it only handles layout and binding.

The GenericListOrchestrator is a reusable powerhouse that handles:

  • Reactive Search (Debounced via System.Reactive)
  • State Management (Busy, Error, Data)
  • Real-time SignalR integration
List.razor.cs
01
protected override async Task OnInitializedAsync()
02
{
03
  // The Orchestrator handles all complexity
04
  _orchestrator = new GenericListOrchestrator<MerchantDto>(
05
    apiFunc: _client.GetPagedMerchantsAsync,
06
    signalR: _hub.StreamMerchantUpdates
07
  );
08

09
  // Reactive Search Pipeline
10
  _orchestrator.SearchSubject
11
    .Throttle(TimeSpan.FromMilliseconds(400))
12
    .Subscribe(RefreshGrid);
13
}

2. Master-Detail Composition

Complex forms use a Centralized State Orchestrator. It holds the primary entity and all child collections as a single source of truth.

We use a Data Down, Events Up communication pattern. Child components (`ChildTab.razor`) manage their own UI logic but notify the parent Orchestrator via `EventCallback` to synchronize the global state.

MasterPage.razor (Orchestrator)
↓ [Parameter] Data
ChildTab A
ChildTab B
↑ EventCallback (OnAdded)
Orchestrator.RefreshState()

3. The Analytics Pipeline

Dashboards are not just data dumpers. The code-behind acts as a pipeline orchestrator:

  1. Ingest: Parallel fetch of raw datasets.
  2. Analyze: Pass data to specialized C# Analyzers (`RiskAnalyzer`, `PredictionEngine`).
  3. Visualize: Map insights to `MudChart` and `MudDataGrid`.
Dashboard.razor.cs
01
var rawData = await Task.WhenAll(_loaders);
02

03
// Strategy Pattern for Analysis
04
RiskProfile = _riskAnalyzer.Analyze(rawData);
05
Forecast = _predictionEngine.Predict(rawData);
06

07
// Bind to UI
08
ChartSeries = Forecast.ToMudSeries();

4. FastEndpoints & REPR

We reject "Fat Controllers" in favor of the REPR Pattern (Request-Endpoint-Response).

Each endpoint is a single class with a single responsibility. It delegates business logic to a Service layer and handles HTTP concerns (Routing, Auth, Serialization).

Functional Safety: We use `Either` to handle errors without exceptions.

CreateMerchantEndpoint.cs
01
public class CreateEndpoint : Endpoint<Req, Resp>
02
{
03
  public override async Task HandleAsync(Req r, CancellationToken c)
04
  {
05
    var result = await _service.CreateAsync(r);
06

07
    // Functional match - No try/catch
08
    await result.Match(
09
      Right: m => SendOkAsync(new Resp(m)),
10
      Left: err => SendErrorsAsync(400, err)
11
    );
12
  }
13
}

5. Data Access Strategy

We employ a Cache-Aside Strategy built on the Repository Pattern.

  1. Read: Request hits `RedisReadRepository`. On miss, it falls back to `EfRepository` (SQL), then populates Redis.
  2. Write: Writes go to SQL. Cache invalidation logic immediately clears relevant Redis keys.
Service
Redis Repo
EF SQL Repo

Writes invalidate specific cache keys intelligently.

8. Advanced Specifications

We don't write LINQ in services. We use Ardalis Specifications to encapsulate query logic.

The V7 Graph Spec is an "In-Database BI Engine." It uses projection (`.Select()`) to translate complex C# calculations into optimized SQL, returning a flattened, pre-computed DTO.

MerchantAdvancedGraphSpecV7.cs
01
Query.Where(x => x.IsActive)
02
  .Select(c => new MerchantDto {
03
    // Runs inside SQL Engine
04
    AvgScore = c.Reviews.Average(r => r.Score),
05
    IsCritical = c.Debt > 50000,
06
    GraphMetric = c.Children.SelectMany(x => x.GrandKids).Count()
07
  });

9. Metadata-Driven Saga Engine

We don't hardcode workflows. Sagas are defined as JSON Recipes.

The engine uses a Finite State Machine (Stateless) and a Compensation Stack. If step 5 fails, the engine automatically rolls back steps 4, 3, 2, and 1.

SignalR
RabbitMQ
Polly
SagaRecipe.json
01
{
02
  "Flow": "Onboarding",
03
  "Steps": [
04
    { "Action": "CreateUser", "Compensate": "DeleteUser" },
05
    { "Action": "ChargeCard", "Compensate": "Refund" },
06
    { "Action": "SendEmail", "Policy": "Retry3x" }
07
  ]
08
}

12. Oracle 23ai Vector Integration

We leverage In-Database AI. No external vector DBs. No ETL pipelines.

The architecture allows for Hybrid Search: Combining precise SQL filters (WHERE Category = 'Tech') with fuzzy Semantic Search (VECTOR_DISTANCE) in a single, atomic query.

OracleVectorService.cs
01
const string sql = @"
02
SELECT * FROM Products p
03
WHERE p.Category = :category
04
ORDER BY VECTOR_DISTANCE(
05
p.Embedding,
06
VECTOR_EMBEDDING(:model USING :query)
07
)
08
FETCH FIRST 10 ROWS ONLY";

14. Performance as Code (NBomber)

We don't guess performance; we assert it. The solution includes a generated .PerformanceTests project.

  • Bogus: Generates realistic fake data payloads.
  • Scenarios: Simulates full CRUD lifecycles and complex parent-child creation loops.
  • Diagnostic Endpoints: Tests trigger internal benchmarks to compare query strategies (V4 vs V7) under load.
NBomber Runner
Virtual User 1
Virtual User 2
...
↓↓ Load (HTTP) ↓↓
API Endpoint (Performance Harness)