Skip to content

Commit 5027cad

Browse files
committed
Merge branch 'graph'
2 parents 1d2d906 + d127e7b commit 5027cad

15 files changed

Lines changed: 1072 additions & 19 deletions
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Push IO taxonomy to Fuseki
2+
3+
on:
4+
workflow_dispatch: {}
5+
# schedule:
6+
# - cron: "0 6 * * *" # daily at 06:00 UTC; adjust as needed
7+
8+
9+
jobs:
10+
push:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: "20"
18+
19+
- run: npm ci
20+
21+
- run: node scripts/push-io-taxonomy.mjs
22+
env:
23+
SANITY_PROJECT_ID: ${{ secrets.SANITY_PROJECT_ID }}
24+
SANITY_DATASET: ${{ secrets.SANITY_DATASET }}
25+
SANITY_TOKEN: ${{ secrets.SANITY_TOKEN }}
26+
SANITY_API_VERSION: "2025-06-10"
27+
28+
TAXONOMY_BASE_IRI: "https://uxmethods.org/taxonomies/io#"
29+
30+
FUSEKI_GSP_ENDPOINT: ${{ secrets.FUSEKI_GSP_ENDPOINT }}
31+
FUSEKI_GRAPH_IRI: "https://uxmethods.org/taxonomies/io"
32+
FUSEKI_USER: ${{ secrets.FUSEKI_USER }}
33+
FUSEKI_PASSWORD: ${{ secrets.FUSEKI_PASSWORD }}
34+
35+
LANG_TAG: "en"

