Skip to main content

Construction — site operations, safety & documents

The problem. A construction site runs on documents as much as data: drawings, permits, method statements, inspection sign-offs — each belonging to a specific zone of the site, each needing to be on hand the moment an inspector or crew lead asks. On top of that, equipment utilisation and safety incidents need tracking. The challenge is keeping the paperwork, the machines, and the incidents all tied to the right part of the site.

This scenario pairs document management with safety events on a modelled site.

Set up demo data

New workspace? Run this once (Python) to create the site graph and a crane-utilisation series. (The drawing upload in step 1 needs a local file — any PDF works.) Safe to re-run.

import datahub_sdk, numpy as np, pandas as pd

client = datahub_sdk.DataHubClient.from_env()

client.resources.create(
[datahub_sdk.Resource(external_id=x, name=x, labels=[lbl]) for x, lbl in
[("site_harbour_tower", "Site"), ("zone_level_12", "Zone")]],
[datahub_sdk.RelForm.by_external_ids("site_harbour_tower", "zone_level_12", "contains")])

client.timeseries.create([datahub_sdk.TimeSeries(external_id="crane_02_hours", name="Crane 02 hours", unit="h", value_type="float")])
idx = pd.date_range(end=pd.Timestamp.now(tz="UTC"), periods=14, freq="1d")
client.timeseries.insert_from_lists(timestamps=idx, values=np.random.uniform(4, 9, 14), ts="crane_02_hours")

1. Model the site and attach its documents

A site contains zones. Each zone's drawings and permits live in its folder, tagged so a crew can find the current revision instantly. See Attach files.

ResourceForm site = new ResourceForm();
site.setExternalId("site_harbour_tower");
site.setName("Harbour Tower");
site.setLabels(List.of("Site"));

ResourceForm zone = new ResourceForm();
zone.setExternalId("zone_level_12");
zone.setName("Level 12");
zone.setLabels(List.of("Zone"));

RelForm contains = new RelForm();
contains.setName("contains");
contains.setFromExternalId("site_harbour_tower");
contains.setToExternalId("zone_level_12");

client.resources().create(List.of(site, zone), List.of(contains));

byte[] drawing = Files.readAllBytes(Path.of("level_12_rev_c.pdf"));
client.files().upload(
FileUploadRequest.builder()
.path("harbour_tower/level_12/drawings/structural_rev_c.pdf")
.content(drawing)
.contentType("application/pdf")
.externalId("drawing_level_12_structural_rev_c")
.description("Level 12 structural — revision C")
.build());

2. Record a safety incident against its zone

A near-miss or incident becomes a safety_incident event, tied to the zone via metadata so the HSE team can see a zone's full history and trend.

EventModel incident = new EventModel();
incident.setExternalId("safety_incident_l12_" + System.currentTimeMillis());
incident.setType("safety_incident");
incident.setSubType("near_miss");
incident.setStatus("open");
incident.setMetadata(Map.of("zone", "zone_level_12", "category", "dropped_object"));
incident.setEventTime(ZonedDateTime.now());
client.events().create(List.of(incident));

3. Track equipment use

Crane and hoist utilisation are series (crane_02_hours, hoist_north_cycles); roll them up to see idle plant and plan hire returns with Query & aggregate.

See the result

The recorded near-miss lands as an event against its zone:

safety_incident_l12_… → open (dropped-object near-miss on zone_level_12)

See also