Skip to content

Commit 21f1b8c

Browse files
namedgraphclaude
andcommitted
Create LDH container scaffolding via app/ + LDH CLI, not bulk-loaded trigs
The bulk-loaded container documents rendered no children listings: LDH only renders one when the container document itself carries an rdf:_1 block pointing at an ldh:Object with rdf:value ldh:ChildrenView. Scaffolding is now a LinkedDataHub-Apps-style app/ tree — one Turtle file per container (root + 9 top-level containers + 7 taxonomy scheme containers, schemes keeping their skos:ConceptScheme as #this) — PUT over HTTP by `make install` via the LDH CLI (put.sh + Jena turtle from a ../LinkedDataHub checkout, LDH_HOME-overridable). LDH adds sioc:has_parent, dct:created/modified and acl:owner server-side and strips any client-sent sioc triples. ETL datasets now contain only dh:Item documents, still bulk-loaded with `make load`, attaching to the scaffolding via unchanged sioc:has_container URIs: the etl/containers/ domain is gone and the 7 taxonomy mappings no longer emit scheme graphs. validate.sh is strict again (dct:title + foaf:primaryTopic on every graph); SHACL keeps only the :ItemShape as LDH-specific, and :ConceptShape's scheme references switch from sh:class to host-agnostic IRI patterns since the scheme entity left the files. Also fix a stale-base trap: static-CSV taxonomy outputs kept the previous BASE because make skips missing intermediate cache/*.nt when the .trig looks up to date (this had committed localhost-based trigs for the 4 static schemes). A cache/.base stamp now invalidates the chain when BASE changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a84c365 commit 21f1b8c

50 files changed

Lines changed: 20459 additions & 20388 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ uv run --project etl/tools ltlod-reconcile <admin-units|persons> --input … --o
1919

2020
make up # deploy LinkedDataHub at https://localhost:4443/ (root Makefile;
2121
# bootstraps secrets + server cert, then docker compose up -d)
22+
make install # one-time: PUT app/ scaffolding (root + containers + taxonomy
23+
# schemes) via LDH CLI; needs ../LinkedDataHub checkout (LDH_HOME=…)
2224
make load # bulk-load datasets/current/*/*.trig into fuseki-end-user TDB2;
2325
# regenerate with `make -C etl` first (committed data has prod base);
2426
# ends with `make public` (anonymous read, LDH make-public.sh equivalent)
@@ -41,10 +43,9 @@ Every domain runs the same four stages (shared scripts in `etl/lib/`):
4143
(`mappings/*.rq`, `$base`-parameterized) executed by `arq` → TriG. The `.rq`
4244
files are reusable verbatim as LinkedDataHub CSV imports.
4345
4. **validate**`riot --validate` + every graph must have `dct:title` and
44-
`foaf:primaryTopic` on the graph URI (`foaf:primaryTopic` waived for
45-
`dh:Container` docs; see `etl/lib/validate.sh`) + SHACL shapes per entity
46-
type (`etl/shapes/<domain>.ttl`, auto-selected by output dir, executed via
47-
`etl/lib/shacl.sh`; also run in CI on committed datasets
46+
`foaf:primaryTopic` on the graph URI (see `etl/lib/validate.sh`) + SHACL
47+
shapes per entity type (`etl/shapes/<domain>.ttl`, auto-selected by output
48+
dir, executed via `etl/lib/shacl.sh`; also run in CI on committed datasets
4849
by `.github/workflows/shacl-validation.yml`).
4950

5051
Post-ETL: `ltlod-reconcile` matches entities to Wikidata (closed candidate sets
@@ -59,11 +60,12 @@ merge on load). Unmatched entities go to `cache/unmatched*.csv`, never force-mat
5960
keys** from the source registry (AR codes, JAR codes, Seimas `asmens_id`) — any
6061
pipeline mints cross-links from bare foreign keys. Single source of truth:
6162
`etl/URI-SCHEME.md` — update it when adding containers.
62-
- **LDH document hierarchy**: every document is `a dh:Item` +
63-
`sioc:has_container <its-container>`; container docs (`etl/containers/`
64-
`datasets/current/containers/containers.trig`) and taxonomy schemes are
65-
`dh:Container` + `sioc:has_parent`. This is what makes LinkedDataHub
66-
container pages list children — add both triples in any new mapping.
63+
- **LDH document hierarchy**: ETL outputs are *only* `dh:Item` docs with
64+
`sioc:has_container <its-container>` — add both triples in any new mapping.
65+
Containers and taxonomy scheme docs come from `app/` (one Turtle file per
66+
container, PUT via LDH CLI by `make install`); each carries an
67+
`rdf:_1 <#select-children>``ldh:Object`/`ldh:ChildrenView` block, without
68+
which LDH renders no children listing at all.
6769
- **Vocabulary cascade**: W3C specs first → domain-specific third-party vocabs
6870
(EU SEMIC, OP authority tables, FOAF) → schema.org as general fallback → custom
6971
(`http://linkeddata.lt/ns#`) last. Rationale per domain: `etl/ONTOLOGY-NOTES.md`.
@@ -101,6 +103,11 @@ merge on load). Unmatched entities go to `cache/unmatched*.csv`, never force-mat
101103
- Seimas API params: `kadencijos_id` (not `p_kade_id`); position rows may reference
102104
units absent from current feeds (dissolved commissions, the Board) — org-units
103105
mapping derives those from the members feed.
106+
- **Switching `BASE` auto-invalidates static-CSV taxonomies** via the
107+
`cache/.base` stamp in `etl/taxonomies/Makefile` (normalize outputs embed
108+
the base URI; fetched domains are immune — fetch is FORCE'd). Note `make
109+
clean` alone does NOT force the rebuild: missing `cache/*.nt` are
110+
intermediate files, which make skips when the `.trig` looks up to date.
104111
- **`make load` bypasses LDH's HTTP API**: it runs `tdb2.tdbloader` directly against
105112
the end-user TDB2 store via the one-off `tdb-loader` compose service (the
106113
`atomgraph/fuseki` image bundles the full Jena CLI inside the fuseki-server jar).
@@ -110,6 +117,11 @@ merge on load). Unmatched entities go to `cache/unmatched*.csv`, never force-mat
110117
- **Fuseki ports are never published to the host** — query via
111118
`https://localhost:4443/sparql` or from inside the network:
112119
`docker compose exec linkeddatahub curl http://varnish-end-user/ds/`.
120+
- **LDH strips client-sent `sioc:has_parent`/`sioc:has_container` on PUT** and
121+
manages the hierarchy itself (re-adds `sioc:has_parent` for `dh:Container`,
122+
adds `dh:Item` + `sioc:has_container` otherwise, plus `dct:created`/
123+
`acl:owner`) — never put sioc triples in `app/*.ttl`. `make install` is
124+
idempotent: PUT replaces the whole named graph.
113125
- **Public read access is class-based**: `make public` grants
114126
`acl:accessToClass def:Root, dh:Container, dh:Item, nfo:FileDataObject`
115127
ETL documents match because mappings type them `dh:Item`/`dh:Container`.

Makefile

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
SHELL := /bin/bash
22

3-
.PHONY: up down stop logs cert secrets load public drop
3+
.PHONY: up down stop logs cert secrets install load public drop
4+
5+
# LDH CLI checkout (provides put.sh etc.); Jena provides the `turtle` command
6+
LDH_HOME ?= ../LinkedDataHub
7+
include etl/config.mk # for JENA_HOME (its BASE is unused here)
8+
include .env # PROTOCOL/HOST/HTTPS_PORT/HTTPS_CLIENT_CERT_PORT/ABS_PATH
9+
10+
ifeq ($(HTTPS_PORT),443)
11+
BASE_URI := $(PROTOCOL)://$(HOST)$(ABS_PATH)
12+
else
13+
BASE_URI := $(PROTOCOL)://$(HOST):$(HTTPS_PORT)$(ABS_PATH)
14+
endif
15+
PROXY_URI := $(PROTOCOL)://$(HOST):$(HTTPS_CLIENT_CERT_PORT)$(ABS_PATH)
416

517
SECRET_FILES := secrets/owner_cert_password.txt \
618
secrets/secretary_cert_password.txt \
@@ -32,6 +44,22 @@ stop:
3244
logs:
3345
docker compose logs -f linkeddatahub
3446

47+
# Create/update the container scaffolding (root + containers + taxonomy scheme
48+
# docs from app/) via LDH CLI PUTs. Run once after `make up`; re-running is
49+
# safe (PUT replaces). Order: make up -> make install -> make load.
50+
install:
51+
@[ -d "$(LDH_HOME)/bin" ] || \
52+
{ echo "ERROR: LDH CLI not found — clone https://github.com/AtomGraph/LinkedDataHub to $(LDH_HOME) or pass LDH_HOME=…"; exit 1; }
53+
@[ -n "$$(docker compose ps -q linkeddatahub)" ] || \
54+
{ echo "ERROR: linkeddatahub container not found — run 'make up' first."; exit 1; }
55+
@echo "Waiting for LinkedDataHub health (first-boot seeding must finish)..."
56+
@until [ "$$(docker inspect -f '{{.State.Health.Status}}' $$(docker compose ps -q linkeddatahub))" = "healthy" ]; do \
57+
sleep 5; echo " ...waiting"; \
58+
done
59+
PATH="$$(find "$$(cd $(LDH_HOME) && pwd)/bin" -type d | tr '\n' ':')$(JENA_HOME)/bin:$$PATH" \
60+
./app/install.sh "$(BASE_URI)" ssl/owner/cert.pem \
61+
"$$(cat secrets/owner_cert_password.txt)" "$(PROXY_URI)"
62+
3563
# Bulk-load datasets/current/*/*.trig into the end-user TDB2 store. APPEND-ONLY:
3664
# clean rebuild = `make down && rm -rf fuseki/end-user && make up && make load`.
3765
load:

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ du Fuseki, Varnish kešai).
150150

151151
```shell
152152
make up # sugeneruoja slaptažodžius + serverio sertifikatą ir paleidžia LDH
153+
make install # vienkartinis: sukuria konteinerių dokumentus per LDH CLI (reikia ../LinkedDataHub)
153154
make -C etl # perkuria rinkinius su numatytąja baze https://localhost:4443/
154155
make load # užkrauna datasets/current/*/*.trig tiesiai į triplestore
155156
```
@@ -163,11 +164,22 @@ sugeneruoti su produkcine baze `https://linkeddata.lt/`, tad prieš `make load`
163164
reikia perkurti su numatytąja lokalia baze (`make -C etl`) — kitaip dokumentų URI
164165
nesutaps su LDH adresu ir jie nebus pasiekiami.
165166

166-
`make load` duomenis rašo **tiesiogiai į `fuseki-end-user` TDB2 saugyklą**
167-
(`tdb2.tdbloader` per vienkartinį `tdb-loader` konteinerį) — ne po vieną dokumentą per
168-
HTTP, kaip daro LDH CLI įrankiai: ~1 mln. ketvertų užsikrauna per kelias minutes.
169-
Pabaigoje suteikiama vieša skaitymo prieiga (`make public` — LDH CLI `make-public.sh`
170-
atitikmuo, vykdomas tiesiogiai per `fuseki-admin` konteinerių tinkle).
167+
Duomenų struktūra kuriama dviem lygiais:
168+
169+
- **Karkasas** (`make install`): šakninis dokumentas, konteineriai ir taksonomijų
170+
schemos iš `app/` katalogo dokumentas po dokumento **per LDH CLI** (`put.sh`,
171+
kaip [LinkedDataHub-Apps](https://github.com/AtomGraph/LinkedDataHub-Apps)
172+
projektuose) — taip dokumentai gauna `ldh:ChildrenView` bloką, dėl kurio
173+
konteinerių puslapiai rodo vaikų sąrašus. Reikia šalia išklonintos
174+
[LinkedDataHub](https://github.com/AtomGraph/LinkedDataHub) repozitorijos
175+
(`../LinkedDataHub`, keičiama per `make install LDH_HOME=…`).
176+
- **Duomenys** (`make load`): ETL rinkiniai — vien `dh:Item` dokumentai su
177+
`sioc:has_container` nuorodomis į karkasą — rašomi **tiesiogiai į
178+
`fuseki-end-user` TDB2 saugyklą** (`tdb2.tdbloader` per vienkartinį
179+
`tdb-loader` konteinerį), ne po vieną dokumentą per HTTP: ~1 mln. ketvertų
180+
užsikrauna per kelias minutes. Pabaigoje suteikiama vieša skaitymo prieiga
181+
(`make public` — LDH CLI `make-public.sh` atitikmuo, vykdomas tiesiogiai per
182+
`fuseki-admin` konteinerių tinkle).
171183
Triplestore prievadai **neatveriami į host'ą** — SPARQL užklausos teikiamos per LDH:
172184
<https://localhost:4443/sparql>. Krovimas yra *append-only*: pakartotinis `make load`
173185
tik papildo saugyklą; švariam perkrovimui:
@@ -188,9 +200,9 @@ Pastabos:
188200
`datasets/owner`, `datasets/secretary`) — `datasets/current/` niekada neliečiamas.
189201
- Prievadai 81/4443/5443 sutampa su kitų lokalių LDH diegimų (pvz., `LinkedDataHub`
190202
repozitorijos) prievadais — vienu metu gali veikti tik vienas stack'as.
191-
- Dokumentai naršomi per LDH konteinerius: kiekvienas dokumentas yra `dh:Item` su
192-
`sioc:has_container`, o patys konteineriai (`datasets/current/containers/`) —
193-
`dh:Container` dokumentai (pvz., <https://localhost:4443/admin-units/>).
203+
- Dokumentai naršomi per LDH konteinerius: kiekvienas ETL dokumentas yra `dh:Item`
204+
su `sioc:has_container`, o konteineriai — LDH CLI sukurti `dh:Container`
205+
dokumentai iš `app/` (pvz., <https://localhost:4443/admin-units/>).
194206

195207
## Ką jau galima atsakyti?
196208

app/.ldhignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root.ttl

app/admin-units.ttl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
2+
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> .
3+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4+
@prefix dct: <http://purl.org/dc/terms/> .
5+
6+
<> a dh:Container ;
7+
dct:title "Administraciniai vienetai"@lt ;
8+
rdf:_1 <#select-children> .
9+
10+
<#select-children> a ldh:Object ;
11+
rdf:value ldh:ChildrenView .

app/install.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env bash
2+
# Creates/updates the LTLOD container scaffolding (root document + containers +
3+
# taxonomy scheme containers) on a running LinkedDataHub instance via the LDH
4+
# CLI. Requires LinkedDataHub's bin/ subdirs and Jena's bin/ (for `turtle`) on
5+
# $PATH — `make install` in the root Makefile sets this up.
6+
# Deliberately does NOT call make-public.sh: `make load` ends with `make public`.
7+
set -euo pipefail
8+
9+
if [ "$#" -ne 3 ] && [ "$#" -ne 4 ]; then
10+
echo "Usage: $0" '$base $cert_pem_file $cert_password [$proxy]' >&2
11+
echo "Example: $0" 'https://localhost:4443/ ./ssl/owner/cert.pem Password https://localhost:5443/' >&2
12+
echo "Note: special characters such as $ need to be escaped in passwords!" >&2
13+
exit 1
14+
fi
15+
16+
base="$1"
17+
cert_pem_file=$(realpath "$2")
18+
cert_password="$3"
19+
proxy="${4:-$base}"
20+
21+
app_dir="$(cd "$(dirname "$0")" && pwd)"
22+
23+
printf "\n### Updating root document: %s\n" "$base"
24+
turtle --base="$base" < "$app_dir/root.ttl" | put.sh \
25+
-f "$cert_pem_file" \
26+
-p "$cert_password" \
27+
--proxy "$proxy" \
28+
-t "application/n-triples" \
29+
"$base"
30+
31+
printf "\n### Updating container documents\n"
32+
"$app_dir/update-folder.sh" "$base" "$cert_pem_file" "$cert_password" "$app_dir" "$app_dir" "$proxy"

app/legal-entities.ttl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
2+
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> .
3+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4+
@prefix dct: <http://purl.org/dc/terms/> .
5+
6+
<> a dh:Container ;
7+
dct:title "Juridiniai asmenys"@lt ;
8+
rdf:_1 <#select-children> .
9+
10+
<#select-children> a ldh:Object ;
11+
rdf:value ldh:ChildrenView .

app/org-units.ttl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
2+
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> .
3+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4+
@prefix dct: <http://purl.org/dc/terms/> .
5+
6+
<> a dh:Container ;
7+
dct:title "Seimo padaliniai"@lt ;
8+
rdf:_1 <#select-children> .
9+
10+
<#select-children> a ldh:Object ;
11+
rdf:value ldh:ChildrenView .

app/organizations.ttl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
2+
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> .
3+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4+
@prefix dct: <http://purl.org/dc/terms/> .
5+
6+
<> a dh:Container ;
7+
dct:title "Organizacijos"@lt ;
8+
rdf:_1 <#select-children> .
9+
10+
<#select-children> a ldh:Object ;
11+
rdf:value ldh:ChildrenView .

app/parliamentary-groups.ttl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
2+
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> .
3+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4+
@prefix dct: <http://purl.org/dc/terms/> .
5+
6+
<> a dh:Container ;
7+
dct:title "Parlamentinės grupės"@lt ;
8+
rdf:_1 <#select-children> .
9+
10+
<#select-children> a ldh:Object ;
11+
rdf:value ldh:ChildrenView .

0 commit comments

Comments
 (0)