Files
ExperionCrawler/AGENTS.md
2026-05-08 17:22:10 +09:00

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 DB
  • ExperionHistoryService — periodic snapshot (60s) from realtime_table → history_table
  • ExperionOpcServerService — exposes realtime data as OPC UA server (port 4841)
  • McpServerHostedService — Python MCP server bridge
  • ExperionFastService — high-frequency data capture sessions
  • ExperionFastCleanupService — 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]; use DefaultSessionFactory.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 SelectEndpointAsync with a 10s CancellationTokenSource (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.