Skip to content

Architecture

The Linked Data Explorer is a monorepo with two packages: a React frontend SPA and a Node.js/Express backend API. The frontend renders in the browser; the backend handles SPARQL queries, Operaton calls, and chain orchestration.


System architecture

Browser
  └── Frontend (React + TypeScript, Azure Static Web Apps)
            │ HTTPS/REST
  └── Backend (Node.js + Express, Azure App Service)
            ├── SPARQL ──────► TriplyDB (knowledge graph)
            └── REST API ────► Operaton (DMN execution engine)

The frontend never calls TriplyDB or Operaton directly in production. All calls go through the backend, which handles authentication, CORS, caching, and variable orchestration. In local development, the frontend can also use a CORS proxy fallback for public SPARQL endpoints.


Frontend architecture

The frontend is a single-page application with no routing library. Navigation state is managed as an enum (ViewMode) in the top-level App.tsx.

App.tsx
├── Sidebar navigation (ViewMode selector)
├── QueryEditor view
│   ├── SparqlEditor (query input)
│   ├── ResultsTable (tabular results)
│   └── GraphView (D3.js force-directed graph)
├── ChainBuilder view
│   ├── DmnList (available DMNs, left panel)
│   ├── ChainComposer (drag-drop zone, centre panel)
│   │   └── SemanticAnalysis tab
│   ├── ChainConfig (inputs + execution, right panel)
│   │   ├── InputForm
│   │   ├── ExecutionProgress
│   │   ├── ChainResults
│   │   └── ExportChain (JSON / BPMN 2.0)
│   └── ValidationPanel
├── BpmnModeler view
│   ├── ProcessList (left panel)
│   ├── BpmnCanvas (bpmn-js wrapper, centre)
│   └── BpmnProperties (right panel)
│       └── DmnTemplateSelector
└── Changelog / Help view

State is managed with React hooks at the component level. There is no global state library. The templateService.ts utility provides the only persistent state — localStorage CRUD for chain templates and BPMN processes.


Backend architecture

The backend is a structured Express application following the Dutch Government API Design Rules (API-20, API-57).

src/
├── index.ts              entry point, server startup
├── routes/
│   ├── index.ts          registers all route groups
│   ├── dmn.routes.ts     GET /v1/dmns, /v1/dmns/chains, /v1/dmns/semantic-equivalences
│   ├── chain.routes.ts   POST /v1/chains/execute, POST /v1/chains/export
│   ├── triplydb.routes.ts POST /v1/triplydb/query
│   └── health.routes.ts  GET /v1/health
├── services/
│   ├── sparql.service.ts       SPARQL queries against TriplyDB
│   ├── operaton.service.ts     Operaton REST API calls
│   ├── orchestration.service.ts chain execution and variable mapping
│   └── triplydb.service.ts     direct TriplyDB proxy (dynamic endpoints)
├── middleware/
│   ├── cors.ts
│   └── errorHandler.ts
└── utils/
    ├── logger.ts         Winston structured logging
    └── config.ts         environment config with validation

Legacy /api/* routes exist with deprecation headers for backward compatibility. All new work uses /v1/*.


Data flow — chain execution

1. Frontend POST /v1/chains/execute
   { chain: [dmnId1, dmnId2], inputs: {...}, endpoint: "..." }

2. orchestration.service.ts
   for each DMN in chain:
     a. sparql.service.ts → fetch DMN metadata from TriplyDB (cached 5 min)
     b. Flatten previous step outputs into current step inputs
     c. operaton.service.ts → POST /engine-rest/decision-definition/key/{id}/evaluate
     d. Collect and flatten results

3. Return combined results to frontend

Caching

The backend caches DMN metadata per endpoint with a 5-minute TTL. The cache key is the endpoint URL. Switching endpoints in the frontend bypasses the cache and triggers a fresh SPARQL query.


Environment variables

See Deployment for the full list. Key variables:

Variable Description
TRIPLYDB_ENDPOINT Default SPARQL endpoint URL
OPERATON_BASE_URL Operaton engine REST base URL
CORS_ORIGIN Comma-separated list of allowed frontend origins
NODE_ENV development, acceptance, or production
PORT Backend listen port (default 3001 local, 8080 Azure)