144 lines
6.6 KiB
Markdown
144 lines
6.6 KiB
Markdown
# 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<TSignalRDataSource, TDataItem, TId, TLoggerClient> (AyCode.Blazor)
|
||
└── FruitBankGridBase<TDataItem> (FruitBankHybrid.Shared)
|
||
├── GridShippingBase → Shipping
|
||
├── GridShippingDocumentBase → ShippingDocument (detail of Shipping)
|
||
├── GridPartnerBase → Partner
|
||
├── GridGenericAttributeBase → GenericAttributeDto
|
||
└── GridStockTakingItemBase → StockTakingItem
|
||
```
|
||
|
||
### FruitBankGridBase<TDataItem>
|
||
|
||
Project-level adapter that fixes 3 of 4 generic parameters:
|
||
|
||
```csharp
|
||
public class FruitBankGridBase<TDataItem>
|
||
: MgGridBase<SignalRDataSourceObservable<TDataItem>, TDataItem, int, LoggerClient>
|
||
```
|
||
|
||
Adds FruitBank-specific defaults (master vs detail grid settings, alternating row style, header background). For the full settings table see [`FruitBankHybrid.Shared/Components/Grids/README.md`](../FruitBankHybrid.Shared/Components/Grids/README.md).
|
||
|
||
### 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
|
||
<MgGridWithInfoPanel ShowInfoPanel="@IsMasterGrid">
|
||
<GridContent>
|
||
<GridShippingBase @ref="Grid"
|
||
DataSource="Shippings"
|
||
AutoSaveLayoutName="GridShipping"
|
||
SignalRClient="FruitBankSignalRClient"
|
||
Logger="_logger"
|
||
OnGridFocusedRowChanged="Grid_FocusedRowChanged">
|
||
<Columns>
|
||
<DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="Descending" ReadOnly />
|
||
<DxGridDataColumn FieldName="ShippingDate" Caption="Beérkezés" />
|
||
...
|
||
</Columns>
|
||
<DetailRowTemplate>
|
||
@{ var shipping = (Shipping)context.DataItem; }
|
||
<GridShippingDocument ParentDataItem="@shipping" ... />
|
||
</DetailRowTemplate>
|
||
</GridShippingBase>
|
||
</GridContent>
|
||
</MgGridWithInfoPanel>
|
||
```
|
||
|
||
## 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
|