astro/src/pages/method/[slug].astro

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ async function getSharedOutput() {
3838
headers: {
3939
"Content-Type": "application/sparql-query",
4040
Accept: "application/sparql-results+json",
41-
// 🚨 Change after testing — it's been committed to the repo
42-
Authorization: "Basic " + btoa(KG_AUTH),
4341
},
4442
// Narrow this to the present method? Or at least limit return.
4543
body: `

graph/.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# build output
2+
build/
3+
4+
# dependencies
5+
node_modules/
6+
7+
# logs
8+
pnpm-debug.log*
9+
10+
# environment variables
11+
.env
12+
.env.production
13+
.env.local
14+
15+
# macOS-specific files
16+
.DS_Store

graph/README.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# UX Methods Graph
2+
3+
This folder contains the knowledge graph assets for UX Methods: the core ontology, exported instance data, SPARQL queries, and scripts for exporting/pushing RDF to Fuseki.
4+
5+
The near-term goals:
6+
7+
- prototype an integrated knowledge graph locally (Protégé + SPARQL)
8+
- keep ontology (TBox), taxonomy (SKOS), and content instance data (ABox) cleanly separated
9+
- load the same artifacts into Fuseki as named graphs
10+
11+
Long-term goals include:
12+
13+
- maintain UX Methods content quality/consistency over time
14+
- generate semantically rich connections between resources (methods, artifacts, steps, dependencies)
15+
- expose a queryable SPARQL endpoint
16+
- support graph-driven "plan builder" / "method stack generator" tooling
17+
18+
## Directory structure
19+
20+
```
21+
graph/
22+
build/ # GENERATED RDF outputs (do not edit by hand)
23+
ontologies/
24+
uxmethods-core.ttl # curated ontology (TBox)
25+
workspace.ttl # local entrypoint ontology for testing and development (imports only)
26+
catalog-v001.xml # Protégé catalog: maps ontology IRIs -> local files
27+
queries/ # SPARQL queries for testing & validation
28+
scripts/ # tools for generating RDF and loading to Fuseki
29+
.env # local config (ignored)
30+
package.json
31+
README.md
32+
```
33+
34+
**Source vs generated**
35+
36+
- Curated / versioned by hand: `ontologies/*`, `queries/*`, `scripts/*`
37+
- Generated / replaceable: `build/*`
38+
39+
Treat `build/*` as disposable outputs: regenerate them from Sanity whenever content changes.
40+
41+
## IRIs and naming conventions
42+
43+
### IO taxonomy (SKOS)
44+
45+
- Concept Scheme IRI (slash): `https://uxmethods.org/taxonomies/io`
46+
- Named graph IRI (slash): `https://uxmethods.org/taxonomies/io`
47+
- Concept namespace (hash): `https://uxmethods.org/taxonomies/io#<conceptId>`
48+
49+
### Methods
50+
51+
- Method instance IRIs: `https://uxmethods.org/method/<slug>`
52+
53+
### Methods export ontology IRI
54+
55+
- Methods data ontology IRI: `https://uxmethods.org/graph/methods`
56+
57+
## Named graph strategy
58+
59+
Different “kinds” of knowledge in kept in separate **named graphs** so that each collection can:
60+
- evolve schemas independently from content
61+
- import/replace curated terms without touching core semantics
62+
- load/unload entire domains of data cleanly
63+
- write queries that target only the graph(s) they need
64+
65+
**Note:** IRIs identify resources globally; named graphs are storage context. A method can reference a SKOS concept by IRI even if its descriptive triples live in a different named graph.
66+
67+
## Local Protégé workflow
68+
69+
The most reliable way to work locally is to open one entrypoint ontology and let imports + a catalog resolve everything.
70+
71+
`workspace.ttl` imports:
72+
73+
- uxmethods-core ontology
74+
- io-taxonomy export
75+
- methods-data export
76+
77+
Protégé + the SPARQL plugin then behave like a "merged model over the imports closure", which works for iteration and testing.
78+
79+
### SPARQL behavior note
80+
81+
Protégé's SPARQL Query plugin typically queries a merged model (active ontology + imports closure), so you can write queries without `GRAPH {}` blocks locally. In Fuseki, you will usually need `GRAPH` unless you configure union default graph.
82+
83+
## Scripts
84+
85+
Your pnpm doesn't support `-C`, so use `pnpm --dir graph …` or `cd graph` first.
86+
87+
### Export methods (local file)
88+
89+
From repo root:
90+
91+
```bash
92+
pnpm --dir graph exec node scripts/method-export.js
93+
```
94+
95+
**Output:**
96+
97+
- `graph/build/methods-data.ttl`
98+
99+
### Export taxonomy + push to Fuseki
100+
101+
**Dry run (no PUT):**
102+
103+
```bash
104+
DRY_RUN=1 pnpm --dir graph exec node scripts/push-io-taxonomy.js
105+
```
106+
107+
**Write file + push to Fuseki:**
108+
109+
```bash
110+
pnpm --dir graph exec node scripts/push-io-taxonomy.js
111+
```
112+
113+
This does a Graph Store Protocol PUT to:
114+
115+
- `.../ds/data?graph=https://uxmethods.org/taxonomies/io`
116+
117+
with header:
118+
119+
- `X-API-Token: <FUSEKI_API_TOKEN>`
120+
121+
## Generated file requirements (Protégé-friendly)
122+
123+
Generated TTL files include an ontology header so Protégé can import them by logical IRI (not `file:`):
124+
125+
- `build/io-taxonomy.ttl` declares:
126+
- `<https://uxmethods.org/taxonomies/io> a owl:Ontology .`
127+
- `build/methods-data.ttl` declares:
128+
- `<https://uxmethods.org/graph/methods> a owl:Ontology .`
129+
130+
This prevents Protégé's "Import using supplied physical URI (not recommended)" warning and enables clean catalog mappings.
131+
132+
## Queries
133+
134+
Queries live in `graph/queries/*.rq`. These are intended for:
135+
136+
- quick iteration in Protégé (copy/paste into SPARQL Query tab)
137+
- later automation/regression tests against Fuseki
138+
139+
**Example (method output enables another method input):**
140+
141+
- `queries/method-output-enables-method-input*.rq`
142+
143+
## Troubleshooting
144+
145+
### Protégé import tries to fetch a web URL and fails
146+
147+
- Add `ontologies/catalog-v001.xml` under Protégé's Ontology Catalogs
148+
- Ensure the imported files declare an `owl:Ontology` IRI (generated scripts now do this)
149+
150+
### Fuseki write returns 403 Forbidden
151+
152+
- nginx requires `X-API-Token`; confirm `FUSEKI_API_TOKEN` is set and the script sends the header
153+
- confirm you're writing to `/ds/data` (not `/ds/`)
154+
155+
### Protégé still "sees" an import after you remove it
156+
157+
Protégé may keep ontologies loaded in memory for the session. Restart/reload if you need a clean imports-closure test.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- If Protégé imports fail, check that build/*.ttl exists (run exporters). -->
2+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
3+
<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
4+
<uri name="https://uxmethods.org/graph/methods" uri="../build/methods-data.ttl"/>
5+
<uri name="https://uxmethods.org/taxonomies/io" uri="../build/io-taxonomy.ttl"/>
6+
<uri name="https://uxmethods.org/ontologies/uxmethods-core/0.1.0" uri="uxmethods-core.ttl"/>
7+
</catalog>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- If Protégé imports fail, check that build/*.ttl exists (run exporters). -->
2+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
3+
<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
4+
<uri name="https://uxmethods.org/graph/methods" uri="../build/methods-data.ttl"/>
5+
<uri name="https://uxmethods.org/taxonomies/io" uri="../build/io-taxonomy.ttl"/>
6+
<uri name="https://uxmethods.org/ontologies/uxmethods-core/0.1.0" uri="uxmethods-core.ttl"/>
7+
</catalog>

graph/ontologies/catalog-v001.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
3+
<uri name="https://uxmethods.org/graph/methods" uri="../build/methods-data.ttl"/>
4+
<uri name="https://uxmethods.org/taxonomies/io" uri="../build/io-taxonomy.ttl"/>
5+
<uri name="https://uxmethods.org/ontologies/uxmethods-core/0.1.0" uri="uxmethods-core.ttl"/>
6+
</catalog>

0 commit comments

Comments
 (0)