- Introduced new JavaScript file `fis.admin_txt_de.js` for German translations of administration-related terms and messages. - Created `fis.admin.css` for styling the administration interface, including layout, cards, and buttons. - Added `fis.admin.de.js` for the main functionality of the administration module, implementing features such as system status checks and email testing. - Minified version of the German JavaScript file created as `fis.admin.de.min.js`. - Minified CSS file created as `fis.admin.min.css` for optimized loading.
9.0 KiB
9.0 KiB
CLAUDE.md — Project instructions for Claude Code
⚠️ Instruction Sync
This file,
CODEX.md, and.github/copilot-instructions.mdare three 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 all three files in the same commit. This file may add Claude Code / workflow specifics; the shared project facts must matchCODEX.mdandcopilot-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 byfntoDo_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).eRechnungLibis a submodule (ZUGFeRD/Factur-X + XRechnung generation) — invoices are moving to eRechnung output.MT940Parseris 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. - Frontend assets are source-built: run the gulp tasks in
Fuchs/(npx gulp min, ornpx gulp allwhen copied/static assets also need refreshing) whenever JS or SCSS/CSS sources change. The generated files underFuchs/wwwroot/web/are what the app serves. - 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
: errorlines as failures. - Commit only when asked. Co-author trailer:
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>. - The working tree may contain an untracked
Fuchs_Database/SQL project — it is not part of app changes; nevergit add -Ait 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— neverWeb.config/System.Configuration.ConfigurationManager. App settings nested under"Fuchs"; connection strings under"ConnectionStrings". FuchsOcmsIntranet.Initialize(configuration)runs inProgram.csbefore DI registration.appsettings.Development.json(git-ignored) overrides secrets locally.Fuchs:Email:OverrideRecipient(IOptions<FuchsEmailSettings>, sectionFuchs:Email) is a dev/test safety net: when non-empty,ProcessWebComService.SendEmailAsyncdiscards the real recipient of every outbound email and redirects it to this single address instead, so a locally-enabled mailer can never reach a real tenant-owner or end-customer. Set only inappsettings.Development.json— must stay empty in Production.
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 intoIntranetController. Do not reintroduce static God-classes or pass the controller into helpers. - Services:
IComService(ProcessWeb Mailer API; honors theFuchs:Email:OverrideRecipientdev safety net — see Configuration),IPdfService,IInvoiceService,IReminderService,IReportService,IWidgetService,IBankingService,IMfrClientFactory,ISystemStatusService(Admin module diagnostics: config snapshot + DB/Key Vault/blob/MFR connectivity probes + test-email; restricted tofds_sys> 4). Stateless ones are singletons; DB/request-scoped ones are scoped (seeProgram.cs). FdsInvoiceData/FdsReminderDataare pure data holders; load/persist/render belongs in services. NoTask.Run(...).Wait()sync-over-async.- Data access is SQL-first via OCORE helpers + stored procedures (no EF Core).
MFR ERP integration
MFR_RESTClientis the REST/OData client for the mfr (Mobile Field Report) ERP. Its contract (base URLs, auth, OData conventions, pagination, error/retry, deep-create + document-upload) is inMFR_RESTClient/Docs/mfr_interface_description.md— read it before changing the client.- HTTP Basic auth; configurable timeout; idempotent GETs retry on transient errors (429/5xx, network/timeout) with backoff. Create clients via
IMfrClientFactory. Active project isMFR_RESTClient.csproj(legacy.vbprojremoved).
Database
- Schema source of truth:
Fuchs_DatabaseSSDT project. SQL-first backend (stored procs, table types e.g.fds__tt__bankingtransactions, functions via OCORE — no EF Core). - Changing a proc signature or table type → update the SSDT project and the calling C# together; verify every
[dbo].[…]the backend calls exists inFuchs_Database.
Bank statement parsing (MT940 + CAMT)
MT940Parser(external, SWIFT text) andCAMTParser(in-repo, ISO 20022 camt.052/053/054 XML) feed the same pipeline.BankingService.ParseToDatatableauto-detects (XML → CAMT, else MT940) →fds__tt__bankingtransactions.bam/up+ the frontend accept both formats.CAMTParseris namespace-agnostic. Keep both column mappings aligned with the banking schema.
Observability
- OpenTelemetry. Instrumentation is centralised in
Fuchs/Observability/FuchsTelemetry.cs(oneActivitySource, oneMeter). - For meaningful operations: start an activity, record the matching counter/histogram, and log entry/result/timing/errors via injected
ILogger<T>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. Testing must be extensive, not superficial:- For each service/handler change, cover both an intentionally succeeding and an intentionally failing path where feasible (stubs/mocks;
InternalsVisibleTois enabled). - Cover edge cases and boundary conditions (empty/null/invalid input, disabled/feature-flag-off states, API/network errors) via
[Theory]/[InlineData]/[MemberData]rather than a single happy-path[Fact]. - When behavior depends on configuration (e.g.
appsettings.jsonvsappsettings.Development.json), prefer loading the real files layered the same way ASP.NET Core does (ConfigurationBuilder+AddJsonFile) over hand-typed literals only, so drift in the actual files is caught (seeProcessWebComServiceTests.SendEmailAsync_OverrideRecipientFromRealAppsettings_ClearsRecipientWheneverConfiguredfor the pattern). - Assert on the observable contract (e.g. the outgoing request payload) and on emitted telemetry (counters/histograms) when the code records them — not just the boolean return value.
- Name tests
MethodName_Scenario_ExpectedResult. - Cover pure logic for DB-bound paths that can't be unit-tested.
- For each service/handler change, cover both an intentionally succeeding and an intentionally failing path where feasible (stubs/mocks;
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 prefixfuchs; register new keys inManagedSecretKeysinappsettings.json.
Decisions & Concepts
Fuchs/Docs/Decisions/holds immutable ADRs (architecture decision records);Fuchs/Docs/Concepts/holds living design write-ups kept in sync with the code. Each folder'sREADME.mdexplains the format, naming, and required YAML frontmatter — read it before creating or editing entries there.- Accepted decisions must be followed. Before working in an area covered by a decision, read it and conform to it; don't silently deviate. Every file's YAML frontmatter has an
applyToglob — scan frontmatter across the folder first (cheap) and only read the full body of entries relevant to the files you're touching. - Capture new decisions and concepts as they happen. When a non-obvious architectural or cross-cutting choice gets settled (by the user or in the course of implementation), add a decision in
Docs/Decisionsin the same change, and create/update the matching concept doc inDocs/Conceptsif the subsystem's design is otherwise non-obvious from the code.
Documentation map
Fuchs/Docs/ARCHITECTURE.md— solution architecture (keep current when structure changes).Fuchs/Docs/USER_GUIDE.md— end-user process guide.Fuchs/Docs/Decisions/— ADRs; seeDecisions & Conceptsabove.Fuchs/Docs/Concepts/— living subsystem design docs; seeDecisions & Conceptsabove.MFR_RESTClient/Docs/mfr_interface_description.md— mfr ERP REST/OData interface contract..github/instructions/*.instructions.md— domain-specific contributor guidance.