Files
Fuchs_Intranet/.github/copilot-instructions.md
T
Stefan 2a75664625 Docs: reference mfr_interface_description.md + Fuchs_Database
- ARCHITECTURE.md: add Fuchs_Database (SSDT) and the MFR interface doc to the
  project table; new MFR ERP Integration and Database sections.
- copilot-instructions.md + CLAUDE.md (kept in sync): add MFR ERP integration
  and Database sections pointing to MFR_RESTClient/Docs/mfr_interface_description.md
  as the contract to read before changing the client; CLAUDE.md doc map updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 15:05:49 +02:00

7.7 KiB

Copilot Instructions

⚠️ Instruction Sync

This file (.github/copilot-instructions.md) and the Claude Code instructions (/CLAUDE.md) are two views of the same project rules and must stay in sync. Whenever you change one, make the equivalent change in the other in the same commit. CLAUDE.md may add tool-specific workflow notes, but the shared project facts (architecture, coding standards, configuration, libraries, secrets, observability) must match.

Project Overview

  • Fuchs Intranet is an ASP.NET Core (.NET 10) web application — the intranet IS the entire website, served from /.
  • Routes: /{fn?}/{id?}/{code?}IntranetController.Index; /do/{fn?}/{id?}/{code?}IntranetController.Do.
  • Project structure (relative to Fuchs/):
    • Controllers/IntranetController partials (no area)
    • code/ — business logic, PDF, email, widgets, data models
    • css/intranet/ — intranet SCSS source files
    • js/intranet/ — intranet JS source files (modules in js/intranet/modules/)
    • Data/ — static data assets (images for PDF, HTML files)
    • Views/Intranet/ — Razor views; Views/Shared/_Layout.cshtml; Views/Partials/

Coding Standards

  • All code must be written in C#.
  • Keep files to a limit of 400 (max 600) lines of code to ensure maintainability and readability. Proactively refactor larger files into smaller, focused classes or components as needed.
  • Follow standard C# naming conventions (PascalCase for classes and methods, camelCase for variables and parameters).
  • Use modern, performance-oriented C# .NET 10 features and best practices, such as async/await for asynchronous programming, LINQ for data manipulation, and dependency injection for better testability and maintainability.

Configuration

  • All application settings live in Fuchs/appsettings.jsondo not use Web.config or System.Configuration.ConfigurationManager.
  • App-specific settings are nested under the "Fuchs" key (e.g., _config["Fuchs:SMS_APIKey"]).
  • Connection strings are stored under the standard "ConnectionStrings" key and read via IConfiguration.GetConnectionString(...).
  • FuchsOcmsIntranet.Initialize(configuration) must be called at app start (in Program.cs) before DI registration; Fuchs_intranet receives IConfiguration via its constructor.
  • appsettings.Development.json (git-ignored) can override secrets for local development.

Libraries

  • Do not upgrade Spire.PDF beyond version 8.10.5.
  • Make use of OCORE libraries where possible, especially for common tasks such as logging, configuration management, and data access.
  • Whenever possible, prefer OCORE_web_pdf / OCORE PDF functions for PDF-related tasks over rewriting.
  • Do not use OCMS or OCMS_sharp; use only OCORE or OCORE_web.
  • For builds failing due to SixLabors.ImageSharp requiring a license (v4.0.0+), check copilot-instructions.md for the SixLabors license key/handling info before downgrading ImageSharp.

Services & Dependency Injection

  • Business logic lives in DI-registered services under Fuchs/Services/ behind interfaces; inject them into IntranetController (constructor injection). Do not reintroduce static God-classes or pass the whole controller into helpers.
    • IComService (email/SMS via ProcessWeb Mailer API, attachments sent inline as base64), IPdfService (MigraDoc render), IInvoiceService, IReminderService, IReportService (SQL report engine via FuchsVisualization), IWidgetService, IBankingService, IMfrClientFactory.
    • Lifetimes: stateless services (IPdfService, IBankingService, IMfrClientFactory) are singletons; request-scoped DB services (IInvoiceService, IReminderService, IReportService, IWidgetService, IComService) are scoped. Register in Program.cs.
  • FdsInvoiceData / FdsReminderData are pure data holders (parse + properties). Loading, persistence and PDF generation belong in the services — never Task.Run(...).Wait() sync-over-async.
  • Data access stays SQL-first via OCORE helpers (getSQLDataSet_async, setSQLValue_async) + stored procedures; no EF Core.

