This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Proprietary Windows Forms (.NET 9) desktop tool for StudioU, an online photo-print service. It turns WooCommerce order exports into print-ready file packages, product catalogs, printable labels, and emailed digital downloads. UI text, comments, and CSV column names are predominantly Czech — match that when editing user-facing strings.
# Build whole solution
dotnet build qdr.app.studiou.orders2printpack.sln
# Run the app (WinExe Windows Forms — Windows only)
dotnet run --project App
# Run all tests (NUnit)
dotnet test
# Run a single test fixture or test
dotnet test --filter "FullyQualifiedName~EmailStorageProcessorTests"
dotnet test --filter "Name=MethodNameHere"
Notes:
net9.0-windows7.0; Test targets net9.0-windows. Nullable and ImplicitUsings are enabled in both.bo_strong_key_pair.snk (referenced as ..\bo_strong_key_pair.snk).Setup/Setup.vdproj is a Visual Studio Installer project — only buildable in Visual Studio with the installer-projects extension, not via dotnet. Bump Version/AssemblyVersion/FileVersion in App/...csproj and the README changelog together when releasing (see commit history convention).qdr.fnd.core (Quadarax.Foundation.Core) — shared foundation: ILogger/ILog logging, FileSearch, FileUtils, CsvHelper/CsvUtils (DataTable CSV), and ParameterizedString (the {token} substitution engine used for output filenames). Source is not in this repo; treat as an opaque library.qdr.app.tss.client — REST client for Quadarax Temporary Shared Storage (TSS); used to upload ZIPs and get a download permalink (FileUploadService, UploadFileRequest).DocumentFormat.OpenXml — used to generate .xlsx label sheets without Office installed.Program.cs launches FormLauncher, a hub with buttons opening four independent workflows plus a config editor. Each workflow is a self-contained Form with its own logic — there is no shared controller/service layer; forms read/write the shared AppSettings (user settings) directly.
The four workflows:
FormBatch — the core "orders → print package" flow. Loads a WooCommerce order CSV into a DataTable, scans a source RAW-image folder (FileSearch), matches each order line's image URL to a local file by filename, then copies/renames files into the output folder. Output paths are built from AppSettings.OutputFileMask via ParameterizedString ({order_no}, {prod_name}, {ordinal}, {ext}, plus every CSV column normalized to lower_snake_case). Quantity expands to multiple numbered copies. Lines whose format matches FormatDigitalContains and have an email are routed into a per-email subfolder (the "digital" path) instead of print. Can also emit a protocol CSV (GenerateProtocol) stamping external order number/date.
FormProductEdit + ProductStorage/ — edit/import the product catalog. ProductStorage holds a flat list of ProductDto rows where a row is either a product (Type == "variable") or a variant (Type == "variation", linked to parent by SKU). Variants and categories are derived views over that list. ProductDto.IsValid encodes the catalog validity rules. Import builds URLs/descriptions from AppSettings.ImportTpl* templates.
FormLabelPrint + Labels/ExcelLabelGenerator.cs — CSV → printable .xlsx label sheet. ProcessData first aggregates rows (group-by LabelAggregateColumns, building computed columns via LabelAggegationDataExpression). ExcelLabelGenerator lays labels out in an N×M grid per A4 page using OpenXML, expanding {columnName} placeholders and a lightweight markup in LabelTemplate: **bold**, __italic__, _underline_, ^^size^text^^, and {cr} → newline.
FormDigitalSend + EmailStorage/EmailStorageProcessor.cs — emails download links for digital orders. EmailStorageProcessor is the substantive class here (FormDigitalSend itself is largely a stub). It treats each subdirectory of an input folder as one recipient (directory name = email address), and drives a state machine persisted in metadata.json: Ready → Processing → Uploading → Sending → Sent (or Error). Per item it zips the JPGs, uploads to TSS, generates a download password + permalink, personalizes the email template ({{DOWNLOAD_LINK}}, {{PASSWORD}}, {{RECIPIENT}}, {{ORDERS}}), sends via SMTP, and moves the ZIP through hidden dirs .processing/ → .sending/ → .sent/. Order numbers are parsed from filenames matching ^(\d+)_.*\.jpg$.
CsvParser (App/Extensions/CsvParserUtility.cs) — reflection/attribute-based; maps CSV columns to typed properties via [CsvColumn("Header Name")]. Used for the strongly-typed product catalog (ProductDto).CsvHelper / CsvUtils (DataTable-based, mostly from qdr.fnd.core) — used by FormBatch and FormLabelPrint where columns are dynamic and addressed by name at runtime.Both respect AppSettings.CSVDelimiter.
AppSettings)All operational config lives in the generated Properties/AppSettings user-settings class (AppSettings.settings), edited at runtime through dlgSettings / dlgEditCfg. Key groups: MapCol* (map logical fields to actual CSV column names — change these, not the code, when an export's headers differ), output/import templates, label layout + template, TSS credentials (TSSApiKey/TSSUri/TSSChunkSizeBytes), and SMTP. "Reset config" on the launcher restores defaults.
File I/O goes through System.IO.Abstractions (IFileSystem), so logic is unit-testable with MockFileSystem. New file-touching logic should take/use IFileSystem rather than System.IO.File/Directory directly. Tests use NUnit + Moq + System.IO.Abstractions.TestingHelpers; EmailStorageProcessorTests is the model to follow.