# AOT Readiness Implementation Plan
## Overview
Make the JdeScopingTool .NET 10 solution ready for Native AOT compilation by addressing three critical areas:
1. **JSON Source Generation** - Replace reflection-based System.Text.Json with source generators
2. **Dapper AOT** - Enable compile-time SQL mapping generation
3. **Configuration Binding** - Replace reflection-based options binding and validation
**Current AOT Score:** ~25/100 (1 of 14 projects ready)
**Target AOT Score:** 90/100 (all projects AOT-compatible with known library exceptions)
---
## Current State Summary
### Projects by AOT Readiness
| Status | Project | Key Blockers |
|--------|---------|--------------|
| ✅ Ready | `JdeScoping.Domain` | None - pure domain models |
| ❌ Needs Work | `JdeScoping.DataAccess` | Dapper, SqlKata, Oracle driver |
| ❌ Needs Work | `JdeScoping.DataSync` | Dapper + STJ without source gen |
| ❌ Needs Work | `JdeScoping.Core` | STJ + Configuration.Binder |
| ❌ Needs Work | `JdeScoping.Infrastructure` | STJ + SecureStore + LDAP |
| ❌ Needs Work | `JdeScoping.Api` | STJ + Swashbuckle + config binding |
| ❌ Needs Work | `JdeScoping.Host` | Depends on API/DataSync |
| ❌ Needs Work | `JdeScoping.Client` | STJ + Radzen + SignalR |
| ❌ Needs Work | `JdeScoping.ExcelIO` | ClosedXML |
| ❌ Needs Work | `JdeScoping.Database` | dbup-sqlserver |
| ❌ Needs Work | ConfigManager.* | STJ + System.CommandLine + Avalonia |
### No Existing AOT Configuration
- No `PublishAot` property
- No `IsAotCompatible` markers
- No `TrimMode` settings
- No `[DynamicallyAccessedMembers]` attributes
- No `[RequiresUnreferencedCode]` attributes
---
## Phase 1: Solution-Wide AOT Configuration
### 1.1 Create Directory.Build.props
**File:** `NEW/src/Directory.Build.props` (new)
```xml
true
true
true
true
true
false
```
### 1.2 Update Host Project for AOT Publishing
**File:** `NEW/src/JdeScoping.Host/JdeScoping.Host.csproj`
Add:
```xml
false
true
partial
```
---
## Phase 2: JSON Source Generation (~45 types)
### 2.1 Create JsonSerializerContext Classes
| Project | Context File | Types Count |
|---------|-------------|-------------|
| JdeScoping.Core | `Json/CoreJsonContext.cs` | ~30 (ViewModels, Auth, Search) |
| JdeScoping.DataSync | `Json/DataSyncJsonContext.cs` | ~6 (ETL pipeline configs) |
| JdeScoping.Api | `Json/ApiJsonContext.cs` | ~10 (FileUploadResult, HealthCheck) |
| JdeScoping.Client | `Json/ClientJsonContext.cs` | ~15 (Client-side types) |
| ConfigManager.Core | `Json/ConfigManagerJsonContext.cs` | ~13 (ConfigModel sections) |
### 2.2 Types Requiring [JsonSerializable] Attributes
#### Core Authentication & Identity Types
- `UserInfoDto` - `JdeScoping.Core/Models/Auth/UserInfoDto.cs`
- `LoginResultModel` - `JdeScoping.Core/Models/Auth/LoginResultModel.cs`
- `LoginModel` - `JdeScoping.Core/Models/Auth/LoginModel.cs`
#### Search & Criteria Types
- `SearchCriteria` - `JdeScoping.Core/Models/Search/SearchCriteria.cs`
- `Search` - `JdeScoping.Core/Models/Search/Search.cs`
- `SearchViewModel` - `JdeScoping.Core/ViewModels/SearchViewModel.cs`
- `SearchUpdateViewModel` - `JdeScoping.Core/ViewModels/SearchUpdateViewModel.cs`
- `StatusUpdateViewModel` - `JdeScoping.Core/ViewModels/StatusUpdateViewModel.cs`
#### File Upload & Result Types
- `FileUploadResult` - `JdeScoping.Client/Models/FileUploadResult.cs`
- `FileUploadResult` - `JdeScoping.Api/Models/FileUploadResult.cs`
#### Data Sync & Manual Sync Types
- `ManualSyncRequestViewModel` - `JdeScoping.Api/Contracts/ManualSync/ManualSyncRequestViewModel.cs`
- `CreateManualSyncRequestDto` - `JdeScoping.Core/ViewModels/CreateManualSyncRequestDto.cs`
- `PipelineInfoViewModel` - `JdeScoping.Api/Contracts/ManualSync/PipelineInfoViewModel.cs`
#### ETL Pipeline Configuration Types
- `EtlPipelineConfig` - `JdeScoping.DataSync/Configuration/EtlPipelineConfig.cs`
- `SourceElement` - `JdeScoping.DataSync/Configuration/SourceElement.cs`
- `DestinationElement` - `JdeScoping.DataSync/Configuration/DestinationElement.cs`
- `TransformElement` - `JdeScoping.DataSync/Configuration/TransformElement.cs`
- `ScriptElement` - `JdeScoping.DataSync/Configuration/ScriptElement.cs`
- `ParameterElement` - `JdeScoping.DataSync/Configuration/ParameterElement.cs`
#### Configuration Model Types
- `ConfigModel` - `Utils/JdeScoping.ConfigManager.Core/Models/ConfigModel.cs`
- `ConnectionStringsSection` - `Utils/JdeScoping.ConfigManager.Core/Models/ConnectionStringsSection.cs`
- `ConnectionStringEntry` - `Utils/JdeScoping.ConfigManager.Core/Models/ConnectionStringEntry.cs`
#### Data ViewModels
- `WorkOrderViewModel`, `ItemViewModel`, `WorkCenterViewModel`, `ProfitCenterViewModel`
- `PartOperationViewModel`, `JdeUserViewModel`, `LotViewModel`, `ComponentLotViewModel`, `OperatorViewModel`
### 2.3 Key Files to Create
**`NEW/src/JdeScoping.Core/Json/CoreJsonContext.cs`** - Central context with:
- All ViewModels (SearchViewModel, WorkOrderViewModel, ItemViewModel, etc.)
- Auth models (UserInfoDto, LoginResultModel, LoginModel)
- SearchCriteria, ApiError, ValidationError
**`NEW/src/JdeScoping.DataSync/Json/DataSyncJsonContext.cs`**:
- EtlPipelineConfig, SourceElement, DestinationElement, TransformElement
**`NEW/src/JdeScoping.Api/Json/ApiJsonContext.cs`**:
- FileUploadResult instantiations for each ViewModel type
- HealthCheckResponse (replace anonymous type)
### 2.4 Registration Updates
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** (line ~80):
```csharp
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, CoreJsonContext.Default);
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, ApiJsonContext.Default);
});
```
**`NEW/src/JdeScoping.Client/Services/ApiClientBase.cs`** (line ~16):
```csharp
private static readonly JsonSerializerOptions JsonOptions = new()
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(
ClientJsonContext.Default,
CoreJsonContext.Default)
};
```
### 2.5 Fix Anonymous Type in Health Check
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** - Replace anonymous object with typed `HealthCheckResponse` class.
---
## Phase 3: Dapper AOT (15+ model types)
### 3.1 Dapper Usage Locations
| File | Dapper Methods | Model Types |
|------|---------------|-------------|
| `LotFinderRepository.SearchManagement.cs` | QueryAsync, QueryFirstOrDefaultAsync | Search |
| `LotFinderRepository.Lookups.cs` | QueryAsync | Item, Lot, WorkOrder, WorkCenter, ProfitCenter, JdeUser |
| `LotFinderRepository.DataSync.cs` | QueryAsync | DataUpdate |
| `SearchProcessor.cs` | QueryAsync, QuerySingleOrDefaultAsync | SearchResult, MisSearchResult, MisNonMatchSearchResult |
| `ManualSyncRequestService.cs` | QueryAsync, QuerySingleAsync, ExecuteAsync | ManualSyncRequest |
| `WorkOrderTraversalService.cs` | QuerySingleAsync | (int, int) tuple |
| `DataUpdateRepository.cs` | QueryAsync, ExecuteScalarAsync, ExecuteAsync | DataUpdate, (string, int, DateTime?, int) tuple |
| `SearchRepository.cs` | QueryFirstOrDefaultAsync, ExecuteAsync | Search |
### 3.2 Add Dapper.AOT Package
**Files:** `JdeScoping.DataAccess.csproj`, `JdeScoping.DataSync.csproj`
```xml
$(InterceptorsPreviewNamespaces);Dapper.AOT
```
### 3.3 Enable AOT for Assemblies
**`NEW/src/JdeScoping.DataAccess/DapperAotConfiguration.cs`** (new):
```csharp
[assembly: DapperAot]
```
### 3.4 Fix Private Field Mapping Pattern
Change 6 models from private to internal for Dapper.AOT compatibility:
| Model | File |
|-------|------|
| Item | `Core/Models/Inventory/Item.cs` |
| Lot | `Core/Models/Inventory/Lot.cs` |
| WorkOrder | `Core/Models/WorkOrders/WorkOrder.cs` |
| WorkCenter | `Core/Models/Organization/WorkCenter.cs` |
| ProfitCenter | `Core/Models/Organization/ProfitCenter.cs` |
| JdeUser | `Core/Models/Organization/JdeUser.cs` |
Change:
```csharp
private int LastUpdateDate { get; set; } // Before
[Column("LastUpdateDate")]
internal int LastUpdateDate { get; set; } // After
```
### 3.5 Replace Tuple Queries with Named Types
Create explicit result types:
**`NEW/src/JdeScoping.DataAccess/Models/TraversalResult.cs`** (new):
```csharp
public sealed class TraversalResult
{
public int IterationsCompleted { get; init; }
public int TotalWorkOrders { get; init; }
}
```
**`NEW/src/JdeScoping.DataSync/Models/TableSyncStatusRow.cs`** (new):
```csharp
public sealed class TableSyncStatusRow
{
public string TableName { get; init; } = string.Empty;
public int UpdateType { get; init; }
public DateTime? LastSuccessfulSync { get; init; }
public int RecentFailures { get; init; }
}
```
---
## Phase 4: Configuration Binding
### 4.1 Options Classes Inventory
| Project | Options Class | Has DataAnnotations | Uses ValidateDataAnnotations |
|---------|--------------|---------------------|------------------------------|
| JdeScoping.Core | SecureStoreOptions | No | No |
| JdeScoping.Core | RsaKeyOptions | No | No |
| JdeScoping.Infrastructure | LdapOptions | Yes (1 Range) | No |
| JdeScoping.Api | AuthOptions | No | No |
| JdeScoping.DataAccess | DataAccessOptions | No | No |
| JdeScoping.DataAccess | SearchProcessingOptions | No | No |
| JdeScoping.DataAccess | SearchProcessingConfiguration | No | No |
| JdeScoping.DataSync | DataSyncOptions | Yes (6 Range) | **Yes** |
| JdeScoping.DataSync | WorkProcessorOptions | Yes (3 Range) | **Yes** |
| JdeScoping.ExcelIO | ExcelExportOptions | No | No |
| JdeScoping.DataSync.Dev | DevPipelineOptions | No | No |
### 4.2 Create AOT-Compatible Validators
Replace `ValidateDataAnnotations()` with `IValidateOptions`:
**`NEW/src/JdeScoping.DataSync/Validation/DataSyncOptionsValidator.cs`** (new)
**`NEW/src/JdeScoping.DataSync/Validation/WorkProcessorOptionsValidator.cs`** (new)
### 4.3 Update DependencyInjection Files
**`NEW/src/JdeScoping.DataSync/DependencyInjection.cs`** (lines 27-36):
```csharp
// Before
.ValidateDataAnnotations()
// After
services.AddSingleton, DataSyncOptionsValidator>();
```
**`NEW/src/JdeScoping.Infrastructure/DependencyInjection.cs`** (lines 33-35):
Replace `GetSection().Get()` with `GetSection().GetValue()`.
**`NEW/src/JdeScoping.Api/DependencyInjection.cs`** (lines 33-35):
Replace `GetSection().Get()` with explicit property binding.
### 4.4 Remove Unused Package
**`NEW/src/JdeScoping.DataSync/JdeScoping.DataSync.csproj`**:
Remove `Microsoft.Extensions.Options.DataAnnotations` reference.
---
## Phase 5: Third-Party Library Handling
### 5.1 Package Risk Assessment
| Risk Level | Packages |
|------------|----------|
| 🔴 High | Dapper (mitigated by Dapper.AOT), SqlKata, Swashbuckle, ClosedXML, dbup-sqlserver |
| 🟠 Medium | protobuf-net-data, System.CommandLine, SecureStore |
| 🟡 Low | Microsoft.Data.SqlClient, Oracle driver, LDAP, Serilog |
| 🟢 Safe | Cronos, OneOf (has source generator), ZstdSharp |
### 5.2 Create Trimmer Roots
**`NEW/src/JdeScoping.Host/TrimmerRoots.xml`** (new):
```xml
```
### 5.3 Known Limitations
These packages have partial/no AOT support - preserved via trimmer roots:
- ClosedXML (Excel generation)
- Oracle.ManagedDataAccess.Core
- dbup-sqlserver (migrations - dev only)
- Swashbuckle (Swagger - dev only)
---
## Implementation Sequence
| Step | Task | Files |
|------|------|-------|
| 1 | Create Directory.Build.props | 1 new |
| 2 | Create CoreJsonContext | 1 new |
| 3 | Create DataSyncJsonContext | 1 new |
| 4 | Create ApiJsonContext + HealthCheckResponse | 1 new |
| 5 | Create ClientJsonContext | 1 new |
| 6 | Create ConfigManagerJsonContext | 1 new |
| 7 | Update Api DependencyInjection (JSON registration) | 1 edit |
| 8 | Update ApiClientBase (JSON options) | 1 edit |
| 9 | Update PipelineRegistry (JSON options) | 1 edit |
| 10 | Add Dapper.AOT packages | 2 edits |
| 11 | Create DapperAotConfiguration | 1 new |
| 12 | Update 6 models (private→internal) | 6 edits |
| 13 | Create TraversalResult, TableSyncStatusRow | 2 new |
| 14 | Update tuple queries to use named types | 2 edits |
| 15 | Create DataSyncOptionsValidator | 1 new |
| 16 | Create WorkProcessorOptionsValidator | 1 new |
| 17 | Update DataSync DependencyInjection | 1 edit |
| 18 | Update Infrastructure DependencyInjection | 1 edit |
| 19 | Update Api DependencyInjection (config) | 1 edit |
| 20 | Update Host csproj (AOT settings) | 1 edit |
| 21 | Create TrimmerRoots.xml | 1 new |
| 22 | Remove DataAnnotations package | 1 edit |
**Total: 14 new files, 18 edits**
---
## Verification
### Build Verification
```bash
dotnet build NEW/JdeScoping.slnx
```
Should complete with no new errors.
### AOT Analysis
```bash
dotnet publish NEW/src/JdeScoping.Host -c Release -p:PublishAot=true --no-build
```
Check for AOT compatibility warnings.
### Trim Analysis
```bash
dotnet publish NEW/src/JdeScoping.Host -c Release -p:PublishTrimmed=true
```
Review trim warnings and verify TrimmerRoots coverage.
### Test Suite
```bash
dotnet test NEW/JdeScoping.slnx
```
All existing tests should pass.
### E2E Verification
Run Playwright tests to verify JSON serialization works end-to-end.
---
## Critical Files Summary
**New Files (14):**
- `NEW/src/Directory.Build.props`
- `NEW/src/JdeScoping.Core/Json/CoreJsonContext.cs`
- `NEW/src/JdeScoping.DataSync/Json/DataSyncJsonContext.cs`
- `NEW/src/JdeScoping.Api/Json/ApiJsonContext.cs`
- `NEW/src/JdeScoping.Client/Json/ClientJsonContext.cs`
- `NEW/src/Utils/JdeScoping.ConfigManager.Core/Json/ConfigManagerJsonContext.cs`
- `NEW/src/JdeScoping.DataAccess/DapperAotConfiguration.cs`
- `NEW/src/JdeScoping.DataAccess/Models/TraversalResult.cs`
- `NEW/src/JdeScoping.DataSync/Models/TableSyncStatusRow.cs`
- `NEW/src/JdeScoping.DataSync/Validation/DataSyncOptionsValidator.cs`
- `NEW/src/JdeScoping.DataSync/Validation/WorkProcessorOptionsValidator.cs`
- `NEW/src/JdeScoping.Host/TrimmerRoots.xml`
**Key Edits:**
- `NEW/src/JdeScoping.Api/DependencyInjection.cs` - JSON + config
- `NEW/src/JdeScoping.Client/Services/ApiClientBase.cs` - JSON options
- `NEW/src/JdeScoping.DataSync/DependencyInjection.cs` - Validators
- `NEW/src/JdeScoping.Infrastructure/DependencyInjection.cs` - Config binding
- `NEW/src/JdeScoping.Host/JdeScoping.Host.csproj` - AOT settings
- 6 model files for private→internal field change