Skip to content

Architecture

The Linked Data Explorer is a monorepo with three workspaces under packages/: a React frontend SPA, a Node.js/Express backend API, and ropa-site, the static public site for the register of processing activities. 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 does not call TriplyDB or Operaton itself. Queries, deployments and chain execution all go through the backend, which handles authentication, CORS, caching, variable orchestration โ€” and, since v2026.09.5, the outbound guard that checks every host a caller names. That includes the SPARQL Query Editor, which until v2026.09.5 fetched the chosen endpoint straight from the browser and fell back to the third-party api.allorigins.win proxy; both paths are gone. The one thing the browser still loads from TriplyDB directly is organisation logo images, which the frontend's Content-Security-Policy admits in img-src.


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)
โ”‚   โ”‚   โ””โ”€โ”€ Deploy modal (one-click Operaton deployment)
โ”‚   โ””โ”€โ”€ BpmnProperties (right panel)
โ”‚       โ”œโ”€โ”€ DmnTemplateSelector (BusinessRuleTask)
โ”‚       โ””โ”€โ”€ FormTemplateSelector (UserTask / StartEvent)  โ† new in v1.0.0
โ”œโ”€โ”€ FormEditor view                                       โ† new in v1.0.0
โ”‚   โ”œโ”€โ”€ FormList (left panel)
โ”‚   โ””โ”€โ”€ FormCanvas (@bpmn-io/form-js editor, centre)
โ””โ”€โ”€ Changelog / Help view

The FormEditor view and BpmnModeler view share the FormService localStorage layer โ€” forms authored in FormEditor are immediately available to FormTemplateSelector in the BPMN properties panel with no explicit synchronisation step.

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: middleware, route mounting, server startup
โ”œโ”€โ”€ routes/               one file per route group, mounted under /v1 by routes/index.ts
โ”‚   โ”œโ”€โ”€ registry.ts       the route topology, described once (the root page reads it)
โ”‚   โ”œโ”€โ”€ health ยท openapi ยท dmn ยท chain ยท template ยท process ยท shacl ยท norms
โ”‚   โ”œโ”€โ”€ triplydb ยท vendor ยท dso ยท edocs ยท cache ยท cspReports
โ”‚   โ””โ”€โ”€ assets ยท assets.public ยท ropa ยท ropa.public
โ”œโ”€โ”€ services/             one per external system or domain: sparql, operaton,
โ”‚                         orchestration, triplydb, dso, edocs, vendor, norms, template,
โ”‚                         dmn-validation, shacl-validation, assets, ropa, externalTaskWorker
โ”œโ”€โ”€ db/                   pg pool, idempotent migrations, row mappers
โ”œโ”€โ”€ openapi/              document.ts serves the built description; testing/ holds the
โ”‚                         helpers that validate route responses against it
โ”œโ”€โ”€ middleware/
โ”‚   โ”œโ”€โ”€ cors.middleware.ts      allowlist, plus wildcard for the three public mounts
โ”‚   โ”œโ”€โ”€ error.middleware.ts     central RFC 9457 problem-details handler
โ”‚   โ””โ”€โ”€ version.middleware.ts   API-Version header
โ””โ”€โ”€ utils/
    โ”œโ”€โ”€ outboundUrl.ts    route-level checks on caller-supplied endpoints
    โ”œโ”€โ”€ outboundHttp.ts   the guarded axios client for caller-chosen hosts
    โ”œโ”€โ”€ problem.ts        builds problem-details responses
    โ”œโ”€โ”€ validation.ts     body validators for the asset and ROPA upserts
    โ”œโ”€โ”€ publicPaths.ts    the three mounts served to any origin
    โ”œโ”€โ”€ buildInfo.ts      reads deploy/build-info.json for /v1/health
    โ”œโ”€โ”€ config.ts         environment configuration
    โ””โ”€โ”€ logger.ts         Winston structured logging

The request and response shapes of every route are in the API Specification, built from packages/backend/openapi/openapi.yaml.

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)