MFR ERP integration

  • MFR_RESTClient talks to the mfr (Mobile Field Report) ERP over REST/OData. Its contract (base URLs, auth, OData conventions, pagination, error/retry, deep-create + document-upload) is documented in MFR_RESTClient/Docs/mfr_interface_description.mdread it before changing the client.
  • The client uses HTTP Basic auth, a configurable timeout, and retries idempotent GETs on transient errors (429/5xx, network/timeout) with backoff. Create clients via IMfrClientFactory (don't new them). The legacy VB project files have been removed; the active project is MFR_RESTClient.csproj.

Database

  • The SQL schema source of truth is the Fuchs_Database SSDT project. The backend is SQL-first (stored procedures, table types like fds__tt__bankingtransactions, functions via OCORE helpers — no EF Core).
  • When you change a stored proc name/params or a table type, update both the SSDT project and the calling C# in the same change. Verify every [dbo].[…] the backend calls actually exists in Fuchs_Database.

Bank statement parsing (MT940 + CAMT)

  • Two parsers feed the same banking pipeline: the external MT940Parser (SWIFT text) and the in-repo CAMTParser project (ISO 20022 camt.052/053/054 XML).
  • BankingService.ParseToDatatable auto-detects the format (XML → CAMT, else MT940) and maps both into the fds__tt__bankingtransactions schema. The bam/up handler and the frontend file picker accept both (.sta/.mt940/.txt and .xml/.camt).
  • CAMTParser is namespace-agnostic (matches elements by local name) so it handles every camt schema version. Keep both parsers' column mappings aligned when changing the banking schema.

Observability

  • Use OpenTelemetry. The app's instrumentation is centralised in Fuchs/Observability/FuchsTelemetry.cs (one ActivitySource + one Meter).
  • When adding a meaningful operation: start an activity (FuchsTelemetry.StartActivity(...)), record the relevant counter/histogram, and log entry/result/timing/errors via the injected ILogger<T>. Prefer structured logging (named placeholders), never string interpolation in log messages.
  • Tracing/metrics are always collected; OTLP export is opt-in via Fuchs:Telemetry:OtlpEndpoint. Don't add exporters that fail hard when no collector is present.

Testing

  • xUnit in Fuchs.Tests. For every service/handler change add tests covering both an intentionally succeeding and an intentionally failing path where feasible (use stubs/mocks; the test project has InternalsVisibleTo). DB-bound paths that can't be unit-tested should at least have their pure logic covered.

Azure Key Vault — Secret Naming

  • Secret names must satisfy the pattern ^[0-9a-zA-Z-]+$ (alphanumerics and hyphens only; no underscores, dots, or spaces).
  • Hierarchy levels are separated by -- (double hyphen), which maps to : in IConfiguration.
  • Underscores within a name segment are encoded as a single - in Key Vault and decoded back to _ when the key is reconstructed.
  • The app prefix fuchs is prepended to every secret name.
  • Format: {appname}--{Section}--{key-with-hyphens-for-underscores}
  • Examples:
    • fuchs--ConnectionStrings--ocms-ConnectionStringConnectionStrings:ocms_ConnectionString
    • fuchs--Fuchs--SMS-APIKeyFuchs:SMS_APIKey
    • fuchs--Fuchs--Email--Main--passwordFuchs:Email:Main:password
  • When adding new secrets: replace every _ in the original config key with - for the Key Vault name, and add the entry to ManagedSecretKeys in appsettings.json (using the same hyphenated form without the fuchs-- prefix).