3.1 KiB
ExperionCrawler — Agent Instructions
Build / Run / Test
| Action | Command | Working Dir |
|---|---|---|
| Build | dotnet build src/Web/ExperionCrawler.csproj |
repo root |
| Run (dev) | dotnet run |
src/Web/ |
| Publish | dotnet publish -c Release -o /opt/ExperionCrawler |
src/Web/ |
| Tests | dotnet test |
repo root |
Single project: src/Web/ExperionCrawler.csproj. Core and Infrastructure are included via <Compile Include> globs — there are no separate projects to build. Runtime target is linux-arm64.
Architecture
src/
├── Core/ — Interfaces (IExperionServices.cs), Domain entities, DTOs, Application Services
├── Infrastructure/ — OpcUa/, Database/, Certificates/, Csv/, Mcp/
└── Web/ — Program.cs, Controllers/, wwwroot/ (SPA)
All controllers are in src/Web/Controllers/ExperionControllers.cs (single file). All interfaces are in src/Core/Application/Interfaces/IExperionServices.cs (single file).
Database
PostgreSQL (NOT SQLite — README is stale). Connection strings in src/Web/appsettings.json. TimescaleDB extension may be enabled on history_table via DDL only; no app code changes needed.
Critical Convention — JSON camelCase
PropertyNamingPolicy = null in Program.cs means C# PascalCase becomes JSON keys. Frontend expects camelCase. Every controller Ok(...) response MUST use explicit anonymous objects with camelCase keys:
// ✅ Correct
return Ok(new { id = x.Id, tagName = x.TagName });
// ❌ Broken — JS gets undefined
return Ok(new { x.Id, x.TagName });
return Ok(myDto); // typed object
See CODING_CONVENTIONS.md for full details and checklist.
Background Services (HostedServices in Program.cs)
ExperionRealtimeService— OPC UA subscription, 500ms batch flush to DBExperionHistoryService— periodic snapshot (60s) from realtime_table → history_tableExperionOpcServerService— exposes realtime data as OPC UA server (port 4841)McpServerHostedService— Python MCP server bridgeExperionFastService— high-frequency data capture sessionsExperionFastCleanupService— expired session cleanup
All registered as Singleton + HostedService. RealtimeService and OpcServerService share autostart flag files (realtime_autostart.json, opcserver_autostart.json) in the working directory.
Frontend
Vanilla JS SPA. wwwroot/index.html + js/app.js + css/style.css. No build step. Tab-based navigation; tabs do NOT auto-fire API calls on entry (performance fix).
OPC UA SDK Gotchas
- SDK v1.5.378.134 —
Session.Create()is[Obsolete]; useDefaultSessionFactory.CreateAsync() Subscription.Create()/Delete()/ApplyChanges()also deprecated → async variants preferred- Certificate validation must be attached AFTER
OpcUaConfigProvider.GetConfigAsync()returns the config - TCP connect timeout: wrap
SelectEndpointAsyncwith a 10sCancellationTokenSource(OS default is 127s)
Deploy
sudo bash deploy.sh — publishes to /opt/ExperionCrawler, creates systemd service experioncrawler, sets up PKI dirs. Service runs as www-data.