Structures Data
Research organizations β institutions, laboratories, teams β are a key part of the research information managed by CRISalid. Getting them into the graph is often the first step, and it can involve some work: mapping your local identifiers, encoding the hierarchy, handling supervision relationships between units and institutions. This page is here to help you through it.
Two options to connect to institutional directories
CRISalid directory bridge offers two ways to feed structure data into the knowledge graph. Both produce the same AMQP message format consumed by the IKG middleware.
| Option | Source | DAG | Best suited for |
|---|---|---|---|
| 1 β LDAP + spreadsheet | LDAP directory (SUPANN 2021) + CSV complement | load_ldap_structures |
Institutions with a SUPANN-compliant directory |
| 2 β Spreadsheet | CSV spreadsheet | load_spreadsheet_structure |
Manual curation, institutions without LDAP, graduate schools, cross-institutional units |
Option 1 β LDAP + spreadsheet
The load_ldap_structures DAG queries an LDAP directory filtered on SUPANN object classes and converts entries into IKG-compliant structure records.
Key LDAP attributes used: supannCodeEntite (identifier), supannCodeEntiteParent (hierarchy), supannTypeEntite, supannRefId (external identifiers such as ROR, NNS), eduOrgLegalName, ou, description, businessCategory, labeledURI.
CSV complement
When OVERRIDE_LDAP_STRUCTURE_DATA_FROM_SPREADSHEET=True, the DAG also reads a CSV file and merges it into the LDAP results: any non-empty CSV value overwrites the corresponding LDAP field, while LDAP values are kept where the CSV is blank. Use it to supply fields that LDAP does not carry (national identifiers, tutelle relationships, HAL collections, research classifications) or to add structures not listed in LDAP. A CSV-only structure (absent from LDAP) is added to the result set; a structure with generic_type=ignore is dropped.
Generating a CSV template from live LDAP
Rather than building the CSV from scratch, use the provided script to pre-fill it from your live directory:
APP_ENV=DEV python scripts/generate_structure_template.py --output data/structures.csvThe script connects to LDAP using the credentials defined in the environment file matching APP_ENV (.env.dev, .env.staging, .env.prod, β¦), fetches all structures, and writes a CSV with one row per entry. It maps the fields it can derive from LDAP (local_id, short_labels, long_labels, descriptions, web, main_mission, inclusions) and leaves the rest blank for you to fill in. Redirect to stdout by omitting --output.
Once you have the template you can open it in a spreadsheet editor or edit it directly, then use the tools below to validate and sort it before ingestion.
Option 2 β Spreadsheet
The load_spreadsheet_structure DAG (in crisalid-directory-bridge) reads a UTF-8 CSV file whose columns follow the CRISalid structures format. This is the recommended path for structures that are not in the institutional LDAP, or for institutions that prefer to maintain a fully curated file.
File format reference
The full column specification and annotation syntax (labels with language tags, relationship entries with supervision codes and date ranges) is documented on the wiki:
π Import des donnΓ©es structures on the CRISalid Esup Portail wiki
Tooling for CSV files
Three standalone Python scripts are available in the repository to prepare and inspect a structures CSV β whether you use the LDAP+CSV combined path or the pure spreadsheet path. They require only the standard library (no Airflow, no virtualenv).
Fixing row ordering
The CSV is processed row by row, so any structure referenced in inclusions or participations must appear in an earlier row than the structure that references it. If you have ordering violations β for example after inserting rows manually β the sort script rewrites the file in the correct topological order:
python scripts/sort_structures.py path/to/structures.csvThe script uses Kahnβs topological sort and preserves the original relative order of rows as much as possible. If a circular dependency is detected it prints a warning and leaves the file unchanged.
Validating the CSV
python .claude/commands/check_structures.py path/to/structures.csvPrints all errors and warnings with row numbers, then exits with a non-zero status if errors are found.
What it checks:
- Required columns and fields
local_idformat (max 10 chars, alphanumeric /-/_/:)- Duplicate
local_idvalues;generic_type=ignorerows are only checked for duplicates - National type compatibility with
generic_type(fetched live from the IKG model) - Mission fields (
main_missionrequired and valid for units; warns if set on other types) - Conditional identifier requirements (UAI for institutions; NNS or ROR for research units)
- Identifier format (bare ROR/ISNI IDs, RNSR pattern for NNS)
- Reference integrity β every
local-*target must exist in the file - Ordering β a referenced structure must appear in an earlier row
- Isolation β warns on teams and unit subdivisions with no parent
- Date annotation format (YYYYMMDD)
- Label language tags
Visualising the hierarchy
python .claude/commands/visualize_structures.py path/to/structures.csv [output.html] \
[--root-institution LOCAL_ID]Generates a self-contained HTML file (no server required, opens in any browser). --root-institution sets the root node used for the initial viewport centering and the default 1-level expanded view; omit it to start fully expanded. If output.html is not specified, the file is written next to the CSV with the same basename.
As Claude Code slash commands
If you use Claude Code inside the crisalid-directory-bridge repository, the same tools are available as slash commands:
/check-structures path/to/structures.csv
/visualize-structures path/to/structures.csv [output.html]