Skip to content

Latest commit

Β 

History

History
759 lines (615 loc) Β· 34.4 KB

File metadata and controls

759 lines (615 loc) Β· 34.4 KB

ONTOLOGY.md β€” HeritageGraph Ontology & Form System Guide

Audience: Developers, researchers, and AI agents who need to understand, modify, or extend the ontology-driven form system in HeritageGraph.
Last Updated: February 2026 (aligned with ontology/HeritageGraph.yaml v1.0.0)


Table of Contents

  1. Overview β€” How It All Connects
  2. Architecture Diagram
  3. Source of Truth Files
  4. Ontology β†’ Frontend Mapping
  5. Registered Entity Types (24 total)
  6. Controlled Vocabularies (Enums)
  7. How to Make Changes
  8. Field Type Reference
  9. OntologyClass Interface
  10. OntologyField Interface
  11. Ontology ↔ Backend Model Alignment
  12. Data Flow: Form β†’ API β†’ Database
  13. CIDOC-CRM Alignment Reference
  14. PROV-O Provenance Layer
  15. Troubleshooting & Common Mistakes
  16. File Map

1. Overview β€” How It All Connects

HeritageGraph uses a registry-driven architecture where a single TypeScript file (registry.ts) defines every entity type. The entire UI β€” forms, data tables, detail views, and navigation β€” auto-generates from this registry.

HeritageGraph.yaml (LinkML)        ← Canonical ontology (classes, slots, enums)
        β”‚
        β–Ό
Heritage.ttl (OWL/Turtle)          ← Generated OWL for linked-data consumers
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Frontend (heritage_graph_ui/src/lib/ontology/)                 β”‚
β”‚                                                                 β”‚
β”‚  types.ts     β†’ TypeScript interfaces (OntologyField, etc.)     β”‚
β”‚  enums.ts     β†’ Controlled vocabularies (dropdown options)      β”‚
β”‚  registry.ts  β†’ Entity class definitions (fields, sections...)  β”‚
β”‚  index.ts     β†’ Barrel re-export                                β”‚
β”‚                                                                 β”‚
β”‚  ↓ auto-generates ↓                                             β”‚
β”‚                                                                 β”‚
β”‚  OntologyForm     β†’ Contribute forms                            β”‚
β”‚  OntologyDataTable β†’ Knowledge tables                           β”‚
β”‚  Detail views     β†’ Entity detail pages                         β”‚
β”‚  Contribute page  β†’ Dashboard intent cards                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό  (POST/GET via Bearer token)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Backend (heritage_graph/apps/cidoc_data/)                      β”‚
β”‚                                                                 β”‚
β”‚  models.py       β†’ Django models (must match field keys)        β”‚
β”‚  serializers.py  β†’ DRF serializers                              β”‚
β”‚  views.py        β†’ ViewSets + search                            β”‚
β”‚  urls.py         β†’ API routes (must match apiEndpoint)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Golden rule: The field key in the registry must exactly match the Django model field name, and apiEndpoint must match the URL route registered in urls.py.


2. Architecture Diagram

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  ontology/HeritageGraph.yaml  β”‚
                    β”‚  (LinkML β€” 2060 lines)        β”‚
                    β”‚  40+ classes, 100+ slots      β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚  derived from
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  ontology/Heritage.ttl         β”‚
                    β”‚  (OWL/Turtle β€” 5190 lines)     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚                     β”‚                      β”‚
   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  enums.ts   β”‚    β”‚  registry.ts    β”‚    β”‚  Django models  β”‚
   β”‚  22 enums   │───▢│  24 classes     β”‚    β”‚  cidoc_data     β”‚
   β”‚  dropdowns  β”‚    β”‚  fields/cols    β”‚    β”‚  heritage_data  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚                      β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  OntologyForm       β”‚    β”‚  DRF Serializer β”‚
                    β”‚  auto-generates UI  │───▢│  API ViewSet    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3. Source of Truth Files

File Location Purpose Lines
HeritageGraph.yaml ontology/HeritageGraph.yaml Canonical LinkML schema β€” classes, slots, enums, prefixes ~2060
Heritage.ttl ontology/Heritage.ttl Generated OWL/Turtle for linked-data consumers ~5190
types.ts heritage_graph_ui/src/lib/ontology/types.ts TypeScript interfaces (OntologyField, OntologyClass, etc.) ~103
enums.ts heritage_graph_ui/src/lib/ontology/enums.ts Controlled vocabularies for select fields ~230
registry.ts heritage_graph_ui/src/lib/ontology/registry.ts All 24 entity class definitions with fields, sections, columns ~900
index.ts heritage_graph_ui/src/lib/ontology/index.ts Barrel export ~17

Relationship between ontology YAML and frontend registry

HeritageGraph.yaml concept Frontend equivalent
classes: block OntologyClass in registry.ts
slots: block OntologyField in each class's fields array
enums: block Entry in ontologyEnums in enums.ts
class_uri classUri property on OntologyClass
is_a (inheritance) parentClass property on OntologyClass
slot_usage (required, range) required, options, relationTo on OntologyField

4. Ontology β†’ Frontend Mapping

When translating from HeritageGraph.yaml to the frontend registry, follow these rules:

YAML construct Frontend mapping Example
ArchitecturalStructure class const architecturalStructure: OntologyClass with key: "structure" registry.ts
name slot with slot_uri: rdfs:label nameField("Structure Name") Every class
note slot with slot_uri: crm:P3_has_note noteField() Every class
has_current_location slot with range: Place { type: "relation", relationTo: "location" } Structures
ArchitecturalStyleEnum enum ontologyEnums.ArchitecturalStyleEnum in enums.ts Structure form
multivalued: true in YAML multivalued: true on OntologyField Ritual deity links
required: true in slot_usage required: true on OntologyField Name fields

5. Registered Entity Types (24 total)

Navigable (show in sidebar & contribute dashboard)

Registry Key Label Category Ontology Class CIDOC-CRM URI API Endpoint
person Person social Person crm:E21_Person /cidoc/persons/
location Place spatiotemporal Place crm:E53_Place /cidoc/locations/
event Event event HistoricalEvent crm:E5_Event /cidoc/events/
period Historical Period spatiotemporal β€” crm:E4_Period /cidoc/historical_periods/
tradition Tradition conceptual β€” crm:E55_Type /cidoc/traditions/
source Source provenance DataSource crm:E73_Information_Object /cidoc/sources/
deity Deity conceptual Deity crm:E28_Conceptual_Object /cidoc/deities/
guthi Guthi social Guthi crm:E74_Group /cidoc/guthis/
structure Architectural Structure tangible ArchitecturalStructure crm:E22_Human-Made_Object /cidoc/structures/
ritual Ritual Event event RitualEvent crm:E7_Activity /cidoc/rituals/
festival Festival event Festival crm:E7_Activity /cidoc/festivals/
iconography Iconographic Object tangible IconographicObject crm:E22_Human-Made_Object /cidoc/iconographic_objects/
monument Monument tangible BuddhistMonument heritageGraph:BuddhistMonument /cidoc/monuments/
calendar Calendar System spatiotemporal CalendarSystem time:Calendar /cidoc/calendar_systems/
syncretism Syncretic Relationship conceptual SyncreticRelationship crm:E13_Attribute_Assignment /cidoc/syncretic_relationships/
kumari_tenure Living Goddess Tenure event LivingGoddessTenure crm:E4_Period /cidoc/kumari_tenures/
kumari_selection Living Goddess Selection event LivingGoddessSelection heritageGraph:LivingGoddessSelection /cidoc/kumari_selections/
kumari_retirement Living Goddess Retirement event LivingGoddessRetirement heritageGraph:LivingGoddessRetirement /cidoc/kumari_retirements/
documentation Documentation Activity provenance DocumentationActivity crm:E7_Activity /cidoc/documentation_activities/
caste_group Caste Group social CasteGroup crm:E74_Group /cidoc/caste_groups/
assertion Heritage Assertion provenance HeritageAssertion crminf:I2_Belief /cidoc/assertions/

Non-navigable (used as lookup/reference types)

Registry Key Label Ontology Class Purpose
material Material Material Physical substances used in construction/ritual
technique Technique Technique Craft methods used in production
religious_tradition Religious Tradition ReligiousTradition Reference for tradition dropdowns

Categories

Category Key Label Icon Entities
tangible Tangible Heritage landmark structure, iconography, monument, material, technique
conceptual Conceptual Entities lightbulb deity, tradition, syncretism, religious_tradition
event Events & Rituals calendar event, ritual, festival, kumari_tenure, kumari_selection, kumari_retirement
social Social Organizations users person, guthi, caste_group
spatiotemporal Spaces & Time map location, period, calendar
provenance Sources & Provenance book-open source, documentation, assertion

