1376779224
- ARCHITECTURE.md: reflect the implemented DI service layer, CAMTParser, OpenTelemetry/observability, the ported report engine, and CAMT+MT940 banking; mark the resolved observations. - copilot-instructions.md: add Services/DI, dual-format banking, observability and testing sections; add an Instruction-Sync banner. - CLAUDE.md (new): Claude Code project instructions mirroring the shared rules, plus build/test workflow notes. Both files state they must stay in sync. - USER_GUIDE.md (new, Fuchs/Docs): end-user process guide (login, invoices, reminders, requests, banking incl. MT940/CAMT upload, DATEV, reports). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.6 KiB
6.6 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.mdmay 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/—IntranetControllerpartials (no area)code/— business logic, PDF, email, widgets, data modelscss/intranet/— intranet SCSS source filesjs/intranet/— intranet JS source files (modules injs/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.json— do not useWeb.configorSystem.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 viaIConfiguration.GetConnectionString(...). FuchsOcmsIntranet.Initialize(configuration)must be called at app start (inProgram.cs) before DI registration;Fuchs_intranetreceivesIConfigurationvia 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 intoIntranetController(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 viaFuchsVisualization),IWidgetService,IBankingService,IMfrClientFactory.- Lifetimes: stateless services (
IPdfService,IBankingService,IMfrClientFactory) are singletons; request-scoped DB services (IInvoiceService,IReminderService,IReportService,IWidgetService,IComService) are scoped. Register inProgram.cs.
FdsInvoiceData/FdsReminderDataare pure data holders (parse + properties). Loading, persistence and PDF generation belong in the services — neverTask.Run(...).Wait()sync-over-async.- Data access stays SQL-first via OCORE helpers (
getSQLDataSet_async,setSQLValue_async) + stored procedures; no EF Core.
Bank statement parsing (MT940 + CAMT)
- Two parsers feed the same banking pipeline: the external
MT940Parser(SWIFT text) and the in-repoCAMTParserproject (ISO 20022 camt.052/053/054 XML). BankingService.ParseToDatatableauto-detects the format (XML → CAMT, else MT940) and maps both into thefds__tt__bankingtransactionsschema. Thebam/uphandler and the frontend file picker accept both (.sta/.mt940/.txtand.xml/.camt).CAMTParseris 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(oneActivitySource+ oneMeter). - When adding a meaningful operation: start an activity (
FuchsTelemetry.StartActivity(...)), record the relevant counter/histogram, and log entry/result/timing/errors via the injectedILogger<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 hasInternalsVisibleTo). 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:inIConfiguration. - 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
fuchsis prepended to every secret name. - Format:
{appname}--{Section}--{key-with-hyphens-for-underscores} - Examples:
fuchs--ConnectionStrings--ocms-ConnectionString→ConnectionStrings:ocms_ConnectionStringfuchs--Fuchs--SMS-APIKey→Fuchs:SMS_APIKeyfuchs--Fuchs--Email--Main--password→Fuchs:Email:Main:password
- When adding new secrets: replace every
_in the original config key with-for the Key Vault name, and add the entry toManagedSecretKeysinappsettings.json(using the same hyphenated form without thefuchs--prefix).