# Fuchs Intranet — Solution Architecture > Auto-generated architecture analysis > .NET 10 · ASP.NET Core MVC · SQL Server --- ## 1. Solution Overview The **Fuchs Intranet** solution is a line-of-business web application for **Sebastian Fuchs Bad und Heizung GmbH & Co. KG** (a plumbing/heating company in Düsseldorf). It manages invoices, reminders, service requests, banking transactions, reports, and user authentication — all exposed through a single-page intranet front-end. | Project | Type | Purpose | |---|---|---| | **Fuchs** | ASP.NET Core Web (MVC) | Main web application — the intranet | | **Fuchs_DataService** | Console / Windows Service (Topshelf) | Background data sync service (MFR ERP polling) | | **MFR_RESTClient** | Class Library | REST/OData client for the MFR ERP system | | **OCORE** | Class Library (shared) | Core utilities: SQL, crypto, email, IO, logging | | **OCORE_web** | Class Library (shared) | Web utilities: MVC helpers, middleware, auth, captcha | | **OCORE_web_pdf** | Class Library (shared) | PDF generation (MigraDoc/PDFsharp, HTML→PDF) | | **OCORE_Charting** | Class Library (shared) | Data visualization / charting (ported System.Windows.Forms.DataVisualization) | | **MT940Parser** | Class Library (shared) | SWIFT MT940/MT942 bank statement parser | **All projects target `net10.0`.** --- ## 2. Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ CLIENTS (Browser) │ │ SPA-like JS front-end (js/intranet/) │ └──────────────────────────────┬──────────────────────────────────────────┘ │ HTTP (GET / POST) ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Fuchs (ASP.NET Core MVC) │ │ │ │ Program.cs ─── ConfigureServices / ConfigureApp │ │ │ │ │ ├── Cookie Authentication (scheme: "fuchs_intranet") │ │ ├── Distributed Memory Cache │ │ └── DI Registrations: │ │ • Fuchs_intranet (singleton — config + auth + DB helper) │ │ • IFdsMfr → FdsMfr (singleton — ERP sync) │ │ │ │ Routes: │ │ /{fn?}/{id?}/{code?} → IntranetController.Index (SPA shell) │ │ /do/{fn?}/{id?}/{code?} → IntranetController.Do (API) │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ IntranetController (partial class) │ │ │ │ │ │ │ │ .cs — core: Index, Do dispatcher, Auth, Login/Logout │ │ │ │ .Invoices.cs — invoice CRUD, DATEV export, PDF │ │ │ │ .Invoices2.cs— invoice sub-handlers (MFR refresh, get, list) │ │ │ │ .Reminder.cs — payment reminder CRUD + PDF │ │ │ │ .Requests.cs — service request management │ │ │ │ .Banking.cs — MT940 upload, transaction queries │ │ │ │ .Reports.cs — report catalog, execution │ │ │ └──────────┬──────────────────────────────────────────────────────┘ │ │ │ calls │ │ ┌──────────▼──────────────────────────────────────────────────────┐ │ │ │ code/ (Business Logic) │ │ │ │ │ │ │ │ FuchsIntranet.cs — Fuchs_intranet singleton (config, auth, │ │ │ │ DB connections, debug logging) │ │ │ │ FdsInvoiceData.cs — Invoice data model + PDF generation │ │ │ │ FdsReminderData.cs — Reminder data model + PDF generation │ │ │ │ FuchsPdf.cs — PDF layout/rendering (MigraDoc) │ │ │ │ FuchsWidgets.cs — Dashboard widget data (SQL-driven) │ │ │ │ FuchsReports.cs — Report dispatch │ │ │ │ FuchsFdsEmail.cs — Email sending + DB logging │ │ │ │ Banking.cs — MT940 parsing to DataTable │ │ │ │ MigraDocExtensions — MigraDoc helper extensions │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ Logging/FuchsLoggerProvider.cs — custom ILoggerProvider │ └────────┬────────────────┬──────────────────┬───────────────────────┬────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ ┌──────────────────┐ │ OCORE │ │ OCORE_web │ │ OCORE_web_pdf │ │ MT940Parser │ │ │ │ │ │ │ │ │ │ • SQL helper │ │ • MVC helper │ │ • MigraDoc/ │ │ • SWIFT MT940/ │ │ (ADO.NET) │ │ (JSON,File)│ │ PDFsharp │ │ MT942 parser │ │ • Email │ │ • Cookie Auth│ │ • HTML→PDF │ │ │ │ • IO/Files │ │ • Middleware │ │ • Font resolver │ │ │ │ • Crypto │ │ • Captcha │ │ │ │ │ │ • Logging │ │ • Background │ │ │ │ │ │ • CSV/XML │ │ services │ │ │ │ │ │ • DateTime │ │ • Security │ │ │ │ │ └──────────────┘ └──────────────┘ └────────────────┘ └──────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Fuchs_DataService (Windows Service / Console) │ │ │ │ FdsMain.cs — Topshelf host, job definitions │ │ PeriodicHostedService — BackgroundService with PeriodicTimer │ │ FdsMfr.cs (IFdsMfr) — MFR sync orchestration │ │ FdsMfrClient.cs — MFR REST client wrapper │ │ FdsShared.cs — FdsConfig (appsettings.json reader) │ │ FdsZip.cs — 7-Zip archive handling (DATEV export) │ │ FdsDebug.cs — Debug/file logging │ │ │ │ Jobs: MfrSync (every N min) │ │ → UpdateIfNecessary_async (entity table sync) │ │ → UpdateRequested_async (on-demand entity refresh) │ │ → GetInvoiceFiles_async (invoice PDF download) │ └────────────────────────┬────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ MFR_RESTClient │ │ │ │ MFRClient.cs — RestSharp-based REST/OData client │ │ MFRClientModels.cs — Config, credentials, entity types │ │ ODataEnvelope.cs — OData response wrapper │ │ Entities/MfrGeneric.cs— Generic entity helpers │ └────────────────────────┬────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────┐ │ MFR ERP System │ │ (External REST) │ └─────────────────────┘ ┌─────────────────────┐ All projects ──────►│ SQL Server │ │ (fuchs_fds DB) │ │ Stored procedures │ │ Symmetric key enc. │ └─────────────────────┘ ``` --- ## 3. Dependency Graph ``` Fuchs (Web) ├── OCORE ├── OCORE_web ──► OCORE ├── OCORE_web_pdf ├── MT940Parser ├── MFR_RESTClient └── Fuchs_DataService ├── OCORE ├── OCORE_web └── MFR_RESTClient OCORE_Charting (standalone — referenced by solution but no direct project reference) ``` --- ## 4. Key Architectural Patterns ### 4.1 Partial Controller Pattern `IntranetController` is split across **7 partial-class files**, each handling a business domain (invoices, reminders, banking, etc.). The main `Do()` action uses a `switch` expression to dispatch to domain-specific methods. ### 4.2 Singleton Configuration Object `Fuchs_intranet` is a manually-managed singleton (via `FuchsOcmsIntranet`) initialized at startup with `IConfiguration`. It holds connection strings, app settings, auth helpers, and DB connection factory methods. ### 4.3 Static Business Logic Classes Most business logic lives in **static classes** (`FuchsPdf`, `FuchsWidgets`, `FuchsReports`, `FuchsFdsEmail`, `Banking`) that receive the controller instance or `Fuchs_intranet` as a parameter. This is a legacy pattern from the VB.NET conversion. ### 4.4 SQL-First Data Access There is no ORM (no EF Core). All data access uses **ADO.NET via OCORE SQL helpers** (`getSQLDatatable_async`, `getSQLDataSet_async`, `setSQLValue_async`) calling stored procedures and inline SQL. `DataTable`/`DataRow` is the primary data transfer mechanism. ### 4.5 Background Service `Fuchs_DataService` runs as a Windows Service (Topshelf) with a `PeriodicHostedService` that polls the MFR ERP system on a timer, syncing entities and downloading invoice files. ### 4.6 Authentication Cookie-based authentication (`CookieAuthenticationDefaults`) with custom claims (`FuchsUserIdentity`). SQL-based user/password verification. --- ## 5. DI Service Extraction Candidates The following static classes and tightly-coupled code sections are strong candidates for refactoring into proper DI-registered services. This improves testability, decouples dependencies, and aligns with ASP.NET Core best practices. --- ### 5.1 `FuchsFdsEmail` → `IEmailService` **Current state:** Static class using `System.Configuration.ConfigurationManager` (legacy!) and receiving `Fuchs_intranet` as a parameter. **Problem:** Uses `cfg.AppSettings["FDS_EmailSettings"]` — violates the project's own rule to not use `System.Configuration.ConfigurationManager`. Untestable. Static state (`_settings` cache). **Proposed service:** ```csharp public interface IEmailService { Task SendEmailAsync(string reference, string subject, string html, string email, string name, Dictionary? attachments); } public class FuchsEmailService : IEmailService { private readonly EmailServerSettings _settings; private readonly Fuchs_intranet _intranet; // Inject IConfiguration, Fuchs_intranet, ILogger } ``` **Registration:** `builder.Services.AddSingleton();` **Files affected:** `Fuchs\code\FuchsFdsEmail.cs`, all callers in controller partials. --- ### 5.2 `FuchsPdf` → `IPdfService` **Current state:** Large static class with static helper methods, hardcoded license key, company-specific constants. **Problem:** Not injectable, not testable, mixes configuration (colors, company data) with PDF rendering logic. **Proposed service:** ```csharp public interface IPdfService { Document CreateInvoicePdf(FdsInvoiceData invoice); Document CreateReminderPdf(FdsReminderData reminder); Task DocToImageCollectionAsync(Document doc); } public class FuchsPdfService : IPdfService { // Inject ILogger // Company data could come from IOptions } ``` **Registration:** `builder.Services.AddSingleton();` **Files affected:** `Fuchs\code\FuchsPdf.cs`, `FdsInvoiceData.cs`, `FdsReminderData.cs`, controller partials. --- ### 5.3 `FuchsWidgets` → `IWidgetService` **Current state:** Static class that receives the entire `IntranetController` as a parameter to access `_intranet`, `UserAccountID`, `DbSec`, etc. **Problem:** Tight coupling to controller — passes the whole controller instance. Cannot be unit tested independently. **Proposed service:** ```csharp public interface IWidgetService { Task GetUserWidgetsAsync(string userAccountId, DatabaseSecurity dbSec); Task GetWidgetDataAsync(string widgetId, string userAccountId, DatabaseSecurity dbSec); Task GetSingleWidgetAsync(string shortName, string userAccountId, DatabaseSecurity dbSec); } public class FuchsWidgetService : IWidgetService { private readonly Fuchs_intranet _intranet; // Inject Fuchs_intranet, ILogger } ``` **Registration:** `builder.Services.AddScoped();` **Files affected:** `Fuchs\code\FuchsWidgets.cs`, `IntranetController.cs` (Do method). --- ### 5.4 `Banking` → `IBankingService` **Current state:** Static class with MT940 parsing logic. **Problem:** Minor — already fairly stateless, but takes `ILogger` as parameter instead of injection. **Proposed service:** ```csharp public interface IBankingService { DataTable ParseMT940(Stream stream, DataTable? schema = null); } public class BankingService : IBankingService { private readonly ILogger _logger; // Inject ILogger } ``` **Registration:** `builder.Services.AddSingleton();` **Files affected:** `Fuchs\code\Banking.cs`, `IntranetController.Banking.cs`. --- ### 5.5 `FdsInvoiceData` / `FdsReminderData` → Factory Services **Current state:** Data model classes that directly call stored procedures and PDF generation in their constructors/methods. They receive `IntranetController` as a parameter for DB access. **Problem:** Business objects doing their own persistence (Active Record anti-pattern). Tightly coupled to controller. **Proposed services:** ```csharp public interface IInvoiceService { Task LoadInvoiceAsync(string id, string userAccountId); Task RegisterInvoiceAsync(FdsInvoiceData invoice, bool change); Task GenerateInvoicePdfAsync(FdsInvoiceData invoice); } public interface IReminderService { Task LoadReminderAsync(string id, string userAccountId); Task RegisterReminderAsync(FdsReminderData reminder, bool change); Task GenerateReminderPdfAsync(FdsReminderData reminder); } ``` **Registration:** `builder.Services.AddScoped();` **Files affected:** `FdsInvoiceData.cs`, `FdsReminderData.cs`, all controller partials that create these objects. --- ### 5.6 `FuchsReports` → `IReportService` **Current state:** Static class with a single dispatch method, receives controller. **Proposed service:** ```csharp public interface IReportService { Task ProcessRequestAsync(string action, string id, string userAccountId, DatabaseSecurity dbSec); } ``` --- ### 5.7 `FdsMfrClient` → Injectable MFR Client **Current state:** Created with `new FdsMfrClient()` directly in controller code (e.g., `IntranetController.Invoices2.cs` line 26). Uses static `FdsConfig` for credentials. **Problem:** Cannot be mocked for testing. Credentials hardwired to static config. **Proposed service:** ```csharp public interface IMfrClientFactory { FdsMfrClient Create(); } public class MfrClientFactory : IMfrClientFactory, IDisposable { private readonly ILoggerFactory _loggerFactory; private readonly MFRClientCredentials _credentials; // Inject ILoggerFactory, IOptions } ``` **Registration:** `builder.Services.AddSingleton();` **Files affected:** `FdsMfrClient.cs`, `IntranetController.Invoices2.cs`, any code doing `new FdsMfrClient()`. --- ### 5.8 `Fuchs_intranet` — Decompose the God Object **Current state:** Single class handling configuration, DB connections, authentication, module auth queries, debug logging, and PDF licensing. **Recommended split:** | Responsibility | Proposed Service | Lifetime | |---|---|---| | Configuration (conn strings, app settings) | `IOptions` | Singleton | | DB connection factory | `IDbConnectionFactory` | Singleton | | User authentication | `IAuthenticationService` | Scoped | | Module authorization | `IAuthorizationService` (custom) | Scoped | | Debug/error logging | Use built-in `ILogger` | — | --- ## 6. Priority Ranking | Priority | Candidate | Impact | Effort | |---|---|---|---| | 🔴 **1** | `FuchsFdsEmail` → `IEmailService` | Fixes `ConfigurationManager` violation, high testability gain | Low | | 🔴 **2** | `FuchsWidgets` → `IWidgetService` | Removes controller coupling | Low | | 🟡 **3** | `FdsMfrClient` → `IMfrClientFactory` | Removes `new` in controllers, enables mocking | Medium | | 🟡 **4** | `Banking` → `IBankingService` | Clean DI pattern, minor effort | Low | | 🟡 **5** | `FuchsPdf` → `IPdfService` | Large file, significant but high-value refactor | Medium | | 🟠 **6** | `FdsInvoiceData`/`FdsReminderData` → Services | Major architectural improvement, most effort | High | | 🟠 **7** | `Fuchs_intranet` decomposition | God-object split, foundational but risky | High | | 🟢 **8** | `FuchsReports` → `IReportService` | Minimal current logic, prep for future | Low | --- ## 7. Additional Observations 1. **`System.Configuration.ConfigurationManager` usage** in `FuchsFdsEmail.cs` directly violates the project's coding standards (`appsettings.json` only). 2. **No dependency injection in `FdsInvoiceData`/`FdsReminderData`** — these classes receive the entire controller, creating circular-style dependencies. 3. **`FdsMfrClient` is `new`-ed directly** in controller partials (e.g., `IntranetController.Invoices2.cs`) instead of being injected. 4. **`OCORE_Charting`** is in the solution but not directly referenced by any project — verify if it's still needed. 5. **Topshelf** in `Fuchs_DataService` could be replaced with native `dotnet` Worker Service hosting for .NET 10 alignment.