Semantic Web and Web 3.0 · class 12 · demo
The complete path, end to end
The six lines of the slide «Integration check», walked on the example project — following one company, Acme Lda (tax number 501234567), and its products and certificate. Each step points at its evidence, taken live from the graph this server built at start-up.
An action in the interface reaches the domain service and produces an event.
not in this demo There is no interface and no broker here: they are each group's own.
What stands in for the event is the domain service's data — the rows of the catalogue database the pipeline reads
(sources/catalogue.sql) and the supplier row in sources/suppliers.csv:
(1, 'Acme Lda', '501234567'),
(100, 'Bearing 6204', 4.90, 1),
(101, 'Bearing 6205', 5.40, 1),
501234567,ACME LDA,PT,Porto,Rua das Oficinas 12
In the group's project this line is proved by clicking in the interface and seeing the event in the
broker log (02-integration-checklist, line 1).
The event is ingested and updates the graph without manual intervention.
The pipeline ran inside this process at start-up, with nobody typing: one prov:Activity,
run:2026-11-01T13:21:28. Product 100 in the graph, and the named graph each triple sits in:
product:100
| Predicate | Object | Named graph |
|---|---|---|
| a | onto:Product | graph:catalogue |
| onto:manufacturedBy | manufacturer:1 | graph:catalogue |
| onto:price | "4.90"^^xsd:decimal | graph:catalogue |
| schema:name | "Bearing 6204"@en | graph:catalogue |
The same company under its tax-number IRI: in the CSV, in the external source (aligned with
CONSTRUCT) and in the domain graph that holds its certificate:
manufacturer:501234567
| Predicate | Object | Named graph |
|---|---|---|
| a | onto:Manufacturer | graph:domain |
| onto:hasCertificate | certificate:2026-001 | graph:domain |
| onto:taxId | "501234567" | graph:domain |
| schema:name | "Acme Lda"@en | graph:domain |
| a | onto:Manufacturer | graph:source-external |
| onto:country | country:PT | graph:source-external |
| prov:wasDerivedFrom | https://source.external/supplier/501234567 | graph:source-external |
| schema:name | "Acme Lda" | graph:source-external |
| a | onto:Manufacturer | graph:suppliers-csv |
| onto:country | country:PT | graph:suppliers-csv |
| onto:district | "Porto" | graph:suppliers-csv |
| onto:taxId | "501234567" | graph:suppliers-csv |
| schema:name | "ACME LDA"@en | graph:suppliers-csv |
Identity resolution joined them: link:1: manufacturer:1 owl:sameAs manufacturer:501234567, confidence 1.0. And each graph says where it came from, and when:
| Named graph | prov:wasDerivedFrom | prov:generatedAtTime |
|---|---|---|
| graph:catalogue | sqlite://sources/catalogue.db | 2026-11-01T13:21:28+00:00 |
| graph:suppliers-csv | file://sources/suppliers.csv | 2026-11-01T13:21:28+00:00 |
The graph check passes on all of it: the report.
A SPARQL query crosses data from at least two sources.
products-by-manufacturer.rq, with country=PT. The products and their manufacturer come from
the catalogue (SQL); the country is only in the CSV and the external source; the two meet through
owl:sameAs, from the identity graph.
| ?manufacturer | ?name | ?products |
|---|---|---|
| manufacturer:1 | Acme Lda | 2 |
| manufacturer:2 | Barros & Filhos, S.A. | 2 |
| manufacturer:3 | Cerdeira Industrial Unipessoal | 1 |
The checklist's proof: switch a source off and the results change.
| Graph taken away | Rows | Result |
|---|---|---|
| default graph (provenance) | 3 | same |
| graph:catalogue | 0 | empty |
| graph:chain | 3 | same |
| graph:domain | 3 | same |
| graph:identity | 0 | empty |
| graph:source-external | 3 | same |
| graph:suppliers-csv | 2 | changed |
The on-chain component emits an event that reaches the graph through the indexer.
The class 11 indexer's output, chain/chain.nt, loaded into graph:chain. The record for
Acme's certificate:
log:0x3146f3dd408865142c073519b175ecfff7a6e0dad59e6e6a8c38d79b6c8b7d55
| Predicate | Object | Named graph |
|---|---|---|
| a | onto:OnChainRecord | graph:chain |
| onto:block | "8412991"^^xsd:integer | graph:chain |
| onto:document | certificate:2026-001 | graph:chain |
| onto:documentDigest | "0x3146f3dd408865142c073519b175ecfff7a6e0dad59e6e6a8c38d79b6c8b7d55" | graph:chain |
| onto:revoked | "false"^^xsd:boolean | graph:chain |
| onto:transaction | "0x1a4cc0125cf332c26d338d5d074828dfe4439ff5f44f38eba74aee8e641c53b3" | graph:chain |
| onto:validUntil | "2027-12-31T00:00:00+00:00"^^xsd:dateTime | graph:chain |
| prov:wasAttributedTo | address:0x1111111111111111111111111111111111111111 | graph:chain |
The chain check counts these records: the report. Empty the file →
The interface shows information that only exists because of the crossing.
suppliers-certificates.rq: the name and the certificate come from the domain graph; the block and the
revocation from the chain graph. The status column exists in neither — only in the crossing.
| ?manufacturer | ?certificate | ?status | ?block |
|---|---|---|---|
| Acme Lda | certificate:2026-001 | anchored | 8412991 |
| Barros & Filhos, S.A. | certificate:2026-002 | revoked | 8412991 |
| Cerdeira Industrial | certificate:2026-003 | not anchored | unbound |
| Graph taken away | Rows | Result |
|---|---|---|
| graph:chain | 3 | changed |
| graph:domain | 0 | empty |
The failure of any accessory component degrades the system; it does not bring it down.
Take the chain graph away — the indexer is down — and run the same query. It still answers; the chain half
was in an OPTIONAL, so every certificate falls back to «not anchored»:
| ?manufacturer | ?certificate | ?status | ?block |
|---|---|---|---|
| Acme Lda | certificate:2026-001 | not anchored | unbound |
| Barros & Filhos, S.A. | certificate:2026-002 | not anchored | unbound |
| Cerdeira Industrial | certificate:2026-003 | not anchored | unbound |
The interface degrades instead of falling over. But it is wrong without saying so, which is why the verifier has a separate chain check: see it catch exactly this →. Stopping the external source, the store and each micro frontend, one at a time, is the group's part of this line.