# Architecture ## Solution Dependency Graph ``` FruitBank.Common (shared domain, net9.0) ↑ FruitBank.Common.Server (server-side services, nopCommerce, net9.0) ↑ FruitBankHybrid.Shared.Common (shared utilities, net10.0) ↑ FruitBankHybrid.Shared (Blazor UI components, pages, services, net10.0) ↑ ↑ ↑ FruitBankHybrid FruitBankHybrid.Web FruitBankHybrid.Web.Client (MAUI, net10.0) (Server, net10.0) (WASM, net10.0) ``` All projects also reference **AyCode.Core** (net9.0) and **AyCode.Blazor** (net10.0) via DLL references (not ProjectReference). > **Context:** When a type or base class is not found in this solution, browse the external repos: > - **AyCode.Core**: `../../../Aycode/Source/AyCode.Core/` — SignalR, serialization, binary protocol, data sources > - **AyCode.Blazor**: `../../../Aycode/Source/AyCode.Blazor/` — MgGridBase, UI components, layout persistence > - **Mango.Nop Libraries**: `../NopCommerce.Common/4.70/Libraries/` — independent library with own [copilot-instructions](../NopCommerce.Common/4.70/Libraries/.github/copilot-instructions.md) and [docs/](../NopCommerce.Common/4.70/Libraries/docs/) > - **FruitBank Plugin**: `../NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/` — server-side SignalR hubs, measurement services, DbTable classes ## Target Frameworks nopCommerce 4.80.9 requires .NET 9 | Project | TFM | Reason | |---|---|---| | FruitBank.Common | net9.0 | nopCommerce entity references | | FruitBank.Common.Server | net9.0 | nopCommerce server integration | | FruitBankHybrid.Shared | net10.0 | Blazor UI | | FruitBankHybrid.Shared.Common | net10.0 | Shared utilities | | FruitBankHybrid | net10.0‑android/ios/win | MAUI Hybrid | | FruitBankHybrid.Web | net10.0 | Blazor Server host | | FruitBankHybrid.Web.Client | net10.0 | Blazor WASM | | FruitBankHybrid.Shared.Tests | net10.0 | Tests | | **AyCode.Core** (external) | net9.0 | Foundation — used by nopCommerce layer | | **AyCode.Blazor** (external) | net10.0 | UI framework | | **AyCode.Core.Serializers.SourceGenerator** | netstandard2.0 | Roslyn analyzer requirement | ## Three Deployment Targets | Target | Project | How UI Runs | |---|---|---| | **MAUI Hybrid** | FruitBankHybrid | Native app with BlazorWebView | | **Blazor Server** | FruitBankHybrid.Web | Server-side rendering + SignalR | | **Blazor WASM** | FruitBankHybrid.Web.Client | Downloaded to browser, runs in WASM | All three share the same UI components from `FruitBankHybrid.Shared`. ## Data Flow ``` User → DevExpress Grid → AcSignalRDataSource → SignalR (AcBinary) → DevAdminSignalRHub ↓ DynamicMethodRegistry ↓ IFruitBankDataControllerServer ICustomOrderSignalREndpointServer IStockSignalREndpointServer ↓ nopCommerce Database ``` ## MgGrid — Grid System All data screens use **MgGridBase** from AyCode.Blazor (see [AyCode.Blazor/docs/MGGRID.md](../../../Aycode/Source/AyCode.Blazor/docs/MGGRID.md) for full technical docs). ### FruitBank Grid Hierarchy ``` MgGridBase (AyCode.Blazor) └── FruitBankGridBase (FruitBankHybrid.Shared) ├── GridShippingBase → Shipping ├── GridShippingDocumentBase → ShippingDocument (detail of Shipping) ├── GridPartnerBase → Partner ├── GridGenericAttributeBase → GenericAttributeDto └── GridStockTakingItemBase → StockTakingItem ``` ### FruitBankGridBase Project-level adapter that fixes 3 of 4 generic parameters: ```csharp public class FruitBankGridBase : MgGridBase, TDataItem, int, LoggerClient> ``` Adds FruitBank-specific defaults: - `GetLayoutUserId()` → `LoggedInModel.CustomerDto?.Id ?? 0` (per-user layout) - Master grid: filter row, group panel, search box, `PageSize=20`, `EditMode=EditRow` - Detail grid: no filter/group/search, `PageSize=10` - Alternating row style (`.alt-item`), header background (`#E6E6E6`) - Detail rows hidden for non-admin users (`hideDetailButton` CSS) ### SignalR Tag Mapping Each concrete grid sets CRUD tags in its constructor: ```csharp public GridShippingBase() { GetAllMessageTag = SignalRTags.GetShippings; // e.g. 300 AddMessageTag = SignalRTags.AddShipping; // e.g. 302 UpdateMessageTag = SignalRTags.UpdateShipping; // e.g. 303 } ``` Tags are defined in `FruitBank.Common/SignalRs/SignalRTags.cs` with numeric ranges per domain area. ### Grid Usage Pattern (Razor) ```razor ... @{ var shipping = (Shipping)context.DataItem; } ``` ## Key Architectural Decisions - **nopCommerce plugin** — Customer, Order, Product are nopCommerce entities extended via GenericAttributes and DTOs - **SignalR over REST** — all data flows through SignalR with AcBinary protocol - **DevExpress Blazor 25.1.3** — exclusive UI component library - **MgGridBase** — canonical grid base from AyCode.Blazor for all data screens (SignalR CRUD, layout persistence, master-detail) - **Three measurement hierarchies** — Shipping/Order/StockTaking share same base but have different audit rules - **Client-side database** — `DatabaseClient` caches entities in ConcurrentDictionary for offline/fast access - **Platform-specific credential storage** — MAUI uses SecureStorage, Web uses obfuscated localStorage, Server uses no-op