Data-architectuur Jottem

A Collection of Interesting Ideas,

This version:
https://github.com/inside-out-time-machines/design
Editor:
Bob Coret (Gouda Tijdmachine)

1. Inleiding en lagenmodel

Dit document beschrijft de data-architectuur van het Jottem-platform: welke data waar wordt vastgelegd, hoe die door het platform stroomt en in welke vormen die aan de buitenwereld wordt aangeboden. Het sluitstuk is de outputcontrole: per output is nagegaan of alle benodigde data beschikbaar is in de eerdere lagen; de daarbij gevonden hiaten zijn direct in het datamodel verwerkt.

De data leeft in drie lagen:

Laag Opslag Inhoud
Bronlaag PostgreSQL (ERD), externe Object Storage (S3), miiify PostgreSQL is de bron van waarheid voor organisaties, gebruikers, media en metadata; de externe Object Storage (S3) bevat de mediabestanden (originelen, afgeleiden, thumbnails, audio); miiify bevat de W3C-annotaties met versiegeschiedenis.
Verwerkingslaag Celery-workers, Elasticsearch, Fuseki Workers genereren afgeleiden en thumbnails, mappen metadata naar RDF (upsert in Fuseki), indexeren in Elasticsearch en versturen e-mail. Elasticsearch en Fuseki zijn afgeleide stores: ze zijn altijd volledig te herbouwen uit de bronlaag.
Outputlaag api/iiif/anno/data.iotm.nl, RSS De standaard-interfaces voor de buitenwereld: IIIF (Image, Presentation, Change Discovery), W3C Web Annotation Protocol, RDF/SPARQL/datadump met datasetbeschrijving, de REST-API’s en RSS-feeds.

Leidend principe (zie ook de systeemarchitectuur): standaarden aan de buitenkant - elke output volgt een open standaard zodat harvesters en aggregators (o.a. NDE) zonder maatwerk kunnen aansluiten - en PostgreSQL plus miiify en de Object Storage als bron van waarheid, zodat elke afgeleide store en elke output reproduceerbaar is.

2. ERD diagram

erDiagram

Organisatie {
  int id PK
  string naam
  string slug
  string beschrijving
  string website
  string NAAN
  string kleurenpalet
  string logo
  string favicon
}

Project {
  uuid projectId PK
  string naam
  string slug
  string beschrijving
  string oproep
  date startDatum
  date eindDatum
  string afbeelding
  string datasetLicentie
  string terminologiebronnen
  string status
  int organisatieId FK
}

Gebruiker {
  int gebruikersId PK
  string naam
  string email
  bool naamPubliek
  date bevestigingsDatum
  date registratieDatum
  date laatsteLoginDatum
  bool favorietenPubliek
}

GebruikerRol {
  int gebruikerRolId PK
  int gebruikersId FK
  int organisatieId FK
  string rol
}

Media {
  uuid mediaId PK
  string titel
  string beschrijving
  string bestandsnaam
  string genre
  string licentie
  int breedte
  int hoogte
  string mimeType
  string status
  string afkeurReden
  string herkenbaar
  float herkenbaarBetrouwbaarheid
  bool toestemmingPersonen
  string ark
  date creatieDatum
  date publicatieDatum
  date wijzigingsDatum
  int gebruikersId FK
  int organisatieId FK
  uuid projectId FK
}

Metadata {
  int metadataId PK
  uuid mediaId FK
  int gebruikersId FK
  string type
  string label
  string value
  string uri
}

Favoriet {
  int favorietId PK
  int gebruikersId FK
  uuid mediaId FK
  date creatieDatum
}

Verwijderverzoek {
  int verzoekId PK
  uuid mediaId FK
  string reden
  string email
  string status
  string toelichting
  date creatieDatum
  date afhandelDatum
}

Melding {
  int meldingId PK
  uuid mediaId FK
  string annotatieIri
  string reden
  string status
  date creatieDatum
  date afhandelDatum
}

Gebeurtenislog {
  int logId PK
  string type
  date tijdstip
  int organisatieId FK
  uuid projectId FK
  int gebruikersId FK
  string payload
  date verwerktOp
}

