Telemetry reading
- Oil temp
- 102.4 °C alarm 105 °C
- Winding temp
- 118.7 °C warn 110 °C
- Load factor
- 93% warn 100%
- Voltage
- 0.984 pu
- DGA H₂
- 64 ppm
- DGA C₂H₂
- 0.60 ppm
GridSight is a vertical slice of a real-feeling utility tool: a fleet view of eight plausibly-Swedish substation transformers and feeder breakers, each emitting SCADA-style telemetry (top-oil and winding temperatures, load factor, voltage, dissolved-gas readings) every 5 seconds via an in-process simulator. Threshold rules referenced to IEEE C57.91 (transformer loading) and IEEE C57.104 (DGA condition limits) raise alerts as soon as a reading crosses warning or alarm levels. The Angular frontend subscribes to a single Server-Sent Events stream and updates the dashboard, asset detail charts, and alert feed live, with reconnect-with-exponential-backoff baked into the SSE client.
The backend is Node 20 + Express + strict TypeScript, with SQLite (better-sqlite3, WAL mode) for storage, Zod at every API boundary, pino for structured logging, prom-client for /metrics, and a hand-authored OpenAPI 3.1 spec served at /openapi. The simulator and the alert engine are pure functions over a TelemetryReading type, with vitest unit tests covering the threshold matrix and asserting that compound failures (overload + high oil temp) raise multiple alerts. Helmet, CORS allowlist, express-rate-limit, and graceful SIGTERM shutdown round out the security and operability defaults.
The AI feature is the differentiator and the security-conscious bit. The recommendations endpoint is env-gated: if ANTHROPIC_API_KEY is set, the route calls Claude with a tool-use schema enforcing the response shape (urgency, root_cause, recommended_actions[], confidence, references); if the key is missing, it serves a hand-authored fixture matched to the alert rule. The five fixtures (healthy, oil-temp-high, load-imbalance, winding-fault, dga-spike) are written to read like recommendations a maintenance planner could actually act on, citing IEEE references and explicit priority levels (now / soon / planned). The portfolio page narrative around this is the point: real integration in the repo, fixtures in the public demo, key never leaves local dev.
The Angular frontend is intentionally modern: standalone components, signals (state), control-flow @if/@for, OnPush change detection, lazy-loaded routes, RxJS via takeUntilDestroyed for cleanup, Angular Material for chrome, and a hand-rolled inline-SVG sparkline component instead of pulling in a chart library. The whole bundle stays under 500kb initial. Architecture is env-driven and stateless, so although the demo runs on Vercel, the same binaries are Azure App Service portable. That trade-off is documented on this page rather than papered over.
TR-RASUNDA-11A reading captured mid-fault. Same data shape that flows over the SSE stream and into the AI recommendation endpoint.
Top-oil temperature has crossed the IEEE C57.91 alarm threshold (105 °C) while load factor remained near rated capacity. The combination indicates the cooling system is under-performing relative to thermal demand, most commonly a fouled radiator surface, degraded fan operation, or low oil level.
Sustained operation above 105 °C accelerates insulation aging by ~2× per 6 °C (Arrhenius). Load reduction is the only corrective lever available remotely.
Three of the four most common causes of high-oil-temp events are cooling-system mechanical and can be diagnosed in a single 30-minute site visit.
Thermography reveals partial blockages and uneven flow that are not detectable from oil-temp telemetry alone.
The integration code in api/src/domain/recommender.ts calls Claude with a tool-use schema enforcing this exact shape. The deployed demo doesn't ship the API key. It serves five hand-authored fixtures matched to the alert rule. Flip ANTHROPIC_API_KEY in env to switch paths.
The recommendations endpoint is env-gated: with ANTHROPIC_API_KEY set, the route calls Claude with a tool-use schema enforcing
the response shape; without it, the route serves one of five hand-authored fixtures. Same
JSON contract, two paths. The deployed demo never holds the key.
Field naming follows IEC 60076; threshold rules reference IEEE C57.91 (oil 95/105 °C, winding 130 °C) and IEEE C57.104 (DGA condition 2/3). The simulator injects compound failures and the alert engine raises the right combinations.
Stateless API + env-driven config = Azure App Service portable. The demo runs on Vercel; moving it to Azure is a Bicep file and a connection string.