6. Controlled Vocabularies (Enums)

All enums live in heritage_graph_ui/src/lib/ontology/enums.ts. Each is an array of { value, label, description? }.

Enum Key Values Used By Ontology Source
ConditionTypeEnum Good, Damaged, Ruined, Restored Structure condition ConditionTypeEnum
ExistenceStatusEnum Extant, PartiallyExtant, Destroyed, Lost, Hypothetical, Unknown Structure/Monument status ExistenceStatusEnum
RitualTypeEnum 19 values (NityaPuja β†’ ProcessionalMovement) Ritual type RitualTypeEnum
DatePrecisionEnum Exact, Year, Decade, Century, Circa TimeSpan precision DatePrecisionEnum
ArchitecturalStyleEnum Pagoda, Shikhara, Dome, Chaitya, Stupa Structure style ArchitecturalStyleEnum
GuthiTypeEnum SiGuthi β†’ RajGuthi (8 types) Guthi classification GuthiTypeEnum
SyncreticTypeEnum Equivalence, Appropriation, Fusion, Historical Syncretic relationship type SyncreticTypeEnum
LocationTypeEnum city, village, region, temple, monument, museum, archaeological_site Place type Custom
SourceTypeEnum book, journal, archive, thesis, web, field_note, oral_history, inscription Source material type Custom
TraditionCategoryEnum ritual, dance, storytelling, craft, music, festival Tradition category Custom
EventTypeEnum festival, ritual, historical, ceremony Event classification Custom
RecurrenceEnum annual, biennial, monthly, one_time Event frequency Custom
ReligiousTraditionEnum Hindu, Buddhist, Syncretic, Jain, Animist, Other Deity/calendar tradition ReligiousTradition
CustodianTypeEnum government, academic, community, museum, private, religious Data custodian type Custom
DataCiteResourceTypeEnum Dataset, Text, Image, Audio, Interview, PhysicalObject, Collection Source resource type DataCite
IdentifierTypeEnum DOI, ISBN, Handle, URL, LocalArchiveID, ISSN Persistent ID type DataCite
VerificationMethodEnum cross_check, expert_review, field_visit, archival_comparison, oral_testimony Verification method Custom
DocumentationMethodEnum 8 methods (photographic_survey β†’ drone_survey) Documentation activity Custom
FestivalTypeEnum ChariotFestival, MaskedDance, Jatra, Other Festival classification Ontology
StructureTypeEnum 9 types (Temple β†’ Other) Structure classification Ontology subclasses
IconographicObjectTypeEnum Paubha, Murti, Other Iconographic object type Ontology subclasses
MonumentTypeEnum Stupa, Chaitya, Other Monument type Ontology subclasses

7. How to Make Changes

7.1 Add a Field to an Existing Entity

Scenario: Add a "patron_deity" field to the Guthi form.

Step 1 β€” Edit registry.ts:

Find the guthi definition and add to its fields array:

{
  key: "patron_deity",             // Must match Django model field name
  label: "Patron Deity",           // Human-readable label
  type: "relation",                // Field type (see Section 8)
  section: "function",             // Which section to place it in
  order: 2,                        // Sort order within section
  relationTo: "deity",             // Related ontology class key
  relationEndpoint: "/cidoc/deities/",  // API endpoint for search
  description: "Primary deity this Guthi serves"
},

Step 2 β€” Django model (if new field):

# heritage_graph/apps/cidoc_data/models.py
class Guthi(CIDOCBaseModel):
    # ... existing fields ...
    patron_deity = models.ForeignKey('Deity', null=True, blank=True, on_delete=models.SET_NULL)

Step 3 β€” Serializer + migration:

cd heritage_graph
python manage.py makemigrations cidoc_data
python manage.py migrate

Add the field to the serializer's Meta.fields list if needed.

That's it. The form, table, and detail view all update automatically.


7.2 Add a New Enum (Dropdown)

Scenario: Add a "MaterialTypeEnum" for construction materials.

Step 1 β€” Edit enums.ts:

Add inside the ontologyEnums object:

MaterialTypeEnum: [
  { value: "stone", label: "Stone", description: "Natural stone (brick, slate, marble)" },
  { value: "wood", label: "Wood", description: "Timber construction material" },
  { value: "brick", label: "Brick", description: "Fired clay brick" },
  { value: "metal", label: "Metal", description: "Bronze, copper, iron" },
  { value: "terracotta", label: "Terracotta", description: "Unglazed ceramic" },
],

Step 2 β€” Use it in a field:

{
  key: "primary_material",
  label: "Primary Material",
  type: "select",
  options: ontologyEnums.MaterialTypeEnum,
  section: "architecture",
  order: 4,
},

Step 3 β€” Django model:

Add corresponding choices tuple to the Django model field.


7.3 Add a New Entity Type

Scenario: Add an "Inscription" entity for stone/copper-plate inscriptions.

Step 1 β€” Define the class in registry.ts:

const inscription: OntologyClass = {
  key: "inscription",
  label: "Inscription",
  labelPlural: "Inscriptions",
  description: "Stone or copper-plate inscription with epigraphic content",
  classUri: "crm:E34_Inscription",
  icon: "file-text",                    // Lucide icon name
  apiEndpoint: "/cidoc/inscriptions/",  // Must match Django URL
  category: "tangible",                 // Category group
  navigable: true,                      // Show in sidebar/nav
  sections: [
    { key: "basic", label: "Basic Information" },
    { key: "content", label: "Epigraphic Content" },
    { key: "location", label: "Location" },
  ],
  fields: [
    nameField("Inscription Name"),
    { key: "script", label: "Script", type: "text", section: "content", order: 1,
      placeholder: "e.g., Lichhavi Brahmi, Ranjana", description: "Writing system used" },
    { key: "language", label: "Language", type: "text", section: "content", order: 2,
      placeholder: "e.g., Sanskrit, Nepal Bhasa" },
    { key: "transcription", label: "Transcription", type: "textarea", section: "content", order: 3,
      description: "Full transcription of the inscription text" },
    { key: "date_earliest", label: "Date", type: "text", section: "basic", order: 2,
      placeholder: "e.g., 464 CE (Lichhavi)" },
    { key: "location_name", label: "Location", type: "text", section: "location", order: 1 },
    { key: "coordinates", label: "Coordinates", type: "coordinates", section: "location", order: 2 },
    noteField(),
  ],
  columns: [
    { key: "name", label: "Name", sortable: true, visible: true },
    { key: "script", label: "Script", sortable: true, visible: true, format: "badge" },
    { key: "language", label: "Language", sortable: true, visible: true },
    { key: "date_earliest", label: "Date", sortable: true, visible: true },
  ],
};

Step 2 β€” Register it:

Add to the ontologyClasses export:

export const ontologyClasses: Record<string, OntologyClass> = {
  // ... existing entries ...
  inscription,
};

Step 3 β€” Create the contribute page:

Create heritage_graph_ui/src/app/dashboard/contribute/inscription/page.tsx:

"use client";

import OntologyForm from "@/components/ontology-form";
import { getOntologyClass } from "@/lib/ontology";

export default function ContributeInscriptionPage() {
  const cls = getOntologyClass("inscription")!;
  return <OntologyForm ontologyClass={cls} />;
}

Step 4 β€” Add to contribute dashboard (optional):

Edit heritage_graph_ui/src/app/dashboard/contribute/page.tsx β€” add an entry to contributionIntents:

{
  key: "inscription",
  label: "Record an Inscription",
  description: "Stone or copper-plate inscriptions with transcription and dating.",
  icon: "πŸ“œ",
  category: "Tangible Heritage",
  route: "/dashboard/contribute/inscription",
  difficulty: "advanced",
  gradient: "from-blue-500 to-sky-600",
},

Step 5 β€” Django backend:

  1. Add model in heritage_graph/apps/cidoc_data/models.py
  2. Add serializer in serializers.py
  3. Add ViewSet in views.py
  4. Register route in urls.py β†’ router.register(r'inscriptions', InscriptionViewSet)
  5. Run makemigrations + migrate

Step 6 β€” Knowledge page (auto-generated):

Create heritage_graph_ui/src/app/dashboard/knowledge/inscription/page.tsx following the same pattern as other knowledge pages.


7.4 Add a Relation Field (Entity Linking)

Relation fields let users link entities together (e.g., "this ritual invokes deity X").

{
  key: "invokes_deity",              // Django field name
  label: "Invokes Deity",            // Form label
  type: "relation",                  // Must be "relation"
  section: "participation",          // Form section
  order: 2,
  relationTo: "deity",               // Registry key of the related class
  relationEndpoint: "/cidoc/deities/", // API endpoint for autocomplete search
  multivalued: true,                 // Allow linking multiple entities
  description: "Deity invoked or made present through ritual"
},

The EntitySearch component renders an autocomplete dropdown that calls the related API endpoint.


7.5 Add a New Form Section

Sections visually group fields in the form. Add to the sections array:

sections: [
  { key: "basic", label: "Basic Information" },
  { key: "provenance", label: "Provenance & Sources" },       // ← new
  { key: "status", label: "Status & Condition", description: "Current physical state" },
],

Then set section: "provenance" on any field you want in that group.


7.6 Add to the Contribute Dashboard

The contribute page at /dashboard/contribute/ shows intent cards grouped by category.

Edit heritage_graph_ui/src/app/dashboard/contribute/page.tsx:

// Add to the contributionIntents array
{
  key: "your_entity",               // Unique key
  label: "Your Label",              // Card title
  description: "Description...",    // Card description
  icon: "πŸ›οΈ",                      // Emoji icon
  category: "Tangible Heritage",    // Category group header
  route: "/dashboard/contribute/your-entity",  // Must match page route
  difficulty: "beginner",           // beginner | intermediate | advanced
  gradient: "from-blue-500 to-sky-500",       // Tailwind gradient
},

8. Field Type Reference

Type Renders As When to Use Example
text Single-line input Short strings, names, dates as text Name, aliases, "c. 1200 CE"
textarea Multi-line textarea Long descriptions, notes, transcriptions Biography, route description
number Number input Integer values Year offset, start year
float Number input (decimal) Decimal values Confidence score (0.0–1.0)
date Date picker ISO dates Last known existence date
select Dropdown Pick one from enum Structure type, ritual type
multiselect Multi-select Pick many from enum (not yet fully implemented)
boolean Checkbox Yes/no flags is_critical_for_festival
url URL input Web links Digital source URL
coordinates Lat/Long input GPS positions Structure coordinates
relation Entity search autocomplete Link to another entity Deity β†’ Structure, Ritual β†’ Festival

9. OntologyClass Interface

interface OntologyClass {
  key: string;            // Machine key ("structure", "deity")
  label: string;          // Human label ("Architectural Structure")
  labelPlural: string;    // Plural ("Architectural Structures")
  description: string;    // From ontology description
  classUri?: string;      // CIDOC-CRM URI ("crm:E22_Human-Made_Object")
  parentClass?: string;   // Inheritance ("structure" β†’ "monument")
  icon?: string;          // Lucide icon name
  apiEndpoint: string;    // Django API route ("/cidoc/structures/")
  fields: OntologyField[];    // Form fields
  columns: OntologyColumn[];  // Data table columns
  sections?: { key, label, description? }[];  // Form section groupings
  navigable?: boolean;    // Show in sidebar/nav? (default: false)
  category?: string;      // "tangible"|"conceptual"|"event"|"social"|"spatiotemporal"|"provenance"
}

10. OntologyField Interface

interface OntologyField {
  key: string;            // Must match Django model field name exactly
  label: string;          // Human-readable label
  type: FieldType;        // "text"|"textarea"|"select"|"relation"|...
  description?: string;   // Help text below the field
  required?: boolean;     // Form validation
  options?: Array<{ value, label, description? }>;  // For select/multiselect
  relationTo?: string;    // For relation: related class registry key
  relationEndpoint?: string;  // For relation: API endpoint for search
  multivalued?: boolean;  // Accept multiple values
  section?: string;       // Section key for grouping
  order?: number;         // Sort order within section
  placeholder?: string;   // Input placeholder text
  defaultValue?: any;     // Default value
}

11. Ontology ↔ Backend Model Alignment

Every frontend entity class must have a corresponding Django model, serializer, ViewSet, and URL route.

Checklist for adding a new entity:

Step File What to do
1 cidoc_data/models.py Add Django model with fields matching registry key values
2 cidoc_data/serializers.py Add ModelSerializer
3 cidoc_data/views.py Add ModelViewSet
4 cidoc_data/urls.py Register with router: router.register(r'endpoint', ViewSet)
5 Run migrations python manage.py makemigrations cidoc_data && python manage.py migrate
6 ontology/enums.ts Add any new enums
7 ontology/registry.ts Add OntologyClass definition
8 contribute/<key>/page.tsx Create contribute page
9 contribute/page.tsx Add intent card

Key field name mapping rules:

  • Registry key β†’ Django model field name β†’ API JSON key (all identical)
  • coordinates fields serialize as "lat,long" strings
  • select field value must match Django choices tuple first element
  • relation fields typically map to ForeignKey or ManyToManyField in Django

12. Data Flow: Form β†’ API β†’ Database

User fills form
      β”‚
      β–Ό
OntologyForm component reads class definition from registry
      β”‚
      β–Ό
Collects field values, validates required fields
      β”‚
      β–Ό
POST to apiEndpoint (e.g., /cidoc/structures/)
with Authorization: Bearer <session.accessToken>
      β”‚
      β–Ό
Django REST Framework serializer validates & saves
      β”‚
      β–Ό
PostgreSQL (prod) / SQLite (dev) stores the data
      β”‚
      β–Ό
Knowledge table fetches via GET to same apiEndpoint

13. CIDOC-CRM Alignment Reference

The ontology is fully aligned with CIDOC-CRM (ISO 21127). Key mappings:

HeritageGraph Class CIDOC-CRM Class Role
ArchitecturalStructure E22 Human-Made Object Physical heritage objects
Temple, Stupa, Chaitya E22 (subclassed) Domain-specific subtypes
Deity E28 Conceptual Object Divine concepts (not physical)
Person E21 Person Actors who perform activities
Guthi E74 Group Social organizations
Place E53 Place Geographic locations
TimeSpan E52 Time-Span Temporal extents
Production E12 Production Object creation events
RitualEvent E7 Activity Intentional activities
Consecration E7 Activity Ritual activation events
Enshrinement E7 Activity Deity installation events
TransferOfCustody E10 Transfer of Custody Stewardship changes
ConditionAssessment E14 Condition Assessment Condition evaluations
DataSource E73 Information Object Documentary sources
HeritageAssertion CRMinf I2 Belief Propositional claims
SyncreticRelationship E13 Attribute Assignment Syncretic equivalence claims

Key properties (slots):

HeritageGraph Slot CIDOC-CRM Property Meaning
name rdfs:label Primary label
note P3 has note Free-text description
has_current_location P55 has current location Current location
was_produced_by_event P108i was produced by Production link
carried_out_by P14 carried out by Actor who performed event
has_timespan P4 has time-span Temporal extent
took_place_at P7 took place at Event location
depicts_deity P62 depicts Iconographic depiction
enshrined_deity P12 occurred in the presence of Deity installed
invokes_deity P12 occurred in the presence of Deity invoked

14. PROV-O Provenance Layer

HeritageGraph implements assertion-level provenance using PROV-O:

HeritageAssertion (prov:Entity / crminf:I2_Belief)
  β”œβ”€β”€ assertion_content       β†’ prov:value (the claim text)
  β”œβ”€β”€ asserted_property       β†’ what property is being claimed
  β”œβ”€β”€ asserted_value           β†’ the claimed value
  β”œβ”€β”€ was_derived_from_source β†’ prov:wasDerivedFrom β†’ DataSource
  β”œβ”€β”€ was_attributed_to_agent β†’ prov:wasAttributedTo β†’ Person
  β”œβ”€β”€ generated_at_time        β†’ prov:generatedAtTime (ISO datetime)
  β”œβ”€β”€ confidence_score         β†’ 0.0–1.0 reliability
  β”œβ”€β”€ reconciliation_status    β†’ confirmed | conflicting | unverified
  └── supersedes_assertion     β†’ prov:invalidated (version chain)

This means every factual claim about a heritage entity can be traced back to:

  • Who said it (agent)
  • When they said it (timestamp)
  • Where they got it (source)
  • How confident we are (score)
  • Whether it conflicts with other claims (reconciliation)

15. Troubleshooting & Common Mistakes

Form field doesn't appear

  • βœ… Check section matches a key in the class's sections array
  • βœ… Check order is set (fields without order sort unpredictably)
  • βœ… Check the class is exported in ontologyClasses in registry.ts

Dropdown shows empty

  • βœ… Check type: "select" is set
  • βœ… Check options: ontologyEnums.YourEnum points to an existing enum
  • βœ… Check the enum is properly exported from enums.ts

API call returns 404

  • βœ… Check apiEndpoint matches the Django URL route exactly (including trailing slash)
  • βœ… Check the ViewSet is registered in cidoc_data/urls.py
  • βœ… Check the backend is running

Field saves but doesn't load on edit

  • βœ… Check the Django serializer includes the field in Meta.fields
  • βœ… Check the field key exactly matches the model field name (case-sensitive)

Relation field autocomplete doesn't search

  • βœ… Check relationEndpoint is correct (must be a valid API endpoint)
  • βœ… Check the related entity's ViewSet supports search/list

Entity doesn't show in sidebar

  • βœ… Check navigable: true is set on the class
  • βœ… Check category is set to a valid category key

New contribute page shows blank

  • βœ… Check getOntologyClass("your_key") uses the correct registry key
  • βœ… Check the file is at contribute/your-route/page.tsx
  • βœ… Check the contribute dashboard card's route matches the page path

16. File Map

heritage_graph_ui/
└── src/
    β”œβ”€β”€ lib/ontology/
    β”‚   β”œβ”€β”€ types.ts              # TypeScript interfaces
    β”‚   β”œβ”€β”€ enums.ts              # 22 controlled vocabularies
    β”‚   β”œβ”€β”€ registry.ts           # 24 entity class definitions
    β”‚   └── index.ts              # Barrel export
    β”‚
    β”œβ”€β”€ components/
    β”‚   β”œβ”€β”€ ontology-form.tsx     # Auto-generates forms from registry
    β”‚   └── contribute/
    β”‚       β”œβ”€β”€ step-wizard.tsx   # Multi-step wizard container
    β”‚       β”œβ”€β”€ step-indicator.tsx # Wizard progress bar
    β”‚       β”œβ”€β”€ type-picker.tsx   # Card-based type selector
    β”‚       β”œβ”€β”€ entity-search.tsx # Autocomplete entity linker
    β”‚       └── assertion-wrapper.tsx # Provenance fields
    β”‚
    └── app/dashboard/
        β”œβ”€β”€ contribute/
        β”‚   β”œβ”€β”€ page.tsx          # Contribute dashboard (21 intent cards)
        β”‚   β”œβ”€β”€ person/page.tsx   # Person form
        β”‚   β”œβ”€β”€ deity/page.tsx    # Deity form
        β”‚   β”œβ”€β”€ structure/page.tsx # Structure wizard
        β”‚   β”œβ”€β”€ ritual/page.tsx   # Ritual wizard
        β”‚   β”œβ”€β”€ festival/page.tsx # Festival form
        β”‚   β”œβ”€β”€ guthi/page.tsx    # Guthi form
        β”‚   β”œβ”€β”€ location/page.tsx # Place form
        β”‚   β”œβ”€β”€ source/page.tsx   # Source form
        β”‚   β”œβ”€β”€ event/page.tsx    # Event form
        β”‚   β”œβ”€β”€ period/page.tsx   # Period form
        β”‚   β”œβ”€β”€ tradition/page.tsx # Tradition form
        β”‚   β”œβ”€β”€ iconography/page.tsx # Iconographic object form
        β”‚   β”œβ”€β”€ monument/page.tsx # Monument form
        β”‚   β”œβ”€β”€ calendar/page.tsx # Calendar system form
        β”‚   β”œβ”€β”€ syncretism/page.tsx # Syncretic relationship form
        β”‚   β”œβ”€β”€ kumari-tenure/page.tsx    # Living Goddess tenure form
        β”‚   β”œβ”€β”€ kumari-selection/page.tsx  # Living Goddess selection form
        β”‚   β”œβ”€β”€ kumari-retirement/page.tsx # Living Goddess retirement form
        β”‚   β”œβ”€β”€ documentation/page.tsx    # Documentation activity form
        β”‚   β”œβ”€β”€ caste-group/page.tsx      # Caste group form
        β”‚   └── assertion/page.tsx        # Heritage assertion form
        β”‚
        └── knowledge/
            └── [domain]/page.tsx  # Auto-generated data tables

ontology/
β”œβ”€β”€ HeritageGraph.yaml   # Canonical LinkML schema (source of truth)
└── Heritage.ttl         # Generated OWL/Turtle

heritage_graph/apps/cidoc_data/
β”œβ”€β”€ models.py            # Django models (must match field keys)
β”œβ”€β”€ serializers.py       # DRF serializers
β”œβ”€β”€ views.py             # ViewSets + search
└── urls.py              # API route registration

See also: FORMS.md for detailed form mechanics, AGENTS.md for full project context, ARCHITECTURE.md for system design.