%% Project: campagne op organisatieniveau (bijv. "Smaak van Gouda"), beheerd door de
%% organisatiebeheerder. Elke organisatie heeft minstens een project; elke jottem hoort
%% bij precies een project (Media.projectId verplicht). Project.status: actief / afgerond.
%% Project.datasetLicentie: licentie van de projectdataset (datasetbeschrijving per project).
%% Project.terminologiebronnen: lijst van bron-URI’s uit het NDE Termennetwerk die binnen
%% dit project beschikbaar zijn voor term-URI’s (standaard: alle bronnen).
%% Publiek zichtbare identifiers (mediaId, projectId) zijn betekenisloze UUID’s; interne
%% id’s (gebruikersId e.d.) blijven interne sleutels.
%% Rollen: een gebruiker kan meerdere rollen hebben, per organisatie (GebruikerRol);
%% de rol platformbeheerder heeft geen organisatieId. Lidmaatschap van een organisatie
%% volgt uit de GebruikerRol-rijen. GebruikerRol is de LEIDENDE bron voor autorisatie;
%% de IdP (Authentik) doet uitsluitend authenticatie (koppeling via sub-claim).
%% Media.status: nieuw / goedgekeurd / afgekeurd / gedepubliceerd; afkeurReden alleen bij
%% afgekeurd. Afgekeurde jottems kunnen door de uploader worden bijgewerkt en opnieuw
%% ingediend (terug naar nieuw); gedepubliceerd volgt uit een gehonoreerd verwijderverzoek
%% (tombstone op de duurzame URL, schoning van alle outputs).
%% Verwijderverzoek.status: open / gehonoreerd / afgewezen.
%% Gebeurtenislog: bron voor statistieken (type: login, upload, goedkeuring, afkeuring,
%% annotatie, ...); persoonsgebonden regels worden na een bewaartermijn geaggregeerd of
%% geanonimiseerd (AVG).
%% Media.herkenbaar (ja/nee) + herkenbaarBetrouwbaarheid: resultaat van de Herkenbaar API
%% bij upload (paradata, geen gebruikersmetadata); toestemmingPersonen: verklaring van de
%% uploader dat toestemming van herkenbare personen is geregeld.
%% Media.titel/beschrijving/licentie, breedte/hoogte/mimeType en wijzigingsDatum zijn
%% toegevoegd n.a.v. de outputcontrole in de data-architectuur (IIIF-label/rights/canvas,
%% RDF schema:name/license, RSS en IIIF Change Discovery).
%% Organisatie.beschrijving/website: nodig voor publisher-informatie, IIIF provider en
%% RSS-channel. Gebruiker.naamPubliek: bepaalt of de naam als creator bij annotaties
%% getoond wordt.
%% Organisatie.NAAN en Media.ark zijn gereserveerd voor de ARK-fase (uitgesteld,
%% zie keuze-oplossingsrichting).
%% Locatie- en tijdlijngegevens (adres, openings-/sluitingsjaar, geo-WKT, archiefbron)
%% worden vastgelegd als Metadata-rijen op Media; er is geen apart locatiemodel.
%% De coordinaten komen van de speld die de uploader op de kaart prikt (lat/lon als
%% Metadata-rijen); er is geen geocoding-dienst in de MVP.
%% Melding: rapportage van een annotatie of reactie (spam/ongepast) door bezoekers;
%% annotatieIri wijst naar de W3C-annotatie in miiify, status: nieuw / afgehandeld /
%% afgewezen. Afhandeling door de moderator, gelogd in het Gebeurtenislog.
%% Gebeurtenislog is tevens de transactional outbox (zie systeemarchitectuur):
%% payload beschrijft de mutatie, verwerktOp markeert succesvolle doorwerking naar
%% Elasticsearch / Fuseki / Varnish-purge.

%% Relationships
Organisatie ||--o{ GebruikerRol : "kent"
Organisatie ||--o{ Media : "bevat"
Organisatie ||--o{ Project : "voert_uit"

Project ||--o{ Media : "verzamelt"

Gebruiker ||--o{ GebruikerRol : "heeft"
Gebruiker ||--o{ Media : "uploadt"

Media ||--o{ Metadata : "heeft"

Gebruiker ||--o{ Favoriet : "maakt"
Media ||--o{ Favoriet : "wordt_gefavoriet"

Media ||--o{ Verwijderverzoek : "betreft"
Media ||--o{ Melding : "betreft"
Organisatie ||--o{ Gebeurtenislog : "logt"

Gebruiker ||--o{ Metadata : "maakt"

3. URI-strategie en content negotiation

Elke gepubliceerde jottem krijgt een duurzame platform-URL die als identifier in alle outputs wordt gebruikt:

Resource URI-patroon
Jottem (duurzame link) https://www.iotm.nl/jottem/{mediaId}
Projectpagina (publiek) https://www.iotm.nl/{organisatieSlug}/{projectSlug}
Project (API) https://api.iotm.nl/v1/project/{projectId}
IIIF Image API https://iiif.iotm.nl/3/{mediaId} (/info.json, tiles)
IIIF Manifest https://api.iotm.nl/v1/jottem/{mediaId}/iiif/manifest
IIIF Collection https://api.iotm.nl/v1/organisatie/{slug}/jottems/iiif/collection en https://api.iotm.nl/v1/project/{projectId}/iiif/collection
Annotaties van een jottem (container) https://anno.iotm.nl/annotations/{jottemId}/
Annotatie https://anno.iotm.nl/annotations/{jottemId}/{annotationId}
Annotaties van organisatie / project https://api.iotm.nl/v1/organisatie/{slug}/annotations en https://api.iotm.nl/v1/project/{projectId}/annotations
Projectdataset https://data.iotm.nl/project/{projectId}/dataset (beschrijving), https://data.iotm.nl/project/{projectId}/dump.nt.gz (dump), https://data.iotm.nl/sparql (endpoint)

Deelbaarheid. Elke jottem-detailpagina toont deelknoppen naar sociale media en de HTML-weergave bevat Open Graph-metadata, zodat gedeelde links (ook via de deel-oproep in de goedkeuringsmail) een nette preview tonen:

Open Graph-element Bron
og:title Media.titel
og:description Media.beschrijving
og:image (+ og:image:width/height) afgeleide uit de Object Storage (voldoende groot voor previews, ± 1200×630)
og:url de duurzame jottem-URL
og:type, og:site_name, og:locale vast (article, "Jottem", nl_NL)

De duurzame jottem-URL ondersteunt content negotiation: Accept: text/html levert de HTML-weergave (IIIF-viewer + metadata + annotaties), application/ld+json, text/turtle of application/rdf+xml levert de RDF-representatie conform schema.org AP NDE (303-redirect naar data.iotm.nl). De mediaId en projectId zijn niet-herbruikbare, betekenisloze identifiers (UUID); duurzame data-URI’s zijn daarop gebaseerd, terwijl publiekspagina’s leesbare slugs gebruiken. Zo kan in de latere ARK-fase (zie het keuzedocument) een ARK ark:/{NAAN}/{shoulder}{mediaId} zonder linkbreuk op dezelfde resource worden gelegd.

4. IIIF

4.1. IIIF Image API v3

Cantaloupe serveert per gepubliceerde jottem info.json, tiles, regio’s en formaten op basis van de pyramidal TIFF/JP2-afgeleide in de Object Storage (derivatives-bucket). De benodigde data:

Element Bron
id URI-strategie (afgeleid van Media.mediaId)
width, height Media.breedte, Media.hoogte (vastgelegd bij verwerking van de upload)
beeldata (tiles) Object Storage derivatives (pyramidal TIFF/JP2, gegenereerd door worker)

4.2. IIIF Presentation API v3 (Manifest en Collection)

De backend genereert per jottem een Manifest en per organisatie en per project een Collection (met iiif-prezi3), rechtstreeks uit de database:

Manifest-element Bron
id, type URI-strategie
label Media.titel
summary Media.beschrijving
metadata (paren) Metadata-rijen (vervaardiger, datering, plaats, steekwoorden, ...)
rights Media.licentie (URI)
requiredStatement (bronvermelding) Organisatie.naam + inzender (indien Gebruiker.naamPubliek)
provider Organisatie.naam, Organisatie.logo, Organisatie.website
navDate Metadata type datering
thumbnail Object Storage thumbs
canvas (width/height) Media.breedte, Media.hoogte
image service IIIF Image API (zie boven)
annotations (AnnotationPage) miiify, per jottem-target
Collection-items Media per organisatieId/projectId (status goedgekeurd)

Audio-jottems (fase 2, zie de uploadscope in de requirements) krijgen een manifest met een audio-canvas (duration; vastgelegd bij verwerking van de upload) en het bestand uit de audio-bucket als painting annotation.

4.3. IIIF Change Discovery v1

Per organisatie publiceert de backend een ActivityStreams-feed (OrderedCollection met pages) waarmee harvesters nieuwe en gewijzigde jottems kunnen volgen:

Element Bron
Create-activiteit Media.publicatieDatum (moment van goedkeuring/publicatie)
Update-activiteit Media.wijzigingsDatum
object (het Manifest) URI-strategie
endTime de betreffende datum

Regel: elke mutatie die de outputs raakt - metadata-wijziging, nieuwe/gewijzigde/verwijderde annotatie, depublicatie - werkt Media.wijzigingsDatum bij, zodat de Change Discovery-feed (en schema:dateModified in de RDF) ook annotatie-wijzigingen omvat, zoals de usecase voor API-gebruikers vraagt. Het verwijderen van een annotatie levert daarbij een Update-activity op de jottem op (géén Delete: de jottem zelf blijft bestaan; Delete/tombstone is voorbehouden aan depublicatie van de jottem). De AnnotationCollections komen live uit miiify en tonen de verwijderde annotatie direct niet meer; de workers hersynchroniseren daarna de named graph in Fuseki en de zoekindex via het outbox-mechanisme uit de systeemarchitectuur.

5. Annotaties

Annotaties volgen het W3C Web Annotation Data Model en worden opgeslagen in miiify; lezen kan publiek en standaardconform via het W3C Web Annotation Protocol op anno.iotm.nl (de Miifi API). Schrijven verloopt via de beheer-API, die de geauthenticeerde gebruiker als creator toevoegt en autorisatie bewaakt (eigen annotaties bewerken en verwijderen; de git-backend van miiify bewaart de versiegeschiedenis).

Element Bron
id, created, modified miiify
motivation vocabulaire, zie § 9 Vocabulaires en termen
target (gehele jottem) duurzame jottem-URL of Canvas-URI
target (getekend vlak) Canvas-URI + SVG/FragmentSelector (Annotorious)
body (vrije tekst: herinnering, aanvulling, correctie) TextualBody
body (identificatie persoon/gebouw/bedrijf/plaats/gebeurtenis) SpecificResource met label + externe URI (zie § 9 Vocabulaires en termen)
body (geo: standpunt fotograaf, zichtveld) WKT/GeoJSON-body, zie § 10 Zoekindex en geo-data
reactie op annotatie annotatie met de bestaande annotatie als target
creator Gebruiker.naam indien Gebruiker.naamPubliek, anders geanonimiseerd

5.1. Ontsluiting: AnnotationCollection per jottem en per organisatie

De annotatieserver hanteert één container per jottem (containernaam = mediaId). Daarmee zijn annotaties op drie niveaus opvraagbaar, telkens W3C-conform:

Niveau Endpoint Output
Individuele annotatie https://anno.iotm.nl/annotations/{jottemId}/{annotationId} (en GET /annotation/{annotationId} in de publieke API) Annotation
Per jottem GET https://anno.iotm.nl/annotations/{jottemId}/ - rechtstreeks uit de container; de publieke API biedt GET /jottem/{jottemId}/annotations als doorverwijzing en het IIIF Manifest verwijst hiernaar via annotations AnnotationCollection (gepagineerd via AnnotationPages)
Per project GET /project/{projectId}/annotations in de publieke API - de backend aggregeert de containers van alle gepubliceerde jottems van het project (jottem-lijst uit Media.projectId) AnnotationCollection (gepagineerd via AnnotationPages)
Per organisatie GET /organisatie/{slug}/annotations in de publieke API - de backend aggregeert de containers van alle gepubliceerde jottems van de organisatie (jottem-lijst uit Media) AnnotationCollection (gepagineerd via AnnotationPages)

6. RDF en datadump

6.1. Mapping naar schema.org AP NDE

Een worker mapt elke gepubliceerde jottem naar RDF conform het schema.org-profiel van NDE en upsert deze in Fuseki (named graph per organisatie). De representatie is opvraagbaar via content negotiation op de duurzame URL, via SPARQL en via de datadump.

schema.org AP NDE Bron
@id duurzame jottem-URL (URI-strategie)
@type schema:ImageObject / schema:AudioObject op basis van Media.mimeType
schema:name Media.titel
schema:description Media.beschrijving
schema:genre / schema:additionalType Media.genre + term-URI (zie § 9 Vocabulaires en termen)
schema:license Media.licentie
schema:datePublished / schema:dateModified Media.publicatieDatum / Media.wijzigingsDatum
schema:dateCreated Metadata type datering
schema:creator Metadata type vervaardiger
schema:contentLocation Metadata type plaats/adres (schema:Place, schema:sameAs naar term-URI, schema:geo bij WKT/GeoJSON)
schema:temporalCoverage Metadata openings-/sluitingsjaar
schema:about Metadata/annotaties: personen, gebouwen, bedrijven, gebeurtenissen (label + URI)
schema:keywords Metadata type steekwoord
schema:isBasedOn / schema:subjectOf Metadata type archiefbron (label + URI)
schema:contentUrl, schema:width, schema:height, schema:encodingFormat IIIF Image-URI, Media.breedte/hoogte/mimeType
schema:thumbnailUrl Object Storage thumbs
schema:publisher Organisatie.naam + Organisatie.website
schema:isPartOf de projectdataset-IRI (Media.projectId)
schema:inLanguage vast nl (NL-only, zie niet-functionele requirements)
annotaties verwijzing naar het W3C Annotation Protocol-endpoint per jottem

Persoonsgegevens van inzenders komen niet in de RDF: de inzender wordt alleen als schema:contributor opgenomen indien Gebruiker.naamPubliek.

6.2. Datasetbeschrijving en datadump

Per project publiceert het platform een datasetbeschrijving als schema:Dataset conform de NDE-requirements voor datasets, aanmeldbaar bij het NDE Datasetregister; de platformbrede datacatalogus (schema:DataCatalog, /datacatalog) bundelt alle projectdatasets. Omdat elke jottem bij precies één project hoort, dekken de projectdatasets samen alle gepubliceerde data.

Verplicht/aanbevolen element Bron
IRI van de dataset https://data.iotm.nl/project/{projectId}/dataset
schema:name Project.naam
schema:description Project.beschrijving
schema:license (van de dataset) Project.datasetLicentie
schema:publisher Organisatie.naam, Organisatie.website
schema:distribution datadump (dump.nt.gz, application/n-triples) én SPARQL-endpoint; aanvullend zie § 6.3 Aanvullende distributies (verkenning)
schema:dateModified afgeleid: max(Media.wijzigingsDatum) per project
schema:temporalCoverage Project.startDatumProject.eindDatum
schema:inLanguage vast nl

De datadump wordt per project periodiek (nachtelijks) door een worker gegenereerd uit Fuseki (named graph per project) en is tevens onderdeel van de exit-/exportstrategie uit het keuzedocument: de dumps plus de mediabestanden vormen samen een volledige, herbruikbare export van de gepubliceerde data.

Beheer en aanmelding. De organisatiebeheerder bewerkt per project de velden waaruit de datasetbeschrijving wordt gegenereerd (Project.naam, beschrijving, datasetLicentie; publisher-gegevens uit de organisatie) en kan de beschrijving - uitsluitend wanneer het project openbare (gepubliceerde) data heeft - valideren en aanmelden bij het NDE Datasetregister via de Datasetregister-API: de backend valideert eerst tegen het SHACL-shape van het register (PUT /datasets/validate), meldt daarna de URL van de datasetbeschrijving aan (POST /datasets) en kan deze ook weer afmelden (DELETE /datasets). Het domein iotm.nl moet daarvoor eenmalig op de allowlist van het register staan (POST /allowed-domains). Zie de bijbehorende endpoints in de beheer-API.

6.3. Aanvullende distributies (verkenning)

Naast de RDF-datadump en het SPARQL-endpoint kunnen ook de andere outputkanalen van een project als schema:distribution in de projectdatasetbeschrijving worden opgenomen; een distributie vereist slechts een schema:contentUrl en schema:encodingFormat, en het SHACL-shape van het register staat extra distributies toe. Dat maakt álle toegangswegen tot de projectdata vindbaar via één datasetbeschrijving:

Kandidaat-distributie contentUrl encodingFormat Overwegingen
RDF-datadump (bestaand) https://data.iotm.nl/project/{projectId}/dump.nt.gz application/n-triples de kern-distributie voor NDE-compatibiliteit
SPARQL-endpoint (bestaand) https://data.iotm.nl/sparql application/sparql-results+json bevraagbaar per named graph (project)
IIIF Collection de collection per project application/ld+json (IIIF Presentation-profile) direct bruikbaar in IIIF-viewers en -aggregators; bestaat in de publieke API
RSS de jottem-feed per project application/rss+xml laagdrempelig volgen van nieuwe jottems in het project; geen linked data, maar als distributie toegestaan
Webannotaties per project GET /project/{projectId}/annotations (zie § 5.1 Ontsluiting: AnnotationCollection per jottem en per organisatie) application/ld+json (W3C anno-profile) ontsluit de verrijkingslaag als zelfstandig herbruikbare (deel)dataset; het aggregerende endpoint bestaat in de publieke API (containerindeling: per jottem)
IIIF Change Discovery de ActivityStreams-feed per organisatie application/ld+json maakt incrementeel harvesten vindbaar; kanttekening: de feed is organisatiebreed (activiteiten van alle projecten), harvesters filteren desgewenst op de Manifest-URI’s van het project

Aanbeveling: alle kandidaten als extra distributies opnemen - de endpoints bestaan in de publieke API, het is louter een uitbreiding van de gegenereerde projectdatasetbeschrijving. Alle kandidaten zijn volledig afleidbaar uit de bestaande bronlagen; er is geen nieuwe brondata nodig.

6.4. E-depot-export: BagIt als verpakking, RO-Crate als beschrijving

Naast de RDF-datadump kan per project een compleet exportpakket worden aangemaakt waarmee al het materiaal van een project kan worden aangeboden aan het e-depot van een archiefinstelling (het SIP in OAIS-termen), en dat tevens de exit-strategie uit het keuzedocument concreet maakt:

{projectSlug}-{datum}.zip  (BagIt)
├── bagit.txt / bag-info.txt          project, organisatie, datum, aantallen
├── manifest-sha512.txt               checksums van alle payload-bestanden
└── data/
    ├── ro-crate-metadata.json        beschrijft alles (schema.org)
    ├── dump.nt.gz                    de RDF-datadump van het project
    ├── media/{mediaId}.(tif|jpg|…)   originelen uit de Object Storage
    ├── metadata/{mediaId}.jsonld     per jottem (schema.org AP NDE)
    └── annotaties/{mediaId}.jsonld   W3C Web Annotations per jottem

Een instellingsspecifieke metadatalaag (MDTO, of een E-ARK SIP/CSIP-structuur) wordt bewust niet standaard gegenereerd: Nederlandse e-depots verschillen daarvoor te sterk (zie de infrastructuuranalyse); zo’n laag is maatwerk per ontvangende instelling en kan bovenop de bag worden toegevoegd. METS/PREMIS genereert het e-depot zelf bij ingest.

Proces. De organisatiebeheerder start de export per project; een worker stelt het pakket asynchroon samen (originelen uit de Object Storage, metadata en annotaties uit de bronlagen) en plaatst het in een aparte exports-bucket met beperkte bewaartermijn. Zodra het pakket klaar is, ontvangt de organisatiebeheerder een e-mail met een directe downloadlink.

7. API-beschrijvingen

De API is gesplitst in een publieke lees-API (zonder authenticatie, voor bezoekers en API-gebruikers/harvesters) en een beheer-API (OIDC Bearer-authenticatie, voor uploaden, modereren en beheren).

7.1. Publieke API

7.2. Beheer-API

8. RSS

Twee feedtypen conform de RSS 2.0-specificatie: een platformbrede feed met nieuwe organisaties en per organisatie een feed met nieuwe jottems.

Element Bron
channel title / link / description Organisatie.naam / organisatiepagina-URL / Organisatie.beschrijving
item title Media.titel
item link / guid duurzame jottem-URL
item description Media.beschrijving + thumbnail
item pubDate Media.publicatieDatum
item enclosure Object Storage thumbs (met Media.mimeType)

9. Vocabulaires en termen

Vaste waardelijsten voorkomen vrije-tekstwildgroei en maken facetteren en linken mogelijk:

9.1. NDE Termennetwerk (GraphQL)

Alle term-lookups (genres én term-URI’s) verlopen via de GraphQL API van het NDE Termennetwerk (https://termennetwerk-api.netwerkdigitaalerfgoed.nl/graphql), één externe API die zoeken in vele terminologiebronnen bundelt (CHT, Wikidata, GTAA, thesauri van RKD, RCE, e.a.):

Terminologiebronnen per project. De organisatiebeheerder stelt per project in welke terminologiebronnen beschikbaar zijn voor term-URI’s (Project.terminologiebronnen, een lijst van bron-URI’s uit de sources-query; standaard staan alle bronnen open). De upload- en annotatie-interfaces beperken hun terms-queries tot die bronnen, zodat bijdragers per project passende thesauri aangeboden krijgen (bijv. CHT + Wikidata voor Smaak van Gouda). De backend biedt hiervoor een sources-proxy in de beheer-API.

10. Zoekindex en geo-data

Elasticsearch is een afgeleide store, gevuld door de indexeer-worker bij publicatie of wijziging (incl. annotatie-mutaties):

Indexveld Bron Gebruik
titel, beschrijving Media fulltext
metadata_labels, steekwoorden Metadata fulltext + facet
annotatie_teksten miiify (gesynct bij annotatie-mutatie) fulltext (usecase: annotaties zoeken)
genre, organisatie, project Media, Organisatie, Project facet
periode Metadata datering/jaren facet/range
locatie (geo_point/geo_shape) Metadata WKT/GeoJSON kaartzoeken
publicatieDatum Media sorteren

Geo-data wordt vastgelegd als WKT/GeoJSON in Metadata-rijen (adres/locatie van de jottem, standpunt fotograaf, zichtveld) en in annotatie-bodies, en gebruikt in: de kaart-frontend (MapLibre), de pand-tijdlijn (adres + openings-/sluitingsjaar), de koppeling met externe tijdmachines (zoals de Gouda Tijdmachine), Elasticsearch (geo-queries) en de RDF (schema:geo). Voor IIIF is de navPlace-extensie een optie om geo-informatie ook in manifests op te nemen.

11. Outputcontrole (traceability)

De veld→bron-tabellen in de voorgaande secties vormen de controle of alle benodigde data aan de outputkant beschikbaar is in de bronlagen. Daarbij zijn de volgende hiaten gevonden; deze zijn direct in het ERD verwerkt:

Gevonden hiaat Benodigd voor Oplossing in datamodel
Geen titel/beschrijving als eigen velden IIIF label/summary, RDF schema:name/description, RSS Media.titel, Media.beschrijving
Geen licentie/rechten per jottem IIIF rights, RDF schema:license, herbruikvoorwaarden Media.licentie (de uploader bevestigt bij het indienen de projectlicentie; die waarde wordt op de jottem vastgelegd)
Geen afbeeldingsdimensies/formaat IIIF info.json en canvas, RDF schema:width/height/encodingFormat Media.breedte, Media.hoogte, Media.mimeType (vastgelegd bij verwerking upload)
Geen wijzigingsdatum IIIF Change Discovery Update, RDF schema:dateModified Media.wijzigingsDatum + regel: elke relevante mutatie (ook annotaties) werkt deze bij
Geen organisatiebeschrijving/website publisher-informatie, IIIF provider, RSS-channel Organisatie.beschrijving, Organisatie.website
Albumconcept onderontwikkeld (persoonlijk fotoboek vs. campagne) projectpagina’s, datasetbeschrijving per project, IIIF Collection/RSS/annotaties per project Project-entiteit op organisatieniveau (uuid, naam, slug, beschrijving, oproep, periode, afbeelding, datasetLicentie, status); Media.projectId verplicht - elke jottem hoort bij precies één project en elke organisatie heeft er minstens één
Geen privacykeuze voor naamsvermelding annotatie-creator, IIIF requiredStatement, RDF schema:contributor Gebruiker.naamPubliek
Verwijderverzoeken wel in de API, niet in het datamodel afhandelworkflow, depublicatie (status "gedepubliceerd", tombstone) Verwijderverzoek-entiteit + status gedepubliceerd op Media
Geen bron voor statistieken statistieken per organisatie/project (logins, uploads, moderatie, annotaties) Gebeurtenislog-entiteit; persoonsgebonden regels na bewaartermijn geaggregeerd/geanonimiseerd (AVG)

Aandachtspunten die geen datamodel-wijziging vragen maar wel een implementatieregel zijn: