Vocabularies
Fields of type Term (and controlled Enum fields) take their values from vocabularies. Each vocabulary is a SKOS concept scheme stored as JSON-LD in the schemas repository. The editor offers its concepts in a picker; a chosen term stores the concept URI and its label.
Files
| Path | What it is |
|---|---|
vocabs/skos/*.jsonld | One SKOS concept scheme per file: the source of truth. template-scheme.jsonld is a starter for a new one and is skipped by the build. |
vocabs/raw/ | Downloads from the authorities, used by the converters. |
vocabs/field-attachments.json | Which field uses which schemes, and how strictly. |
vocabs/curation-registry.json | Per scheme: source, approach (authority-import, local-authoritative, curated-subset, curated), status, scope, concept count and label languages. |
vocabs/snapshots/<name>/ | Frozen copies of the vocabulary state, made by scripts/create_vocab_snapshot.sh. |
vocabs/skos/README.md | Curation and notation rules. |
Binding a vocabulary to a field
Add an entry to vocabs/field-attachments.json:
{
"fieldPath": "distribution.license",
"vocab": {
"kind": "term",
"schemes": ["https://spdx.org/licenses/", "https://creativecommons.org/"],
"enforcement": { "schema": "closed", "value": "open" },
"allowCustomLabel": true
}
}fieldPath: the field's dotted property path in the document, as shown under Path in the reference.kind:termstores a Term (URI and label);scalarstores the plain code, for example a language code.enforcement.schema:closedallows only the listed schemes;openalso accepts terms from other schemes.enforcement.value:closedallows only concepts from the schemes;openlets the user type a value of their own.allowCustomLabel: the user may type a label that is not in the vocabulary.
The build compiles the attachments (GenJSONSchema/compile_skos_vocab.py, which also reports schemes that do not exist) and embeds them into the schema as x-sidedoc.vocab (scripts/embed_vocab_in_schema.py). build.sh embeds into datasheet.json; build-local.sh also into cmdi-data-envelope.json. The app additionally reads field-attachments.json from the version bundle at run time and applies it by path to the profile being edited.
To verify
Paths in field-attachments.json are not tied to a profile. A path such as language matches any profile with a top-level language field. Check that a new path does not bind a vocabulary to a field of another profile by accident.
Adding a vocabulary
- Download the source into
vocabs/raw/(scripts/fetch_vocab_sources.shfetches the ones that are imported from authorities). - Write or generate
vocabs/skos/<name>.jsonld. Keep the authority's URIs and notations for imported vocabularies. Local vocabularies usehttps://sidedoc.app/vocabs/<name>and lowercase kebab-case notations. Every concept needs a stable@idand askos:prefLabel; add labels in more languages when the source has them. - Add the scheme to
vocabs/curation-registry.jsonwith itsskosFile,currentConceptCountand label languages. - Bind it to fields in
vocabs/field-attachments.json. - Build, then copy the SKOS files into the app (
SIDEDOC_SCHEMAS_DIR=/path/to/schemas npm run sync:vocab -w sidedoc-frontend), where they are served at/vocab/<scheme>.
Refreshing imported vocabularies
build.sh refreshes the imported vocabularies on every run with one converter each:
| Vocabulary | Converter |
|---|---|
| RDA Content Type | scripts/convert_rda_content_type.py |
| AI4Culture categories and application types | scripts/convert_ai4culture_filters.py |
| IANA media types | scripts/convert_iana_media_types.py |
| ISO 639-2 | vocabs/convert_iso639_2.py |
| EU frequency | vocabs/convert_eu_frequency.py |
| EU language | vocabs/convert_eu_language.py |
| TaDiRAH | scripts/convert_tadirah.py |
| schema.org classes | scripts/convert_schemaorg_classes.py |
| SPDX licenses | scripts/convert_spdx_licenses.py |
| Creative Commons licenses (static list) | scripts/convert_cc_licenses.py |
| rightsstatements.org | scripts/convert_rightsstatements.py |
When a source cannot be reached, the build keeps the existing file and goes on. build-local.sh skips the refresh and uses the files as they are. The CMDI vocabularies (cmdi-*.jsonld) come from scripts/convert_cmdi_profile.py.
Checks
The build runs two checks before it compiles:
python3 scripts/validate_skos_vocab.py --skos-dir vocabs/skos
python3 scripts/check_vocab_registry_drift.py --registry vocabs/curation-registry.json --root-dir .validate_skos_vocab.pychecks each scheme: concept ids, duplicate ids and notations, missing labels, brokenskos:broaderreferences, and the notation policy (kebab-case for local schemes).check_vocab_registry_drift.pycompares the registry with the SKOS files: concept count, scheme URI,skos:inSchemereferences and label languages. After a refresh changes a vocabulary, updatecurrentConceptCountand the languages in the registry, or the build stops.
Snapshots
To freeze the current vocabularies, so a later rebuild does not depend on third-party sources:
scripts/create_vocab_snapshot.sh [name] # default name: today's date; FORCE=1 to overwriteThe snapshot holds the SKOS files, the raw downloads, the registry, the attachments and the compiled output.