diff --git a/CLAUDE.md b/CLAUDE.md index 617293c..31bdb47 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,13 +1,22 @@ # CLAUDE.md +> **IMPORTANT**: Always keep this document updated when functionality changes, entities are added/modified, new pages or services are created, or architectural patterns evolve. + This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview -CutList is a Windows Forms 1D bin packing optimization application that helps users optimize material cutting. It calculates efficient bin packing solutions to minimize waste when cutting stock materials into required parts. +CutList is a 1D bin packing optimization application that helps users optimize material cutting. It calculates efficient bin packing solutions to minimize waste when cutting stock materials into required parts. -**Framework**: .NET 8.0 (Windows Forms) -**Key Dependencies**: Math-Expression-Evaluator (input parsing), Newtonsoft.Json (serialization) +The solution contains three projects: + +| Project | Framework | Purpose | +|---------|-----------|---------| +| **CutList** | .NET 8.0 Windows Forms | Original desktop UI (MVP pattern) | +| **CutList.Core** | .NET 8.0 Class Library | Domain models and packing algorithms (platform-agnostic) | +| **CutList.Web** | .NET 8.0 Blazor Server | Web-based UI with EF Core + SQL Server | + +**Key Dependencies**: Math-Expression-Evaluator (input parsing), Newtonsoft.Json (serialization), Entity Framework Core (data access), Bootstrap 5 + Bootstrap Icons (UI) ## Build Commands @@ -15,12 +24,18 @@ CutList is a Windows Forms 1D bin packing optimization application that helps us # Build entire solution dotnet build CutList.sln -# Build specific project +# Build specific projects dotnet build CutList/CutList.csproj dotnet build CutList.Core/CutList.Core.csproj +dotnet build CutList.Web/CutList.Web.csproj -# Run the application -dotnet run --project CutList/CutList.csproj +# Run applications +dotnet run --project CutList/CutList.csproj # WinForms +dotnet run --project CutList.Web/CutList.Web.csproj # Blazor + +# EF Core migrations (always apply immediately after creating) +dotnet ef migrations add --project CutList.Web +dotnet ef database update --project CutList.Web # Clean build dotnet clean CutList.sln @@ -28,69 +43,179 @@ dotnet clean CutList.sln ## Architecture -### Project Structure +### CutList.Core — Domain & Algorithms -- **CutList/** - Main Windows Forms application (UI layer) -- **CutList.Core/** - Core library with domain models and packing algorithms (shareable, platform-agnostic) - -### Key Patterns - -**MVP (Model-View-Presenter)** -- `MainForm` implements `IMainView` (pure UI, no business logic) -- `MainFormPresenter` orchestrates all business logic -- `Document` contains application state - -**Result Pattern** -- `Result` in Common/Result.cs for standardized error handling -- Use `Result.Success(value)` and `Result.Failure(error)` instead of exceptions for expected errors - -**Factory Pattern** -- `IEngineFactory` creates packing engines -- Allows swapping algorithm implementations - -### Data Flow - -1. User enters parts/bins in MainForm -2. MainFormPresenter calls CutListService.Pack() -3. CutListService converts input models to core models (MultiBin, BinItem) -4. MultiBinEngine coordinates packing across bin types -5. AdvancedFitEngine performs 1D bin packing (first-fit decreasing with optimization) -6. Results displayed in ResultsForm - -### Key Services - -- **CutListService**: Bridges UI models to core packing algorithms -- **DocumentService**: JSON file persistence - -### Domain Models (CutList.Core) - -- **BinItem**: Item to be packed (with label, length) +**Key Domain Models**: +- **BinItem**: Item to be packed (label, length) - **MultiBin**: Stock bin type with length, quantity (-1 = unlimited), priority -- **Bin**: Packed bin containing items +- **Bin**: Packed bin containing items, tracks remaining length - **Tool**: Cutting tool with kerf/blade width -### Unit Handling +**Packing Engine**: +- `MultiBinEngine` coordinates packing across bin types +- `AdvancedFitEngine` performs 1D bin packing (first-fit decreasing with optimization) +- `PackingStrategy.AdvancedFit` is the standard strategy -- **ArchUnits**: Converts feet/inches/fractions to decimals (accepts "12'", "6\"", "12 1/2\"", etc.) -- **FormatHelper**: Converts decimals to mixed fractions for display +**Unit Handling**: +- `ArchUnits` — Converts feet/inches/fractions to decimal inches (accepts "12'", "6\"", "12 1/2\"", etc.) +- `FormatHelper` — Converts decimals to mixed fractions for display - Internal calculations use inches; format on display -## Important Conventions +**Patterns**: +- `Result` for standardized error handling (Success/Failure instead of exceptions) +- `IEngineFactory` for swappable algorithm implementations +- Lower priority number = used first in bin selection -- **Nullable reference types enabled** - handle nulls explicitly -- **Collections are encapsulated** - use AsReadOnly(), access via Add* methods -- **Validation in domain models** - constructors and properties validate inputs -- **Parameterless constructors** on Tool/MultiBin are for JSON serialization only -- **Spacing property** on engines handles blade/kerf width -- **Priority system**: Lower priority bins are used first +### CutList (WinForms) — Desktop UI + +- MVP pattern: `MainForm` implements `IMainView`, `MainFormPresenter` orchestrates logic +- `Document` holds application state +- `CutListService` bridges UI models to core packing algorithms +- `DocumentService` handles JSON file persistence + +### CutList.Web (Blazor Server) — Web UI + +**Database**: SQL Server via Entity Framework Core (connection string: `DefaultConnection`) + +**Service Registration** (Program.cs): All services registered as Scoped — MaterialService, SupplierService, StockItemService, JobService, CutListPackingService, ReportService, PurchaseItemService + +## CutList.Web Entities + +### Material +- `Shape` (MaterialShape enum): Round Bar, Round Tube, Flat Bar, Square Bar, Square Tube, Rectangular Tube, Angle, Channel, I-Beam, Pipe +- `Type` (MaterialType enum): Steel, Aluminum, Stainless, Brass, Copper +- `Grade` (string?), `Size` (string), `Description` (string?), `IsActive` (bool), `SortOrder` (int) +- **DisplayName**: "{Shape} - {Size}" +- **Relationships**: `Dimensions` (1:1 MaterialDimensions), `StockItems` (1:many), `JobParts` (1:many) + +### MaterialDimensions (TPH Inheritance) +Abstract base; derived types per shape: `RoundBarDimensions`, `RoundTubeDimensions`, `FlatBarDimensions`, `SquareBarDimensions`, `SquareTubeDimensions`, `RectangularTubeDimensions`, `AngleDimensions`, `ChannelDimensions`, `IBeamDimensions`, `PipeDimensions`. Each generates its own `SizeString` and `SortOrder`. + +### StockItem +- `MaterialId`, `LengthInches` (decimal), `QuantityOnHand` (int), `IsActive` +- **Unique constraint**: (MaterialId, LengthInches) +- **Relationships**: `Material`, `SupplierOfferings` (1:many), `Transactions` (1:many StockTransaction) + +### StockTransaction +- `StockItemId`, `Quantity` (signed delta), `Type` (Received/Used/Adjustment/Scrapped/Returned) +- Optional: `JobId`, `SupplierId`, `UnitPrice` + +### Supplier +- `Name` (required), `ContactInfo`, `Notes`, `IsActive` +- **Relationships**: `Offerings` (1:many SupplierOffering) + +### SupplierOffering +- Links Supplier to StockItem with optional `PartNumber`, `Price`, `Notes` +- **Unique constraint**: (SupplierId, StockItemId) + +### CuttingTool +- `Name`, `KerfInches` (decimal), `IsDefault` (bool), `IsActive` +- **Seeded**: Bandsaw (0.0625"), Chop Saw (0.125"), Cold Cut Saw (0.0625"), Hacksaw (0.0625") + +### Job +- `JobNumber` (auto-generated "JOB-#####", unique), `Name`, `Customer`, `CuttingToolId`, `Notes` +- `LockedAt` (DateTime?) — set when materials ordered; `IsLocked` computed property +- **Relationships**: `Parts` (1:many JobPart), `Stock` (1:many JobStock), `CuttingTool` + +### JobPart +- `JobId`, `MaterialId`, `Name`, `LengthInches` (decimal), `Quantity` (int), `SortOrder` + +### JobStock +- `JobId`, `MaterialId`, `StockItemId?`, `LengthInches`, `Quantity` (-1 = unlimited), `IsCustomLength`, `Priority` (lower = used first), `SortOrder` + +### PurchaseItem +- `StockItemId`, `SupplierId?`, `JobId?`, `Quantity`, `Status` (Pending/Ordered/Received), `Notes` + +## CutList.Web Services + +### MaterialService +- CRUD with soft delete, dimension management (`CreateWithDimensionsAsync`, `UpdateWithDimensionsAsync`) +- Search by dimension (e.g., `SearchRoundBarByDiameterAsync`, `SearchAngleByLegAsync`) with tolerance +- `CreateDimensionsForShape(shape)` factory method + +### StockItemService +- CRUD with soft delete +- Stock transactions: `AddStockAsync`, `UseStockAsync`, `AdjustStockAsync`, `ScrapStockAsync` +- `GetTransactionHistoryAsync`, `RecalculateQuantityAsync` +- Pricing: `GetAverageCostAsync`, `GetLastPurchasePriceAsync` + +### SupplierService +- CRUD for suppliers and offerings +- `GetOfferingsForStockItemAsync` — all supplier options for a stock item + +### JobService +- Job CRUD: `CreateAsync` (auto-generates JobNumber), `DuplicateAsync` (deep copy), `QuickCreateAsync` +- Lock/Unlock: `LockAsync(id)`, `UnlockAsync(id)` — controls job editability after ordering +- Parts: `AddPartAsync`, `UpdatePartAsync`, `DeletePartAsync` (all update job timestamp) +- Stock: `AddStockAsync`, `UpdateStockAsync`, `DeleteStockAsync` +- Cutting tools: full CRUD with single-default enforcement + +### CutListPackingService +- `PackAsync(parts, kerfInches, jobStock?)` — runs optimization per material group +- Separates results into `InStockBins` (from inventory) and `ToBePurchasedBins` +- `GetSummary(result)` — calculates total bins, pieces, waste, efficiency % + +### PurchaseItemService +- CRUD + `CreateBulkAsync` for batch creation from optimization results +- `UpdateStatusAsync(id, status)`, `UpdateSupplierAsync(id, supplierId)` + +### ReportService +- `FormatLength(inches)`, `GroupItems(items)` for print report formatting + +## CutList.Web Pages + +| Route | Page | Purpose | +|-------|------|---------| +| `/` | Home | Welcome page with feature cards and workflow guide | +| `/jobs` | Jobs/Index | Job list with pagination, lock icons, Quick Create, Duplicate, Delete | +| `/jobs/new` | Jobs/Edit | New job form (details only) | +| `/jobs/{Id}` | Jobs/Edit | Tabbed editor (Details, Parts, Stock); locked jobs show banner + disable editing | +| `/jobs/{Id}/results` | Jobs/Results | Optimization results, summary cards, "Add to Order List" (locks job), Print Report | +| `/materials` | Materials/Index | Material list with MaterialFilter, pagination | +| `/materials/new`, `/materials/{Id}` | Materials/Edit | Material + dimension form (varies by shape) | +| `/stock` | Stock/Index | Stock items with MaterialFilter, quantity badges | +| `/stock/new`, `/stock/{Id}` | Stock/Edit | Stock item form | +| `/orders` | Orders/Index | Tabbed (Pending/Ordered/All), supplier assignment, status transitions | +| `/orders/add` | Orders/Add | Manual purchase item creation | +| `/suppliers` | Suppliers/Index | Supplier list with CRUD | +| `/suppliers/{Id}` | Suppliers/Edit | Supplier + offerings management | +| `/tools` | Tools/Index | Cutting tools CRUD | + +## Shared Components + +| Component | Purpose | +|-----------|---------| +| `ConfirmDialog` | Modal confirmation for destructive actions (Show/Hide methods, OnConfirm callback) | +| `LengthInput` | Architectural unit input — parses "12'", "6\"", "12 1/2\""; reformats on blur; two-way binding via `Value` or `NullableValue` | +| `Pager` | Pagination with "Showing X-Y of Z", prev/next, smart page window with ellipsis | +| `MaterialFilter` | Reusable filter: Shape, Type, Grade dropdowns + search text; used on Materials, Stock, Orders pages | + +## Key Patterns & Conventions + +- **Nullable reference types enabled** — handle nulls explicitly +- **Soft deletes** — Materials, Suppliers, StockItems, CuttingTools use `IsActive` flag +- **Job locking** — `LockedAt` timestamp set when materials ordered; Edit page disables all modification via `
`, hides add/edit/delete buttons; Unlock button to re-enable editing +- **Pagination** — All list pages use `Pager` with `pageSize = 25` +- **ConfirmDialog** — All destructive actions use the shared `ConfirmDialog` component +- **Material selection flow** — Shape dropdown -> Size dropdown -> Length input -> Quantity (conditional dropdowns) +- **Stock priority** — Lower number = used first; `-1` quantity = unlimited +- **Job stock** — Jobs can use auto-discovered inventory OR define custom stock lengths +- **Purchase flow** — Optimize job -> "Add to Order List" creates PurchaseItems + locks job -> Orders page manages status (Pending -> Ordered -> Received) +- **Timestamps** — `CreatedAt` defaults to `GETUTCDATE()`; `UpdatedAt` set on modifications +- **Collections** — Encapsulated in Core; use `AsReadOnly()`, access via `Add*` methods +- **Priority system** — Lower priority bins used first in packing algorithm ## Key Files | File | Purpose | |------|---------| -| `Presenters/MainFormPresenter.cs` | Main business logic orchestrator | -| `Services/CutListService.cs` | Packing algorithm interface | -| `CutList.Core/Nesting/AdvancedFitEngine.cs` | Core packing algorithm | -| `CutList.Core/Nesting/MultiBinEngine.cs` | Multi-bin orchestration | -| `CutList.Core/ArchUnits.cs` | Unit conversion | -| `CutList.Core/FormatHelper.cs` | Output formatting | +| `CutList.Core/Nesting/AdvancedFitEngine.cs` | Core 1D bin packing algorithm | +| `CutList.Core/Nesting/MultiBinEngine.cs` | Multi-bin type orchestration | +| `CutList.Core/ArchUnits.cs` | Architectural unit parsing/conversion | +| `CutList.Core/Formatting/FormatHelper.cs` | Display formatting | +| `CutList.Web/Data/ApplicationDbContext.cs` | EF Core context with all DbSets and configuration | +| `CutList.Web/Services/JobService.cs` | Job orchestration (CRUD, parts, stock, tools, lock/unlock) | +| `CutList.Web/Services/CutListPackingService.cs` | Bridges web entities to Core packing engine | +| `CutList.Web/Components/Pages/Jobs/Edit.razor` | Job editor (tabbed: Details, Parts, Stock) | +| `CutList.Web/Components/Pages/Jobs/Results.razor` | Optimization results + order creation | +| `CutList/Presenters/MainFormPresenter.cs` | WinForms business logic orchestrator |