# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Commands ```bash # Build dotnet build # Run (dev server at http://localhost:5225) cd Schaad.Accounting.UI && dotnet run # Test dotnet test # Publish dotnet publish -c Release ``` Tests live in `Schaad.Accounting.Tests` (xUnit + NSubstitute + Shouldly). There is no lint command. ## Architecture **AccountingNext** is a Swiss personal accounting app built with ASP.NET Core 9 + Blazor (interactive server-side rendering) and Microsoft Fluent UI. Data is stored as XML files on disk — no database. ### Projects | Project | Role | |---|---| | `Schaad.Accounting.UI` | Blazor web app — pages, dialogs, layout | | `Schaad.Accounting.Services` | Business logic — balances, FX conversion, file import, charts | | `Schaad.Accounting.Db` | Repository layer — XML serialization/deserialization | | `Schaad.Accounting.Common` | Shared models, DTOs, interfaces | ### Data flow ``` Blazor Pages/Dialogs (UI) → Services (ViewService, FileService, ChartService) → Repositories (AccountRepository, TransactionRepository, …) → XML files: {DataPath}/{year}/{mandator}/Data/*.xml ``` Data is multi-year and multi-mandator. Each combination has its own directory under `DataPath` (configured in `appsettings.Development.json`). When a new year is opened, the previous year's data is copied as the starting point. ### Key services - **ViewService** — aggregates account balances, applies FX rates, builds datasets for the UI - **FileService** — imports bank statements (MT940, CAMT053 via external `Schaad.Finance.dll`), parses PDFs, manages backups - **ChartService** — produces data for Plotly charts (assets, spendings over time) - **SettingsService** — manages the active year, mandator, and file paths ### UI structure Pages live in `Schaad.Accounting.UI/Components/Pages/`. Each page typically has a companion `Dialogs/` subfolder with Fluent UI dialog components for CRUD operations. The app is hardcoded to the `de-CH` culture. ### Key external dependencies - `Microsoft.FluentUI.AspNetCore.Components` — UI components (FluentDataGrid, FluentDialog, etc.) - `Plotly.Blazor` — charts - `FreeSpire.PDF` — PDF parsing for bank statement imports - `Schaad.Finance.dll` / `Schaad.Finance.Api.dll` — proprietary DLLs for MT940/CAMT053 parsing and FX rate lookups (FixerIo API key in `appsettings.Development.json`) ### Domain constants `ClassIds` in `Schaad.Accounting.Common` defines the Swiss accounting chart-of-accounts classes: Activa=1, Passiva=2, Income=3, Expenses=4. These are the leading digit of an account number (accounts are 4-digit; `Account.Class = Number / 1000`). ## Testing conventions Tests live in `Schaad.Accounting.Tests` and use **xUnit** + **NSubstitute** (mocks) + **Shouldly** (assertions). - **File and class name**: `TestShould` — one file per subject under test. Examples: `ViewServiceTestShould.cs`, `TransactionRepositoryTestShould.cs`, `FormattingTestShould.cs`. - **Test method name**: `DoThisWhenThat` — describes the behavior first, then the condition. Read together the class + method form a sentence: - `ViewServiceTestShould.SumActivaAndPassivaTotalsSeparatelyWhenGettingBalanceView` - `TransactionRepositoryTestShould.ReturnNullWhenGettingUnknownTransactionId` - **Assertions**: use Shouldly (`value.ShouldBe(expected)`, `list.ShouldBeEmpty()`, `x.ShouldBeNull()`, `list.ShouldContain(...)`, `first.ShouldBeSameAs(second)`, etc.). Do **not** use xUnit `Assert.*`. Example: ```csharp public class FormattingTestShould { [Fact] public void RoundToTwoDecimalsWhenValueHasMorePrecision() { 1.234m.ToFormattedString().ShouldBe("1.23"); } } ``` Repository tests that hit real XML I/O use a temp directory via `Path.GetTempPath()` and clean up in `IDisposable.Dispose`. Pure service tests use NSubstitute mocks for every dependency and don't touch the filesystem.