feat: ExperionCrawler IIoT OPC UA Data Bridge Infrastructure

Major project initialization and feature implementation:

**Core Features:**
- OPC UA client for Honeywell Experion HS R530 integration
- Real-time data streaming and history data retrieval
- Text-to-SQL query engine with TimeScaleDB
- JSON-based node configuration system
- SQLite database with migration support

**Architecture:**
- Clean architecture with Domain, Application, Infrastructure layers
- ASP.NET Core Web API frontend
- Web UI with real-time visualization
- PKI-based OPC UA authentication (TLS)

**Infrastructure Components:**
- ExperionOpcClient: OPC UA connection management
- ExperionRealtimeService: Real-time data streaming
- ExperionHistoryService: Historical data queries
- TextToSqlService: Natural language to SQL queries
- SqlValidator: SQL injection prevention

**Database:**
- TimescaleDB integration (recommended) or SQLite fallback
- Entity Framework Core with Extenstion methods
- OPCTag, KeyValue tables for data storage

**Security:**
- Certificate-based OPC UA endpoint security
- SSL/TLS encryption for database connections
- Output param binding injection prevention

**Testing:**
- Unit tests for TextToSqlService and SqlValidator
- Integration tests for Korean time range extraction

See REVIEW_REQUEST.md for detailed code review information.
This commit is contained in:
windpacer
2026-04-26 19:28:56 +09:00
parent e34ec08001
commit 77bdcf1f7f
60 changed files with 10948 additions and 227 deletions

View File

@@ -9,7 +9,12 @@ using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// ── MVC / Swagger ─────────────────────────────────────────────────────────────
builder.Services.AddControllers();
builder.Services.AddControllers()
.AddJsonOptions(opt =>
{
// JSON 직렬화 시 대소문자 구분 없이 처리하도록 PascalCase 유지
opt.JsonSerializerOptions.PropertyNamingPolicy = null;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
c.SwaggerDoc("v1", new() { Title = "ExperionCrawler API", Version = "v1" }));
@@ -17,6 +22,7 @@ builder.Services.AddSwaggerGen(c =>
// ── Infrastructure ────────────────────────────────────────────────────────────
builder.Services.AddSingleton<IExperionCertificateService, ExperionCertificateService>();
builder.Services.AddSingleton<IExperionStatusCodeService, ExperionStatusCodeService>();
builder.Services.AddSingleton<IOpcUaConfigProvider, OpcUaConfigProvider>();
builder.Services.AddScoped<IExperionOpcClient, ExperionOpcClient>();
builder.Services.AddScoped<IExperionCsvService, ExperionCsvService>();
builder.Services.AddScoped<AssetLoader>();
@@ -30,7 +36,21 @@ builder.Services.AddScoped<IExperionDbService, ExperionDbService>();
// ── Application Services ──────────────────────────────────────────────────────
builder.Services.AddScoped<ExperionCrawlService>();
// ── KST 시간대 관리 서비스 ──────────────────────────────────────────────────
builder.Services.AddSingleton<IClock, SystemClock>();
builder.Services.AddSingleton<KstClock>();
// ── 한글 시간 범위 추출기 ──────────────────────────────────────────────────
builder.Services.AddSingleton<KoreanTimeRangeExtractor>();
// ── Text-to-SQL Service ──────────────────────────────────────────────────────
builder.Services.AddSingleton<SqlValidatorOptions>(_ => new SqlValidatorOptions
{
RequiredTables = ["history_table"],
AllowedTables = ["history_table", "node_map_master"],
MaxSubqueryDepth = 4
});
builder.Services.AddSingleton<SqlValidator>();
builder.Services.AddScoped<ITextToSqlService, TextToSqlService>();
// ── Realtime & History BackgroundServices ─────────────────────────────────────