Initial commit: JDE Scoping Tool migration project

Set up repository with legacy .NET Framework 4.8 source (OLD/),
new .NET 10 Blazor solution (NEW/), OpenSpec specifications,
documentation, and project configuration.
This commit is contained in:
Joseph Doherty
2026-01-02 07:43:29 -05:00
commit 26ff8d9b4f
1761 changed files with 596509 additions and 0 deletions
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<ProjectReference Include="..\JdeScoping.Api\JdeScoping.Api.csproj" />
<ProjectReference Include="..\JdeScoping.Client\JdeScoping.Client.csproj" />
<ProjectReference Include="..\JdeScoping.Core\JdeScoping.Core.csproj" />
<ProjectReference Include="..\JdeScoping.Database\JdeScoping.Database.csproj" />
<ProjectReference Include="..\JdeScoping.DataAccess\JdeScoping.DataAccess.csproj" />
<ProjectReference Include="..\JdeScoping.DataSync\JdeScoping.DataSync.csproj" />
<ProjectReference Include="..\JdeScoping.ExcelIO\JdeScoping.ExcelIO.csproj" />
<ProjectReference Include="..\JdeScoping.Infrastructure\JdeScoping.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.1" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
+81
View File
@@ -0,0 +1,81 @@
using JdeScoping.Api;
using JdeScoping.Core.Interfaces;
using JdeScoping.Core.Options;
using JdeScoping.DataAccess.Configuration;
using JdeScoping.Database;
using Microsoft.Extensions.Options;
var builder = WebApplication.CreateBuilder(args);
// Windows Service support (no-op on non-Windows)
builder.Host.UseWindowsService();
// Run database migrations (skip in Testing environment)
if (!builder.Environment.IsEnvironment("Testing"))
{
var migrator = new DatabaseMigrator(builder.Configuration);
var migrationResult = migrator.Migrate();
if (!migrationResult.Successful)
{
Console.WriteLine($"Database migration failed: {migrationResult.Error?.Message}");
return 1;
}
}
// ASP.NET Core services
builder.Services.AddRazorPages();
// Module registration (in dependency order)
builder.Services
.AddDataAccess(builder.Configuration) // 1. Database access + search processing
.AddInfrastructure(builder.Configuration) // 2. Infrastructure (JDE/CMS/Auth)
.AddDataSyncServices(builder.Configuration) // 3. Data sync background service
.AddExcelIO(builder.Configuration) // 4. Result export
.AddWebApi(builder.Configuration); // 5. Web API (controllers, auth, SignalR)
var app = builder.Build();
// Startup validation - verify critical services are registered
ValidateServices(app.Services);
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
app.UseStaticFiles();
app.UseBlazorFrameworkFiles();
app.UseRouting();
// Configure Web API middleware (authentication, authorization, controllers, SignalR hub)
app.UseWebApi();
app.MapRazorPages();
app.MapFallbackToFile("index.html");
app.Run();
return 0;
// Validates that critical services are properly registered
static void ValidateServices(IServiceProvider services)
{
using var scope = services.CreateScope();
var provider = scope.ServiceProvider;
// Validate Options classes are bound
_ = provider.GetRequiredService<IOptions<DataAccessOptions>>();
_ = provider.GetRequiredService<IOptions<DataSyncOptions>>();
_ = provider.GetRequiredService<IOptions<JdeScoping.DataSync.Configuration.DataSyncOptions>>();
_ = provider.GetRequiredService<IOptions<ExcelExportOptions>>();
_ = provider.GetRequiredService<IOptions<SearchProcessingOptions>>();
_ = provider.GetRequiredService<IOptions<DataSourceOptions>>();
// Validate data source services
_ = provider.GetRequiredService<IJdeDataSource>();
_ = provider.GetRequiredService<ICmsDataSource>();
Console.WriteLine("Service validation completed successfully.");
}
@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5294",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7159;http://localhost:5294",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
+147
View File
@@ -0,0 +1,147 @@
{
"ConnectionStrings": {
"LotFinder": "Server=localhost,1434;Database=ScopingTool;User Id=scopingapp;Password=Sc0ping@pp_Dev#2024;TrustServerCertificate=true",
"JDE": "Data Source=jde-server:1521/JDEPROD;User Id=${JDE_USER};Password=${JDE_PASSWORD}",
"CMS": "Data Source=cms-server:1521/CMSPROD;User Id=${CMS_USER};Password=${CMS_PASSWORD}"
},
"DataAccess": {
"CommandTimeoutSeconds": 120,
"EnableDetailedLogging": false
},
"DataSync": {
"Enabled": true,
"CheckInterval": "00:01:00",
"MaxDegreeOfParallelism": 8,
"BatchSize": 1000000,
"BulkCopyBatchSize": 10000,
"LookbackMultiplier": 3,
"PurgeRetentionDays": 30,
"SyncTimeoutSeconds": 3600,
"DataSources": [
{
"TableName": "WorkOrder_Curr",
"SourceSystem": "JDE",
"SourceData": "WORKORDER",
"FetcherTypeName": "JdeWorkOrderFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 }
},
{
"TableName": "LotUsage_Curr",
"SourceSystem": "JDE",
"SourceData": "LOTUSAGE",
"FetcherTypeName": "JdeLotUsageFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 }
},
{
"TableName": "Item",
"SourceSystem": "JDE",
"SourceData": "ITEM",
"FetcherTypeName": "JdeItemFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
},
{
"TableName": "Lot",
"SourceSystem": "JDE",
"SourceData": "LOT",
"FetcherTypeName": "JdeLotFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 }
},
{
"TableName": "WorkCenter",
"SourceSystem": "JDE",
"SourceData": "WORKCENTER",
"FetcherTypeName": "JdeWorkCenterFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
},
{
"TableName": "ProfitCenter",
"SourceSystem": "JDE",
"SourceData": "PROFITCENTER",
"FetcherTypeName": "JdeProfitCenterFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
},
{
"TableName": "JdeUser",
"SourceSystem": "JDE",
"SourceData": "JDEUSER",
"FetcherTypeName": "JdeUserFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
},
{
"TableName": "Branch",
"SourceSystem": "JDE",
"SourceData": "BRANCH",
"FetcherTypeName": "JdeBranchFetcher",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
},
{
"TableName": "MisData",
"SourceSystem": "CMS",
"SourceData": "MISDATA",
"FetcherTypeName": "CmsMisDataFetcher",
"PostProcessorTypeName": "MisDataPostProcessor",
"IsEnabled": true,
"MassConfig": { "Enabled": true, "IntervalMinutes": 10080, "PrepurgeData": true, "ReIndexData": true },
"DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 },
"HourlyConfig": { "Enabled": false }
}
]
},
"Auth": {
"UseFakeAuth": false,
"CookieName": "ScopingTool.Auth",
"CookieExpirationMinutes": 480,
"AdminBypassUsers": []
},
"Ldap": {
"ServerUrls": ["ldap.corp.example.com"],
"GroupDn": "CN=ScopingTool-Users,OU=Groups,DC=corp,DC=example,DC=com",
"SearchBase": "DC=corp,DC=example,DC=com",
"ConnectionTimeoutSeconds": 30
},
"ExcelExport": {
"TempDirectory": "/tmp/lotfinder",
"MaxRowsPerSheet": 1048576,
"DefaultDateFormat": "yyyy-MM-dd HH:mm:ss"
},
"SearchProcessing": {
"PollingIntervalSeconds": 5,
"MaxConcurrentSearches": 2,
"SearchTimeoutMinutes": 30
},
"DataSource": {
"UseFileDataSource": false,
"FileDirectory": "DevData"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}