standardise slots

This commit is contained in:
kempersc 2026-01-14 09:51:14 +01:00
parent e3adb4ed60
commit b8914761b8
94 changed files with 6531 additions and 2778 deletions

View file

@ -34,3 +34,6 @@ prometheus-client>=0.19.0
# Utilities
python-dotenv>=1.0.0
# Production server
gunicorn>=21.0.0

View file

@ -1,12 +1,12 @@
{
"generated": "2026-01-14T08:15:17.717Z",
"generated": "2026-01-14T08:50:13.029Z",
"schemaRoot": "/schemas/20251121/linkml",
"totalFiles": 2923,
"totalFiles": 2913,
"categoryCounts": {
"main": 4,
"class": 662,
"class": 671,
"enum": 147,
"slot": 2106,
"slot": 2087,
"module": 4
},
"categories": [
@ -1080,6 +1080,11 @@
"path": "modules/classes/ExhibitionSpace.yaml",
"category": "class"
},
{
"name": "Expenses",
"path": "modules/classes/Expenses.yaml",
"category": "class"
},
{
"name": "ExtractionMetadata",
"path": "modules/classes/ExtractionMetadata.yaml",
@ -1200,6 +1205,16 @@
"path": "modules/classes/FrenchPrivateArchivesRecordSetTypes.yaml",
"category": "class"
},
{
"name": "FunctionType",
"path": "modules/classes/FunctionType.yaml",
"category": "class"
},
{
"name": "FunctionTypes",
"path": "modules/classes/FunctionTypes.yaml",
"category": "class"
},
{
"name": "FundingAgenda",
"path": "modules/classes/FundingAgenda.yaml",
@ -1475,6 +1490,11 @@
"path": "modules/classes/Kustodie.yaml",
"category": "class"
},
{
"name": "Label",
"path": "modules/classes/Label.yaml",
"category": "class"
},
{
"name": "Landsarkiv",
"path": "modules/classes/Landsarkiv.yaml",
@ -1490,6 +1510,11 @@
"path": "modules/classes/LanguageProficiency.yaml",
"category": "class"
},
{
"name": "Laptop",
"path": "modules/classes/Laptop.yaml",
"category": "class"
},
{
"name": "LayoutMetadata",
"path": "modules/classes/LayoutMetadata.yaml",
@ -2035,6 +2060,11 @@
"path": "modules/classes/OutdoorSite.yaml",
"category": "class"
},
{
"name": "Overview",
"path": "modules/classes/Overview.yaml",
"category": "class"
},
{
"name": "ParentOrganizationUnit",
"path": "modules/classes/ParentOrganizationUnit.yaml",
@ -2175,6 +2205,11 @@
"path": "modules/classes/PhotoAttribution.yaml",
"category": "class"
},
{
"name": "Photography",
"path": "modules/classes/Photography.yaml",
"category": "class"
},
{
"name": "PhotoMetadata",
"path": "modules/classes/PhotoMetadata.yaml",
@ -2370,6 +2405,11 @@
"path": "modules/classes/ReadingRoomAnnex.yaml",
"category": "class"
},
{
"name": "RealnessStatus",
"path": "modules/classes/RealnessStatus.yaml",
"category": "class"
},
{
"name": "ReconstructedEntity",
"path": "modules/classes/ReconstructedEntity.yaml",
@ -3155,6 +3195,11 @@
"path": "modules/classes/WebEnrichment.yaml",
"category": "class"
},
{
"name": "WebLink",
"path": "modules/classes/WebLink.yaml",
"category": "class"
},
{
"name": "WebObservation",
"path": "modules/classes/WebObservation.yaml",
@ -4142,24 +4187,14 @@
"path": "modules/slots/admin_office_id.yaml",
"category": "slot"
},
{
"name": "administrative_expenses",
"path": "modules/slots/administrative_expenses.yaml",
"category": "slot"
},
{
"name": "administrative_functions",
"path": "modules/slots/administrative_functions.yaml",
"category": "slot"
},
{
"name": "affects_or_affected_organization",
"path": "modules/slots/affects_or_affected_organization.yaml",
"category": "slot"
},
{
"name": "agenda_id",
"path": "modules/slots/agenda_id.yaml",
"name": "affects_or_affected",
"path": "modules/slots/affects_or_affected.yaml",
"category": "slot"
},
{
@ -4172,59 +4207,14 @@
"path": "modules/slots/aggregates_or_aggregated_from.yaml",
"category": "slot"
},
{
"name": "all_data_real",
"path": "modules/slots/all_data_real.yaml",
"category": "slot"
},
{
"name": "all_links",
"path": "modules/slots/all_links.yaml",
"category": "slot"
},
{
"name": "allocates_or_allocated",
"path": "modules/slots/allocates_or_allocated.yaml",
"category": "slot"
},
{
"name": "allows_laptops",
"path": "modules/slots/allows_laptops.yaml",
"category": "slot"
},
{
"name": "allows_or_allowed_laptop",
"path": "modules/slots/allows_or_allowed_laptop.yaml",
"category": "slot"
},
{
"name": "allows_or_allowed_photography",
"path": "modules/slots/allows_or_allowed_photography.yaml",
"category": "slot"
},
{
"name": "allows_photography",
"path": "modules/slots/allows_photography.yaml",
"category": "slot"
},
{
"name": "alpha_2",
"path": "modules/slots/alpha_2.yaml",
"category": "slot"
},
{
"name": "alpha_3",
"path": "modules/slots/alpha_3.yaml",
"category": "slot"
},
{
"name": "also_identifies_name",
"path": "modules/slots/also_identifies_name.yaml",
"category": "slot"
},
{
"name": "annex_id",
"path": "modules/slots/annex_id.yaml",
"name": "allows_or_allowed",
"path": "modules/slots/allows_or_allowed.yaml",
"category": "slot"
},
{
@ -4292,11 +4282,6 @@
"path": "modules/slots/asserted_by.yaml",
"category": "slot"
},
{
"name": "assertion_id",
"path": "modules/slots/assertion_id.yaml",
"category": "slot"
},
{
"name": "associated_encompassing_bodies",
"path": "modules/slots/associated_encompassing_bodies.yaml",
@ -4327,21 +4312,11 @@
"path": "modules/slots/auto_generated.yaml",
"category": "slot"
},
{
"name": "auxiliary_place_id",
"path": "modules/slots/auxiliary_place_id.yaml",
"category": "slot"
},
{
"name": "auxiliary_places",
"path": "modules/slots/auxiliary_places.yaml",
"category": "slot"
},
{
"name": "auxiliary_platform_id",
"path": "modules/slots/auxiliary_platform_id.yaml",
"category": "slot"
},
{
"name": "auxiliary_platforms",
"path": "modules/slots/auxiliary_platforms.yaml",
@ -7257,11 +7232,6 @@
"path": "modules/slots/funding_source.yaml",
"category": "slot"
},
{
"name": "fundraising_expense",
"path": "modules/slots/fundraising_expense.yaml",
"category": "slot"
},
{
"name": "gallery_subtype",
"path": "modules/slots/gallery_subtype.yaml",
@ -7587,11 +7557,6 @@
"path": "modules/slots/has_agenda_document_url.yaml",
"category": "slot"
},
{
"name": "has_agenda_identifier",
"path": "modules/slots/has_agenda_identifier.yaml",
"category": "slot"
},
{
"name": "has_agenda_short_name",
"path": "modules/slots/has_agenda_short_name.yaml",
@ -7627,11 +7592,6 @@
"path": "modules/slots/has_air_changes_per_hour.yaml",
"category": "slot"
},
{
"name": "has_all_data_real_flag",
"path": "modules/slots/has_all_data_real_flag.yaml",
"category": "slot"
},
{
"name": "has_allocation_date",
"path": "modules/slots/has_allocation_date.yaml",
@ -7662,11 +7622,6 @@
"path": "modules/slots/has_annex_description.yaml",
"category": "slot"
},
{
"name": "has_annex_identifier",
"path": "modules/slots/has_annex_identifier.yaml",
"category": "slot"
},
{
"name": "has_annex_name",
"path": "modules/slots/has_annex_name.yaml",
@ -7852,11 +7807,6 @@
"path": "modules/slots/has_assertion_date.yaml",
"category": "slot"
},
{
"name": "has_assertion_identifier",
"path": "modules/slots/has_assertion_identifier.yaml",
"category": "slot"
},
{
"name": "has_assertion_rationale",
"path": "modules/slots/has_assertion_rationale.yaml",
@ -7952,11 +7902,6 @@
"path": "modules/slots/has_auxiliary_place.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_place_identifier",
"path": "modules/slots/has_auxiliary_place_identifier.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_place_type",
"path": "modules/slots/has_auxiliary_place_type.yaml",
@ -7967,11 +7912,6 @@
"path": "modules/slots/has_auxiliary_platform.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_platform_identifier",
"path": "modules/slots/has_auxiliary_platform_identifier.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_platform_type",
"path": "modules/slots/has_auxiliary_platform_type.yaml",
@ -8272,16 +8212,6 @@
"path": "modules/slots/has_or_had_admin_staff_count.yaml",
"category": "slot"
},
{
"name": "has_or_had_administrative_expense",
"path": "modules/slots/has_or_had_administrative_expense.yaml",
"category": "slot"
},
{
"name": "has_or_had_administrative_function",
"path": "modules/slots/has_or_had_administrative_function.yaml",
"category": "slot"
},
{
"name": "has_or_had_admission_fee",
"path": "modules/slots/has_or_had_admission_fee.yaml",
@ -8452,6 +8382,11 @@
"path": "modules/slots/has_or_had_comment_reply.yaml",
"category": "slot"
},
{
"name": "has_or_had_comprehensive_overview",
"path": "modules/slots/has_or_had_comprehensive_overview.yaml",
"category": "slot"
},
{
"name": "has_or_had_condition_note",
"path": "modules/slots/has_or_had_condition_note.yaml",
@ -8582,6 +8517,11 @@
"path": "modules/slots/has_or_had_exhibition_catalog.yaml",
"category": "slot"
},
{
"name": "has_or_had_expenses",
"path": "modules/slots/has_or_had_expenses.yaml",
"category": "slot"
},
{
"name": "has_or_had_exposed_collection",
"path": "modules/slots/has_or_had_exposed_collection.yaml",
@ -8612,6 +8552,11 @@
"path": "modules/slots/has_or_had_fond.yaml",
"category": "slot"
},
{
"name": "has_or_had_function",
"path": "modules/slots/has_or_had_function.yaml",
"category": "slot"
},
{
"name": "has_or_had_generate",
"path": "modules/slots/has_or_had_generate.yaml",
@ -8892,6 +8837,11 @@
"path": "modules/slots/has_or_had_scene_segment.yaml",
"category": "slot"
},
{
"name": "has_or_had_secondary_label",
"path": "modules/slots/has_or_had_secondary_label.yaml",
"category": "slot"
},
{
"name": "has_or_had_secondary_system",
"path": "modules/slots/has_or_had_secondary_system.yaml",
@ -9442,6 +9392,11 @@
"path": "modules/slots/includes_object_tracking.yaml",
"category": "slot"
},
{
"name": "includes_or_included",
"path": "modules/slots/includes_or_included.yaml",
"category": "slot"
},
{
"name": "includes_segmentation_mask",
"path": "modules/slots/includes_segmentation_mask.yaml",
@ -9482,11 +9437,6 @@
"path": "modules/slots/innovation_budget.yaml",
"category": "slot"
},
{
"name": "innovation_expense",
"path": "modules/slots/innovation_expense.yaml",
"category": "slot"
},
{
"name": "inscription",
"path": "modules/slots/inscription.yaml",
@ -9762,6 +9712,11 @@
"path": "modules/slots/is_or_was_platform_of.yaml",
"category": "slot"
},
{
"name": "is_or_was_real",
"path": "modules/slots/is_or_was_real.yaml",
"category": "slot"
},
{
"name": "is_or_was_related_to",
"path": "modules/slots/is_or_was_related_to.yaml",
@ -12042,11 +11997,6 @@
"path": "modules/slots/program_activity.yaml",
"category": "slot"
},
{
"name": "program_expense",
"path": "modules/slots/program_expense.yaml",
"category": "slot"
},
{
"name": "programme_period",
"path": "modules/slots/programme_period.yaml",

View file

@ -6,14 +6,16 @@ imports:
- ./ReconstructedEntity
- ./CustodianObservation
- ./ReconstructionActivity
- ./FunctionType
- ../slots/was_derived_from
- ../slots/was_generated_by
- ../slots/has_or_had_access_restriction
- ../slots/has_admin_office_description
- ../slots/admin_office_id
- ../slots/has_admin_office_name
- ../slots/has_or_had_admin_staff_count
- ../slots/administrative_functions
# administrative_functions REMOVED - migrated to has_or_had_function (Rule 53)
# has_or_had_administrative_function REMOVED - bespoke slot replaced by generic has_or_had_function (Rule 53)
- ../slots/has_or_had_function
- ../slots/is_leased
- ../slots/lease_expiry
- ../slots/specificity_annotation
@ -21,7 +23,6 @@ imports:
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_admin_office_identifier
- ../slots/has_or_had_administrative_function
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
@ -36,25 +37,75 @@ classes:
AdministrativeOffice:
is_a: ReconstructedEntity
class_uri: org:Site
description: "Non-public administrative building or office space of a heritage custodian.\n\n**DEFINITION**:\n\nAn AdministrativeOffice\
\ is a secondary physical location where a heritage\ncustodian performs back-office, administrative, or support functions\
\ that\ndo not directly serve the public. These locations typically house staff\nperforming finance, HR, IT, management,\
\ or other operational activities.\n\n**W3C ORG ALIGNMENT**:\n\n`org:Site` - \"An office or other premise at which the\
\ organization is located.\"\n\nAdministrativeOffice specializes org:Site for non-public administrative spaces:\n- Financial/accounting\
\ departments\n- Human resources offices\n- IT infrastructure locations\n- Executive/management offices\n\n**DISTINCTION\
\ FROM OTHER AUXILIARY PLACE TYPES**:\n\n| Type | Public Access | Primary Function |\n|------|---------------|------------------|\n\
| BranchOffice | Yes | Public service delivery |\n| **AdministrativeOffice** | No | Back-office operations |\n| ResearchCenter\
\ | Limited | Research/conservation |\n| Storage | No | Collection storage |\n\n**TYPICAL CHARACTERISTICS**:\n\n- **Staff-only\
\ access**: No public visitors\n- **Administrative functions**: Finance, HR, IT, management\n- **Separate from collections**:\
\ No collection materials stored\n- **Cost center**: Often in lower-cost location than main building\n\n**USE CASES**:\n\
\n1. **Separate Administrative Building**:\n - Museum finance department in office park\n - Archive IT/digitization\
\ support center\n\n2. **Executive Offices**:\n - Foundation board meeting space\n - Director's office separate\
\ from main building\n\n3. **Support Services**:\n - Facilities management office\n - Marketing/communications department\n\
\n**Example - Administrative Annex**:\n```yaml\nAdministrativeOffice:\n admin_office_id: \"https://nde.nl/ontology/hc/aux/rijksmuseum-admin-zuidas\"\
\n admin_office_name: \"Rijksmuseum Administrative Offices - Zuidas\"\n admin_office_description: |\n Administrative\
\ support offices housing finance, HR, and IT departments.\n Staff access only. Located in Zuidas business district\
\ for \n cost efficiency.\n administrative_functions:\n - \"Finance and accounting\"\n - \"Human resources\"\
\n - \"Information technology\"\n - \"Legal affairs\"\n access_restriction: \"Staff badge required\"\n```\n"
description: >-
Non-public administrative building or office space of a heritage custodian.
**DEFINITION**:
An AdministrativeOffice is a secondary physical location where a heritage
custodian performs back-office, administrative, or support functions that
do not directly serve the public. These locations typically house staff
performing finance, HR, IT, management, or other operational activities.
**W3C ORG ALIGNMENT**:
`org:Site` - "An office or other premise at which the organization is located."
AdministrativeOffice specializes org:Site for non-public administrative spaces:
- Financial/accounting departments
- Human resources offices
- IT infrastructure locations
- Executive/management offices
**DISTINCTION FROM OTHER AUXILIARY PLACE TYPES**:
| Type | Public Access | Primary Function |
|------|---------------|------------------|
| BranchOffice | Yes | Public service delivery |
| **AdministrativeOffice** | No | Back-office operations |
| ResearchCenter | Limited | Research/conservation |
| Storage | No | Collection storage |
**TYPICAL CHARACTERISTICS**:
- **Staff-only access**: No public visitors
- **Administrative functions**: Finance, HR, IT, management
- **Separate from collections**: No collection materials stored
- **Cost center**: Often in lower-cost location than main building
**USE CASES**:
1. **Separate Administrative Building**:
- Museum finance department in office park
- Archive IT/digitization support center
2. **Executive Offices**:
- Foundation board meeting space
- Director's office separate from main building
3. **Support Services**:
- Facilities management office
- Marketing/communications department
**Example - Administrative Annex**:
```yaml
AdministrativeOffice:
has_admin_office_identifier: "https://nde.nl/ontology/hc/aux/rijksmuseum-admin-zuidas"
has_admin_office_name: "Rijksmuseum Administrative Offices - Zuidas"
has_admin_office_description: |
Administrative support offices housing finance, HR, and IT departments.
Staff access only. Located in Zuidas business district for cost efficiency.
has_or_had_function:
- function_category: ADMINISTRATIVE
function_name: "Finance and accounting"
- function_category: ADMINISTRATIVE
function_name: "Human resources"
- function_category: SUPPORT
function_name: "Information technology"
- function_category: ADMINISTRATIVE
function_name: "Legal affairs"
has_or_had_access_restriction: "Staff badge required"
```
exact_mappings:
- org:Site
close_mappings:
@ -66,10 +117,12 @@ classes:
slots:
- has_or_had_access_restriction
- has_admin_office_description
- admin_office_id
- has_admin_office_identifier
- has_admin_office_name
- has_or_had_admin_staff_count
- administrative_functions
# administrative_functions REMOVED - use has_or_had_function (Rule 53)
# has_or_had_administrative_function REMOVED - bespoke, use has_or_had_function (Rule 53)
- has_or_had_function
- is_leased
- lease_expiry
- specificity_annotation
@ -97,15 +150,26 @@ classes:
examples:
- value: Administrative support offices housing finance, HR, and IT departments. Staff access only.
description: Admin office description
has_or_had_administrative_function:
range: string
has_or_had_function:
range: FunctionType
multivalued: true
inlined: true
inlined_as_list: true
description: >-
Organizational functions performed at this administrative office.
Uses generic FunctionType class with function_category classification.
examples:
- value: Finance and accounting
- value:
function_category: ADMINISTRATIVE
function_name: Finance and accounting
description: Financial operations
- value: Human resources
- value:
function_category: ADMINISTRATIVE
function_name: Human resources
description: HR functions
- value: Information technology
- value:
function_category: SUPPORT
function_name: Information technology
description: IT support
has_or_had_access_restriction:
range: string
@ -146,35 +210,43 @@ classes:
- W3C ORG org:Site specialized for administrative functions
- Often in separate building from main heritage operations
- May be leased rather than owned for cost efficiency
- "MIGRATION NOTE: has_or_had_administrative_function replaced by generic has_or_had_function (Rule 53)"
see_also:
- https://www.w3.org/TR/vocab-org/#org:Site
- https://schema.org/Corporation
examples:
- value:
admin_office_id: https://nde.nl/ontology/hc/aux/rijksmuseum-admin-zuidas
admin_office_name: Rijksmuseum Administrative Offices - Zuidas
admin_office_description: Administrative support offices housing finance, HR, and IT departments. Staff access only.
has_admin_office_identifier: https://nde.nl/ontology/hc/aux/rijksmuseum-admin-zuidas
has_admin_office_name: Rijksmuseum Administrative Offices - Zuidas
has_admin_office_description: Administrative support offices housing finance, HR, and IT departments. Staff access only.
Located in Zuidas business district.
has_or_had_administrative_function:
- Finance and accounting
- Human resources
- Information technology
- Legal affairs
access_restriction: Staff badge required
admin_staff_count: 45
has_or_had_function:
- function_category: ADMINISTRATIVE
function_name: Finance and accounting
- function_category: ADMINISTRATIVE
function_name: Human resources
- function_category: SUPPORT
function_name: Information technology
- function_category: ADMINISTRATIVE
function_name: Legal affairs
has_or_had_access_restriction: Staff badge required
has_or_had_admin_staff_count: 45
is_leased: true
lease_expiry: '2028-12-31'
description: Museum administrative office in business district
- value:
admin_office_id: https://nde.nl/ontology/hc/aux/kb-digitization-center
admin_office_name: Koninklijke Bibliotheek Digitization Support Center
admin_office_description: Technical support center for digitization operations. Houses scanning equipment coordination
has_admin_office_identifier: https://nde.nl/ontology/hc/aux/kb-digitization-center
has_admin_office_name: Koninklijke Bibliotheek Digitization Support Center
has_admin_office_description: Technical support center for digitization operations. Houses scanning equipment coordination
and quality control.
has_or_had_administrative_function:
- Digitization project management
- Quality control
- Technical support
access_restriction: Project staff only
admin_staff_count: 12
has_or_had_function:
- function_category: PROGRAM
function_name: Digitization project management
- function_category: SUPPORT
function_name: Quality control
- function_category: SUPPORT
function_name: Technical support
has_or_had_access_restriction: Project staff only
has_or_had_admin_staff_count: 12
is_leased: false
description: Library digitization support facility

View file

@ -25,7 +25,7 @@ imports:
- ../slots/has_or_had_data_service_endpoint
- ../slots/api_documentation
- ../slots/has_or_had_archival_status
- ../slots/auxiliary_platform_id
- ../slots/has_or_had_identifier
- ../slots/has_auxiliary_platform_type
- ../slots/cms_detected
- ../slots/fixity_info
@ -49,7 +49,6 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_auxiliary_platform_identifier
- ../slots/has_api_documentation_url
prefixes:
linkml: https://w3id.org/linkml/
@ -114,7 +113,7 @@ classes:
- api_documentation
- has_or_had_archival_status
- archived_at
- auxiliary_platform_id
- has_or_had_identifier
- has_auxiliary_platform_type
- cms_detected
- has_or_had_data_service_endpoint
@ -142,7 +141,7 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_auxiliary_platform_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true
@ -347,7 +346,7 @@ classes:
- http://usefulinc.com/ns/doap#
examples:
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-rijksstudio
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-rijksstudio
platform_name: Rijksstudio
auxiliary_platform_type: ProjectWebsite
platform_url: https://www.rijksmuseum.nl/nl/rijksstudio
@ -365,7 +364,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksstudio personal collection platform
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-data-api
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-data-api
platform_name: Rijksmuseum Data API
auxiliary_platform_type: APIEndpoint
platform_url: https://data.rijksmuseum.nl/
@ -382,7 +381,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum developer API
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rm-night-watch-experience
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rm-night-watch-experience
platform_name: Operation Night Watch
auxiliary_platform_type: ExhibitionMicrosite
platform_url: https://www.rijksmuseum.nl/en/stories/operation-night-watch
@ -396,7 +395,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Night Watch research project microsite
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/na-ww2-portal
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/na-ww2-portal
platform_name: WW2 Archives Portal
auxiliary_platform_type: ProjectWebsite
platform_url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/ww2

View file

@ -39,7 +39,7 @@ imports:
- ../slots/street_address
- ../slots/postal_code
- ../slots/city
- ../slots/auxiliary_place_id
- ../slots/has_or_had_identifier
- ../slots/has_auxiliary_place_type
- ../slots/country
- ../slots/hosts_branch
@ -59,7 +59,6 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_auxiliary_place_identifier
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
@ -119,7 +118,7 @@ classes:
- org:siteAddress
- vcard:Address
slots:
- auxiliary_place_id
- has_or_had_identifier
- has_auxiliary_place_type
- city
- country
@ -146,7 +145,7 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_auxiliary_place_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true
@ -334,7 +333,7 @@ classes:
- https://www.w3.org/TR/vcard-rdf/
examples:
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/rijksmuseum-depot-amersfoort
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/rijksmuseum-depot-amersfoort
place_name: Depot Amersfoort
auxiliary_place_type: STORAGE_FACILITY
place_description: Off-site storage facility for overflow collections. Climate-controlled. Staff access only.
@ -350,7 +349,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum off-site storage depot
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/rijksmuseum-schiphol
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/rijksmuseum-schiphol
place_name: Rijksmuseum Schiphol
auxiliary_place_type: BRANCH_OFFICE
place_description: Small exhibition space at Schiphol Airport featuring rotating highlights from the collection.
@ -365,7 +364,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum airport branch exhibition
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/nha-reading-room-annex
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/nha-reading-room-annex
place_name: Noord-Hollands Archief Reading Room Annex
auxiliary_place_type: READING_ROOM_ANNEX
specialized_place:

View file

@ -12,7 +12,7 @@ prefixes:
imports:
- linkml:types
- ../metadata
- ../slots/activities_societies
# activities_societies REMOVED - migrated to has_or_had_membership + has_or_had_activity_type (Rule 53)
- ../slots/degree_name
- ../slots/education_description
- ../slots/education_end_year
@ -74,7 +74,7 @@ classes:
- schema:Course
- schema:Degree
slots:
- activities_societies
# activities_societies REMOVED - migrated to has_or_had_membership + has_or_had_activity_type
- degree_name
- education_description
- education_end_year
@ -145,20 +145,6 @@ classes:
description: Completed in 2017
- value: null
description: Ongoing (current student)
activities_societies:
range: string
deprecated: |
DEPRECATED (2026-01-14): Use has_or_had_membership for structured membership data
or has_or_had_activity_type for activity type classifications.
Migration: activities_societies string → has_or_had_membership (Membership instances)
See slot_fixes.yaml entry: https://nde.nl/ontology/hc/slot/activities_societies
description: |
[DEPRECATED] Raw string containing student activities and society memberships.
Use has_or_had_membership for structured membership data instead.
examples:
- value: Student Museum Association, Heritage Preservation Club
description: Raw string format (deprecated)
has_or_had_membership:
range: string
description: |

View file

@ -0,0 +1,192 @@
id: https://nde.nl/ontology/hc/class/Expenses
name: expenses_class
title: Expenses Class
description: >-
Represents financial expenses/expenditures for a heritage custodian.
Provides structured expense categorization following nonprofit functional
expense classification (program, administrative, fundraising).
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
frapo: http://purl.org/cerif/frapo/
dcterms: http://purl.org/dc/terms/
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/has_or_had_amount
- ../slots/has_or_had_currency
- ../slots/valid_from
- ../slots/valid_to
- ../enums/ExpenseTypeEnum
default_prefix: hc
enums:
ExpenseTypeEnum:
description: >-
Functional expense classification for nonprofit organizations.
Based on IRS Form 990 and GAAP nonprofit reporting standards.
permissible_values:
ADMINISTRATIVE:
description: >-
Management and general expenses: executive management, finance/accounting,
HR, facilities overhead, legal, IT infrastructure.
PROGRAM:
description: >-
Direct program service expenses: costs directly attributable to
mission-related activities (exhibitions, conservation, education).
FUNDRAISING:
description: >-
Fundraising expenses: donor cultivation, grant writing, events,
marketing for donations.
INNOVATION:
description: >-
Research and development expenses: new program development,
technology innovation, experimental initiatives.
CAPITAL:
description: >-
Capital expenditures: building improvements, major equipment,
collection acquisitions (if capitalized).
OTHER:
description: >-
Other expenses not classified above.
classes:
Expenses:
class_uri: hc:Expenses
description: >-
Represents a categorized expense/expenditure for a heritage custodian.
**FUNCTIONAL EXPENSE CLASSIFICATION (Nonprofit-Specific)**:
Heritage custodians (predominantly nonprofits) must classify expenses by function:
| Type | Description | Examples |
|------|-------------|----------|
| PROGRAM | Mission-related | Exhibitions, conservation, education |
| ADMINISTRATIVE | Overhead | Executive, finance, HR, facilities |
| FUNDRAISING | Donor relations | Events, grants, marketing |
| INNOVATION | R&D | New programs, technology |
**USAGE**:
The `has_or_had_expenses` slot links entities to Expenses instances:
```yaml
financial_statement:
has_or_had_expenses:
- expense_type: ADMINISTRATIVE
amount: 10000000.0
currency: EUR
description: "Management and general expenses FY2023"
- expense_type: PROGRAM
amount: 62000000.0
currency: EUR
description: "Program service expenses FY2023"
```
**ONTOLOGY ALIGNMENT**:
- No standard ontology has a direct "expense" predicate
- Uses FRAPO (Funding, Research Administration and Projects Ontology) patterns
- Aligns with schema:MonetaryAmount for monetary values
exact_mappings:
- frapo:Expenditure
close_mappings:
- schema:MonetaryAmount
related_mappings:
- frapo:hasFunding
slots:
- id
- expense_type
- amount
- currency
- description
- valid_from
- valid_to
slot_usage:
id:
identifier: true
required: false
expense_type:
range: ExpenseTypeEnum
required: true
description: Functional expense classification.
amount:
range: decimal
required: true
description: Expense amount as decimal value.
currency:
range: string
required: true
description: ISO 4217 currency code (EUR, USD, GBP).
examples:
- value: EUR
- value: USD
- value: GBP
description:
range: string
required: false
description: Human-readable description of the expense.
valid_from:
range: date
required: false
description: Start of period this expense applies to.
valid_to:
range: date
required: false
description: End of period this expense applies to.
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Financial expenses applicable to all heritage custodian types.
custodian_types_primary: M
specificity_score: 0.55
specificity_rationale: >-
Moderately specific - financial expense tracking is specialized but applicable
across institution types with financial reporting requirements.
examples:
- value:
expense_type: ADMINISTRATIVE
amount: 10000000.0
currency: EUR
description: "Management and general expenses for FY2023"
valid_from: "2023-01-01"
valid_to: "2023-12-31"
description: Administrative expense for Dutch museum
- value:
expense_type: PROGRAM
amount: 62000000.0
currency: EUR
description: "Program service expenses including exhibitions, conservation, education"
valid_from: "2023-01-01"
valid_to: "2023-12-31"
description: Program expense for major museum
- value:
expense_type: FUNDRAISING
amount: 3200000.0
currency: EUR
description: "Fundraising and donor relations expenses"
description: Fundraising expense
slots:
expense_type:
description: Functional expense classification (administrative, program, fundraising, etc.).
range: ExpenseTypeEnum
slot_uri: hc:expenseType
amount:
description: Monetary amount of the expense.
range: decimal
slot_uri: schema:price
exact_mappings:
- frapo:hasAmount
currency:
description: ISO 4217 currency code for the expense amount.
range: string
slot_uri: schema:priceCurrency
pattern: "^[A-Z]{3}$"

View file

@ -15,7 +15,6 @@ imports:
- ../enums/FinancialStatementTypeEnum
- ./ReconstructedEntity
- ../slots/publication_date
- ../slots/administrative_expenses
- ../slots/has_audit_date
- ../slots/has_audit_opinion
- ../slots/has_or_had_audit_status
@ -27,11 +26,8 @@ imports:
- ../slots/financial_archival_stage
- ../slots/financial_document_format
- ../slots/financial_document_url
- ../slots/fundraising_expense
- ../slots/id
- ../slots/innovation_expense
- ../slots/managing_unit
- ../slots/program_expense
- ../slots/refers_to_custodian
- ../slots/reporting_period_end
- ../slots/reporting_period_start
@ -52,7 +48,8 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_or_had_administrative_expense
- ../slots/has_or_had_expenses
- ./Expenses
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
@ -114,7 +111,6 @@ classes:
- frapo:hasFunding
- prov:Entity
slots:
- administrative_expenses
- audit_date
- audit_opinion
- audit_status
@ -126,11 +122,9 @@ classes:
- financial_archival_stage
- financial_document_format
- financial_document_url
- fundraising_expense
- has_or_had_expenses
- id
- innovation_expense
- managing_unit
- program_expense
- publication_date
- refers_to_custodian
- reporting_period_end
@ -197,18 +191,28 @@ classes:
total_net_asset:
range: decimal
required: false
program_expense:
range: decimal
required: false
has_or_had_administrative_expense:
range: decimal
required: false
fundraising_expense:
range: decimal
required: false
innovation_expense:
range: decimal
has_or_had_expenses:
range: Expenses
multivalued: true
inlined: true
inlined_as_list: true
required: false
description: >-
Categorized expenses using the Expenses class. Replaces individual
expense slots (administrative_expenses, program_expense, fundraising_expense,
innovation_expense) with a single structured relationship.
examples:
- value:
- expense_type: ADMINISTRATIVE
amount: 10000000.0
currency: EUR
- expense_type: PROGRAM
amount: 62000000.0
currency: EUR
- expense_type: FUNDRAISING
amount: 3200000.0
currency: EUR
description: Functional expense breakdown for Dutch museum
has_or_had_audit_status:
range: string
required: false
@ -305,9 +309,19 @@ classes:
total_assets: 125000000.0
total_liabilities: 15000000.0
total_net_assets: 110000000.0
program_expenses: 62000000.0
administrative_expenses: 10000000.0
fundraising_expenses: 3200000.0
has_or_had_expenses:
- expense_type: PROGRAM
amount: 62000000.0
currency: EUR
description: "Program service expenses including exhibitions, conservation, education"
- expense_type: ADMINISTRATIVE
amount: 10000000.0
currency: EUR
description: "Management and general expenses"
- expense_type: FUNDRAISING
amount: 3200000.0
currency: EUR
description: "Fundraising and donor relations expenses"
audit_status: AUDITED
auditor_name: KPMG Accountants N.V.
audit_opinion: UNQUALIFIED

View file

@ -20,6 +20,8 @@ imports:
- linkml:types
- ./FindingAidType
- ./WebClaim
- ./Overview
- ./WebLink
- ../slots/valid_from
- ../slots/valid_to
- ../slots/id
@ -52,7 +54,7 @@ imports:
- ../slots/isbn
- ../slots/has_or_had_access_condition
- ../slots/is_or_was_access_restricted
- ../slots/all_links
- ../slots/has_or_had_comprehensive_overview
- ../slots/card_description
- ../slots/card_description_en
- ../slots/card_image_url
@ -226,7 +228,7 @@ classes:
- bf:Work
slots:
- finding_aid_access_restriction
- all_links
- has_or_had_comprehensive_overview
- creator
- custodian
- finding_aid_description
@ -298,6 +300,12 @@ classes:
inlined_as_list: true
language:
multivalued: true
has_or_had_comprehensive_overview:
range: Overview
inlined: true
description: |
Comprehensive collection of all links from this finding aid.
Replaces previous all_links slot with typed Overview class.
comments:
- Root class for finding aid metadata YAML files
- Designed for validation with linkml-validate

View file

@ -0,0 +1,173 @@
id: https://nde.nl/ontology/hc/class/FunctionType
name: function_type_class
title: FunctionType Class
description: >-
Abstract base class for organizational functions performed by heritage custodians.
Provides structured function categorization for administrative offices, departments,
and organizational units.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
org: http://www.w3.org/ns/org#
dcterms: http://purl.org/dc/terms/
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
default_prefix: hc
enums:
FunctionTypeEnum:
description: >-
Classification of organizational functions for heritage custodians.
Based on W3C ORG org:purpose patterns and nonprofit organizational structure.
permissible_values:
ADMINISTRATIVE:
description: >-
Administrative/management functions: finance, HR, legal, executive management,
facilities, procurement, governance.
PROGRAM:
description: >-
Program/mission functions: exhibitions, conservation, education, research,
public programming, collection management.
SUPPORT:
description: >-
Support/operational functions: IT, security, maintenance, visitor services,
retail, catering.
DEVELOPMENT:
description: >-
Development/fundraising functions: donor relations, grants, membership,
corporate partnerships, planned giving.
COMMUNICATIONS:
description: >-
Communications/marketing functions: public relations, marketing, social media,
publications, branding.
OTHER:
description: >-
Other functions not classified above.
classes:
FunctionType:
class_uri: hc:FunctionType
abstract: true
description: >-
Abstract base class representing a type of organizational function.
**DESIGN RATIONALE**:
This is an ABSTRACT class following the Type/Types naming convention (Rule 0b).
Concrete function types are defined in FunctionTypes.yaml as subclasses.
**FUNCTION CLASSIFICATION**:
Heritage custodians organize work into functional areas:
| Category | Examples |
|----------|----------|
| ADMINISTRATIVE | Finance, HR, Legal, Executive |
| PROGRAM | Exhibitions, Conservation, Education |
| SUPPORT | IT, Security, Maintenance, Visitor Services |
| DEVELOPMENT | Fundraising, Grants, Membership |
| COMMUNICATIONS | PR, Marketing, Publications |
**USAGE**:
The `has_or_had_function` slot links entities to FunctionType instances:
```yaml
administrative_office:
has_or_had_function:
- function_category: ADMINISTRATIVE
function_name: "Finance and Accounting"
description: "Financial operations and reporting"
- function_category: ADMINISTRATIVE
function_name: "Human Resources"
description: "Staff management and recruitment"
```
**ONTOLOGY ALIGNMENT**:
- Primary: `org:purpose` - "Indicates the purpose of this Organization"
- Related: `schema:roleName` - The role associated with an organizational function
exact_mappings:
- org:purpose
close_mappings:
- schema:Role
related_mappings:
- org:OrganizationalUnit
slots:
- id
- function_category
- function_name
- description
- valid_from
- valid_to
slot_usage:
id:
identifier: true
required: false
function_category:
range: FunctionTypeEnum
required: true
description: High-level function classification.
function_name:
range: string
required: true
description: Specific name of the function (e.g., "Finance and Accounting").
description:
range: string
required: false
description: Human-readable description of the function.
valid_from:
range: date
required: false
description: Start date when this function was established.
valid_to:
range: date
required: false
description: End date when this function was discontinued.
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Organizational functions applicable to all heritage custodian types.
custodian_types_primary: M
specificity_score: 0.50
specificity_rationale: >-
Moderately specific - organizational function classification is applicable
across institution types but specialized for organizational modeling.
examples:
- value:
function_category: ADMINISTRATIVE
function_name: Finance and Accounting
description: "Financial operations, budgeting, and reporting"
description: Administrative function - Finance
- value:
function_category: PROGRAM
function_name: Conservation
description: "Object conservation and preservation activities"
description: Program function - Conservation
- value:
function_category: SUPPORT
function_name: Information Technology
description: "IT infrastructure and support services"
description: Support function - IT
slots:
function_category:
description: High-level classification of organizational function.
range: FunctionTypeEnum
slot_uri: org:classification
exact_mappings:
- org:classification
function_name:
description: Specific name of the organizational function.
range: string
slot_uri: schema:roleName
exact_mappings:
- schema:roleName

View file

@ -0,0 +1,291 @@
id: https://nde.nl/ontology/hc/class/FunctionTypes
name: function_types_classes
title: FunctionTypes Concrete Classes
description: >-
Concrete function type subclasses for heritage custodian organizational functions.
Follows Type/Types naming convention (Rule 0b).
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
org: http://www.w3.org/ns/org#
schema: http://schema.org/
imports:
- linkml:types
- ./FunctionType
default_prefix: hc
classes:
# =============================================================================
# ADMINISTRATIVE FUNCTIONS
# =============================================================================
FinanceFunction:
is_a: FunctionType
class_uri: hc:FinanceFunction
description: >-
Finance and accounting function: budgeting, financial reporting, accounts
payable/receivable, audit coordination, treasury management.
annotations:
function_category: ADMINISTRATIVE
HumanResourcesFunction:
is_a: FunctionType
class_uri: hc:HumanResourcesFunction
description: >-
Human resources function: recruitment, employee relations, compensation,
benefits administration, training and development.
annotations:
function_category: ADMINISTRATIVE
LegalFunction:
is_a: FunctionType
class_uri: hc:LegalFunction
description: >-
Legal and compliance function: contracts, intellectual property, regulatory
compliance, risk management, governance.
annotations:
function_category: ADMINISTRATIVE
ExecutiveFunction:
is_a: FunctionType
class_uri: hc:ExecutiveFunction
description: >-
Executive management function: strategic planning, board relations,
organizational leadership, policy development.
annotations:
function_category: ADMINISTRATIVE
FacilitiesFunction:
is_a: FunctionType
class_uri: hc:FacilitiesFunction
description: >-
Facilities management function: building operations, space planning,
maintenance coordination, vendor management.
annotations:
function_category: ADMINISTRATIVE
ProcurementFunction:
is_a: FunctionType
class_uri: hc:ProcurementFunction
description: >-
Procurement function: purchasing, supplier management, contract negotiation,
inventory management.
annotations:
function_category: ADMINISTRATIVE
# =============================================================================
# PROGRAM FUNCTIONS
# =============================================================================
ExhibitionFunction:
is_a: FunctionType
class_uri: hc:ExhibitionFunction
description: >-
Exhibition function: exhibition planning, design, installation, loan
coordination, traveling exhibitions.
annotations:
function_category: PROGRAM
ConservationFunction:
is_a: FunctionType
class_uri: hc:ConservationFunction
description: >-
Conservation function: object conservation, preventive care, environmental
monitoring, conservation research.
annotations:
function_category: PROGRAM
EducationFunction:
is_a: FunctionType
class_uri: hc:EducationFunction
description: >-
Education function: school programs, public programming, docent training,
curriculum development, outreach.
annotations:
function_category: PROGRAM
ResearchFunction:
is_a: FunctionType
class_uri: hc:ResearchFunction
description: >-
Research function: curatorial research, collection documentation, scholarly
publications, academic partnerships.
annotations:
function_category: PROGRAM
CollectionManagementFunction:
is_a: FunctionType
class_uri: hc:CollectionManagementFunction
description: >-
Collection management function: cataloging, registration, provenance
research, deaccessioning, storage management.
annotations:
function_category: PROGRAM
ArchivalFunction:
is_a: FunctionType
class_uri: hc:ArchivalFunction
description: >-
Archival function: arrangement and description, finding aids, reference
services, records management.
annotations:
function_category: PROGRAM
LibraryFunction:
is_a: FunctionType
class_uri: hc:LibraryFunction
description: >-
Library function: cataloging, circulation, reference services, collection
development, interlibrary loan.
annotations:
function_category: PROGRAM
# =============================================================================
# SUPPORT FUNCTIONS
# =============================================================================
InformationTechnologyFunction:
is_a: FunctionType
class_uri: hc:InformationTechnologyFunction
description: >-
Information technology function: infrastructure, software systems, user
support, cybersecurity, digital preservation.
annotations:
function_category: SUPPORT
SecurityFunction:
is_a: FunctionType
class_uri: hc:SecurityFunction
description: >-
Security function: physical security, access control, emergency response,
collection protection.
annotations:
function_category: SUPPORT
MaintenanceFunction:
is_a: FunctionType
class_uri: hc:MaintenanceFunction
description: >-
Maintenance function: building maintenance, HVAC, cleaning, grounds keeping,
equipment repair.
annotations:
function_category: SUPPORT
VisitorServicesFunction:
is_a: FunctionType
class_uri: hc:VisitorServicesFunction
description: >-
Visitor services function: admissions, information desk, accessibility
services, group tours, volunteer coordination.
annotations:
function_category: SUPPORT
RetailFunction:
is_a: FunctionType
class_uri: hc:RetailFunction
description: >-
Retail function: museum shop operations, merchandise, online sales,
product development.
annotations:
function_category: SUPPORT
CateringFunction:
is_a: FunctionType
class_uri: hc:CateringFunction
description: >-
Catering function: cafe/restaurant operations, event catering, food
service management.
annotations:
function_category: SUPPORT
# =============================================================================
# DEVELOPMENT FUNCTIONS
# =============================================================================
FundraisingFunction:
is_a: FunctionType
class_uri: hc:FundraisingFunction
description: >-
Fundraising function: annual fund, major gifts, donor cultivation,
fundraising events.
annotations:
function_category: DEVELOPMENT
GrantsFunction:
is_a: FunctionType
class_uri: hc:GrantsFunction
description: >-
Grants function: grant writing, foundation relations, grant reporting,
compliance.
annotations:
function_category: DEVELOPMENT
MembershipFunction:
is_a: FunctionType
class_uri: hc:MembershipFunction
description: >-
Membership function: member recruitment, retention, benefits, member
events, member communications.
annotations:
function_category: DEVELOPMENT
CorporatePartnershipsFunction:
is_a: FunctionType
class_uri: hc:CorporatePartnershipsFunction
description: >-
Corporate partnerships function: sponsorships, corporate memberships,
venue rentals, brand partnerships.
annotations:
function_category: DEVELOPMENT
# =============================================================================
# COMMUNICATIONS FUNCTIONS
# =============================================================================
PublicRelationsFunction:
is_a: FunctionType
class_uri: hc:PublicRelationsFunction
description: >-
Public relations function: media relations, press releases, crisis
communications, reputation management.
annotations:
function_category: COMMUNICATIONS
MarketingFunction:
is_a: FunctionType
class_uri: hc:MarketingFunction
description: >-
Marketing function: advertising, digital marketing, audience research,
brand management.
annotations:
function_category: COMMUNICATIONS
SocialMediaFunction:
is_a: FunctionType
class_uri: hc:SocialMediaFunction
description: >-
Social media function: content creation, community management, analytics,
influencer relations.
annotations:
function_category: COMMUNICATIONS
PublicationsFunction:
is_a: FunctionType
class_uri: hc:PublicationsFunction
description: >-
Publications function: catalogs, newsletters, annual reports, scholarly
publications, exhibition materials.
annotations:
function_category: COMMUNICATIONS
DigitizationFunction:
is_a: FunctionType
class_uri: hc:DigitizationFunction
description: >-
Digitization function: scanning, photography, metadata creation, digital
asset management, online access.
annotations:
function_category: PROGRAM

View file

@ -18,7 +18,7 @@ imports:
- ../slots/language
- ../slots/has_agenda_description
- ../slots/has_agenda_document_url
- ../slots/agenda_id
- ../slots/has_or_had_identifier
- ../slots/has_agenda_short_name
- ../slots/has_agenda_title
- ../slots/has_agenda_url
@ -39,7 +39,8 @@ imports:
- ../slots/validity_period
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_agenda_identifier
- ../slots/has_or_had_identifier
- ./CustodianIdentifier
default_prefix: hc
classes:
FundingAgenda:
@ -83,7 +84,7 @@ classes:
slots:
- has_agenda_description
- has_agenda_document_url
- agenda_id
- has_or_had_identifier
- has_agenda_short_name
- has_agenda_title
- has_agenda_url
@ -101,7 +102,10 @@ classes:
- total_investment
- validity_period
slot_usage:
has_agenda_identifier:
has_or_had_identifier:
description: >-
Unique identifier for this funding agenda. Uses the generic has_or_had_identifier
slot with FundingAgenda-specific formatting.
identifier: true
required: true
range: uriorcurie
@ -232,7 +236,7 @@ classes:
- https://www.artscouncil.org.uk/lets-create/strategy-2020-2030
examples:
- value:
agenda_id: https://nde.nl/ontology/hc/agenda/nl/nwa
has_or_had_identifier: https://nde.nl/ontology/hc/agenda/nl/nwa
agenda_title: Nationale Wetenschapsagenda
agenda_short_name: NWA
agenda_description: 'The Dutch Research Agenda (Nationale Wetenschapsagenda, NWA) is a collaborative
@ -315,7 +319,7 @@ classes:
- societal challenges
description: Dutch Research Agenda (NWA) as strategic research framework
- value:
agenda_id: https://nde.nl/ontology/hc/agenda/eu/horizon-europe-sp-2021-2024
has_or_had_identifier: https://nde.nl/ontology/hc/agenda/eu/horizon-europe-sp-2021-2024
agenda_title: Horizon Europe Strategic Plan 2021-2024
agenda_short_name: HE SP 2021-2024
agenda_description: 'The Horizon Europe Strategic Plan 2021-2024 sets out the key strategic

View file

@ -19,13 +19,14 @@ imports:
- ../slots/is_or_was_allocated_by
- ../slots/identifier_format_used
- ../slots/canonical_value
- ../slots/also_identifies_name
- ../slots/has_or_had_secondary_label
- ../slots/has_allocation_date
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./AllocationAgency
- ./Custodian
- ./CustodianName
- ./Label
- ./SpecificityAnnotation
- ./Standard
- ./TemplateSpecificityScores
@ -43,8 +44,8 @@ classes:
\ Which Standard defines this identifier type (ISIL → ISO 15511)\n- allocated_by: Which AllocationAgency assigned this\
\ specific identifier\n- identifier_format_used: Which format variant is used in identifier_value\n- canonical_value:\
\ Normalized form for deduplication and matching\n- allocation_date: When the identifier was assigned\n\n**Dual-Purpose\
\ Identifiers**:\n\nSome identifiers (ISNI, VIAF) also identify name authority records:\n- also_identifies_name: Links\
\ to the CustodianName record this identifier also identifies\n\n**Enables**:\n- External identifier management (scheme\
\ Identifiers**:\n\nSome identifiers (ISNI, VIAF) also identify name authority records:\n- has_or_had_secondary_label: Links\
\ to the CustodianName record this identifier also identifies (as a Label)\n\n**Enables**:\n- External identifier management (scheme\
\ + value)\n- Cross-reference to authority registries\n- Persistent identifier resolution\n- Inter-dataset linking\n\
- Full provenance tracking (who allocated, when, under what standard)\n- Name authority linkage (for ISNI, VIAF)\n"
exact_mappings:
@ -60,7 +61,7 @@ classes:
slots:
- is_or_was_allocated_by
- has_allocation_date
- also_identifies_name
- has_or_had_secondary_label
- canonical_value
- defined_by_standard
- identifier_format_used
@ -87,7 +88,11 @@ classes:
required: false
canonical_value:
required: false
also_identifies_name:
has_or_had_secondary_label:
description: |
For dual-purpose identifiers (ISNI, VIAF), links to the name authority
record this identifier also identifies.
range: Label
required: false
has_allocation_date:
required: false

View file

@ -0,0 +1,98 @@
# Label class
# Generic class for labeled entities with language tagging
#
# Generation date: 2026-01-15
# Rule compliance: 0 (LinkML single source of truth), 38 (slot centralization)
# Migration: Supports has_or_had_secondary_label slot (replaces also_identifies_name)
id: https://nde.nl/ontology/hc/class/Label
name: label_class
title: Label Class
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
skos: http://www.w3.org/2004/02/skos/core#
rdfs: http://www.w3.org/2000/01/rdf-schema#
schema: http://schema.org/
default_prefix: hc
imports:
- linkml:types
- ../metadata
- ../slots/has_or_had_label
- ../slots/language
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
classes:
Label:
class_uri: rdfs:Resource
description: |
A human-readable label for an entity, with optional language tagging.
**Purpose**:
Label provides a reusable class for representing named/labeled references
across the heritage custodian schema. Used when an identifier or reference
also identifies a secondary named entity (e.g., name authority records).
**Ontological Alignment**:
- **Primary**: `rdfs:Resource` - generic resource with label
- **Close**: `skos:Concept` - labeled concept in controlled vocabulary
**Use Cases**:
- Dual-purpose identifiers (ISNI, VIAF) that identify both an entity
and its name authority record
- Secondary labels/references for complex relationships
- Language-tagged names and labels
**Enables**:
- Multilingual label representation (via language slot)
- Typed labels with explicit language codes
- Reusable labeled references across schema
exact_mappings:
- rdfs:Resource
close_mappings:
- skos:Concept
- schema:Thing
slots:
- has_or_had_label
- language
- specificity_annotation
- template_specificity
slot_usage:
has_or_had_label:
description: The textual value of this label.
range: string
required: true
language:
description: |
ISO 639-1 two-letter language code for this label.
Examples: "en", "nl", "de", "fr"
range: string
required: false
pattern: "^[a-z]{2}$"
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Generic label class applicable to all types.
custodian_types_primary: null
specificity_score: 0.3
specificity_rationale: Broadly applicable generic class for labeled references.
examples:
- value: |
has_or_had_label: Rijksmuseum
language: nl
description: "Dutch language label for Rijksmuseum name authority"
- value: |
has_or_had_label: National Library of the Netherlands
language: en
description: "English language label for KB name authority"

View file

@ -0,0 +1,155 @@
id: https://nde.nl/ontology/hc/class/Laptop
name: laptop_class
title: Laptop Class
description: >-
Represents laptop use permission in a heritage custodian facility.
Models whether personal laptops are permitted in reading rooms
and under what conditions.
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `allows_laptops` and
`allows_or_allowed_laptop` to generic `allows_or_allowed` slot
with typed class. See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
dcterms: http://purl.org/dc/terms/
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
- ../slots/condition
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
classes:
Laptop:
class_uri: schema:LocationFeatureSpecification
description: >-
Permission specification for laptop use in reading rooms or study areas.
**DEFINITION**:
A policy specification indicating whether researchers may use personal
laptops when consulting materials in reading rooms.
**SCHEMA.ORG ALIGNMENT**:
Maps to `schema:LocationFeatureSpecification` as it describes an amenity
or feature availability at a location (the reading room).
**TYPICAL CONDITIONS**:
- Silent operation required
- No external keyboards/mice
- Power outlets available
- WiFi access included/separate
**TEMPORAL SEMANTICS**:
Laptop policies may change over time:
- Pre-2010: Many archives prohibited laptops
- 2010s: Most became laptop-friendly
- COVID era: Some restrictions due to spacing
**EXAMPLE**:
```yaml
allows_or_allowed:
- permitted_item: Laptop
is_permitted: true
conditions:
- "Silent operation required"
- "No external keyboards"
valid_from: "2015-01-01"
```
exact_mappings:
- schema:LocationFeatureSpecification
close_mappings:
- schema:amenityFeature
slots:
- id
- is_permitted
- description
- condition
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
is_permitted:
range: boolean
required: true
description: >-
Whether laptops are permitted (true) or prohibited (false).
description:
range: string
description: >-
Human-readable description of the laptop policy.
condition:
range: string
multivalued: true
description: >-
Conditions or restrictions on laptop use.
Examples: "Silent operation", "No external keyboards"
annotations:
custodian_types: '["A", "L", "R", "M"]'
custodian_types_rationale: >-
Primarily relevant to archives, libraries, research centers, and museums
with reading rooms or study spaces.
custodian_types_primary: A
specificity_score: 0.75
specificity_rationale: >-
Moderately specific - applies to facilities with on-site research spaces.
comments:
- Part of reading room amenity specification system
- Replaces boolean allows_laptops and allows_or_allowed_laptop slots
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- https://schema.org/LocationFeatureSpecification
- https://schema.org/amenityFeature
examples:
- value:
id: hc:laptop-policy/nationaal-archief
is_permitted: true
description: "Laptops welcome in the study room"
condition:
- "Silent operation required"
- "Power outlets available at each desk"
valid_from: "2010-01-01"
description: Archive laptop-friendly policy
- value:
id: hc:laptop-policy/special-collections-restricted
is_permitted: false
description: "Laptops not permitted in special collections reading room"
condition:
- "Pencils only for note-taking"
- "Institution-provided terminals available"
valid_from: "2020-01-01"
description: Restricted laptop policy for special collections
slots:
is_permitted:
description: >-
Whether the item or activity is permitted.
range: boolean
slot_uri: schema:value

View file

@ -18,7 +18,8 @@ imports:
- ./HeritageRelevance
- ./LanguageProficiency
- ../slots/has_or_had_about_text
- ../slots/all_data_real
- ../slots/is_or_was_real
- ./RealnessStatus
- ../slots/has_assessment_date
- ../slots/connections_text
- ../slots/data_source_whatsapp
@ -56,7 +57,7 @@ imports:
- ./LinkedInProfile
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_all_data_real_flag
- ../slots/has_assessment_date
default_range: string
classes:
LinkedInProfile:
@ -331,7 +332,7 @@ classes:
'
slots:
- all_data_real
- is_or_was_real
- data_source_whatsapp
- enriched_date
- enrichment_method_whatsapp
@ -351,5 +352,14 @@ classes:
- value: public_linkedin_profile
no_fabrication:
range: boolean
has_all_data_real_flag:
range: boolean
is_or_was_real:
range: RealnessStatus
inlined: true
description: >-
Realness status of the enrichment data.
Indicates whether the enrichment data is real production data or test/synthetic.
examples:
- value:
status: REAL
description: "Verified production data from LinkedIn profile"
description: Real production enrichment data

View file

@ -0,0 +1,188 @@
id: https://nde.nl/ontology/hc/class/Overview
name: overview_class
title: Overview Class
description: >-
A comprehensive collection of links and resources.
Represents a structured overview or collection of web links and related
resources. Used to aggregate multiple WebLink instances into a coherent
collection with shared context or purpose.
**ONTOLOGY ALIGNMENT**:
- Dublin Core: dcterms:Collection (collection of resources)
- Schema.org: schema:ItemList (list of items)
- RiC-O: rico:RecordSet (archival collection concept)
**USE CASES**:
1. All links from a finding aid page
2. Comprehensive resource listings
3. Navigation link collections
4. Related resource aggregations
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `all_links` to
`has_or_had_comprehensive_overview` with `Overview` and `WebLink` typed classes.
See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
dcterms: http://purl.org/dc/terms/
schema: http://schema.org/
rico: https://www.ica.org/standards/RiC/ontology#
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/name
- ../slots/description
- ../slots/title
- ../slots/includes_or_included
- ../slots/valid_from
- ../slots/valid_to
- ../slots/source_url
- ../slots/date_retrieved
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./WebLink
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
classes:
Overview:
class_uri: dcterms:Collection
description: >-
A comprehensive collection of links and resources.
**DEFINITION**:
An aggregation of WebLink instances representing all links or resources
from a particular source or context. Enables structured representation
of comprehensive link collections from web pages or other sources.
**DUBLIN CORE ALIGNMENT**:
Maps to `dcterms:Collection` as it represents a collection of related
resources gathered together for a purpose.
**TEMPORAL SEMANTICS**:
Overview collections can change over time:
- New links may be added
- Existing links may be removed or updated
- The collection scope may change
**RELATIONSHIP TO INCLUDES_OR_INCLUDED**:
Uses the generic `includes_or_included` slot to link to WebLink
instances, following RiC-O hierarchical patterns.
**EXAMPLE**:
```yaml
overview:
id: hc:overview/findingaid-familyhistory-links
title: "Family History Research Links"
description: "All links from the family history finding aid page"
source_url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/familiegeschiedenis
date_retrieved: "2025-01-14"
includes_or_included:
- id: hc:link/civil-registry
url: https://example.org/civil-registry
link_text: "Civil Registry"
- id: hc:link/notarial-records
url: https://example.org/notarial
link_text: "Notarial Records"
```
exact_mappings:
- dcterms:Collection
close_mappings:
- schema:ItemList
- rico:RecordSet
slots:
- id
- name
- title
- description
- includes_or_included
- source_url
- date_retrieved
- link_count
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
name:
range: string
description: >-
Short name for the overview collection.
title:
range: string
description: >-
Descriptive title for the overview.
description:
range: string
description: >-
Human-readable description of the overview's purpose and scope.
includes_or_included:
range: WebLink
multivalued: true
inlined_as_list: true
description: >-
The web links included in this overview collection.
source_url:
range: uri
description: >-
The URL of the page from which links were extracted.
date_retrieved:
range: date
description: >-
Date when the overview was extracted or compiled.
link_count:
range: integer
description: >-
Total number of links in the overview.
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types as comprehensive
link collections are universal navigation patterns.
custodian_types_primary: "*"
specificity_score: 0.30
specificity_rationale: >-
Low specificity - broadly applicable for link collection
and navigation modeling.
comments:
- Collection of WebLink instances
- Used with has_or_had_comprehensive_overview slot
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- http://purl.org/dc/terms/Collection
- http://schema.org/ItemList
examples:
- value:
id: hc:overview/findingaid-001-links
title: "Family History Research Links"
description: "Comprehensive collection of links from the family history finding aid"
source_url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/familiegeschiedenis
date_retrieved: "2025-01-14"
link_count: 15
description: Overview of links from a finding aid page
slots:
link_count:
description: >-
Total number of links in an overview collection.
range: integer
slot_uri: schema:numberOfItems

View file

@ -0,0 +1,202 @@
id: https://nde.nl/ontology/hc/class/Photography
name: photography_class
title: Photography Class
description: >-
Represents photography permission in a heritage custodian facility.
Models whether researchers may photograph materials (usually with personal cameras)
and under what conditions.
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `allows_photography` and
`allows_or_allowed_photography` to generic `allows_or_allowed` slot
with typed class. See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
dcterms: http://purl.org/dc/terms/
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
- ../slots/condition
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
classes:
Photography:
class_uri: schema:LocationFeatureSpecification
description: >-
Permission specification for photography in reading rooms or collection areas.
**DEFINITION**:
A policy specification indicating whether researchers may photograph
materials for personal research use when consulting collections.
**SCHEMA.ORG ALIGNMENT**:
Maps to `schema:LocationFeatureSpecification` as it describes a feature
or amenity availability at a location.
**TYPICAL CONDITIONS**:
- Personal research use only
- No flash photography
- No tripods
- Some materials excluded (fragile, copyright)
- Declaration/waiver may be required
**COPYRIGHT CONSIDERATIONS**:
Photography permissions typically apply to:
- Public domain materials
- Materials where institution holds rights
- Personal research use (fair use/dealing)
Materials still under third-party copyright may have different rules.
**TEMPORAL SEMANTICS**:
Photography policies have evolved significantly:
- Pre-2000s: Generally prohibited, had to order copies
- 2000s-2010s: Gradual liberalization
- 2010s onwards: Many institutions allow free photography
**EXAMPLE**:
```yaml
allows_or_allowed:
- permitted_item: Photography
is_permitted: true
conditions:
- "Personal research use only"
- "No flash"
- "Fragile materials excluded"
valid_from: "2018-01-01"
```
exact_mappings:
- schema:LocationFeatureSpecification
close_mappings:
- schema:amenityFeature
- dcterms:accessRights
slots:
- id
- is_permitted
- description
- condition
- requires_declaration
- excluded_materials
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
is_permitted:
range: boolean
required: true
description: >-
Whether photography is permitted (true) or prohibited (false).
description:
range: string
description: >-
Human-readable description of the photography policy.
condition:
range: string
multivalued: true
description: >-
Conditions or restrictions on photography.
Examples: "No flash", "Personal use only", "No tripods"
requires_declaration:
range: boolean
description: >-
Whether a declaration or waiver must be signed.
excluded_materials:
range: string
multivalued: true
description: >-
Types of materials excluded from photography permission.
Examples: "Fragile manuscripts", "Materials under copyright", "Loan items"
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types with physical collections.
custodian_types_primary: M
specificity_score: 0.5
specificity_rationale: >-
Moderately specific - broadly applicable to institutions with collections.
comments:
- Part of reading room amenity specification system
- Replaces boolean allows_photography and allows_or_allowed_photography slots
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- https://schema.org/LocationFeatureSpecification
- https://schema.org/amenityFeature
examples:
- value:
id: hc:photography-policy/nationaal-archief
is_permitted: true
description: "Photography permitted for personal research use"
condition:
- "No flash"
- "Personal research use only"
- "No commercial use without permission"
requires_declaration: true
valid_from: "2015-01-01"
description: Archive photography-friendly policy
- value:
id: hc:photography-policy/special-collections-restricted
is_permitted: false
description: "Photography not permitted in special collections"
condition:
- "Reproduction service available"
- "Digital scans may be ordered"
excluded_materials:
- "All materials in this reading room"
valid_from: "2020-01-01"
description: Restricted photography policy for fragile materials
- value:
id: hc:photography-policy/museum-gallery
is_permitted: true
description: "Photography allowed in permanent galleries"
condition:
- "No flash"
- "No tripods or selfie sticks"
- "Temporary exhibitions may have different rules"
excluded_materials:
- "Loan items marked with no-photography symbol"
- "Temporary exhibitions unless noted"
valid_from: "2018-06-01"
description: Museum gallery photography policy
slots:
requires_declaration:
description: >-
Whether a declaration or waiver is required before the activity.
range: boolean
slot_uri: schema:requiredCollateral
excluded_materials:
description: >-
Materials or areas excluded from the permission.
range: string
multivalued: true
slot_uri: schema:itemListElement

View file

@ -12,7 +12,7 @@ imports:
- ../slots/is_or_was_about_digital_presence
- ../slots/asserted_by
- ../slots/has_assertion_date
- ../slots/assertion_id
- ../slots/has_or_had_identifier
- ../slots/has_assertion_rationale
- ../slots/has_assertion_value
- ../slots/has_or_had_based_on_observation
@ -22,7 +22,6 @@ imports:
- ../slots/temporal_extent
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_assertion_identifier
- ../slots/was_asserted_by
prefixes:
linkml: https://w3id.org/linkml/
@ -94,7 +93,7 @@ classes:
- is_or_was_about_digital_presence
- asserted_by
- has_assertion_date
- assertion_id
- has_or_had_identifier
- has_assertion_rationale
- has_assertion_value
- has_or_had_based_on_observation
@ -106,7 +105,7 @@ classes:
- template_specificity
- temporal_extent
slot_usage:
has_assertion_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true

View file

@ -18,8 +18,9 @@ imports:
- ../slots/has_wifi
- ../slots/requires_registration
- ../slots/requires_appointment
- ../slots/allows_photography
- ../slots/allows_laptops
- ../slots/allows_or_allowed
- ./Laptop
- ./Photography
- ../slots/has_supervised_handling
- ../slots/has_locker
- ../slots/opening_hour
@ -74,8 +75,7 @@ classes:
- schema:ReadingRoom
slots:
- has_or_had_accessibility_feature
- allows_laptops
- allows_photography
- allows_or_allowed
- has_computer_terminal
- has_locker
- has_microfilm_reader
@ -165,17 +165,17 @@ classes:
description: Appointment required
- value: false
description: Walk-in access
allows_or_allowed_photography:
range: boolean
allows_or_allowed:
range: string
multivalued: true
description: >-
Permitted activities and equipment in the reading room.
Use Laptop and Photography classes for structured permissions.
examples:
- value: true
description: Photography permitted
allows_or_allowed_laptop:
range: boolean
ifabsent: 'true'
examples:
- value: true
description: Laptops permitted
- value: "Laptops permitted"
description: Laptop use allowed
- value: "Photography for personal research"
description: Photography allowed with conditions
has_supervised_handling:
range: boolean
examples:
@ -229,8 +229,9 @@ classes:
has_wifi: true
requires_registration: true
requires_appointment: false
allows_photography: true
allows_laptops: true
allows_or_allowed:
- "Laptops permitted"
- "Photography for personal research use"
has_lockers: true
opening_hours: Tu-Fr 09:00-17:00, Sa 09:00-13:00
has_or_had_accessibility_feature:
@ -248,7 +249,8 @@ classes:
terminal_count: 4
requires_registration: true
requires_appointment: true
allows_photography: false
allows_or_allowed:
- "Photography not permitted - reproduction service available"
has_supervised_handling: true
has_lockers: true
opening_hours: Mo-Fr 10:00-16:00

View file

@ -8,7 +8,7 @@ imports:
- ./ReconstructionActivity
- ./ReadingRoom
- ../slots/has_annex_description
- ../slots/annex_id
- ../slots/has_or_had_identifier
- ../slots/has_annex_name
- ../slots/has_annex_reason
- ../slots/is_annex_of_reading_room
@ -25,7 +25,7 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_annex_identifier
- ./CustodianIdentifier
- ../enums/ReadingRoomAnnexReasonEnum
prefixes:
linkml: https://w3id.org/linkml/
@ -50,7 +50,7 @@ classes:
\ FOR ANNEX**:\n\n1. **Capacity overflow**: Main reading room at capacity\n2. **Specialized materials**: Maps, newspapers,\
\ genealogy\n3. **Geographic reach**: Serve researchers in another city\n4. **Renovation**: Temporary reading room during\
\ construction\n5. **Partnership**: Shared space with another institution\n\n**USE CASES**:\n\n1. **Overflow Annex**:\n\
\ ```yaml\n ReadingRoomAnnex:\n annex_id: \"https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg\"\n \
\ ```yaml\n ReadingRoomAnnex:\n has_or_had_identifier: \"https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg\"\n \
\ annex_name: \"Noord-Hollands Archief Reading Room Annex\"\n annex_reason: CAPACITY_OVERFLOW\n is_annex_of_reading_room:\
\ \"https://nde.nl/ontology/hc/aux/nha-studiezaal\"\n ```\n\n2. **Specialized Materials Annex**:\n ```yaml\n ReadingRoomAnnex:\n\
\ annex_name: \"Stadsarchief Kaartenkamer Annex\"\n annex_reason: SPECIALIZED_MATERIALS\n material_specialization:\
@ -67,7 +67,7 @@ classes:
- schema:branch
slots:
- has_annex_description
- annex_id
- has_or_had_identifier
- has_annex_name
- has_annex_reason
- is_annex_of_reading_room
@ -83,10 +83,11 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_annex_identifier:
range: uriorcurie
has_or_had_identifier:
range: CustodianIdentifier
required: true
identifier: true
description: Unique identifier for this reading room annex following NDE Heritage Custodian ontology conventions.
examples:
- value: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
description: Noord-Hollands Archief annex
@ -176,7 +177,7 @@ classes:
- http://vocab.getty.edu/aat/300004051
examples:
- value:
annex_id: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
has_or_had_identifier: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
annex_name: Noord-Hollands Archief Reading Room Annex
annex_description: Overflow reading room at Kleine Houtweg for peak research periods. Same registration as main studiezaal.
annex_reason: CAPACITY_OVERFLOW
@ -188,7 +189,7 @@ classes:
is_temporary: false
description: Overflow reading room annex
- value:
annex_id: https://nde.nl/ontology/hc/aux/sa-renovation-annex
has_or_had_identifier: https://nde.nl/ontology/hc/aux/sa-renovation-annex
annex_name: Stadsarchief Temporary Reading Room
annex_description: Temporary reading room during main building renovation. Limited services available.
annex_reason: RENOVATION

View file

@ -0,0 +1,219 @@
id: https://nde.nl/ontology/hc/class/RealnessStatus
name: realness_status_class
title: RealnessStatus Class
description: >-
Realness status classification for data records.
Models whether data represents real-world entities (production data)
or is synthetic/test data created for development, testing, or demonstration.
**ONTOLOGY ALIGNMENT**:
- DQV: dqv:QualityAnnotation (data quality metadata)
- PROV-O: prov:Entity (provenance tracking)
**USE CASES**:
1. Distinguish production data from test fixtures
2. Quality filtering in data pipelines
3. Provenance tracking for data trustworthiness
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `all_data_real` (stub) to
`is_or_was_real` slot with `RealnessStatus` typed class.
See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
dqv: http://www.w3.org/ns/dqv#
prov: http://www.w3.org/ns/prov#
schema: http://schema.org/
skos: http://www.w3.org/2004/02/skos/core#
dcterms: http://purl.org/dc/terms/
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
enums:
RealnessStatusEnum:
description: >-
Classification of data realness/authenticity.
permissible_values:
REAL:
description: >-
Data represents real-world entities. Production data that reflects
actual heritage institutions, persons, or events.
meaning: hc:RealData
SYNTHETIC:
description: >-
Artificially generated data for testing or demonstration.
Does not represent real-world entities.
meaning: hc:SyntheticData
TEST:
description: >-
Test data used during development. May be partially real
but should not be used in production.
meaning: hc:TestData
ANONYMIZED:
description: >-
Real data that has been anonymized or pseudonymized.
Represents real entities but with identifying information removed.
meaning: hc:AnonymizedData
SIMULATED:
description: >-
Data generated by simulation or modeling processes.
May reflect plausible scenarios but not actual events.
meaning: hc:SimulatedData
UNKNOWN:
description: >-
Realness status cannot be determined.
Data requires verification.
meaning: hc:UnknownRealnessStatus
classes:
RealnessStatus:
class_uri: dqv:QualityAnnotation
description: >-
Annotation indicating whether data is real (production) or synthetic/test.
**DEFINITION**:
A quality annotation that classifies data records by their realness status,
enabling filtering of test/synthetic data from production datasets.
**DQV ALIGNMENT**:
Maps to `dqv:QualityAnnotation` as this is a quality-related metadata
annotation about the data's authenticity and provenance.
**TEMPORAL SEMANTICS**:
Realness status can change over time:
- Test data may be promoted to production after verification
- Real data may be flagged as test if errors are discovered
- Anonymization may be applied to previously real data
**EXAMPLE**:
```yaml
realness_status:
status: REAL
description: "Verified production data from ISIL registry"
verification_date: "2025-01-14"
verified_by: "human-curator"
```
exact_mappings:
- dqv:QualityAnnotation
close_mappings:
- prov:Entity
- schema:DataCatalog
slots:
- id
- status
- description
- verification_date
- verified_by
- verification_method
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
status:
range: RealnessStatusEnum
required: true
description: >-
The realness classification of the data.
description:
range: string
description: >-
Human-readable explanation of the realness determination.
verification_date:
range: date
description: >-
Date when the realness status was verified.
verified_by:
range: string
description: >-
Agent (human or automated) that verified the realness status.
verification_method:
range: string
description: >-
Method used to determine realness status.
Examples: "manual_review", "automated_validation", "source_verification"
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types as data quality
metadata is universal.
custodian_types_primary: "*"
specificity_score: 0.3
specificity_rationale: >-
Low specificity - broadly applicable quality metadata.
comments:
- Part of data quality provenance system
- Enables filtering test/synthetic data from production
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- http://www.w3.org/ns/dqv#QualityAnnotation
- https://www.w3.org/TR/vocab-dqv/
examples:
- value:
id: hc:realness/production-data-2025
status: REAL
description: "Verified production data from authoritative ISIL registry"
verification_date: "2025-01-14"
verified_by: "human-curator"
verification_method: "source_verification"
description: Real production data with full verification
- value:
id: hc:realness/test-fixture-001
status: TEST
description: "Test fixture for unit tests - do not use in production"
verification_date: "2025-01-14"
verified_by: "automated-pipeline"
verification_method: "filename_pattern_match"
description: Test data identified automatically
slots:
status:
description: >-
The realness classification status.
range: RealnessStatusEnum
slot_uri: dqv:value
verification_date:
description: >-
Date when the realness status was verified.
range: date
slot_uri: dcterms:date
verified_by:
description: >-
Agent that verified the realness status.
range: string
slot_uri: prov:wasAttributedTo
verification_method:
description: >-
Method used to determine realness status.
range: string
slot_uri: prov:wasGeneratedBy

View file

@ -7,8 +7,8 @@ imports:
- ./CustodianObservation
- ./ReconstructionActivity
- ./TimeSpan
- ../slots/actual_end
- ../slots/actual_start
# actual_end and actual_start REMOVED - migrated to temporal_extent with TimeSpan (Rule 53)
# TimeSpan uses begin_of_the_begin/end_of_the_end for CIDOC-CRM compliant temporal modeling
- ../slots/is_active
- ../slots/planned_end
- ../slots/planned_start
@ -26,8 +26,6 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_actual_start_date
- ../slots/has_actual_end_date
- ../enums/TemporaryLocationReasonEnum
prefixes:
linkml: https://w3id.org/linkml/
@ -63,7 +61,7 @@ classes:
\ POP_UP_PROGRAM\n planned_start: \"2024-07-01\"\n planned_end: \"2024-09-30\"\n reason_description: \"\
Summer pop-up exhibition in Groninger Forum\"\n ```\n\n3. **Emergency Storage**:\n ```yaml\n TemporaryLocation:\n\
\ temp_location_name: \"Emergency Collection Storage - Watersnood\"\n temp_location_reason: EMERGENCY\n \
\ actual_start: \"2024-01-15\"\n planned_end: null # Unknown when main facility will be repaired\n reason_description:\
\ temporal_extent:\n begin_of_the_begin: \"2024-01-15\" # Actual start\n planned_end: null # Unknown when main facility will be repaired\n reason_description:\
\ \"Emergency relocation due to flooding at main depot\"\n ```\n"
exact_mappings:
- org:Site
@ -75,8 +73,8 @@ classes:
- crm:E7_Activity
- schema:TemporaryLocation
slots:
- actual_end
- actual_start
# actual_end and actual_start REMOVED - use temporal_extent with TimeSpan (Rule 53)
# TimeSpan provides begin_of_the_begin, end_of_the_begin, begin_of_the_end, end_of_the_end
- is_active
- planned_end
- planned_start
@ -92,41 +90,7 @@ classes:
- temporal_extent
- was_derived_from
- was_generated_by
- has_actual_start_date
- has_actual_end_date
slot_usage:
actual_start:
range: date
deprecated: |
DEPRECATED (2026-01-14): Use has_actual_start_date for simple dates or
temporal_extent (TimeSpan) for full CIDOC-CRM temporal modeling.
Migration: actual_start → has_actual_start_date (convenience) or
actual_start → temporal_extent.begin_of_the_begin (CIDOC-CRM)
See slot_fixes.yaml entry: https://nde.nl/ontology/hc/slot/actual_start
description: |
[DEPRECATED] The actual start date of the temporary location.
Use has_actual_start_date for simple dates or temporal_extent for
fuzzy temporal bounds following CIDOC-CRM E52_Time-Span pattern.
examples:
- value: '2020-06-15'
description: Actual start (deprecated format)
actual_end:
range: date
deprecated: |
DEPRECATED (2026-01-14): Use has_actual_end_date for simple dates or
temporal_extent (TimeSpan) for full CIDOC-CRM temporal modeling.
Migration: actual_end → has_actual_end_date (convenience) or
actual_end → temporal_extent.end_of_the_end (CIDOC-CRM)
See slot_fixes.yaml entry: https://nde.nl/ontology/hc/slot/actual_end
description: |
[DEPRECATED] The actual end date of the temporary location.
Use has_actual_end_date for simple dates or temporal_extent for
fuzzy temporal bounds following CIDOC-CRM E52_Time-Span pattern.
examples:
- value: '2022-03-15'
description: Actual end (deprecated format)
temp_location_id:
range: uriorcurie
required: true
@ -175,25 +139,29 @@ classes:
examples:
- value: '2021-12-31'
description: Planned renovation completion
has_actual_start_date:
range: date
examples:
- value: '2020-06-15'
description: Actual start (2 weeks delayed)
has_actual_end_date:
range: date
examples:
- value: '2022-03-15'
description: Actual end (3 months delayed)
temporal_extent:
range: TimeSpan
description: >-
The actual temporal extent of this temporary location using CIDOC-CRM TimeSpan.
Use begin_of_the_begin for actual start date, end_of_the_end for actual end date.
For precise dates, set begin_of_the_begin == end_of_the_begin (and same for end).
examples:
- value:
begin_of_the_begin: '2020-06-15'
end_of_the_begin: '2020-06-15'
begin_of_the_end: '2022-03-15'
end_of_the_end: '2022-03-15'
description: Precise actual start (2020-06-15) and end (2022-03-15) dates for renovation
- value:
begin_of_the_begin: '2024-06-01'
end_of_the_begin: '2024-07-15'
begin_of_the_end: '2024-09-15'
end_of_the_end: '2024-10-31'
description: Summer 2024 pop-up with fuzzy boundaries
description: Summer 2024 pop-up with fuzzy boundaries (soft open June-July, wind-down Sept-Oct)
- value:
begin_of_the_begin: '2024-01-15'
end_of_the_begin: '2024-01-15'
description: Emergency storage with known start but unknown end (ongoing)
is_active:
range: boolean
examples:
@ -240,14 +208,17 @@ classes:
reason_description: Main entrance renovation including new accessibility features.
planned_start: '2020-06-01'
planned_end: '2021-12-31'
actual_start: '2020-06-15'
actual_end: '2022-03-15'
temporal_extent:
begin_of_the_begin: '2020-06-15'
end_of_the_begin: '2020-06-15'
begin_of_the_end: '2022-03-15'
end_of_the_end: '2022-03-15'
is_active: false
replaces_primary_location: true
serves_function_of:
- Public entrance
- Ticket sales
description: Museum renovation temporary entrance (completed)
description: Museum renovation temporary entrance (completed) - actual dates via temporal_extent
- value:
temp_location_id: https://nde.nl/ontology/hc/aux/rijksmuseum-popup-groningen
temp_location_name: Rijksmuseum Pop-up Groningen
@ -256,12 +227,14 @@ classes:
reason_description: Outreach program bringing collection highlights to northern Netherlands.
planned_start: '2024-07-01'
planned_end: '2024-09-30'
actual_start: '2024-07-01'
temporal_extent:
begin_of_the_begin: '2024-07-01'
end_of_the_begin: '2024-07-01'
is_active: true
replaces_primary_location: false
serves_function_of:
- Exhibition space
description: Pop-up exhibition (active)
description: Pop-up exhibition (active) - actual start via temporal_extent, no end yet
- value:
temp_location_id: https://nde.nl/ontology/hc/aux/emergency-storage-2024
temp_location_name: Emergency Collection Storage - Watersnood 2024
@ -269,10 +242,12 @@ classes:
temp_location_reason: EMERGENCY
reason_description: Flooding on 2024-01-14 damaged main storage facility. Collections evacuated to temporary climate-controlled
space.
actual_start: '2024-01-15'
temporal_extent:
begin_of_the_begin: '2024-01-15'
end_of_the_begin: '2024-01-15'
planned_end: null
is_active: true
replaces_primary_location: true
serves_function_of:
- Collection storage
description: Emergency storage (active, end date unknown)
description: Emergency storage (active, end date unknown) - actual start via temporal_extent

View file

@ -0,0 +1,176 @@
id: https://nde.nl/ontology/hc/class/WebLink
name: web_link_class
title: WebLink Class
description: >-
A hyperlink reference to a web resource.
Generic class for representing web links with their text, URL, type,
and contextual information. Used as components within Overview collections
or any context requiring structured link representation.
**ONTOLOGY ALIGNMENT**:
- Schema.org: schema:WebPage (web resource reference)
- Dublin Core: dcterms:URI (uniform resource identifier)
- FOAF: foaf:Document (document reference)
**USE CASES**:
1. Links extracted from finding aid pages
2. External resource references
3. Navigation links within heritage custodian websites
4. Related resource connections
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `all_links` to
`has_or_had_comprehensive_overview` with `Overview` and `WebLink` typed classes.
See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
dcterms: http://purl.org/dc/terms/
foaf: http://xmlns.com/foaf/0.1/
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/url
- ../slots/title
- ../slots/link_text
- ../slots/link_type
- ../slots/link_context
- ../slots/xpath
- ../slots/valid_from
- ../slots/valid_to
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../enums/LinkTypeEnum
default_prefix: hc
default_range: string
classes:
WebLink:
class_uri: schema:WebPage
description: >-
A hyperlink to a web resource with associated metadata.
**DEFINITION**:
Represents a web link with its URL, display text, type classification,
and optional contextual information about where and why the link appears.
**SCHEMA.ORG ALIGNMENT**:
Maps to `schema:WebPage` as it represents a reference to a web page
or web resource.
**TEMPORAL SEMANTICS**:
Links can change over time:
- URLs may become invalid (link rot)
- Link text or context may be updated
- Links may be added or removed from pages
**EXAMPLE**:
```yaml
web_link:
id: hc:link/findingaid-civil-registry
url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/burgerlijke-stand
link_text: "Burgerlijke Stand"
link_type: SUB_GUIDE
link_context: "Related finding aids for family history research"
```
exact_mappings:
- schema:WebPage
close_mappings:
- foaf:Document
- dcterms:URI
slots:
- id
- url
- link_text
- title
- description
- link_type
- link_context
- xpath
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
url:
range: uri
required: true
description: >-
The URL of the web resource.
link_text:
range: string
description: >-
The visible text of the hyperlink.
title:
range: string
description: >-
Title attribute of the link (if available).
description:
range: string
description: >-
Human-readable description of the link's purpose or destination.
link_type:
range: LinkTypeEnum
description: >-
Classification of the link type.
link_context:
range: string
description: >-
The surrounding text or context where the link appears.
xpath:
range: string
description: >-
XPath location of the link in the source HTML (for provenance).
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types as web links
are universal navigation elements.
custodian_types_primary: "*"
specificity_score: 0.25
specificity_rationale: >-
Very low specificity - fundamental web element applicable
across all contexts.
comments:
- Generic web link representation
- Used within Overview collections
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- http://schema.org/WebPage
- http://xmlns.com/foaf/0.1/Document
examples:
- value:
id: hc:link/na-civil-registry
url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/burgerlijke-stand
link_text: "Burgerlijke Stand"
link_type: SUB_GUIDE
link_context: "Related finding aids section"
description: Link to a sub-guide within the same repository
- value:
id: hc:link/external-genealogy-db
url: https://www.wiewaswie.nl
link_text: "WieWasWie"
link_type: EXTERNAL_RESOURCE
description: "Dutch genealogical database"
description: External resource link

View file

@ -30,7 +30,7 @@ imports:
- ./ReconstructedEntity
- ../slots/has_or_had_data_service_endpoint
- ../slots/is_or_was_aggregated_by
- ../slots/aggregates_from
# aggregates_from REMOVED - migrated to aggregates_or_aggregated_from (Rule 53)
- ../slots/associated_encompassing_bodies
- ../slots/created_by_project
- ../slots/implements_auxiliary_platform
@ -131,7 +131,8 @@ classes:
- dcmitype:Collection
slots:
- is_or_was_aggregated_by
- aggregates_from
# aggregates_from REMOVED - use aggregates_or_aggregated_from (Rule 53)
- aggregates_or_aggregated_from
- has_or_had_api_endpoint
- associated_encompassing_bodies
- created_by_project

View file

@ -0,0 +1,97 @@
# affects_or_affected slot
# Generic slot for entities affected by an event or change
#
# Following RiC-O naming convention (Rule 39): "affectsOrAffected" pattern
# for temporal relationships in heritage domain.
#
# slot_fixes.yaml revision:
# - label: affects_or_affected
# type: slot
# - label: HeritageCustodian
# type: class
#
# Generation date: 2026-01-14
# Rule compliance: 38 (slot centralization + semantic URI), 39 (RiC-O naming), 42 (no prefix), 53 (full migration)
id: https://nde.nl/ontology/hc/slot/affects_or_affected
name: affects_or_affected_slot
title: Affects Or Affected Slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
rico: https://www.ica.org/standards/RiC/ontology#
prov: http://www.w3.org/ns/prov#
schema: http://schema.org/
default_prefix: hc
imports:
- linkml:types
slots:
affects_or_affected:
slot_uri: rico:affectsOrAffected
description: |
Entity or entities affected by this event, change, or action.
**Temporal Semantics** (RiC-O Pattern):
The "affectsOrAffected" naming follows RiC-O convention indicating this
relationship captures both current and historical effects. An event may have
affected entities that no longer exist or have since changed.
**Generic Design**:
This slot accepts any entity type that can be affected by events:
- Heritage custodians (museums, archives, libraries)
- Collections
- Records
- People
- Places
The range should be narrowed in class-specific slot_usage to indicate
what types of entities can be affected in that context.
**Ontological Alignment**:
- **Primary** (`slot_uri`): `rico:affectsOrAffected` - RiC-O predicate
- **Related**: `prov:influenced` - PROV-O influence relationship
- **Related**: `schema:object` - Schema.org action object
range: string
multivalued: true
required: false
exact_mappings:
- rico:affectsOrAffected
related_mappings:
- prov:influenced
- schema:object
annotations:
rico_naming_convention: |
Follows RiC-O predicate naming.
rico:affectsOrAffected is a direct predicate from RiC-O ontology.
See Rule 39: Slot Naming Convention (RiC-O Style)
replaces_slots: "affects_or_affected_organization"
migration_date: "2026-01-14"
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types - events and changes
can affect any type of heritage organization.
custodian_types_primary: M
specificity_score: 0.4
specificity_rationale: >-
Broadly useful slot for tracking event impacts. Used across
organizational change events, transfer events, and other activities.
comments:
- "Generic slot for entities affected by events or changes"
- "Range should be narrowed in slot_usage to HeritageCustodian, Collection, etc."
- "RiC-O naming: affectsOrAffected indicates potentially historical relationship"
- "Replaces bespoke affects_or_affected_organization slot"
examples:
- value: "https://nde.nl/ontology/hc/custodian/nl/rijksmuseum"
description: "Heritage custodian affected by a merger event"
- value: "https://nde.nl/ontology/hc/collection/nl/voc-archives"
description: "Collection affected by a transfer of custody"

View file

@ -0,0 +1,56 @@
id: https://nde.nl/ontology/hc/slot/allows_or_allowed
name: allows_or_allowed_slot
title: Allows Or Allowed Slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
odrl: http://www.w3.org/ns/odrl/2/
default_prefix: hc
imports:
- linkml:types
slots:
allows_or_allowed:
description: >-
Generic slot for expressing what activities, equipment, or behaviors are
permitted in a heritage custodian facility (past or present).
**SEMANTICS**:
Uses RiC-O temporal pattern (is_or_was / has_or_had / allows_or_allowed)
to capture policies that may change over time. A reading room that
"allowed photography" in 2020 may have changed policy by 2025.
**USAGE PATTERN**:
The range should be a typed class representing the permitted activity:
- `Laptop` - laptop use permission
- `Photography` - photography permission
- Future: `Food`, `Beverages`, `MobilePhone`, etc.
**EXAMPLES**:
```yaml
ReadingRoom:
allows_or_allowed:
- permitted_item: Laptop
is_permitted: true
conditions: "Must be silent, no external keyboards"
- permitted_item: Photography
is_permitted: true
conditions: "Personal research use only, no flash"
```
slot_uri: schema:amenityFeature
range: string
multivalued: true
exact_mappings:
- schema:amenityFeature
close_mappings:
- odrl:permission
annotations:
custodian_types: '["*"]'
custodian_types_rationale: All heritage custodians have visitor policies.
custodian_types_primary: A
specificity_score: 0.5
specificity_rationale: Generic permission slot applicable to reading rooms and public spaces.

View file

@ -0,0 +1,86 @@
id: https://nde.nl/ontology/hc/slot/has_or_had_comprehensive_overview
name: has_or_had_comprehensive_overview_slot
title: Has Or Had Comprehensive Overview Slot
description: >-
Generic slot for linking to comprehensive overview collections.
Follows RiC-O temporal naming convention to indicate the relationship
may be current or historical.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
dcterms: http://purl.org/dc/terms/
schema: http://schema.org/
rico: https://www.ica.org/standards/RiC/ontology#
imports:
- linkml:types
default_prefix: hc
slots:
has_or_had_comprehensive_overview:
description: >-
Links an entity to a comprehensive overview collection of resources.
Follows RiC-O temporal naming convention (`hasOrHad*`) to indicate
the relationship may be current or historical.
**USAGE**:
```yaml
finding_aid:
has_or_had_comprehensive_overview:
id: hc:overview/findingaid-links
title: "All Links"
includes_or_included:
- url: https://example.org/link1
link_text: "Related Resource"
```
**DESIGN RATIONALE**:
This is a GENERIC slot for linking to comprehensive collections of
resources. Replaces domain-specific slots like `all_links` with a
typed relationship to an `Overview` class.
**MIGRATION NOTE** (2026-01-14):
Created as replacement for `all_links` slot. The new pattern:
- Uses typed `Overview` class instead of untyped string list
- Uses `includes_or_included` for WebLink composition
- Enables richer metadata about link collections
**ONTOLOGY ALIGNMENT**:
- `dcterms:hasPart` - Dublin Core part-whole relationship
- `schema:hasPart` - Schema.org containment
- `rico:hasOrHadPart` - RiC-O temporal containment
range: Overview
multivalued: false
inlined: true
slot_uri: dcterms:hasPart
exact_mappings:
- dcterms:hasPart
close_mappings:
- schema:hasPart
- rico:hasOrHadPart
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Comprehensive overviews applicable to all heritage custodian types.
custodian_types_primary: A
specificity_score: 0.35
specificity_rationale: >-
Low-moderate specificity - applicable across many contexts
where comprehensive resource collections are needed.
comments:
- Replaces all_links slot
- Uses Overview class for typed collection
- Created from slot_fixes.yaml migration (2026-01-14)

View file

@ -0,0 +1,70 @@
id: https://nde.nl/ontology/hc/slot/has_or_had_expenses
name: has_or_had_expenses_slot
title: Has Or Had Expenses Slot
description: >-
Links an entity to its expense records. Follows RiC-O temporal naming
convention (has_or_had_*) to indicate the relationship may be current
or historical.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
frapo: http://purl.org/cerif/frapo/
imports:
- linkml:types
default_prefix: hc
slots:
has_or_had_expenses:
description: >-
Links an entity (e.g., FinancialStatement, Budget) to its categorized
expense records.
**USAGE**:
```yaml
financial_statement:
has_or_had_expenses:
- expense_type: ADMINISTRATIVE
amount: 10000000.0
currency: EUR
- expense_type: PROGRAM
amount: 62000000.0
currency: EUR
```
**DESIGN RATIONALE**:
This is a GENERIC slot following slot_fixes.yaml revision. Do NOT create
bespoke slots like `has_administrative_expenses` or `has_program_expenses`.
Instead, use this single slot with Expenses instances that have an
`expense_type` classification.
**REPLACES**:
- `administrative_expenses` (deprecated stub)
- `has_or_had_administrative_expense` (bespoke, should not have been created)
- `program_expense` (migrate to Expenses with type=PROGRAM)
- `fundraising_expense` (migrate to Expenses with type=FUNDRAISING)
- `innovation_expense` (migrate to Expenses with type=INNOVATION)
range: Expenses
multivalued: true
inlined: true
inlined_as_list: true
slot_uri: hc:hasOrHadExpenses
exact_mappings:
- frapo:hasExpenditure
related_mappings:
- schema:MonetaryAmount
- frapo:hasFunding
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Financial expenses applicable to all heritage custodian types.
custodian_types_primary: M
specificity_score: 0.55
specificity_rationale: >-
Moderately specific - financial expense tracking is specialized but applicable
across institution types with financial reporting requirements.

View file

@ -0,0 +1,72 @@
id: https://nde.nl/ontology/hc/slot/has_or_had_function
name: has_or_had_function_slot
title: Has Or Had Function Slot
description: >-
Links an entity to its organizational functions. Follows RiC-O temporal naming
convention (has_or_had_*) to indicate the relationship may be current or historical.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
org: http://www.w3.org/ns/org#
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
has_or_had_function:
description: >-
Links an entity (e.g., AdministrativeOffice, OrganizationalUnit) to its
organizational functions.
**USAGE**:
```yaml
administrative_office:
has_or_had_function:
- function_category: ADMINISTRATIVE
function_name: "Finance and Accounting"
description: "Financial operations and reporting"
- function_category: ADMINISTRATIVE
function_name: "Human Resources"
description: "Staff management and recruitment"
```
**DESIGN RATIONALE**:
This is a GENERIC slot following slot_fixes.yaml revision. Do NOT create
bespoke slots like `has_administrative_function` or `has_program_function`.
Instead, use this single slot with FunctionType instances that have a
`function_category` classification.
**REPLACES**:
- `administrative_functions` (deprecated stub)
- `has_or_had_administrative_function` (bespoke, should not have been created)
**ONTOLOGY ALIGNMENT**:
- `org:purpose` - "Indicates the purpose of this Organization"
- Maps to organizational function/role patterns in W3C ORG ontology
range: FunctionType
multivalued: true
inlined: true
inlined_as_list: true
slot_uri: org:purpose
exact_mappings:
- org:purpose
close_mappings:
- schema:roleName
related_mappings:
- org:OrganizationalUnit
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Organizational functions applicable to all heritage custodian types.
custodian_types_primary: M
specificity_score: 0.50
specificity_rationale: >-
Moderately specific - organizational function classification is applicable
across institution types but specialized for organizational modeling.

View file

@ -0,0 +1,79 @@
# has_or_had_secondary_label slot
# Generic slot for secondary/alternative labels beyond the primary identifier
#
# Following RiC-O naming convention (Rule 39): "hasOrHad..." pattern
# for temporal relationships in heritage domain.
#
# Generation date: 2026-01-15
# Rule compliance: 38 (slot centralization + semantic URI), 39 (RiC-O naming), 42 (no prefix)
# Migration: Replaces bespoke also_identifies_name slot
id: https://nde.nl/ontology/hc/slot/has_or_had_secondary_label
name: has_or_had_secondary_label_slot
title: Has Or Had Secondary Label Slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
skos: http://www.w3.org/2004/02/skos/core#
schema: http://schema.org/
default_prefix: hc
imports:
- linkml:types
slots:
has_or_had_secondary_label:
slot_uri: skos:altLabel
description: |
Secondary or alternative label(s) associated with an entity.
**Temporal Semantics** (RiC-O Pattern):
The "hasOrHad" naming follows RiC-O convention indicating this relationship
may be historical - secondary labels may change over time.
**Primary Use Case**:
For dual-purpose identifiers (ISNI, VIAF) that also identify name authority
records, this links to the secondary entity (name) the identifier references.
**Ontological Alignment**:
- **Primary** (`slot_uri`): `skos:altLabel` - SKOS alternative label
- **Close**: `schema:alternateName` - Schema.org alternate name
**Usage**:
In CustodianIdentifier, this enables linking identifiers like ISNI/VIAF
to the name authority record they also identify (beyond the primary entity).
range: Label
required: false
multivalued: true
exact_mappings:
- skos:altLabel
close_mappings:
- schema:alternateName
annotations:
rico_naming_convention: |
Follows RiC-O "hasOrHad" pattern for temporal predicates.
See Rule 39: Slot Naming Convention (RiC-O Style)
replaces_slots: "also_identifies_name"
migration_date: "2026-01-15"
custodian_types: '["*"]'
custodian_types_rationale: Applicable to all heritage custodian types.
specificity_score: 0.5
specificity_rationale: Moderately specific - used for dual-purpose identifiers.
comments:
- "Generic secondary label slot for entities with dual identification"
- "Maps to skos:altLabel as alternative lexical label"
- "Multivalued for multiple secondary references"
- "Replaces bespoke also_identifies_name slot"
examples:
- value: |
label_value: "Rijksmuseum"
label_language: "nl"
description: "VIAF identifier also identifies the name authority record for Rijksmuseum"

View file

@ -0,0 +1,69 @@
id: https://nde.nl/ontology/hc/slot/includes_or_included
name: includes_or_included_slot
title: Includes Or Included Slot
description: >-
Generic hierarchical inclusion slot for modeling part-whole or containment
relationships with temporal semantics.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
org: http://www.w3.org/ns/org#
rico: https://www.ica.org/standards/RiC/ontology#
dcterms: http://purl.org/dc/terms/
imports:
- linkml:types
default_prefix: hc
slots:
includes_or_included:
description: >-
Generic slot indicating that an entity includes or included another entity.
Follows RiC-O temporal naming convention to indicate the relationship may
be current or historical.
**USAGE**:
```yaml
parent_function:
includes_or_included:
- child_function_1
- child_function_2
```
**DESIGN RATIONALE**:
This is a GENERIC hierarchical slot for modeling containment/inclusion
relationships. Use when a parent entity encompasses child entities.
**COMMON USE CASES**:
- FunctionType hierarchy (e.g., "Administrative" includes "Finance", "HR")
- Organizational unit hierarchy
- Collection hierarchy
**ONTOLOGY ALIGNMENT**:
- `rico:includes` - RiC-O inclusion relationship
- `org:hasUnit` - W3C ORG subunit relationship
- `dcterms:hasPart` - Dublin Core part-whole relationship
range: string
multivalued: true
slot_uri: rico:includes
exact_mappings:
- rico:includes
close_mappings:
- org:hasUnit
- dcterms:hasPart
related_mappings:
- org:subOrganizationOf
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Hierarchical relationships applicable to all heritage custodian types.
custodian_types_primary: M
specificity_score: 0.30
specificity_rationale: >-
Broadly applicable - hierarchical inclusion is a fundamental pattern
used across many organizational and collection modeling contexts.

View file

@ -0,0 +1,79 @@
id: https://nde.nl/ontology/hc/slot/is_or_was_real
name: is_or_was_real_slot
title: Is Or Was Real Slot
description: >-
Generic slot indicating data realness status.
**MIGRATION NOTE** (2026-01-14):
Created as replacement for `all_data_real` and `has_all_data_real_flag` slots.
Uses `RealnessStatus` typed class for rich provenance instead of simple boolean.
See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
dqv: http://www.w3.org/ns/dqv#
prov: http://www.w3.org/ns/prov#
imports:
- linkml:types
default_prefix: hc
slots:
is_or_was_real:
description: >-
Indicates whether the data represents real-world entities or is synthetic/test.
Uses RealnessStatus class for rich typing with verification provenance.
**TEMPORAL SEMANTICS** (RiC-O style):
The "is_or_was" naming follows RiC-O convention indicating that realness
status can change over time:
- Test data may be promoted to production after verification
- Real data may be flagged as test if errors are discovered
**REPLACES**:
- `all_data_real` (auto-generated stub, string range)
- `has_all_data_real_flag` (boolean flag, no provenance)
**EXAMPLE**:
```yaml
is_or_was_real:
status: REAL
description: "Verified from ISIL registry"
verification_date: "2025-01-14"
```
range: RealnessStatus
slot_uri: dqv:hasQualityAnnotation
inlined: true
exact_mappings:
- dqv:hasQualityAnnotation
close_mappings:
- prov:wasAttributedTo
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Data quality metadata applicable to all custodian types.
custodian_types_primary: "*"
specificity_score: 0.3
specificity_rationale: >-
Low specificity - broadly applicable quality metadata.
template_specificity:
general_heritage: 0.3
archive_search: 0.3
museum_search: 0.3
library_search: 0.3
comments:
- Created from slot_fixes.yaml migration (2026-01-14)
- Replaces all_data_real and has_all_data_real_flag slots
- Uses typed RealnessStatus class instead of boolean/string
see_also:
- http://www.w3.org/ns/dqv#hasQualityAnnotation
- https://nde.nl/ontology/hc/class/RealnessStatus

View file

@ -12,9 +12,9 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/activities_societies
processed:
status: true
timestamp: '2026-01-14T14:00:00Z'
timestamp: '2026-01-14T15:00:00Z'
session: "session-2026-01-14-type-migration"
notes: "EducationCredential updated: activities_societies deprecated, added has_or_had_membership and has_or_had_activity_type slots with ActivityType range"
notes: "FULLY MIGRATED: EducationCredential - activities_societies REMOVED, using has_or_had_membership + has_or_had_activity_type (Rule 53)"
revision:
- label: has_or_had_activity_type
type: slot
@ -28,9 +28,9 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/actual_end
processed:
status: true
timestamp: '2026-01-14T14:00:00Z'
timestamp: '2026-01-14T16:00:00Z'
session: "session-2026-01-14-type-migration"
notes: "TemporaryLocation updated: actual_end deprecated, use has_actual_end_date or temporal_extent (TimeSpan) for CIDOC-CRM temporal modeling"
notes: "FULLY MIGRATED: TemporaryLocation - actual_end REMOVED, using temporal_extent with TimeSpan.end_of_the_end (Rule 53)"
revision:
- label: end_of_the_end
type: slot
@ -40,9 +40,9 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/actual_start
processed:
status: true
timestamp: '2026-01-14T14:00:00Z'
timestamp: '2026-01-14T16:00:00Z'
session: "session-2026-01-14-type-migration"
notes: "TemporaryLocation updated: actual_start deprecated, use has_actual_start_date or temporal_extent (TimeSpan) for CIDOC-CRM temporal modeling"
notes: "FULLY MIGRATED: TemporaryLocation - actual_start REMOVED, using temporal_extent with TimeSpan.begin_of_the_begin (Rule 53)"
revision:
- label: begin_of_the_begin
type: slot
@ -79,10 +79,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/admin_office_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T16:45:00Z'
session: "session-2026-01-14-type-migration"
notes: "FULLY MIGRATED: AdministrativeOffice - admin_office_id REMOVED, using has_admin_office_identifier (Rule 53)"
revision:
- label: has_or_had_identifier
type: slot
@ -91,10 +91,15 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/administrative_expenses
processed:
status: false
timestamp: null
session: null
notes: "Requires Expenses class creation"
status: true
timestamp: '2026-01-14T19:30:00Z'
session: "session-2026-01-14-expenses-migration"
notes: >-
FULLY MIGRATED: FinancialStatement - administrative_expenses REMOVED.
Created has_or_had_expenses slot and Expenses class per slot_fixes.yaml revision.
Also archived related bespoke slots: has_or_had_administrative_expense,
program_expense, fundraising_expense, innovation_expense.
All expense types now use Expenses class with ExpenseTypeEnum classification.
revision:
- label: has_or_had_expenses
type: slot
@ -103,10 +108,18 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/administrative_functions
processed:
status: false
timestamp: null
session: null
notes: "Requires FunctionType/FunctionTypes class creation"
status: true
timestamp: '2026-01-14T18:20:00Z'
session: "session-2026-01-14-function-type-migration-fix"
notes: >-
FULLY MIGRATED (CORRECTED): Previous migration incorrectly created bespoke
has_or_had_administrative_function slot. Now correctly migrated to:
- Generic has_or_had_function slot (per slot_fixes.yaml revision)
- FunctionType abstract class with FunctionTypeEnum
- FunctionTypes concrete subclasses (27 function types)
- includes_or_included hierarchical slot
- AdministrativeOffice updated to use has_or_had_function
- Bespoke has_or_had_administrative_function archived
revision:
- label: has_or_had_function
type: slot
@ -119,10 +132,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/affects_or_affected_organization
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing HeritageCustodian class"
status: true
timestamp: '2026-01-14T21:00:00Z'
session: "session-2026-01-14-affects-and-agenda-migration"
notes: >-
FULLY MIGRATED: affects_or_affected_organization REMOVED and archived.
Created generic affects_or_affected.yaml slot per slot_fixes.yaml revision.
The slot was not used by any classes yet, so no class updates needed.
Range should be narrowed to HeritageCustodian in slot_usage when used.
revision:
- label: affects_or_affected
type: slot
@ -131,10 +148,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/agenda_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T21:45:00Z'
session: "session-2026-01-14-affects-and-agenda-migration"
notes: "FULLY MIGRATED: agenda_id and has_agenda_identifier REMOVED from modules/slots/, archived to archive/slots/. FundingAgenda.yaml updated to use has_or_had_identifier with Identifier class. Both examples updated."
revision:
- label: has_or_had_identifier
type: slot
@ -143,20 +160,23 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/aggregates_from
processed:
status: false
timestamp: null
session: null
notes: "Slot rename only, no class needed"
status: true
timestamp: '2026-01-14T16:30:00Z'
session: "session-2026-01-14-type-migration"
notes: "FULLY MIGRATED: WebPortal - aggregates_from REMOVED, using aggregates_or_aggregated_from (Rule 53)"
revision:
- label: aggregates_or_aggregated_from
type: slot
- original_slot_id: https://nde.nl/ontology/hc/slot/all_data_real
processed:
status: false
timestamp: null
session: null
notes: "Requires RealnessStatus class creation"
status: true
timestamp: '2026-01-14T22:30:00Z'
session: "session-2026-01-14-realness-migration"
notes: >-
FULLY MIGRATED: all_data_real and has_all_data_real_flag REMOVED and archived.
Created is_or_was_real slot and RealnessStatus class per slot_fixes.yaml revision.
LinkedInProfile.yaml updated - WhatsAppEnrichmentMetadata now uses is_or_was_real.
revision:
- label: is_or_was_real
type: slot
@ -165,10 +185,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/all_links
processed:
status: false
timestamp: null
session: null
notes: "Requires Overview and WebLink class creation"
status: true
timestamp: '2026-01-14T23:00:00Z'
session: "session-2026-01-14-all-links-migration"
notes: >-
FULLY MIGRATED: all_links REMOVED and archived.
Created has_or_had_comprehensive_overview slot, Overview class, and WebLink class.
FindingAid.yaml updated to use new slot with Overview range.
Uses existing includes_or_included slot for WebLink composition.
revision:
- label: has_or_had_comprehensive_overview
type: slot
@ -181,10 +205,13 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_laptops
processed:
status: false
timestamp: null
session: null
notes: "Requires Laptop class creation for policy modeling"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_laptops REMOVED and archived.
Created allows_or_allowed generic slot and Laptop typed class.
ReadingRoom.yaml updated to use allows_or_allowed slot.
revision:
- label: allows_or_allowed
type: slot
@ -193,10 +220,12 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_or_allowed_laptops
processed:
status: false
timestamp: null
session: null
notes: "Duplicate of allows_laptops - same migration"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_or_allowed_laptop REMOVED and archived (duplicate of allows_laptops).
Same migration as allows_laptops - both replaced by generic allows_or_allowed + Laptop class.
revision:
- label: allows_or_allowed
type: slot
@ -205,10 +234,13 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_or_allowed_photography
processed:
status: false
timestamp: null
session: null
notes: "Requires Photography class creation for policy modeling"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_or_allowed_photography REMOVED and archived.
Created allows_or_allowed generic slot and Photography typed class.
ReadingRoom.yaml updated to use allows_or_allowed slot.
revision:
- label: allows_or_allowed
type: slot
@ -217,10 +249,12 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_photography
processed:
status: false
timestamp: null
session: null
notes: "Duplicate of allows_or_allowed_photography - same migration"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_photography REMOVED and archived (duplicate of allows_or_allowed_photography).
Same migration as allows_or_allowed_photography - both replaced by generic allows_or_allowed + Photography class.
revision:
- label: allows_or_allowed
type: slot
@ -229,10 +263,15 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/alpha_2
processed:
status: false
timestamp: null
session: null
notes: "Requires Alpha2Code class creation for ISO 3166-1 codes"
status: true
timestamp: '2026-01-15T00:00:00Z'
session: "session-2026-01-15-alpha-deprecation"
notes: >-
DEPRECATED: Orphan stub archived to archive/slots/alpha_2_archived_20260114.yaml.
No migration needed - proper slot has_iso_3166_1_alpha_2_code already exists and is
correctly implemented in Country class. The alpha_2 stub was never imported by any
class and had no semantic content. References in examples (e.g., covers_country.alpha_2
in ServiceArea.yaml) are YAML example data values, not actual slot imports.
revision:
- label: has_or_had_code
type: slot
@ -241,10 +280,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/alpha_3
processed:
status: false
timestamp: null
session: null
notes: "Requires Alpha3Code class creation for ISO 3166-1 codes"
status: true
timestamp: '2026-01-15T00:00:00Z'
session: "session-2026-01-15-alpha-deprecation"
notes: >-
DEPRECATED: Orphan stub archived to archive/slots/alpha_3_archived_20260114.yaml.
No migration needed - proper slot has_iso_3166_1_alpha_3_code already exists and is
correctly implemented in Country class. The alpha_3 stub was never imported by any
class and had no semantic content.
revision:
- label: has_or_had_code
type: slot
@ -253,10 +296,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/also_identifies_name
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Label class"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-secondary-label-migration"
notes: >-
FULLY MIGRATED: also_identifies_name REMOVED and archived to archive/slots/also_identifies_name_archived_20260115.yaml.
Created has_or_had_secondary_label slot (modules/slots/has_or_had_secondary_label.yaml) and Label class
(modules/classes/Label.yaml) per slot_fixes.yaml revision. CustodianIdentifier (Identifier.yaml) updated
to use new slot with Label range. All imports, slots list, slot_usage, and descriptions updated.
revision:
- label: has_or_had_secondary_label
type: slot
@ -265,10 +312,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/annex_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T22:00:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: annex_id and has_annex_identifier REMOVED from modules/slots/, archived to archive/slots/. ReadingRoomAnnex.yaml updated to use has_or_had_identifier with CustodianIdentifier class. All imports, slots, slot_usage, and examples updated."
revision:
- label: has_or_had_identifier
type: slot
@ -453,10 +500,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/assertion_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T23:00:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: assertion_id and has_assertion_identifier REMOVED from modules/slots/, archived to archive/slots/. PrimaryDigitalPresenceAssertion.yaml updated to use has_or_had_identifier. All imports, slots, and slot_usage updated."
revision:
- label: has_or_had_identifier
type: slot
@ -537,10 +584,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/auxiliary_place_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T23:15:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: auxiliary_place_id and has_auxiliary_place_identifier REMOVED from modules/slots/, archived to archive/slots/. AuxiliaryPlace.yaml updated to use has_or_had_identifier. All imports, slots, slot_usage, and 3 examples updated."
revision:
- label: has_or_had_identifier
type: slot

View file

@ -1484,3 +1484,314 @@
.name-mismatch-indicator svg {
flex-shrink: 0;
}
/* ==========================================
Linkup Search Section
========================================== */
.linkup-search-section {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid var(--border-color, #e0e0e0);
}
.dark .linkup-search-section {
border-top-color: var(--border-color, #2a2a4a);
}
.linkup-search-section .linkup-search-btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.625rem 1rem;
background: linear-gradient(135deg, #0077b5 0%, #0a66c2 100%);
color: white;
border: none;
border-radius: 6px;
font-size: 0.8125rem;
font-weight: 500;
cursor: pointer;
transition: all 0.15s;
}
.linkup-search-section .linkup-search-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #006699 0%, #0854a0 100%);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 119, 181, 0.3);
}
.linkup-search-section .linkup-search-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.linkup-search-section .linkup-search-btn .animate-spin {
animation: spin 1s linear infinite;
}
/* Linkup Error */
.linkup-error {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.75rem;
padding: 0.5rem 0.75rem;
background: rgba(239, 68, 68, 0.1);
color: #dc2626;
border-radius: 6px;
font-size: 0.8125rem;
}
.dark .linkup-error {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
}
/* Linkup Results */
.linkup-results {
margin-top: 0.75rem;
background: var(--bg-secondary, #f8fafc);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 8px;
overflow: hidden;
}
.dark .linkup-results {
background: rgba(0, 0, 0, 0.2);
border-color: var(--border-color, #2a2a4a);
}
.linkup-results h5 {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0;
padding: 0.625rem 0.875rem;
background: rgba(0, 119, 181, 0.1);
color: var(--text-primary, #1e293b);
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.025em;
}
.dark .linkup-results h5 {
background: rgba(0, 119, 181, 0.15);
}
.close-results-btn {
background: none;
border: none;
color: var(--text-secondary, #64748b);
font-size: 1.25rem;
line-height: 1;
cursor: pointer;
padding: 0 0.25rem;
transition: color 0.15s;
}
.close-results-btn:hover {
color: var(--text-primary, #1e293b);
}
.linkup-results-list {
list-style: none;
margin: 0;
padding: 0;
max-height: 200px;
overflow-y: auto;
}
.linkup-result-item {
padding: 0.625rem 0.875rem;
border-bottom: 1px solid var(--border-color, #e0e0e0);
}
.linkup-result-item:last-child {
border-bottom: none;
}
.dark .linkup-result-item {
border-bottom-color: var(--border-color, #2a2a4a);
}
.linkup-result-item .result-name {
font-weight: 500;
font-size: 0.8125rem;
color: var(--text-primary, #1e293b);
margin-bottom: 0.25rem;
}
.dark .linkup-result-item .result-name {
color: var(--text-primary, #e2e8f0);
}
.linkup-result-item .linkedin-link {
display: inline-flex;
align-items: center;
gap: 0.375rem;
font-size: 0.75rem;
color: #0077b5;
text-decoration: none;
}
.linkup-result-item .linkedin-link:hover {
text-decoration: underline;
}
.linkup-result-item .result-snippet {
font-size: 0.75rem;
color: var(--text-secondary, #64748b);
margin-top: 0.375rem;
line-height: 1.4;
}
/* No Results */
.linkup-no-results {
margin-top: 0.75rem;
padding: 0.75rem;
background: var(--bg-secondary, #f8fafc);
border-radius: 6px;
font-size: 0.8125rem;
color: var(--text-secondary, #64748b);
text-align: center;
}
.dark .linkup-no-results {
background: rgba(0, 0, 0, 0.2);
}
/* ==========================================
Manual LinkedIn URL Input
========================================== */
.manual-linkedin-section {
margin-top: 1rem;
}
.manual-linkedin-header {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.75rem;
}
.manual-linkedin-header .divider-text {
position: relative;
padding: 0 0.75rem;
font-size: 0.75rem;
color: var(--text-secondary, #64748b);
text-transform: uppercase;
letter-spacing: 0.025em;
}
.manual-linkedin-header .divider-text::before,
.manual-linkedin-header .divider-text::after {
content: '';
position: absolute;
top: 50%;
width: 40px;
height: 1px;
background: var(--border-color, #e0e0e0);
}
.manual-linkedin-header .divider-text::before {
right: 100%;
}
.manual-linkedin-header .divider-text::after {
left: 100%;
}
.dark .manual-linkedin-header .divider-text::before,
.dark .manual-linkedin-header .divider-text::after {
background: var(--border-color, #2a2a4a);
}
.manual-linkedin-input-group {
display: flex;
gap: 0.5rem;
}
.manual-linkedin-input {
flex: 1;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
font-size: 0.8125rem;
background: var(--bg-primary, #fff);
color: var(--text-primary, #1e293b);
transition: border-color 0.15s, box-shadow 0.15s;
}
.manual-linkedin-input:focus {
outline: none;
border-color: #0077b5;
box-shadow: 0 0 0 3px rgba(0, 119, 181, 0.1);
}
.manual-linkedin-input::placeholder {
color: var(--text-secondary, #94a3b8);
}
.dark .manual-linkedin-input {
background: rgba(0, 0, 0, 0.2);
border-color: var(--border-color, #2a2a4a);
color: var(--text-primary, #e2e8f0);
}
.dark .manual-linkedin-input:focus {
border-color: #0077b5;
box-shadow: 0 0 0 3px rgba(0, 119, 181, 0.2);
}
.add-manual-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
background: linear-gradient(135deg, #0077b5 0%, #0a66c2 100%);
color: white;
border: none;
border-radius: 6px;
font-size: 1.25rem;
font-weight: 500;
cursor: pointer;
transition: all 0.15s;
flex-shrink: 0;
}
.add-manual-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #006699 0%, #0854a0 100%);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 119, 181, 0.3);
}
.add-manual-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.add-manual-btn .animate-spin {
animation: spin 1s linear infinite;
}
.manual-url-error {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.5rem;
padding: 0.5rem 0.75rem;
background: rgba(239, 68, 68, 0.1);
color: #dc2626;
border-radius: 6px;
font-size: 0.75rem;
}
.dark .manual-url-error {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
}

View file

@ -155,6 +155,16 @@ interface LinkedInProfile {
web_claims: Array<Record<string, unknown>>;
}
interface LinkupSearchResult {
url: string;
title: string;
content: string;
snippet?: string;
linkedin_slug: string | null;
extracted_name: string | null;
extracted_headline: string | null;
}
interface ReviewStats {
total_profiles: number;
profiles_with_candidates: number;
@ -265,6 +275,17 @@ export default function EntityReviewPage() {
// Profile search
const [profileSearchQuery, setProfileSearchQuery] = useState('');
// Linkup search state
const [linkupSearching, setLinkupSearching] = useState(false);
const [linkupResults, setLinkupResults] = useState<LinkupSearchResult[]>([]);
const [showLinkupResults, setShowLinkupResults] = useState(false);
const [linkupError, setLinkupError] = useState<string | null>(null);
// Manual LinkedIn URL input
const [manualLinkedinUrl, setManualLinkedinUrl] = useState('');
const [addingManualCandidate, setAddingManualCandidate] = useState(false);
const [manualUrlError, setManualUrlError] = useState<string | null>(null);
// Filtered profiles based on search query
const filteredProfiles = profiles.filter(profile => {
@ -368,6 +389,86 @@ export default function EntityReviewPage() {
}
}, []);
// Perform Linkup search to find additional LinkedIn candidates
const performLinkupSearch = useCallback(async () => {
if (!selectedProfile) return;
setLinkupSearching(true);
setLinkupError(null);
setLinkupResults([]);
try {
const response = await fetch(`${API_BASE}/api/review/linkup-search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: selectedProfile.name,
email: selectedProfile.email || undefined,
email_domain: selectedProfile.email_domain || undefined,
institution_name: selectedProfile.wcms_identifiers?.institution_name || undefined,
}),
});
if (!response.ok) {
const errData = await response.json().catch(() => ({}));
throw new Error(errData.detail || 'Linkup search failed');
}
const data = await response.json();
setLinkupResults(data.results || []);
setShowLinkupResults(true);
} catch (err) {
setLinkupError(err instanceof Error ? err.message : 'Search failed');
} finally {
setLinkupSearching(false);
}
}, [selectedProfile]);
// Add manual LinkedIn candidate by URL
const addManualLinkedinCandidate = useCallback(async () => {
if (!selectedProfile || !manualLinkedinUrl.trim()) return;
setAddingManualCandidate(true);
setManualUrlError(null);
// Extract LinkedIn slug from URL
const urlMatch = manualLinkedinUrl.match(/linkedin\.com\/in\/([^/?]+)/i);
if (!urlMatch) {
setManualUrlError(language === 'nl'
? 'Ongeldige LinkedIn URL. Gebruik format: linkedin.com/in/username'
: 'Invalid LinkedIn URL. Use format: linkedin.com/in/username');
setAddingManualCandidate(false);
return;
}
const linkedinSlug = urlMatch[1];
try {
const response = await fetch(`${API_BASE}/api/review/add-candidate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wcms_ppid: selectedProfile.ppid,
linkedin_slug: linkedinSlug,
}),
});
if (!response.ok) {
const errData = await response.json().catch(() => ({}));
throw new Error(errData.detail || 'Failed to add candidate');
}
// Clear input and refresh profile
setManualLinkedinUrl('');
await fetchProfileDetail(selectedProfile.ppid);
} catch (err) {
setManualUrlError(err instanceof Error ? err.message : 'Failed to add candidate');
} finally {
setAddingManualCandidate(false);
}
}, [selectedProfile, manualLinkedinUrl, language, fetchProfileDetail]);
// Save review decision
const saveDecision = useCallback(async (decision: 'match' | 'not_match' | 'uncertain') => {
if (!selectedProfile || !selectedCandidate) return;
@ -381,6 +482,8 @@ export default function EntityReviewPage() {
wcms_ppid: selectedProfile.ppid,
linkedin_ppid: selectedCandidate.linkedin_ppid,
decision: decision,
// Auto-reject other candidates when matching (not for uncertain)
auto_reject_others: decision === 'match',
}),
});
@ -965,6 +1068,121 @@ export default function EntityReviewPage() {
);
})}
</ul>
{/* Linkup Search Section */}
<div className="linkup-search-section">
<button
className="linkup-search-btn"
onClick={performLinkupSearch}
disabled={linkupSearching}
title={language === 'nl' ? 'Zoek naar meer LinkedIn profielen' : 'Search for more LinkedIn profiles'}
>
{linkupSearching ? (
<Loader2 className="animate-spin" size={16} />
) : (
<Search size={16} />
)}
{linkupSearching
? (language === 'nl' ? 'Zoeken...' : 'Searching...')
: (language === 'nl' ? 'Zoek meer kandidaten' : 'Find more candidates')}
</button>
{linkupError && (
<div className="linkup-error">
<AlertCircle size={14} />
<span>{linkupError}</span>
</div>
)}
{showLinkupResults && linkupResults.length > 0 && (
<div className="linkup-results">
<h5>
{language === 'nl' ? 'Gevonden LinkedIn profielen' : 'Found LinkedIn Profiles'} ({linkupResults.length})
<button
className="close-results-btn"
onClick={() => setShowLinkupResults(false)}
title={language === 'nl' ? 'Sluiten' : 'Close'}
>
×
</button>
</h5>
<ul className="linkup-results-list">
{linkupResults.map((result, idx) => (
<li key={idx} className="linkup-result-item">
<div className="result-name">
{result.extracted_name || result.title}
</div>
{result.linkedin_slug && (
<a
href={`https://linkedin.com/in/${result.linkedin_slug}`}
target="_blank"
rel="noopener noreferrer"
className="linkedin-link"
>
<Link2 size={12} />
{result.linkedin_slug}
</a>
)}
{result.snippet && (
<div className="result-snippet">{result.snippet.slice(0, 100)}...</div>
)}
</li>
))}
</ul>
</div>
)}
{showLinkupResults && linkupResults.length === 0 && !linkupSearching && !linkupError && (
<div className="linkup-no-results">
{language === 'nl' ? 'Geen extra profielen gevonden' : 'No additional profiles found'}
</div>
)}
{/* Manual LinkedIn URL Input */}
<div className="manual-linkedin-section">
<div className="manual-linkedin-header">
<span className="divider-text">
{language === 'nl' ? 'of voeg handmatig toe' : 'or add manually'}
</span>
</div>
<div className="manual-linkedin-input-group">
<input
type="text"
className="manual-linkedin-input"
placeholder={language === 'nl' ? 'LinkedIn URL (bijv. linkedin.com/in/username)' : 'LinkedIn URL (e.g. linkedin.com/in/username)'}
value={manualLinkedinUrl}
onChange={(e) => {
setManualLinkedinUrl(e.target.value);
setManualUrlError(null);
}}
onKeyDown={(e) => {
if (e.key === 'Enter' && manualLinkedinUrl.trim()) {
addManualLinkedinCandidate();
}
}}
disabled={addingManualCandidate}
/>
<button
className="add-manual-btn"
onClick={addManualLinkedinCandidate}
disabled={!manualLinkedinUrl.trim() || addingManualCandidate}
title={language === 'nl' ? 'Kandidaat toevoegen' : 'Add candidate'}
>
{addingManualCandidate ? (
<Loader2 className="animate-spin" size={16} />
) : (
<span>+</span>
)}
</button>
</div>
{manualUrlError && (
<div className="manual-url-error">
<AlertCircle size={14} />
<span>{manualUrlError}</span>
</div>
)}
</div>
</div>
</div>
</div>
@ -1026,17 +1244,6 @@ export default function EntityReviewPage() {
{t('namesSimilar')}: {Math.round(calculateNameSimilarity(selectedProfile.name, linkedinProfile.name) * 100)}%
</div>
</div>
<button
className="linkup-search-btn"
onClick={() => {
const searchQuery = encodeURIComponent(selectedProfile.name);
window.open(`https://www.linkup.com/search?q=${searchQuery}`, '_blank');
}}
title={t('searchLinkup')}
>
<Search size={16} />
{t('searchLinkup')}
</button>
</div>
)}

View file

@ -1,12 +1,12 @@
{
"generated": "2026-01-14T08:32:15.350Z",
"generated": "2026-01-14T08:51:14.564Z",
"schemaRoot": "/schemas/20251121/linkml",
"totalFiles": 2923,
"totalFiles": 2913,
"categoryCounts": {
"main": 4,
"class": 662,
"class": 671,
"enum": 147,
"slot": 2106,
"slot": 2087,
"module": 4
},
"categories": [
@ -1080,6 +1080,11 @@
"path": "modules/classes/ExhibitionSpace.yaml",
"category": "class"
},
{
"name": "Expenses",
"path": "modules/classes/Expenses.yaml",
"category": "class"
},
{
"name": "ExtractionMetadata",
"path": "modules/classes/ExtractionMetadata.yaml",
@ -1200,6 +1205,16 @@
"path": "modules/classes/FrenchPrivateArchivesRecordSetTypes.yaml",
"category": "class"
},
{
"name": "FunctionType",
"path": "modules/classes/FunctionType.yaml",
"category": "class"
},
{
"name": "FunctionTypes",
"path": "modules/classes/FunctionTypes.yaml",
"category": "class"
},
{
"name": "FundingAgenda",
"path": "modules/classes/FundingAgenda.yaml",
@ -1475,6 +1490,11 @@
"path": "modules/classes/Kustodie.yaml",
"category": "class"
},
{
"name": "Label",
"path": "modules/classes/Label.yaml",
"category": "class"
},
{
"name": "Landsarkiv",
"path": "modules/classes/Landsarkiv.yaml",
@ -1490,6 +1510,11 @@
"path": "modules/classes/LanguageProficiency.yaml",
"category": "class"
},
{
"name": "Laptop",
"path": "modules/classes/Laptop.yaml",
"category": "class"
},
{
"name": "LayoutMetadata",
"path": "modules/classes/LayoutMetadata.yaml",
@ -2035,6 +2060,11 @@
"path": "modules/classes/OutdoorSite.yaml",
"category": "class"
},
{
"name": "Overview",
"path": "modules/classes/Overview.yaml",
"category": "class"
},
{
"name": "ParentOrganizationUnit",
"path": "modules/classes/ParentOrganizationUnit.yaml",
@ -2175,6 +2205,11 @@
"path": "modules/classes/PhotoAttribution.yaml",
"category": "class"
},
{
"name": "Photography",
"path": "modules/classes/Photography.yaml",
"category": "class"
},
{
"name": "PhotoMetadata",
"path": "modules/classes/PhotoMetadata.yaml",
@ -2370,6 +2405,11 @@
"path": "modules/classes/ReadingRoomAnnex.yaml",
"category": "class"
},
{
"name": "RealnessStatus",
"path": "modules/classes/RealnessStatus.yaml",
"category": "class"
},
{
"name": "ReconstructedEntity",
"path": "modules/classes/ReconstructedEntity.yaml",
@ -3155,6 +3195,11 @@
"path": "modules/classes/WebEnrichment.yaml",
"category": "class"
},
{
"name": "WebLink",
"path": "modules/classes/WebLink.yaml",
"category": "class"
},
{
"name": "WebObservation",
"path": "modules/classes/WebObservation.yaml",
@ -4142,24 +4187,14 @@
"path": "modules/slots/admin_office_id.yaml",
"category": "slot"
},
{
"name": "administrative_expenses",
"path": "modules/slots/administrative_expenses.yaml",
"category": "slot"
},
{
"name": "administrative_functions",
"path": "modules/slots/administrative_functions.yaml",
"category": "slot"
},
{
"name": "affects_or_affected_organization",
"path": "modules/slots/affects_or_affected_organization.yaml",
"category": "slot"
},
{
"name": "agenda_id",
"path": "modules/slots/agenda_id.yaml",
"name": "affects_or_affected",
"path": "modules/slots/affects_or_affected.yaml",
"category": "slot"
},
{
@ -4172,59 +4207,14 @@
"path": "modules/slots/aggregates_or_aggregated_from.yaml",
"category": "slot"
},
{
"name": "all_data_real",
"path": "modules/slots/all_data_real.yaml",
"category": "slot"
},
{
"name": "all_links",
"path": "modules/slots/all_links.yaml",
"category": "slot"
},
{
"name": "allocates_or_allocated",
"path": "modules/slots/allocates_or_allocated.yaml",
"category": "slot"
},
{
"name": "allows_laptops",
"path": "modules/slots/allows_laptops.yaml",
"category": "slot"
},
{
"name": "allows_or_allowed_laptop",
"path": "modules/slots/allows_or_allowed_laptop.yaml",
"category": "slot"
},
{
"name": "allows_or_allowed_photography",
"path": "modules/slots/allows_or_allowed_photography.yaml",
"category": "slot"
},
{
"name": "allows_photography",
"path": "modules/slots/allows_photography.yaml",
"category": "slot"
},
{
"name": "alpha_2",
"path": "modules/slots/alpha_2.yaml",
"category": "slot"
},
{
"name": "alpha_3",
"path": "modules/slots/alpha_3.yaml",
"category": "slot"
},
{
"name": "also_identifies_name",
"path": "modules/slots/also_identifies_name.yaml",
"category": "slot"
},
{
"name": "annex_id",
"path": "modules/slots/annex_id.yaml",
"name": "allows_or_allowed",
"path": "modules/slots/allows_or_allowed.yaml",
"category": "slot"
},
{
@ -4292,11 +4282,6 @@
"path": "modules/slots/asserted_by.yaml",
"category": "slot"
},
{
"name": "assertion_id",
"path": "modules/slots/assertion_id.yaml",
"category": "slot"
},
{
"name": "associated_encompassing_bodies",
"path": "modules/slots/associated_encompassing_bodies.yaml",
@ -4327,21 +4312,11 @@
"path": "modules/slots/auto_generated.yaml",
"category": "slot"
},
{
"name": "auxiliary_place_id",
"path": "modules/slots/auxiliary_place_id.yaml",
"category": "slot"
},
{
"name": "auxiliary_places",
"path": "modules/slots/auxiliary_places.yaml",
"category": "slot"
},
{
"name": "auxiliary_platform_id",
"path": "modules/slots/auxiliary_platform_id.yaml",
"category": "slot"
},
{
"name": "auxiliary_platforms",
"path": "modules/slots/auxiliary_platforms.yaml",
@ -7257,11 +7232,6 @@
"path": "modules/slots/funding_source.yaml",
"category": "slot"
},
{
"name": "fundraising_expense",
"path": "modules/slots/fundraising_expense.yaml",
"category": "slot"
},
{
"name": "gallery_subtype",
"path": "modules/slots/gallery_subtype.yaml",
@ -7587,11 +7557,6 @@
"path": "modules/slots/has_agenda_document_url.yaml",
"category": "slot"
},
{
"name": "has_agenda_identifier",
"path": "modules/slots/has_agenda_identifier.yaml",
"category": "slot"
},
{
"name": "has_agenda_short_name",
"path": "modules/slots/has_agenda_short_name.yaml",
@ -7627,11 +7592,6 @@
"path": "modules/slots/has_air_changes_per_hour.yaml",
"category": "slot"
},
{
"name": "has_all_data_real_flag",
"path": "modules/slots/has_all_data_real_flag.yaml",
"category": "slot"
},
{
"name": "has_allocation_date",
"path": "modules/slots/has_allocation_date.yaml",
@ -7662,11 +7622,6 @@
"path": "modules/slots/has_annex_description.yaml",
"category": "slot"
},
{
"name": "has_annex_identifier",
"path": "modules/slots/has_annex_identifier.yaml",
"category": "slot"
},
{
"name": "has_annex_name",
"path": "modules/slots/has_annex_name.yaml",
@ -7852,11 +7807,6 @@
"path": "modules/slots/has_assertion_date.yaml",
"category": "slot"
},
{
"name": "has_assertion_identifier",
"path": "modules/slots/has_assertion_identifier.yaml",
"category": "slot"
},
{
"name": "has_assertion_rationale",
"path": "modules/slots/has_assertion_rationale.yaml",
@ -7952,11 +7902,6 @@
"path": "modules/slots/has_auxiliary_place.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_place_identifier",
"path": "modules/slots/has_auxiliary_place_identifier.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_place_type",
"path": "modules/slots/has_auxiliary_place_type.yaml",
@ -7967,11 +7912,6 @@
"path": "modules/slots/has_auxiliary_platform.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_platform_identifier",
"path": "modules/slots/has_auxiliary_platform_identifier.yaml",
"category": "slot"
},
{
"name": "has_auxiliary_platform_type",
"path": "modules/slots/has_auxiliary_platform_type.yaml",
@ -8272,16 +8212,6 @@
"path": "modules/slots/has_or_had_admin_staff_count.yaml",
"category": "slot"
},
{
"name": "has_or_had_administrative_expense",
"path": "modules/slots/has_or_had_administrative_expense.yaml",
"category": "slot"
},
{
"name": "has_or_had_administrative_function",
"path": "modules/slots/has_or_had_administrative_function.yaml",
"category": "slot"
},
{
"name": "has_or_had_admission_fee",
"path": "modules/slots/has_or_had_admission_fee.yaml",
@ -8452,6 +8382,11 @@
"path": "modules/slots/has_or_had_comment_reply.yaml",
"category": "slot"
},
{
"name": "has_or_had_comprehensive_overview",
"path": "modules/slots/has_or_had_comprehensive_overview.yaml",
"category": "slot"
},
{
"name": "has_or_had_condition_note",
"path": "modules/slots/has_or_had_condition_note.yaml",
@ -8582,6 +8517,11 @@
"path": "modules/slots/has_or_had_exhibition_catalog.yaml",
"category": "slot"
},
{
"name": "has_or_had_expenses",
"path": "modules/slots/has_or_had_expenses.yaml",
"category": "slot"
},
{
"name": "has_or_had_exposed_collection",
"path": "modules/slots/has_or_had_exposed_collection.yaml",
@ -8612,6 +8552,11 @@
"path": "modules/slots/has_or_had_fond.yaml",
"category": "slot"
},
{
"name": "has_or_had_function",
"path": "modules/slots/has_or_had_function.yaml",
"category": "slot"
},
{
"name": "has_or_had_generate",
"path": "modules/slots/has_or_had_generate.yaml",
@ -8892,6 +8837,11 @@
"path": "modules/slots/has_or_had_scene_segment.yaml",
"category": "slot"
},
{
"name": "has_or_had_secondary_label",
"path": "modules/slots/has_or_had_secondary_label.yaml",
"category": "slot"
},
{
"name": "has_or_had_secondary_system",
"path": "modules/slots/has_or_had_secondary_system.yaml",
@ -9442,6 +9392,11 @@
"path": "modules/slots/includes_object_tracking.yaml",
"category": "slot"
},
{
"name": "includes_or_included",
"path": "modules/slots/includes_or_included.yaml",
"category": "slot"
},
{
"name": "includes_segmentation_mask",
"path": "modules/slots/includes_segmentation_mask.yaml",
@ -9482,11 +9437,6 @@
"path": "modules/slots/innovation_budget.yaml",
"category": "slot"
},
{
"name": "innovation_expense",
"path": "modules/slots/innovation_expense.yaml",
"category": "slot"
},
{
"name": "inscription",
"path": "modules/slots/inscription.yaml",
@ -9762,6 +9712,11 @@
"path": "modules/slots/is_or_was_platform_of.yaml",
"category": "slot"
},
{
"name": "is_or_was_real",
"path": "modules/slots/is_or_was_real.yaml",
"category": "slot"
},
{
"name": "is_or_was_related_to",
"path": "modules/slots/is_or_was_related_to.yaml",
@ -12042,11 +11997,6 @@
"path": "modules/slots/program_activity.yaml",
"category": "slot"
},
{
"name": "program_expense",
"path": "modules/slots/program_expense.yaml",
"category": "slot"
},
{
"name": "programme_period",
"path": "modules/slots/programme_period.yaml",

View file

@ -25,7 +25,7 @@ imports:
- ../slots/has_or_had_data_service_endpoint
- ../slots/api_documentation
- ../slots/has_or_had_archival_status
- ../slots/auxiliary_platform_id
- ../slots/has_or_had_identifier
- ../slots/has_auxiliary_platform_type
- ../slots/cms_detected
- ../slots/fixity_info
@ -49,7 +49,6 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_auxiliary_platform_identifier
- ../slots/has_api_documentation_url
prefixes:
linkml: https://w3id.org/linkml/
@ -114,7 +113,7 @@ classes:
- api_documentation
- has_or_had_archival_status
- archived_at
- auxiliary_platform_id
- has_or_had_identifier
- has_auxiliary_platform_type
- cms_detected
- has_or_had_data_service_endpoint
@ -142,7 +141,7 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_auxiliary_platform_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true
@ -347,7 +346,7 @@ classes:
- http://usefulinc.com/ns/doap#
examples:
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-rijksstudio
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-rijksstudio
platform_name: Rijksstudio
auxiliary_platform_type: ProjectWebsite
platform_url: https://www.rijksmuseum.nl/nl/rijksstudio
@ -365,7 +364,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksstudio personal collection platform
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-data-api
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rijksmuseum-data-api
platform_name: Rijksmuseum Data API
auxiliary_platform_type: APIEndpoint
platform_url: https://data.rijksmuseum.nl/
@ -382,7 +381,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum developer API
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/rm-night-watch-experience
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/rm-night-watch-experience
platform_name: Operation Night Watch
auxiliary_platform_type: ExhibitionMicrosite
platform_url: https://www.rijksmuseum.nl/en/stories/operation-night-watch
@ -396,7 +395,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Night Watch research project microsite
- value:
auxiliary_platform_id: https://nde.nl/ontology/hc/aux-platform/na-ww2-portal
has_or_had_identifier: https://nde.nl/ontology/hc/aux-platform/na-ww2-portal
platform_name: WW2 Archives Portal
auxiliary_platform_type: ProjectWebsite
platform_url: https://www.nationaalarchief.nl/onderzoeken/zoekhulpen/ww2

View file

@ -39,7 +39,7 @@ imports:
- ../slots/street_address
- ../slots/postal_code
- ../slots/city
- ../slots/auxiliary_place_id
- ../slots/has_or_had_identifier
- ../slots/has_auxiliary_place_type
- ../slots/country
- ../slots/hosts_branch
@ -59,7 +59,6 @@ imports:
- ../slots/was_generated_by
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_auxiliary_place_identifier
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
@ -119,7 +118,7 @@ classes:
- org:siteAddress
- vcard:Address
slots:
- auxiliary_place_id
- has_or_had_identifier
- has_auxiliary_place_type
- city
- country
@ -146,7 +145,7 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_auxiliary_place_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true
@ -334,7 +333,7 @@ classes:
- https://www.w3.org/TR/vcard-rdf/
examples:
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/rijksmuseum-depot-amersfoort
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/rijksmuseum-depot-amersfoort
place_name: Depot Amersfoort
auxiliary_place_type: STORAGE_FACILITY
place_description: Off-site storage facility for overflow collections. Climate-controlled. Staff access only.
@ -350,7 +349,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum off-site storage depot
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/rijksmuseum-schiphol
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/rijksmuseum-schiphol
place_name: Rijksmuseum Schiphol
auxiliary_place_type: BRANCH_OFFICE
place_description: Small exhibition space at Schiphol Airport featuring rotating highlights from the collection.
@ -365,7 +364,7 @@ classes:
refers_to_custodian: https://nde.nl/ontology/hc/nl-nh-ams-m-rm-q190804
description: Rijksmuseum airport branch exhibition
- value:
auxiliary_place_id: https://nde.nl/ontology/hc/aux-place/nha-reading-room-annex
has_or_had_identifier: https://nde.nl/ontology/hc/aux-place/nha-reading-room-annex
place_name: Noord-Hollands Archief Reading Room Annex
auxiliary_place_type: READING_ROOM_ANNEX
specialized_place:

View file

@ -19,13 +19,14 @@ imports:
- ../slots/is_or_was_allocated_by
- ../slots/identifier_format_used
- ../slots/canonical_value
- ../slots/also_identifies_name
- ../slots/has_or_had_secondary_label
- ../slots/has_allocation_date
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./AllocationAgency
- ./Custodian
- ./CustodianName
- ./Label
- ./SpecificityAnnotation
- ./Standard
- ./TemplateSpecificityScores
@ -43,8 +44,8 @@ classes:
\ Which Standard defines this identifier type (ISIL → ISO 15511)\n- allocated_by: Which AllocationAgency assigned this\
\ specific identifier\n- identifier_format_used: Which format variant is used in identifier_value\n- canonical_value:\
\ Normalized form for deduplication and matching\n- allocation_date: When the identifier was assigned\n\n**Dual-Purpose\
\ Identifiers**:\n\nSome identifiers (ISNI, VIAF) also identify name authority records:\n- also_identifies_name: Links\
\ to the CustodianName record this identifier also identifies\n\n**Enables**:\n- External identifier management (scheme\
\ Identifiers**:\n\nSome identifiers (ISNI, VIAF) also identify name authority records:\n- has_or_had_secondary_label: Links\
\ to the CustodianName record this identifier also identifies (as a Label)\n\n**Enables**:\n- External identifier management (scheme\
\ + value)\n- Cross-reference to authority registries\n- Persistent identifier resolution\n- Inter-dataset linking\n\
- Full provenance tracking (who allocated, when, under what standard)\n- Name authority linkage (for ISNI, VIAF)\n"
exact_mappings:
@ -60,7 +61,7 @@ classes:
slots:
- is_or_was_allocated_by
- has_allocation_date
- also_identifies_name
- has_or_had_secondary_label
- canonical_value
- defined_by_standard
- identifier_format_used
@ -87,7 +88,11 @@ classes:
required: false
canonical_value:
required: false
also_identifies_name:
has_or_had_secondary_label:
description: |
For dual-purpose identifiers (ISNI, VIAF), links to the name authority
record this identifier also identifies.
range: Label
required: false
has_allocation_date:
required: false

View file

@ -0,0 +1,98 @@
# Label class
# Generic class for labeled entities with language tagging
#
# Generation date: 2026-01-15
# Rule compliance: 0 (LinkML single source of truth), 38 (slot centralization)
# Migration: Supports has_or_had_secondary_label slot (replaces also_identifies_name)
id: https://nde.nl/ontology/hc/class/Label
name: label_class
title: Label Class
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
skos: http://www.w3.org/2004/02/skos/core#
rdfs: http://www.w3.org/2000/01/rdf-schema#
schema: http://schema.org/
default_prefix: hc
imports:
- linkml:types
- ../metadata
- ../slots/has_or_had_label
- ../slots/language
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
classes:
Label:
class_uri: rdfs:Resource
description: |
A human-readable label for an entity, with optional language tagging.
**Purpose**:
Label provides a reusable class for representing named/labeled references
across the heritage custodian schema. Used when an identifier or reference
also identifies a secondary named entity (e.g., name authority records).
**Ontological Alignment**:
- **Primary**: `rdfs:Resource` - generic resource with label
- **Close**: `skos:Concept` - labeled concept in controlled vocabulary
**Use Cases**:
- Dual-purpose identifiers (ISNI, VIAF) that identify both an entity
and its name authority record
- Secondary labels/references for complex relationships
- Language-tagged names and labels
**Enables**:
- Multilingual label representation (via language slot)
- Typed labels with explicit language codes
- Reusable labeled references across schema
exact_mappings:
- rdfs:Resource
close_mappings:
- skos:Concept
- schema:Thing
slots:
- has_or_had_label
- language
- specificity_annotation
- template_specificity
slot_usage:
has_or_had_label:
description: The textual value of this label.
range: string
required: true
language:
description: |
ISO 639-1 two-letter language code for this label.
Examples: "en", "nl", "de", "fr"
range: string
required: false
pattern: "^[a-z]{2}$"
annotations:
custodian_types: '["*"]'
custodian_types_rationale: Generic label class applicable to all types.
custodian_types_primary: null
specificity_score: 0.3
specificity_rationale: Broadly applicable generic class for labeled references.
examples:
- value: |
has_or_had_label: Rijksmuseum
language: nl
description: "Dutch language label for Rijksmuseum name authority"
- value: |
has_or_had_label: National Library of the Netherlands
language: en
description: "English language label for KB name authority"

View file

@ -0,0 +1,155 @@
id: https://nde.nl/ontology/hc/class/Laptop
name: laptop_class
title: Laptop Class
description: >-
Represents laptop use permission in a heritage custodian facility.
Models whether personal laptops are permitted in reading rooms
and under what conditions.
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `allows_laptops` and
`allows_or_allowed_laptop` to generic `allows_or_allowed` slot
with typed class. See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
dcterms: http://purl.org/dc/terms/
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
- ../slots/condition
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
classes:
Laptop:
class_uri: schema:LocationFeatureSpecification
description: >-
Permission specification for laptop use in reading rooms or study areas.
**DEFINITION**:
A policy specification indicating whether researchers may use personal
laptops when consulting materials in reading rooms.
**SCHEMA.ORG ALIGNMENT**:
Maps to `schema:LocationFeatureSpecification` as it describes an amenity
or feature availability at a location (the reading room).
**TYPICAL CONDITIONS**:
- Silent operation required
- No external keyboards/mice
- Power outlets available
- WiFi access included/separate
**TEMPORAL SEMANTICS**:
Laptop policies may change over time:
- Pre-2010: Many archives prohibited laptops
- 2010s: Most became laptop-friendly
- COVID era: Some restrictions due to spacing
**EXAMPLE**:
```yaml
allows_or_allowed:
- permitted_item: Laptop
is_permitted: true
conditions:
- "Silent operation required"
- "No external keyboards"
valid_from: "2015-01-01"
```
exact_mappings:
- schema:LocationFeatureSpecification
close_mappings:
- schema:amenityFeature
slots:
- id
- is_permitted
- description
- condition
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
is_permitted:
range: boolean
required: true
description: >-
Whether laptops are permitted (true) or prohibited (false).
description:
range: string
description: >-
Human-readable description of the laptop policy.
condition:
range: string
multivalued: true
description: >-
Conditions or restrictions on laptop use.
Examples: "Silent operation", "No external keyboards"
annotations:
custodian_types: '["A", "L", "R", "M"]'
custodian_types_rationale: >-
Primarily relevant to archives, libraries, research centers, and museums
with reading rooms or study spaces.
custodian_types_primary: A
specificity_score: 0.75
specificity_rationale: >-
Moderately specific - applies to facilities with on-site research spaces.
comments:
- Part of reading room amenity specification system
- Replaces boolean allows_laptops and allows_or_allowed_laptop slots
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- https://schema.org/LocationFeatureSpecification
- https://schema.org/amenityFeature
examples:
- value:
id: hc:laptop-policy/nationaal-archief
is_permitted: true
description: "Laptops welcome in the study room"
condition:
- "Silent operation required"
- "Power outlets available at each desk"
valid_from: "2010-01-01"
description: Archive laptop-friendly policy
- value:
id: hc:laptop-policy/special-collections-restricted
is_permitted: false
description: "Laptops not permitted in special collections reading room"
condition:
- "Pencils only for note-taking"
- "Institution-provided terminals available"
valid_from: "2020-01-01"
description: Restricted laptop policy for special collections
slots:
is_permitted:
description: >-
Whether the item or activity is permitted.
range: boolean
slot_uri: schema:value

View file

@ -0,0 +1,202 @@
id: https://nde.nl/ontology/hc/class/Photography
name: photography_class
title: Photography Class
description: >-
Represents photography permission in a heritage custodian facility.
Models whether researchers may photograph materials (usually with personal cameras)
and under what conditions.
**MIGRATION NOTE** (2026-01-14):
Created as part of slot migration from `allows_photography` and
`allows_or_allowed_photography` to generic `allows_or_allowed` slot
with typed class. See slot_fixes.yaml for migration specification.
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
dcterms: http://purl.org/dc/terms/
skos: http://www.w3.org/2004/02/skos/core#
imports:
- linkml:types
- ../slots/id
- ../slots/description
- ../slots/valid_from
- ../slots/valid_to
- ../slots/condition
- ../slots/specificity_annotation
- ../slots/template_specificity
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
default_prefix: hc
default_range: string
classes:
Photography:
class_uri: schema:LocationFeatureSpecification
description: >-
Permission specification for photography in reading rooms or collection areas.
**DEFINITION**:
A policy specification indicating whether researchers may photograph
materials for personal research use when consulting collections.
**SCHEMA.ORG ALIGNMENT**:
Maps to `schema:LocationFeatureSpecification` as it describes a feature
or amenity availability at a location.
**TYPICAL CONDITIONS**:
- Personal research use only
- No flash photography
- No tripods
- Some materials excluded (fragile, copyright)
- Declaration/waiver may be required
**COPYRIGHT CONSIDERATIONS**:
Photography permissions typically apply to:
- Public domain materials
- Materials where institution holds rights
- Personal research use (fair use/dealing)
Materials still under third-party copyright may have different rules.
**TEMPORAL SEMANTICS**:
Photography policies have evolved significantly:
- Pre-2000s: Generally prohibited, had to order copies
- 2000s-2010s: Gradual liberalization
- 2010s onwards: Many institutions allow free photography
**EXAMPLE**:
```yaml
allows_or_allowed:
- permitted_item: Photography
is_permitted: true
conditions:
- "Personal research use only"
- "No flash"
- "Fragile materials excluded"
valid_from: "2018-01-01"
```
exact_mappings:
- schema:LocationFeatureSpecification
close_mappings:
- schema:amenityFeature
- dcterms:accessRights
slots:
- id
- is_permitted
- description
- condition
- requires_declaration
- excluded_materials
- valid_from
- valid_to
- specificity_annotation
- template_specificity
slot_usage:
id:
identifier: true
range: uriorcurie
is_permitted:
range: boolean
required: true
description: >-
Whether photography is permitted (true) or prohibited (false).
description:
range: string
description: >-
Human-readable description of the photography policy.
condition:
range: string
multivalued: true
description: >-
Conditions or restrictions on photography.
Examples: "No flash", "Personal use only", "No tripods"
requires_declaration:
range: boolean
description: >-
Whether a declaration or waiver must be signed.
excluded_materials:
range: string
multivalued: true
description: >-
Types of materials excluded from photography permission.
Examples: "Fragile manuscripts", "Materials under copyright", "Loan items"
annotations:
custodian_types: '["*"]'
custodian_types_rationale: >-
Applicable to all heritage custodian types with physical collections.
custodian_types_primary: M
specificity_score: 0.5
specificity_rationale: >-
Moderately specific - broadly applicable to institutions with collections.
comments:
- Part of reading room amenity specification system
- Replaces boolean allows_photography and allows_or_allowed_photography slots
- Created from slot_fixes.yaml migration (2026-01-14)
see_also:
- https://schema.org/LocationFeatureSpecification
- https://schema.org/amenityFeature
examples:
- value:
id: hc:photography-policy/nationaal-archief
is_permitted: true
description: "Photography permitted for personal research use"
condition:
- "No flash"
- "Personal research use only"
- "No commercial use without permission"
requires_declaration: true
valid_from: "2015-01-01"
description: Archive photography-friendly policy
- value:
id: hc:photography-policy/special-collections-restricted
is_permitted: false
description: "Photography not permitted in special collections"
condition:
- "Reproduction service available"
- "Digital scans may be ordered"
excluded_materials:
- "All materials in this reading room"
valid_from: "2020-01-01"
description: Restricted photography policy for fragile materials
- value:
id: hc:photography-policy/museum-gallery
is_permitted: true
description: "Photography allowed in permanent galleries"
condition:
- "No flash"
- "No tripods or selfie sticks"
- "Temporary exhibitions may have different rules"
excluded_materials:
- "Loan items marked with no-photography symbol"
- "Temporary exhibitions unless noted"
valid_from: "2018-06-01"
description: Museum gallery photography policy
slots:
requires_declaration:
description: >-
Whether a declaration or waiver is required before the activity.
range: boolean
slot_uri: schema:requiredCollateral
excluded_materials:
description: >-
Materials or areas excluded from the permission.
range: string
multivalued: true
slot_uri: schema:itemListElement

View file

@ -12,7 +12,7 @@ imports:
- ../slots/is_or_was_about_digital_presence
- ../slots/asserted_by
- ../slots/has_assertion_date
- ../slots/assertion_id
- ../slots/has_or_had_identifier
- ../slots/has_assertion_rationale
- ../slots/has_assertion_value
- ../slots/has_or_had_based_on_observation
@ -22,7 +22,6 @@ imports:
- ../slots/temporal_extent
- ./SpecificityAnnotation
- ./TemplateSpecificityScores
- ../slots/has_assertion_identifier
- ../slots/was_asserted_by
prefixes:
linkml: https://w3id.org/linkml/
@ -94,7 +93,7 @@ classes:
- is_or_was_about_digital_presence
- asserted_by
- has_assertion_date
- assertion_id
- has_or_had_identifier
- has_assertion_rationale
- has_assertion_value
- has_or_had_based_on_observation
@ -106,7 +105,7 @@ classes:
- template_specificity
- temporal_extent
slot_usage:
has_assertion_identifier:
has_or_had_identifier:
range: uriorcurie
required: true
identifier: true

View file

@ -18,8 +18,9 @@ imports:
- ../slots/has_wifi
- ../slots/requires_registration
- ../slots/requires_appointment
- ../slots/allows_photography
- ../slots/allows_laptops
- ../slots/allows_or_allowed
- ./Laptop
- ./Photography
- ../slots/has_supervised_handling
- ../slots/has_locker
- ../slots/opening_hour
@ -74,8 +75,7 @@ classes:
- schema:ReadingRoom
slots:
- has_or_had_accessibility_feature
- allows_laptops
- allows_photography
- allows_or_allowed
- has_computer_terminal
- has_locker
- has_microfilm_reader
@ -165,17 +165,17 @@ classes:
description: Appointment required
- value: false
description: Walk-in access
allows_or_allowed_photography:
range: boolean
allows_or_allowed:
range: string
multivalued: true
description: >-
Permitted activities and equipment in the reading room.
Use Laptop and Photography classes for structured permissions.
examples:
- value: true
description: Photography permitted
allows_or_allowed_laptop:
range: boolean
ifabsent: 'true'
examples:
- value: true
description: Laptops permitted
- value: "Laptops permitted"
description: Laptop use allowed
- value: "Photography for personal research"
description: Photography allowed with conditions
has_supervised_handling:
range: boolean
examples:
@ -229,8 +229,9 @@ classes:
has_wifi: true
requires_registration: true
requires_appointment: false
allows_photography: true
allows_laptops: true
allows_or_allowed:
- "Laptops permitted"
- "Photography for personal research use"
has_lockers: true
opening_hours: Tu-Fr 09:00-17:00, Sa 09:00-13:00
has_or_had_accessibility_feature:
@ -248,7 +249,8 @@ classes:
terminal_count: 4
requires_registration: true
requires_appointment: true
allows_photography: false
allows_or_allowed:
- "Photography not permitted - reproduction service available"
has_supervised_handling: true
has_lockers: true
opening_hours: Mo-Fr 10:00-16:00

View file

@ -50,7 +50,7 @@ classes:
\ FOR ANNEX**:\n\n1. **Capacity overflow**: Main reading room at capacity\n2. **Specialized materials**: Maps, newspapers,\
\ genealogy\n3. **Geographic reach**: Serve researchers in another city\n4. **Renovation**: Temporary reading room during\
\ construction\n5. **Partnership**: Shared space with another institution\n\n**USE CASES**:\n\n1. **Overflow Annex**:\n\
\ ```yaml\n ReadingRoomAnnex:\n annex_id: \"https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg\"\n \
\ ```yaml\n ReadingRoomAnnex:\n has_or_had_identifier: \"https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg\"\n \
\ annex_name: \"Noord-Hollands Archief Reading Room Annex\"\n annex_reason: CAPACITY_OVERFLOW\n is_annex_of_reading_room:\
\ \"https://nde.nl/ontology/hc/aux/nha-studiezaal\"\n ```\n\n2. **Specialized Materials Annex**:\n ```yaml\n ReadingRoomAnnex:\n\
\ annex_name: \"Stadsarchief Kaartenkamer Annex\"\n annex_reason: SPECIALIZED_MATERIALS\n material_specialization:\
@ -67,7 +67,7 @@ classes:
- schema:branch
slots:
- has_annex_description
- annex_id
- has_or_had_identifier
- has_annex_name
- has_annex_reason
- is_annex_of_reading_room
@ -83,10 +83,11 @@ classes:
- was_derived_from
- was_generated_by
slot_usage:
has_annex_identifier:
range: uriorcurie
has_or_had_identifier:
range: CustodianIdentifier
required: true
identifier: true
description: Unique identifier for this reading room annex following NDE Heritage Custodian ontology conventions.
examples:
- value: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
description: Noord-Hollands Archief annex
@ -176,7 +177,7 @@ classes:
- http://vocab.getty.edu/aat/300004051
examples:
- value:
annex_id: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
has_or_had_identifier: https://nde.nl/ontology/hc/aux/nha-annex-kleine-houtweg
annex_name: Noord-Hollands Archief Reading Room Annex
annex_description: Overflow reading room at Kleine Houtweg for peak research periods. Same registration as main studiezaal.
annex_reason: CAPACITY_OVERFLOW
@ -188,7 +189,7 @@ classes:
is_temporary: false
description: Overflow reading room annex
- value:
annex_id: https://nde.nl/ontology/hc/aux/sa-renovation-annex
has_or_had_identifier: https://nde.nl/ontology/hc/aux/sa-renovation-annex
annex_name: Stadsarchief Temporary Reading Room
annex_description: Temporary reading room during main building renovation. Limited services available.
annex_reason: RENOVATION

View file

@ -0,0 +1,56 @@
id: https://nde.nl/ontology/hc/slot/allows_or_allowed
name: allows_or_allowed_slot
title: Allows Or Allowed Slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
schema: http://schema.org/
odrl: http://www.w3.org/ns/odrl/2/
default_prefix: hc
imports:
- linkml:types
slots:
allows_or_allowed:
description: >-
Generic slot for expressing what activities, equipment, or behaviors are
permitted in a heritage custodian facility (past or present).
**SEMANTICS**:
Uses RiC-O temporal pattern (is_or_was / has_or_had / allows_or_allowed)
to capture policies that may change over time. A reading room that
"allowed photography" in 2020 may have changed policy by 2025.
**USAGE PATTERN**:
The range should be a typed class representing the permitted activity:
- `Laptop` - laptop use permission
- `Photography` - photography permission
- Future: `Food`, `Beverages`, `MobilePhone`, etc.
**EXAMPLES**:
```yaml
ReadingRoom:
allows_or_allowed:
- permitted_item: Laptop
is_permitted: true
conditions: "Must be silent, no external keyboards"
- permitted_item: Photography
is_permitted: true
conditions: "Personal research use only, no flash"
```
slot_uri: schema:amenityFeature
range: string
multivalued: true
exact_mappings:
- schema:amenityFeature
close_mappings:
- odrl:permission
annotations:
custodian_types: '["*"]'
custodian_types_rationale: All heritage custodians have visitor policies.
custodian_types_primary: A
specificity_score: 0.5
specificity_rationale: Generic permission slot applicable to reading rooms and public spaces.

View file

@ -0,0 +1,79 @@
# has_or_had_secondary_label slot
# Generic slot for secondary/alternative labels beyond the primary identifier
#
# Following RiC-O naming convention (Rule 39): "hasOrHad..." pattern
# for temporal relationships in heritage domain.
#
# Generation date: 2026-01-15
# Rule compliance: 38 (slot centralization + semantic URI), 39 (RiC-O naming), 42 (no prefix)
# Migration: Replaces bespoke also_identifies_name slot
id: https://nde.nl/ontology/hc/slot/has_or_had_secondary_label
name: has_or_had_secondary_label_slot
title: Has Or Had Secondary Label Slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
skos: http://www.w3.org/2004/02/skos/core#
schema: http://schema.org/
default_prefix: hc
imports:
- linkml:types
slots:
has_or_had_secondary_label:
slot_uri: skos:altLabel
description: |
Secondary or alternative label(s) associated with an entity.
**Temporal Semantics** (RiC-O Pattern):
The "hasOrHad" naming follows RiC-O convention indicating this relationship
may be historical - secondary labels may change over time.
**Primary Use Case**:
For dual-purpose identifiers (ISNI, VIAF) that also identify name authority
records, this links to the secondary entity (name) the identifier references.
**Ontological Alignment**:
- **Primary** (`slot_uri`): `skos:altLabel` - SKOS alternative label
- **Close**: `schema:alternateName` - Schema.org alternate name
**Usage**:
In CustodianIdentifier, this enables linking identifiers like ISNI/VIAF
to the name authority record they also identify (beyond the primary entity).
range: Label
required: false
multivalued: true
exact_mappings:
- skos:altLabel
close_mappings:
- schema:alternateName
annotations:
rico_naming_convention: |
Follows RiC-O "hasOrHad" pattern for temporal predicates.
See Rule 39: Slot Naming Convention (RiC-O Style)
replaces_slots: "also_identifies_name"
migration_date: "2026-01-15"
custodian_types: '["*"]'
custodian_types_rationale: Applicable to all heritage custodian types.
specificity_score: 0.5
specificity_rationale: Moderately specific - used for dual-purpose identifiers.
comments:
- "Generic secondary label slot for entities with dual identification"
- "Maps to skos:altLabel as alternative lexical label"
- "Multivalued for multiple secondary references"
- "Replaces bespoke also_identifies_name slot"
examples:
- value: |
label_value: "Rijksmuseum"
label_language: "nl"
description: "VIAF identifier also identifies the name authority record for Rijksmuseum"

View file

@ -16,14 +16,7 @@
"aggregates_or_aggregated_from.yaml",
"is_or_was_real.yaml",
"allocates_or_allocated.yaml",
"allows_laptops.yaml",
"allows_or_allowed_laptop.yaml",
"allows_or_allowed_photography.yaml",
"allows_photography.yaml",
"alpha_2.yaml",
"alpha_3.yaml",
"also_identifies_name.yaml",
"annex_id.yaml",
"allows_or_allowed.yaml",
"annual_participants.yaml",
"api_available.yaml",
"api_documentation.yaml",
@ -39,14 +32,12 @@
"area_hectares.yaml",
"arrangement_notes.yaml",
"asserted_by.yaml",
"assertion_id.yaml",
"associated_encompassing_bodies.yaml",
"associated_taxa.yaml",
"audio_event_segments.yaml",
"authentication_required.yaml",
"authors.yaml",
"auto_generated.yaml",
"auxiliary_place_id.yaml",
"auxiliary_places.yaml",
"auxiliary_platform_id.yaml",
"auxiliary_platforms.yaml",
@ -715,7 +706,6 @@
"has_altitude.yaml",
"has_amendment_history.yaml",
"has_annex_description.yaml",
"has_annex_identifier.yaml",
"has_annex_name.yaml",
"has_annex_reason.yaml",
"has_annotation_by.yaml",
@ -753,7 +743,6 @@
"has_articles_of_association.yaml",
"has_aspect_ratio.yaml",
"has_assertion_date.yaml",
"has_assertion_identifier.yaml",
"has_assertion_rationale.yaml",
"has_assertion_value.yaml",
"has_assessment_category.yaml",
@ -773,7 +762,6 @@
"has_authority_file_name.yaml",
"has_authority_file_url.yaml",
"has_auxiliary_place.yaml",
"has_auxiliary_place_identifier.yaml",
"has_auxiliary_place_type.yaml",
"has_auxiliary_platform.yaml",
"has_auxiliary_platform_identifier.yaml",
@ -954,6 +942,7 @@
"has_or_had_resulting_unit.yaml",
"has_or_had_safeguard.yaml",
"has_or_had_scene_segment.yaml",
"has_or_had_secondary_label.yaml",
"has_or_had_secondary_system.yaml",
"has_or_had_section_link.yaml",
"has_or_had_segment.yaml",

View file

@ -205,10 +205,13 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_laptops
processed:
status: false
timestamp: null
session: null
notes: "Requires Laptop class creation for policy modeling"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_laptops REMOVED and archived.
Created allows_or_allowed generic slot and Laptop typed class.
ReadingRoom.yaml updated to use allows_or_allowed slot.
revision:
- label: allows_or_allowed
type: slot
@ -217,10 +220,12 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_or_allowed_laptops
processed:
status: false
timestamp: null
session: null
notes: "Duplicate of allows_laptops - same migration"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_or_allowed_laptop REMOVED and archived (duplicate of allows_laptops).
Same migration as allows_laptops - both replaced by generic allows_or_allowed + Laptop class.
revision:
- label: allows_or_allowed
type: slot
@ -229,10 +234,13 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_or_allowed_photography
processed:
status: false
timestamp: null
session: null
notes: "Requires Photography class creation for policy modeling"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_or_allowed_photography REMOVED and archived.
Created allows_or_allowed generic slot and Photography typed class.
ReadingRoom.yaml updated to use allows_or_allowed slot.
revision:
- label: allows_or_allowed
type: slot
@ -241,10 +249,12 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/allows_photography
processed:
status: false
timestamp: null
session: null
notes: "Duplicate of allows_or_allowed_photography - same migration"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-allows-policy-migration"
notes: >-
FULLY MIGRATED: allows_photography REMOVED and archived (duplicate of allows_or_allowed_photography).
Same migration as allows_or_allowed_photography - both replaced by generic allows_or_allowed + Photography class.
revision:
- label: allows_or_allowed
type: slot
@ -253,10 +263,15 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/alpha_2
processed:
status: false
timestamp: null
session: null
notes: "Requires Alpha2Code class creation for ISO 3166-1 codes"
status: true
timestamp: '2026-01-15T00:00:00Z'
session: "session-2026-01-15-alpha-deprecation"
notes: >-
DEPRECATED: Orphan stub archived to archive/slots/alpha_2_archived_20260114.yaml.
No migration needed - proper slot has_iso_3166_1_alpha_2_code already exists and is
correctly implemented in Country class. The alpha_2 stub was never imported by any
class and had no semantic content. References in examples (e.g., covers_country.alpha_2
in ServiceArea.yaml) are YAML example data values, not actual slot imports.
revision:
- label: has_or_had_code
type: slot
@ -265,10 +280,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/alpha_3
processed:
status: false
timestamp: null
session: null
notes: "Requires Alpha3Code class creation for ISO 3166-1 codes"
status: true
timestamp: '2026-01-15T00:00:00Z'
session: "session-2026-01-15-alpha-deprecation"
notes: >-
DEPRECATED: Orphan stub archived to archive/slots/alpha_3_archived_20260114.yaml.
No migration needed - proper slot has_iso_3166_1_alpha_3_code already exists and is
correctly implemented in Country class. The alpha_3 stub was never imported by any
class and had no semantic content.
revision:
- label: has_or_had_code
type: slot
@ -277,10 +296,14 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/also_identifies_name
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Label class"
status: true
timestamp: '2026-01-14T09:45:00Z'
session: "session-2026-01-14-secondary-label-migration"
notes: >-
FULLY MIGRATED: also_identifies_name REMOVED and archived to archive/slots/also_identifies_name_archived_20260115.yaml.
Created has_or_had_secondary_label slot (modules/slots/has_or_had_secondary_label.yaml) and Label class
(modules/classes/Label.yaml) per slot_fixes.yaml revision. CustodianIdentifier (Identifier.yaml) updated
to use new slot with Label range. All imports, slots list, slot_usage, and descriptions updated.
revision:
- label: has_or_had_secondary_label
type: slot
@ -289,10 +312,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/annex_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T22:00:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: annex_id and has_annex_identifier REMOVED from modules/slots/, archived to archive/slots/. ReadingRoomAnnex.yaml updated to use has_or_had_identifier with CustodianIdentifier class. All imports, slots, slot_usage, and examples updated."
revision:
- label: has_or_had_identifier
type: slot
@ -477,10 +500,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/assertion_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T23:00:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: assertion_id and has_assertion_identifier REMOVED from modules/slots/, archived to archive/slots/. PrimaryDigitalPresenceAssertion.yaml updated to use has_or_had_identifier. All imports, slots, and slot_usage updated."
revision:
- label: has_or_had_identifier
type: slot
@ -561,10 +584,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/auxiliary_place_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: '2026-01-14T23:15:00Z'
session: "session-2026-01-14-identifier-migrations"
notes: "FULLY MIGRATED: auxiliary_place_id and has_auxiliary_place_identifier REMOVED from modules/slots/, archived to archive/slots/. AuxiliaryPlace.yaml updated to use has_or_had_identifier. All imports, slots, slot_usage, and 3 examples updated."
revision:
- label: has_or_had_identifier
type: slot
@ -585,10 +608,10 @@ fixes:
- original_slot_id: https://nde.nl/ontology/hc/slot/auxiliary_platform_id
processed:
status: false
timestamp: null
session: null
notes: "Maps to existing Identifier class"
status: true
timestamp: "2026-01-14T12:15:00Z"
session: "session-2026-01-14-identifier-migrations"
notes: "Migrated to has_or_had_identifier. Updated AuxiliaryDigitalPlatform.yaml class. Archived auxiliary_platform_id.yaml and has_auxiliary_platform_identifier.yaml"
revision:
- label: has_or_had_identifier
type: slot
@ -1223,3 +1246,4 @@ fixes:
type: slot
- label: Identifier
type: class

View file

@ -18,6 +18,7 @@ import os
import tempfile
import shutil
import subprocess
import httpx
from pathlib import Path
from datetime import datetime, timezone
from typing import Optional, List
@ -28,6 +29,10 @@ from fastapi import APIRouter, HTTPException, Depends, Query, Form
from fastapi.security import OAuth2AuthorizationCodeBearer
from pydantic import BaseModel
# Linkup API configuration
LINKUP_API_KEY = os.getenv("LINKUP_API_KEY", "")
LINKUP_API_URL = "https://api.linkup.so/v1/search"
# Email semantics for on-demand analysis
try:
from glam_extractor.entity_resolution.email_semantics import parse_email_semantics
@ -226,12 +231,14 @@ class ReviewRequest(BaseModel):
linkedin_ppid: str
decision: ReviewDecision
notes: Optional[str] = None
auto_reject_others: bool = False # Auto-reject other candidates when matching
class ReviewResponse(BaseModel):
success: bool
message: str
git_commit: Optional[str]
auto_rejected_count: int = 0 # Number of other candidates auto-rejected
class CandidateListResponse(BaseModel):
@ -241,6 +248,47 @@ class CandidateListResponse(BaseModel):
profiles: List[ProfileSummary]
class LinkupSearchRequest(BaseModel):
"""Request for Linkup web search"""
wcms_ppid: str
name: str
email: Optional[str] = None
email_domain: Optional[str] = None
institution: Optional[str] = None # Detected institution from email
additional_context: Optional[str] = None # Any extra search terms
class LinkupSearchResult(BaseModel):
"""Single result from Linkup search"""
url: str
title: str
content: str
linkedin_slug: Optional[str] = None
extracted_name: Optional[str] = None
extracted_headline: Optional[str] = None
class LinkupSearchResponse(BaseModel):
"""Response from Linkup search"""
success: bool
query: str
results: List[LinkupSearchResult]
error: Optional[str] = None
class AddCandidateRequest(BaseModel):
"""Request to add a LinkedIn candidate manually"""
wcms_ppid: str
linkedin_slug: str
class AddCandidateResponse(BaseModel):
"""Response from adding a manual candidate"""
success: bool
message: str
linkedin_ppid: Optional[str] = None
# ============================================================================
# Authentication (Forgejo OAuth)
# ============================================================================
@ -539,6 +587,9 @@ async def save_review_decision(
Updates the candidates file with the review decision.
DOES NOT MERGE profiles - only records the decision for later processing.
If auto_reject_others=True and decision=match, all OTHER candidates for the
same wcms_ppid will be automatically set to not_match.
"""
# Placeholder user until OAuth is configured
user = {"username": "reviewer"}
@ -581,6 +632,34 @@ async def save_review_decision(
c['review_notes'] = request.notes
break
# Auto-reject other candidates if decision is 'match' and auto_reject_others is True
auto_rejected_count = 0
if request.decision == ReviewDecision.MATCH and request.auto_reject_others:
# Find all OTHER candidates for this WCMS profile
for other_key, other_idx in _candidates_list_index.items():
other_wcms_ppid, other_linkedin_ppid = other_key
if other_wcms_ppid == request.wcms_ppid and other_linkedin_ppid != request.linkedin_ppid:
other_candidate = _candidates_cache['candidates'][other_idx]
# Only auto-reject if not already reviewed
if not other_candidate.get('reviewed', False):
other_candidate['reviewed'] = True
other_candidate['review_decision'] = 'not_match'
other_candidate['reviewed_by'] = user.get('username', 'unknown')
other_candidate['reviewed_at'] = now
other_candidate['review_notes'] = 'Auto-rejected: another candidate was matched'
auto_rejected_count += 1
# Also update in-memory cache
if _candidates_by_wcms and request.wcms_ppid in _candidates_by_wcms:
for c in _candidates_by_wcms[request.wcms_ppid]['candidates']:
if c.get('linkedin_ppid') == other_linkedin_ppid:
c['reviewed'] = True
c['review_decision'] = 'not_match'
c['reviewed_by'] = user.get('username', 'unknown')
c['reviewed_at'] = now
c['review_notes'] = 'Auto-rejected: another candidate was matched'
break
# Update metadata
_candidates_cache['metadata']['last_review_at'] = now
_candidates_cache['metadata']['last_reviewed_by'] = user.get('username', 'unknown')
@ -601,10 +680,15 @@ async def save_review_decision(
except Exception as e:
print(f"Git commit skipped: {e}")
message = f"Review saved: {request.decision.value}"
if auto_rejected_count > 0:
message += f" ({auto_rejected_count} other candidate(s) auto-rejected)"
return ReviewResponse(
success=True,
message=f"Review saved: {request.decision.value}",
git_commit=commit_hash
message=message,
git_commit=commit_hash,
auto_rejected_count=auto_rejected_count
)
@ -774,6 +858,238 @@ async def analyze_email(email: str):
}
# ============================================================================
# Linkup Web Search Integration
# ============================================================================
import re
def extract_linkedin_info(url: str, title: str, content: str) -> dict:
"""Extract LinkedIn profile info from search result."""
info = {
'linkedin_slug': None,
'extracted_name': None,
'extracted_headline': None
}
# Extract slug from URL
slug_match = re.search(r'linkedin\.com/in/([^/?]+)', url)
if slug_match:
info['linkedin_slug'] = slug_match.group(1).lower()
# Extract name from title (format: "Name - Title | LinkedIn")
name_match = re.match(r'^([^-|]+)', title)
if name_match:
info['extracted_name'] = name_match.group(1).strip()
# Extract headline from title
headline_match = re.search(r' - ([^|]+)', title)
if headline_match:
info['extracted_headline'] = headline_match.group(1).strip()
return info
@router.post("/linkup-search", response_model=LinkupSearchResponse)
async def linkup_search(request: LinkupSearchRequest):
"""
Search for LinkedIn profiles using Linkup API.
Builds a comprehensive search query from WCMS profile data to find
potential LinkedIn matches for entity resolution.
Returns:
- List of search results with extracted LinkedIn profile info
- Each result includes the LinkedIn slug if found in a LinkedIn URL
"""
if not LINKUP_API_KEY:
return LinkupSearchResponse(
success=False,
query="",
results=[],
error="Linkup API key not configured. Set LINKUP_API_KEY environment variable."
)
# Build comprehensive search query from WCMS profile data
query_parts = [request.name]
# Add institution context if available
if request.institution:
query_parts.append(request.institution)
# Add email domain as potential employer hint
if request.email_domain and request.email_domain not in ['gmail.com', 'outlook.com', 'hotmail.com', 'yahoo.com']:
# Extract org name from domain (e.g., "rijksmuseum.nl" -> "rijksmuseum")
domain_parts = request.email_domain.split('.')
if len(domain_parts) >= 2:
org_hint = domain_parts[0]
if org_hint not in ['mail', 'email', 'info', 'contact']:
query_parts.append(org_hint)
# Add any additional context
if request.additional_context:
query_parts.append(request.additional_context)
# Add LinkedIn context to focus search
query_parts.append("LinkedIn")
query = ' '.join(query_parts)
try:
async with httpx.AsyncClient() as client:
response = await client.post(
LINKUP_API_URL,
headers={
"Authorization": f"Bearer {LINKUP_API_KEY}",
"Content-Type": "application/json"
},
json={
"q": query,
"depth": "standard",
"outputType": "searchResults"
},
timeout=30.0
)
if response.status_code != 200:
return LinkupSearchResponse(
success=False,
query=query,
results=[],
error=f"Linkup API returned status {response.status_code}: {response.text[:200]}"
)
data = response.json()
raw_results = data.get('results', [])
# Process results and extract LinkedIn info
processed_results = []
for result in raw_results:
url = result.get('url', '')
title = result.get('name', '')
content = result.get('content', '')[:500] # Limit content length
# Extract LinkedIn info if this is a LinkedIn URL
linkedin_info = extract_linkedin_info(url, title, content)
processed_results.append(LinkupSearchResult(
url=url,
title=title,
content=content,
linkedin_slug=linkedin_info['linkedin_slug'],
extracted_name=linkedin_info['extracted_name'],
extracted_headline=linkedin_info['extracted_headline']
))
return LinkupSearchResponse(
success=True,
query=query,
results=processed_results
)
except httpx.TimeoutException:
return LinkupSearchResponse(
success=False,
query=query,
results=[],
error="Linkup API request timed out"
)
except Exception as e:
return LinkupSearchResponse(
success=False,
query=query,
results=[],
error=f"Linkup API error: {str(e)}"
)
@router.post("/add-candidate", response_model=AddCandidateResponse)
async def add_manual_candidate(request: AddCandidateRequest):
"""
Add a LinkedIn candidate manually by providing a LinkedIn slug.
This creates a match candidate entry for the given WCMS profile.
"""
import json
import re
from pathlib import Path
from datetime import datetime, timezone
# Normalize the LinkedIn slug (remove any URL parts)
linkedin_slug = request.linkedin_slug.strip().lower()
# Remove any remaining URL fragments
linkedin_slug = re.sub(r'^https?://.*linkedin\.com/in/', '', linkedin_slug)
linkedin_slug = linkedin_slug.rstrip('/')
if not linkedin_slug:
raise HTTPException(status_code=400, detail="Invalid LinkedIn slug")
# Find the WCMS annotation file
wcms_ppid = request.wcms_ppid
# Find annotation file
annotations_dir = Path("data/custodian/person/annotation/wcms")
annotation_files = list(annotations_dir.glob(f"*_{wcms_ppid.replace('/', '_').replace(':', '_')}*.json"))
if not annotation_files:
# Try alternative path patterns
for pattern in [f"*{wcms_ppid.split('_')[-1]}*.json", f"*{wcms_ppid}*.json"]:
annotation_files = list(annotations_dir.glob(pattern))
if annotation_files:
break
if not annotation_files:
raise HTTPException(status_code=404, detail=f"Annotation file not found for {wcms_ppid}")
annotation_file = annotation_files[0]
# Load annotation data
with open(annotation_file, 'r', encoding='utf-8') as f:
annotation_data = json.load(f)
# Check if candidate already exists
match_candidates = annotation_data.get('match_candidates', [])
for candidate in match_candidates:
if candidate.get('linkedin_slug') == linkedin_slug:
return AddCandidateResponse(
success=False,
message=f"Candidate {linkedin_slug} already exists for this profile"
)
# Generate a PPID for the LinkedIn candidate (simplified)
timestamp = datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S')
linkedin_ppid = f"MANUAL_{linkedin_slug}_{timestamp}"
# Create the new candidate entry
new_candidate = {
"linkedin_ppid": linkedin_ppid,
"linkedin_slug": linkedin_slug,
"linkedin_name": linkedin_slug.replace('-', ' ').title(), # Best guess at name
"confidence_score": 0.5, # Manual entries start at 50%
"match_signals": ["manual_entry"],
"reviewed": False,
"review_decision": None,
"review_date": None,
"is_likely_wrong_person": False,
"wrong_person_reason": None,
"added_manually": True,
"added_date": datetime.now(timezone.utc).isoformat()
}
# Add to match_candidates
match_candidates.append(new_candidate)
annotation_data['match_candidates'] = match_candidates
# Save updated annotation
with open(annotation_file, 'w', encoding='utf-8') as f:
json.dump(annotation_data, f, indent=2, ensure_ascii=False)
return AddCandidateResponse(
success=True,
message=f"Added {linkedin_slug} as a candidate",
linkedin_ppid=linkedin_ppid
)
# ============================================================================
# Review Authentication (Separate from main app auth)
# ============================================================================