Skip to content

feat(core): add entity graph endpoint and service#56

Open
brandPittCode wants to merge 57 commits into
mainfrom
feat/entity-graph
Open

feat(core): add entity graph endpoint and service#56
brandPittCode wants to merge 57 commits into
mainfrom
feat/entity-graph

Conversation

@brandPittCode

@brandPittCode brandPittCode commented May 20, 2026

Copy link
Copy Markdown
Collaborator

PR Description

What this PR Provides

This pull request introduces add new domain models and ports for entity graph traversal. Additionally, the package structure is refined to organize exceptions and services by subdomain.

Entity Graph Modeling

  • New domain models are introduced for entity graph traversal: EntityGraphNode and EntityGraphRelation, supporting hierarchical visualization and traversal of entity relationships.
  • A new port interface, EntityGraphRepositoryPort, defines the contract for retrieving entity relationship graphs with support for depth, property inclusion, and efficient lookups.

Domain Model Enhancements

Code Consistency

  • Several domain model and exception classes now explicitly import related types for clarity and consistency.

These changes collectively improve the robustness, clarity, and scalability of the domain layer.

Fixes

Review

The reviewer must double-check these points:

  • The reviewer has tested the feature
  • The reviewer has reviewed the implementation of the feature
  • The documentation has been updated
  • The feature implementation respects the Technical Doc / ADR previously produced
  • The Pull Request title has a ! after the type/scope to identify the breaking
    change in the release note and ensure we will release a major version.

How to test

This guide explains how to manually test the entity graph feature without assuming any pre-existing data. You will set up a 5-node graph structure to validate all filtering capabilities and the edge-case boundaries of the Traversal Mode mechanics.

Graph Structure Required
To thoroughly test all directionality modes—especially the sibling-exclusion rules of DIRECT_LINEAGE—you need a graph with the following characteristics:

Entities
Create 5 entities:

Entity X (Upstream Parent/Consumer) - points into our root node, and also points into a sibling node.

Entity A (Root Node) - the designated entry point for your test queries.

Entity B (Middle Downstream Node) - connected downstream from A, upstream from C.

Entity C (Leaf Downstream Node) - furthest downstream node from the root path.

Entity Y (Sibling Node) - an independent downstream node also connected to Entity X. This node must be excluded during Direct Lineage queries from Entity A.

Properties
Each entity should have 2 properties to test property filtering:

Property 1 - e.g., tier, environment, status

Property 2 - e.g., version, owner, region

Use different values for each entity so you can verify that property data maps accurately.

Relations
Create 2 types of relations to test relation filtering and directionality:

Relation Type 1 - forward dependency chain (X → A → B → C) and the sibling link (X → Y).

Relation Type 2 - a secondary alternative forward path (A → B).

Graph topology:

Plaintext
+--[Relation-Type-1]----> Entity Y (Should be excluded in DIRECT_LINEAGE from A)
|
Entity X ---+--[Relation-Type-1]----> Entity A --[Relation-Type-1]----> Entity B --[Relation-Type-1]----> Entity C
Entity A --[Relation-Type-2]----> Entity B

✅ Scenario 1: Traversal Mode = BIDIRECTIONAL
Goal: Walk full relationships recursively across all nodes, collecting every forward (outbound) and backward (inbound) edge adjacent to any discovered node in the tree pool.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false&traversal_mode=BIDIRECTIONAL

Expected Behavior:

Returns all 5 nodes (A, B, C, X, and Y).

From Entity A: Returns outbound links to B (type-1 & type-2) and its inbound link from X (type-1).

From Entity X: Returns outbound links to both A and Y. Because it goes bidirectional, it discovers Entity Y.

From Entity Y: Returns its inbound link from X.

What to verify:

Full global network transparency: relations (outbound) and relationsAsTarget (inbound) fields are populated for every node within the matching depth radius, including the sibling branch (Entity Y).

✅ Scenario 2: Traversal Mode = OUTBOUND_ONLY
Goal: Strictly follow forward dependency links downstream from the root entity. Upstream consumers and side branches must be entirely omitted.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false&traversal_mode=OUTBOUND_ONLY

Expected Behavior:

Returns 3 nodes (A, B, C).

Excludes Entity X and Entity Y entirely (since they do not sit downstream from A).

From Entity A: Returns outbound edges to B.

From Entity B: Returns outbound edge to C.

The relationsAsTarget (inbound) arrays are completely empty for all nodes in the response.

What to verify:

Node count = 3 (Entity X and Y are missing).

No inbound array properties are populated anywhere in the payload.

✅ Scenario 3: Traversal Mode = DIRECT_LINEAGE
Goal: Isolate explicit routing paths by keeping outbound lines downstream and inbound lines upstream. This scenario explicitly validates that sideways/sibling "noise" (Entity Y) is pruned out.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false&traversal_mode=DIRECT_LINEAGE

Expected Behavior:

