Hierarchies in MakeItMakeSense.io
This document describes the structure, management, and usage of hierarchies within the MakeItMakeSense.io platform. Hierarchies provide a way to organize nodes into structured, multi-level categorizations, and a single node can belong to multiple hierarchies simultaneously.
Core Schema Entities
The hierarchy system is built upon several key Dgraph schema types that define its structure and relationships:
Node: These are the primary content entities within the graph. Nodes can be associated with one or more hierarchies throughHierarchyAssignmentobjects.Hierarchy: This type represents a distinct hierarchical tree or organizational structure (e.g., "Technical Skills," "Project Categories"). Each hierarchy has a name and contains multiple levels.HierarchyLevel: This type defines a specific tier or depth within a particularHierarchy(e.g., "Programming Languages" as a level within "Technical Skills"). Each level has a number and an optional descriptive label. It can also (optionally) specify allowed node types.HierarchyLevelType: Specifies whichNodetypes are permitted at a givenHierarchyLevel, controllingallowedTypesconsumed by both backend validation and UI filtering.HierarchyAssignment: This is the central linking type. An instance ofHierarchyAssignmentexplicitly connects aNodeto a specificHierarchyLevelwithin a particularHierarchy. This record is what places a node into the hierarchical structure.
For detailed Dgraph schema definitions and GraphQL interaction patterns related to these types, please refer to the Dgraph Schema Notes.
(Note: The HierarchyLevelType feature for restricting node types at specific levels is now actively enforced by the backend API during node assignment.)
Rationale for the HierarchyAssignment Model
The use of an intermediate HierarchyAssignment type (rather than a direct link from Node to HierarchyLevel) offers several advantages:
-
Multi-Hierarchy Support: This is the primary benefit. A single
Nodecan have multipleHierarchyAssignmentobjects, each linking it to a differentHierarchy(or even different levels within the same hierarchy, though less common). This allows for rich, multi-faceted organization of knowledge. For example, a "Python" node could be in a "Technical Skills" hierarchy at the "Programming Language" level, and simultaneously in a "Project Stack" hierarchy at the "Backend Technologies" level. -
Rich Relationship Information (Future-Proofing): The
HierarchyAssignmentnode itself can be expanded to store metadata about the assignment. For instance, one could add fields likeassignmentDate,assignedBy, orrelevanceInHierarchydirectly to theHierarchyAssignmenttype. This would be difficult if nodes linked directly to levels. -
Querying Flexibility: This model allows for versatile querying, such as finding all nodes in a specific level of a specific hierarchy, or all hierarchical contexts a particular node belongs to.
-
Clear Semantics: It explicitly models the "act of assignment" as a first-class entity in the graph.
The main trade-off is a slightly more verbose data structure (an extra "hop" through the assignment node), but this is generally outweighed by the flexibility gained, especially for multi-hierarchy requirements.
Hierarchy Management and Usage
Backend API
-
Direct Management (CRUD Operations):
- The API provides RESTful endpoints (primarily under
/api/hierarchy/...) for creating, reading, updating, and deletingHierarchy,HierarchyLevel, andHierarchyAssignmententities. These are publicly accessible as hierarchies are user-managed knowledge organization tools. - Refer to
docs/api-endpoints.mdfor detailed endpoint specifications.
- The API provides RESTful endpoints (primarily under
-
Automatic Assignment during Node Creation (
POST /api/mutatewithaddNode):- When new nodes are created via the
addNodeGraphQL mutation, the API server includes logic (implemented inroutes/graphql.tsandservices/nodeEnrichment.ts) to automatically create aHierarchyAssignment. - Processing Priority for Assignment (Current Implementation):
- Client-Provided
hierarchyAssignmentsArray (Primary): The server first checks if the client provides ahierarchyAssignmentsarray in the input. This is the standard structure sent by the frontendNodeFormModal. If present:- Extracts
hierarchy.idandlevel.idfrom the nested structure - Validates the hierarchy and level IDs exist
- Validates the node type is allowed at the specified level
- Preserves the client's
hierarchyAssignmentsstructure in the Dgraph mutation
- Extracts
- Top-Level
levelId(Compatibility): If nohierarchyAssignmentsarray is provided, checks for a top-levellevelIdproperty. If present:- Uses the
X-Hierarchy-Idheader for the hierarchy context - Validates the level ID and node type compatibility
- Constructs a
hierarchyAssignmentsstructure for Dgraph
- Uses the
- Parent Node Context (Calculated): If neither
hierarchyAssignmentsnorlevelIdis provided, but aparentIdis specified:- Uses
getLevelIdForNodeto calculate the appropriate level (parent's level + 1) - Validates the calculated level and node type compatibility
- Constructs a
hierarchyAssignmentsstructure for Dgraph
- Uses
- Client-Provided
- Header Requirements: The
X-Hierarchy-Idheader is required foraddNodeoperations to provide hierarchy context for cases 2 and 3. - Validation: All hierarchy and level IDs are validated for existence, and node types are checked against level restrictions (
allowedTypes). - Error Handling: Returns 400 Bad Request for missing headers, invalid IDs, or type restrictions violations.
- When new nodes are created via the
Frontend Interaction
-
HierarchyContext(frontend/src/context/HierarchyContext.tsx):- Manages the application-wide state for available hierarchies, the currently selected
hierarchyId, and the levels of that selected hierarchy. - Fetches hierarchy data from
GET /api/hierarchyand level data using a GraphQL query. - The
setHierarchyIdfunction updates the selected hierarchy in the context and automatically updateslocalStorage.setItem('hierarchyId', newId), ensuring synchronization forApiService.
- Manages the application-wide state for available hierarchies, the currently selected
-
ApiService(frontend/src/services/ApiService.ts):- When
executeMutationis called, it readshierarchyIdfromlocalStorageand, if present, adds it as anX-Hierarchy-Idheader to the request. This provides the backend with the "active hierarchy" context for its automatic assignment logic.
- When
-
NodeFormModal(frontend/src/components/NodeFormModal.tsx):- Allows users to select the target
HierarchyandHierarchyLevelwhen creating a new node. - Automatically updates available node types based on the selected level's restrictions.
- Synchronizes the selected type with available types when level selection changes.
- On submission, constructs a
hierarchyAssignmentsarray with the chosenhierarchyIdandlevelId. - Passes this structure to
useGraphState.addNode, which sends it to the backend as the primary source of hierarchy assignment information.
- Allows users to select the target
Data Flow Summary
The complete node creation flow with hierarchy assignment works as follows:
- User Interaction: User opens NodeFormModal and selects hierarchy, level, type, and label
- Frontend Validation: Modal ensures selected type is allowed at the chosen level
- Form Submission: Modal constructs
hierarchyAssignmentsarray and callsuseGraphState.addNode - API Request: Frontend sends mutation with
hierarchyAssignmentsstructure andX-Hierarchy-Idheader - Server Processing: Server processes the
hierarchyAssignmentsarray (Case 1), validates hierarchy/level/type compatibility - Database Storage: Server preserves the client's hierarchy assignment structure in the Dgraph mutation
- Response: Node is created with proper hierarchy assignment
Seeding
- The
tools/seed_data.pyscript demonstrates the programmatic creation of hierarchies, levels, andHierarchyLevelTypeentities using the API. It also shows how to create nodes and assign them to hierarchies, respecting the validation rules (e.g., by passing theX-Hierarchy-Idheader for mutations).
This multi-faceted approach allows for both explicit control over hierarchy assignments (primarily driven by the frontend UI or direct API calls) and robust server-side validation, with the frontend-provided hierarchyAssignments structure taking precedence over other assignment methods.