# CLAUDE.md — Project instructions for Claude Code > ## ⚠️ Instruction Sync > This file and **`.github/copilot-instructions.md`** are two views of the same > project rules and **must stay in sync**. When you change a shared rule > (architecture, coding standards, configuration, libraries, secrets, > observability, testing), make the equivalent change in **both files in the > same commit**. This file may add Claude Code / workflow specifics; the shared > project facts must match `copilot-instructions.md`. ## Project Overview - **Fuchs Intranet** — ASP.NET Core (**.NET 10**) web app; the intranet IS the whole website, served from `/`. - Routes: `/{fn?}/{id?}/{code?}` → `IntranetController.Index`; `/do/{fn?}/{id?}/{code?}` → `IntranetController.Do` (dispatches by `fn` to `Do_Process_*`). - Solution `Fuchs_Intranet.slnx`. Key projects: `Fuchs` (web), `Fuchs_DataService` (MFR sync worker), `MFR_RESTClient`, `CAMTParser`, `Fuchs.Tests`, and the OCORE submodules (`OCORE`, `OCORE_web`, `OCORE_web_pdf`, `OCORE_Charting`). `MT940Parser` is an external referenced project. ## Build & Test (workflow) - Build app: `dotnet build Fuchs/Fuchs.csproj -c Debug`. Build all: `dotnet build Fuchs_Intranet.slnx -c Debug`. - Test: `dotnet test Fuchs.Tests/Fuchs.Tests.csproj -c Debug`. - Always build **and** run the test suite before committing. The build emits many pre-existing analyzer/platform warnings (CA1416 etc.) — those are expected; only treat `: error` lines as failures. - Commit only when asked. Co-author trailer: `Co-Authored-By: Claude Opus 4.8 `. - The working tree may contain an untracked `Fuchs_Database/` SQL project — it is **not** part of app changes; never `git add -A` it into an unrelated commit. Stage explicit paths. ## Coding Standards - C# only. Modern, performance-oriented .NET 10 (async/await, LINQ, DI). - Keep files ≤ 400 (max 600) lines; refactor larger files into focused classes. - PascalCase types/methods, camelCase locals/params. ## Configuration - All settings in `Fuchs/appsettings.json` — **never** `Web.config` / `System.Configuration.ConfigurationManager`. App settings nested under `"Fuchs"`; connection strings under `"ConnectionStrings"`. - `FuchsOcmsIntranet.Initialize(configuration)` runs in `Program.cs` before DI registration. - `appsettings.Development.json` (git-ignored) overrides secrets locally. ## Libraries - Do **not** upgrade Spire.PDF beyond 8.10.5. Prefer OCORE / OCORE_web / OCORE_web_pdf helpers over rewriting. Do not use OCMS/OCMS_sharp — OCORE only. ## Services & Dependency Injection - Business logic lives in **DI-registered services** under `Fuchs/Services/` behind interfaces, injected into `IntranetController`. Do not reintroduce static God-classes or pass the controller into helpers. - Services: `IComService`, `IPdfService`, `IInvoiceService`, `IReminderService`, `IReportService`, `IWidgetService`, `IBankingService`, `IMfrClientFactory`. Stateless ones are singletons; DB/request-scoped ones are scoped (see `Program.cs`). - `FdsInvoiceData` / `FdsReminderData` are **pure data holders**; load/persist/render belongs in services. No `Task.Run(...).Wait()` sync-over-async. - Data access is SQL-first via OCORE helpers + stored procedures (no EF Core). ## Bank statement parsing (MT940 + CAMT) - `MT940Parser` (external, SWIFT text) and **`CAMTParser`** (in-repo, ISO 20022 camt.052/053/054 XML) feed the same pipeline. - `BankingService.ParseToDatatable` auto-detects (XML → CAMT, else MT940) → `fds__tt__bankingtransactions`. `bam/up` + the frontend accept both formats. `CAMTParser` is namespace-agnostic. Keep both column mappings aligned with the banking schema. ## Observability - OpenTelemetry. Instrumentation is centralised in `Fuchs/Observability/FuchsTelemetry.cs` (one `ActivitySource`, one `Meter`). - For meaningful operations: start an activity, record the matching counter/histogram, and log entry/result/timing/errors via injected `ILogger` using **structured** placeholders (never interpolated strings). - Always collected; OTLP export opt-in via `Fuchs:Telemetry:OtlpEndpoint`. No exporters that hard-fail without a collector. ## Testing - xUnit in `Fuchs.Tests`. For each service/handler change, add tests for **both** an intentionally succeeding and an intentionally failing path where feasible (stubs/mocks; `InternalsVisibleTo` is enabled). Cover pure logic for DB-bound paths that can't be unit-tested. ## Secrets (Azure Key Vault) - Full naming rules live in `.github/copilot-instructions.md` (kept in sync). In short: names match `^[0-9a-zA-Z-]+$`, hierarchy via `--` (→ `:`), underscores → `-`, app prefix `fuchs`; register new keys in `ManagedSecretKeys` in `appsettings.json`. ## Documentation map - `Fuchs/Docs/ARCHITECTURE.md` — solution architecture (keep current when structure changes). - `Fuchs/Docs/USER_GUIDE.md` — end-user process guide. - `.github/instructions/*.instructions.md` — domain-specific contributor guidance.