Returns 4 nodes (A, B, C, X).

CRITICAL EXCLUSION: Entity Y is completely excluded from the response. Even though Entity X is fetched (as A's inbound parent), the engine does not follow X's other outbound paths down to sibling nodes.

From Entity A (Root): Shows both its outbound paths (to B) and its inbound paths (from X).

From Entity X: Shows outbound to A, but its relationship array to Y is omitted or ignored for traversal.

From Entity B & C: Evaluates only their outbound paths further down.

What to verify:

High-fidelity lineage line tracing: Node count = 4. Verify Entity Y is completely absent from the graph array pool.

🔍 Relation & Property Filtering Testing
✅ Scenario 4: Full Graph (No Filters)
Goal: Return nodes and edges using default traversal context.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false
What to verify:

Each edge has correct source, target, and type based on the system's default mode.

✅ Scenario 5: Filter by Relation Type 1
Goal: Only traverse edges of Relation-Type-1.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false&relations=relation-type-1
Expected Behavior:

Traverses along the type-1 network route chain.

Excludes the A→B type-2 edge from the resulting structures.

✅ Scenario 6: Filter by Relation Type 2
Goal: Only traverse edges of Relation-Type-2 out from the root.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=false&relations=relation-type-2
Expected Behavior:

Returns 2 nodes (A, B only).

Returns 1 edge (A→B type-2).

Excludes Entities C, X, and Y (since they are not linked via type-2 relations from the root traversal track).

✅ Scenario 7: Include All Properties
Goal: Return property data for all discovered nodes.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=true
Expected Behavior:

Discovered nodes contain a populated data object with both property-1 and property-2 keys.

Example node structure:

{
  "id": "template:entityA",
  "templateIdentifier": "template",
  "identifier": "entityA",
  "name": "Entity A Name",
  "data": {
    "property-1": "value-a-1",
    "property-2": "value-a-2"
  }
}

✅ Scenario 8: Filter Property 1 Only
Goal: Return only property-1 in node data payloads.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=true&properties=property-1
Expected Behavior:

Each node's data object contains only property-1.

property-2 is completely excluded from the response object keys (not set to null).

✅ Scenario 9: Non-Existent Property Filter
Goal: Request a property key name that doesn't exist on any system template definition.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=true&properties=non-existent-property
Expected Behavior:

Returns matching nodes without a data field block. The data key is entirely omitted from the JSON dictionary.

✅ Scenario 10: Combine Relation + Property Filters
Goal: Apply both relation type and property selection restrictions simultaneously.

Request:

HTTP GET /api/v1/entities/{template}/{entityA}/graph?depth=3&include_data=true&relations=relation-type-1&properties=property-1

Expected Behavior:

Returns only nodes and edges found along the relation-type-1 path.

Each returned node contains a data block containing only property-1.

❌ Error Boundary Validation
❌ Scenario 11: Entity Not Found
Request:

HTTP GET /api/v1/entities/{template}/non-existent-entity/graph?depth=3&include_data=false
Expected Behavior:

HTTP 404 Not Found with a clear response body stating the entity identifier does not exist.

❌ Scenario 12: Template Not Found
Request:

HTTP GET /api/v1/entities/non-existent-template/{entityA}/graph?depth=3&include_data=false
Expected Behavior:

HTTP 404 Not Found. Fail-fast validation catches that the template does not exist before executing any database lookups.

Breaking changes (if any)

  • N/A

@brandPittCode brandPittCode changed the title Feat/entity graph feat(core): add entity graph endpoint and service May 20, 2026
@gitguardian

gitguardian Bot commented May 28, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
30005138 Triggered Generic Password 1c6cca0 src/test/java/com/decathlon/idp_core/AbstractIntegrationTest.java View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Comment thread src/test/java/com/decathlon/idp_core/AbstractIntegrationTest.java Fixed
@github-code-quality

github-code-quality Bot commented Jun 11, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: Java

Java / code-coverage/jacoco

The overall coverage in the branch is 89%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File d1e11d3 +/-
com/decathlon/i...rDslParser.java 99%
com/decathlon/i...ionService.java 99%
com/decathlon/i...ityService.java 94%
com/decathlon/i...aphService.java 92%
com/decathlon/i...MapperImpl.java 88%
com/decathlon/i...ionHandler.java 87%
com/decathlon/i...oOutMapper.java 87%
com/decathlon/i...ionService.java 87%
com/decathlon/i...cification.java 80%
com/decathlon/i...ionService.java 77%

Updated June 17, 2026 12:22 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@brandPittCode brandPittCode marked this pull request as ready for review June 11, 2026 09:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 42 changed files in this pull request and generated 13 comments.

Comment thread src/main/resources/db/migration/V5_1__add_target_entity_uuid.sql
Comment thread src/main/java/com/decathlon/idp_core/domain/port/EntityGraphRepositoryPort.java Outdated
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants