Resource Registry — Data Representation (Instances)

Instance Representation

System-Generated Fields

When reading instances via the REST API, the service automatically injects operational fields to assist the client.

Order of System Fields

According to the JSON specification, an object is an unordered set of name/value pairs. Therefore, the exact ordering of keys in the REST API payloads is not technically guaranteed by the server, nor is the server expecting clients to submit payloads in a strict order.

However, purely for didactic purposes, all JSON examples presented in this documentation follow a standardized, predictable ordering for the foundational system fields at the top of the object, before declaring any type-specific data fields:

  1. type

  2. supertypes

  3. id

  4. metadata

  5. contexts

It is important to note that the instance examples presented below are as rich as possible to illustrate the full structural representation. However, in standard REST operations, fields like metadata and contexts might not be returned in the payload depending on the client’s request (e.g., via specific query parameters).

type Field

In a federated graph supporting an Open-World Paradigm and dynamic schemas, every instance must explicitly declare “what it is”. The type field serves this primary purpose: it identifies the exact concrete schema that governs the instance. Knowing the exact type enables both the server and the clients to perform proper validation, polymorphic deserialization, and dynamic class instantiation. As detailed below, if a client does not natively recognize the specific type declared (e.g., because a new schema was installed at runtime), it relies on the supertypes array to gracefully fall back to a known abstraction.

supertypes Array

The supertypes array lists the direct parent Types followed by their ancestors. It provides a robust polymorphic fallback mechanism for clients parsing the JSON: if a client encounters an instance of a Type that it does not recognize (e.g., a Type dynamically installed in the infrastructure after the client was compiled), the client will not know how to natively instantiate or handle it. By iterating through the supertypes array, the client can fall back to the first ancestor Type it does recognize, ensuring it can still safely deserialize and interact with the instance using a known interface. Because it is returned by the server purely for this fallback reason, the client is not required to send it when performing write operations. (Note: Unlike the extendedTypes array in a Type schema definition—which only declares the direct, first-level inheritance—the supertypes array returned on instances flattens and includes the full transitive ancestor chain).

(Note: This array is not present in the representations of structurally known foundational elements—e.g., Context, Metadata, PropagationConstraint, ConsistsOf, QueryTemplate—because their strict hierarchy is immutable and already known by the system and any client. It is strictly injected for instances belonging to dynamically installed schema Types, such as EService or SoftwareFacet, ensuring that a client unaware of the specific dynamic schema can still understand its lineage. As a concrete corollary: while a direct instance of the base ConsistsOf Type does not possess the array, instances of its dynamically installed subtypes—like the IsIdentifiedBy instance shown in the JSON example below—DO receive the supertypes array).

(Note on Abstract Types: Resource, Facet, and IsRelatedTo do not appear in the list above because they are abstract and cannot be instantiated directly. If they were instantiable, they too would not possess a supertypes array, as they are part of the foundational model).

(Note on Embedded Properties: The supertypes array is typically associated with graph instances possessing an identity (like Resource, Facet, IsRelatedTo, and ConsistsOf instances). However, it is also injected into embedded Property values (e.g., inside an Event property) if those values belong to a polymorphic property type hierarchy. This is strictly required to allow strongly typed clients (like Java Jackson) to correctly deserialize nested polymorphic objects without prior knowledge of the full schema).

Type Linearization (Multiple Inheritance)

Because the IS-Model permits multiple inheritance (a Type schema can define multiple extendedTypes), the order in which a Type inherits from its ancestors must be deterministic to ensure predictable polymorphic fallback mechanisms for clients parsing the supertypes array.

The system enforces a strict C3 Linearization[^barrett-1996] (also known as Method Resolution Order, or MRO) when computing the supertypes array for any graph instance or embedded polymorphic property. When a Type extends multiple parent Types, its linearization is computed by merging its direct parents in the exact order they are declared, followed by the linearizations of those parents. The C3 algorithm guarantees two crucial properties:

  1. Monotonicity: No parent Type will ever appear before its child Type in the resolved ancestor list.

  2. Local Precedence: The explicit order of direct parents declared in the schema is strictly respected.

(Note: The server proactively guarantees this integrity. If a schema designer attempts to register a new Type with an inheritance graph that produces a cycle or an unresolvable C3 conflict, the system will reject the schema registration with a 400 Bad Request. For a pedagogical explanation of the C3 algorithm, refer to the Python 2.3 Method Resolution Order documentation).

id Field (REST Profile Mandate)

(REST Profile Note: While the abstract IS-Model allows for implementation-specific ID formats, the REST API strictly mandates the use of UUIDs for all id fields to guarantee global uniqueness and predictable flat addressability across the federated graph).

Client Parsing Resilience (Open-World Extensibility)

Because the Information System operates under an Open-World Assumption, any Resource instance can dynamically have arbitrary Facet instances attached to it via ConsistsOf instances (beyond what is strictly dictated by its schema). Furthermore, through the Schema-Mixed Mode, any instance (including IsRelatedTo instances) can host arbitrary custom property fields.

Therefore, it is a strict architectural requirement that clients MUST implement resilient JSON parsing capable of preserving unknown data. A client parsing an instance representation must not crash when encountering unrecognized property fields or unrecognized Facet instances attached via ConsistsOf instances. Instead, it must successfully instantiate them (e.g., placing custom properties into an extras map, and generically parsing the attached instances) so that they are preserved. Failing to do so guarantees that the client will eventually crash or accidentally destroy data when re-serializing an instance that another user extended with a new, unforeseen aspect or property.

metadata Field

The metadata field encapsulates provenance and tracking information for the instance (such as creation and modification timestamps and authors). This field is physically persisted on the instance, strictly generated and managed by the system. It may be omitted from standard read payloads depending on the client’s request parameters to save bandwidth.

lastUpdateTime Evaluation Logic

For any graph instance, the lastUpdateTime inside the Metadata block represents its latest modification. The specific evaluation logic depends on the instance type:

  • Resource instance: Because it acts as a logical aggregate, its lastUpdateTime is specifically evaluated as the maximum lastUpdateTime among the Resource instance itself, all its ConsistsOf instances, and all its attached Facet instances across all Contexts. (For the architectural and performance rationale regarding this global evaluation, refer to the API Authorization constraints in the REST API chapter).

  • Facet instance: It strictly represents its own individual modification timestamp.

  • IsRelatedTo instance: It strictly represents its own individual modification timestamp.

  • ConsistsOf instance: It strictly represents its own individual modification timestamp.

contexts Map

The contexts field is a dynamically calculated map (UUID -> Path) indicating all Contexts where the instance is currently present. Unlike metadata which is physically persisted on the instance, the contexts map does not physically exist as a persisted field; it is purely a computed, on-the-fly projection of the graph’s topology. Because paths are computed at read time based on the current Context hierarchy, they may change during the lifecycle of the infrastructure. Crucial operational note for clients: if a Context is renamed or reparented, any cached Path string becomes stale. However, the Context UUID (the Key of the map) remains permanently stable and is the only valid identifier for subsequent API operations. A Resource instance exists in a Context if and only if it belongs to that Context’s “Venn diagram” (by possessing at least one Facet instance in that Context). Because computing this map requires dynamic graph traversal and permissions evaluation across all associated instances, it is considered a computationally expensive generated field. Therefore, it is not returned by default and must be requested explicitly via API parameters. (For architectural details on how Contexts and Venn diagrams are physically implemented, see Contexts as Record-Level Security (RLS) Groups).

(Note: The contexts map applies exclusively to Entity and Relation instances. It conceptually makes no sense and is therefore not present on system-level objects (like Context, QueryTemplate, and schema Type definitions) nor on embedded property values (like Metadata and PropagationConstraint)).

Examples: Base Instances

Resource Instance

A full structural representation of a Resource instance is typically serialized as a hierarchical JSON aggregate, nesting the root Resource instance and its attached Facet instances via ConsistsOf instances (or its subtypes) within a single JSON document. (Note: When ConsistsOf instances are nested inside the consistsOf array of a Resource instance payload, the source field is intentionally omitted, as it implicitly defaults to the enclosing Resource instance. When represented as standalone instances, the source field is explicitly included). (Note: The first element in the consistsOf array below uses IsIdentifiedBy. This is a concrete subtype of ConsistsOf in the gcube-model—its presence in the consistsOf array confirms it acts as a composition edge, not an association edge. For references on fields, types and their inheritance, please refer to the live-registry type documentation, generated directly from this instance’s live schema; gcube-model types can also be queried directly (GET /types/{type-name}, QUERY /types/query). Furthermore, the JSON examples are highly simplified for didactic purposes; for example, the EService instance shown here would not be considered valid in production as it lacks mandatory schema structures).

{
    "type": "EService",
    "supertypes": ["Service", "GCubeResource", "Resource"],
    "id": "1a50a46d-2210-4a17-bd2f-22450b109264",
    "metadata": {
        "createdBy": "luca.frosini",
        "creationTime": "2026-04-16 12:09:26.804 +0200",
        "lastUpdateBy": "luca.frosini",
        "lastUpdateTime": "2026-04-16 12:09:26.804 +0200"
    },
    "contexts": {
        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
    },
    "consistsOf": [
        {
            "type": "IsIdentifiedBy",
            "supertypes": ["ConsistsOf"],
            "id": "641c1a36-da8d-4313-94f0-867453185d65",
            "metadata": {
                "createdBy": "luca.frosini",
                "creationTime": "2026-04-16 12:09:26.737 +0200",
                "lastUpdateBy": "luca.frosini",
                "lastUpdateTime": "2026-04-16 12:09:26.737 +0200"
            },
            "contexts": {
                "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
            },
            "propagationConstraint": {
                "type": "PropagationConstraint",
                "add": "propagate",
                "remove": "cascade"
            },
            "target": {
                "type": "SoftwareFacet",
                "supertypes": ["Facet"],
                "id": "cb6795ee-b729-47a7-ac9d-b805ae1df4d2",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-16 12:09:26.732 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-16 12:09:26.732 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
                },
                "group": "test",
                "name": "test",
                "version": "1.0.0"
            }
        },
        {
            "type": "ConsistsOf",
            "id": "16395d26-47d5-419b-8562-4d7c8158e28a",
            "metadata": {
                "createdBy": "luca.frosini",
                "creationTime": "2026-04-16 12:09:26.759 +0200",
                "lastUpdateBy": "luca.frosini",
                "lastUpdateTime": "2026-04-16 12:09:26.759 +0200"
            },
            "contexts": {
                "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
            },
            "propagationConstraint": {
                "type": "PropagationConstraint",
                "add": "propagate",
                "remove": "cascade"
            },
            "target": {
                "type": "AccessPointFacet",
                "supertypes": ["Facet"],
                "id": "9d9a2a48-a82b-43d3-b499-6ce50e1e543c",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-16 12:09:26.755 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-16 12:09:26.755 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
                },
                "endpoint": "https://www.d4science.org"
            }
        },
        {
            "type": "ConsistsOf",
            "id": "2e0ec586-667f-43b7-ba58-b750496a1f0b",
            "metadata": {
                "createdBy": "luca.frosini",
                "creationTime": "2026-04-16 12:09:26.784 +0200",
                "lastUpdateBy": "luca.frosini",
                "lastUpdateTime": "2026-04-16 12:09:26.784 +0200"
            },
            "contexts": {
                "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
            },
            "propagationConstraint": {
                "type": "PropagationConstraint",
                "add": "propagate",
                "remove": "cascade"
            },
            "target": {
                "type": "StateFacet",
                "supertypes": ["Facet"],
                "id": "45e42ef8-8275-4742-99f4-0cf7c8ecd862",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-16 12:09:26.779 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-16 12:09:26.779 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
                },
                "date": "2022-11-30 11:32:38.959 +0100",
                "value": "ready"
            }
        }
    ]
}

Facet Instance

{
    "type": "SoftwareFacet",
    "supertypes": ["Facet"],
    "id": "cb6795ee-b729-47a7-ac9d-b805ae1df4d2",
    "metadata": {
        "createdBy": "luca.frosini",
        "creationTime": "2026-04-16 12:09:26.732 +0200",
        "lastUpdateBy": "luca.frosini",
        "lastUpdateTime": "2026-04-16 12:09:26.732 +0200"
    },
    "contexts": {
        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
    },
    "group": "test",
    "name": "test",
    "version": "1.0.0"
}

IsRelatedTo Instance

(Note: The following represents a standalone Relation representation. In this structure, the source and target can optionally be expanded with their own metadata.).

{
    "type": "Uses",
    "supertypes": ["IsRelatedTo"],
    "id": "8b3fdfaa-9daf-4791-9ca7-02f068153abc",
    "metadata": {
        "createdBy": "luca.frosini",
        "creationTime": "2026-04-16 12:09:26.732 +0200",
        "lastUpdateBy": "luca.frosini",
        "lastUpdateTime": "2026-04-16 12:09:26.732 +0200"
    },
    "contexts": {
        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
    },
    "propagationConstraint": {
        "type": "PropagationConstraint",
        "add": "propagate",
        "remove": "cascade"
    },
    "source": {
        "type": "EService",
        "supertypes": ["Service", "GCubeResource", "Resource"],
        "id": "1a50a46d-2210-4a17-bd2f-22450b109264",
        "metadata": {
            "createdBy": "luca.frosini",
            "creationTime": "2026-04-16 12:09:26.804 +0200",
            "lastUpdateBy": "luca.frosini",
            "lastUpdateTime": "2026-04-16 12:09:26.804 +0200"
        },
        "contexts": {
            "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
        }
    },
    "target": {
        "type": "EService",
        "supertypes": ["Service", "GCubeResource", "Resource"],
        "id": "2b99a46d-1111-4a17-bd2f-33450b109299",
        "metadata": {
            "createdBy": "luca.frosini",
            "creationTime": "2026-04-16 12:09:26.814 +0200",
            "lastUpdateBy": "luca.frosini",
            "lastUpdateTime": "2026-04-16 12:09:26.814 +0200"
        },
        "contexts": {
            "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
        }
    }
}

ConsistsOf Instance

{
    "type": "IsIdentifiedBy",
    "supertypes": ["ConsistsOf"],
    "id": "641c1a36-da8d-4313-94f0-867453185d65",
    "metadata": {
        "createdBy": "luca.frosini",
        "creationTime": "2026-04-16 12:09:26.737 +0200",
        "lastUpdateBy": "luca.frosini",
        "lastUpdateTime": "2026-04-16 12:09:26.737 +0200"
    },
    "contexts": {
        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube"
    },
    "propagationConstraint": {
        "type": "PropagationConstraint",
        "add": "propagate",
        "remove": "cascade"
    },
    "source": {
        "type": "EService",
        "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
    },
    "target": {
        "type": "SoftwareFacet",
        "id": "cb6795ee-b729-47a7-ac9d-b805ae1df4d2"
    }
}

Query Templates Representation

The Resource Registry query engine natively supports JSON Query-By-Example (JSON-QBE), adapting the classical QBE paradigm[^zloof-1975] for document graphs. This paradigm allows clients to retrieve data by providing a JSON fragment that acts as a structural blueprint of the desired result, rather than writing strings of SQL-like query language.

Query Templates elevate this concept by allowing administrators to define pre-packaged, parameterized JSON-QBE payloads that clients can execute simply by name, without needing to know the underlying structural complexity. (Note on Identity: While the system auto-generates an internal id (UUID) for each template as shown in the payload, Query Templates are strictly addressed by their name in all API endpoints. The UUID is purely an internal system artifact and plays no role in client interaction).

Example: Query Template Definition

{
    "type": "QueryTemplate",
    "id": "61454553-5b0c-4e39-b848-b0fe4be4d9da",
    "metadata": {
        "createdBy": "luca.frosini",
        "creationTime": "2025-05-30 19:29:13.020 +0200",
        "lastUpdateBy": "luca.frosini",
        "lastUpdateTime": "2025-05-30 19:29:20.241 +0200"
    },
    "name": "get-all-eservice-with-state",
    "description": "Returns all EService instances with the provided state.",
    "template": {
        "type": "EService",
        "consistsOf": [
            {
                "type": "ConsistsOf",
                "target": {
                    "type": "StateFacet",
                    "value": "$state"
                }
            }
        ]
    },
    "templateVariables": {
        "$state": {
            "type": "TemplateVariable",
            "defaultValue": "down",
            "name": "$state",
            "description": "The state of the EService, e.g. down, ready."
        }
    }
}

Field Explanations

  • template: A JSON-by-Example payload representing the structural query. In this case, it looks for any EService instance that has a ConsistsOf instance pointing to a StateFacet instance. The value uses a parameter $state.

  • name: The unique identifier used in the URL to invoke this query template.

  • templateVariables: A dictionary defining all the bindable parameters (e.g., $state) expected in the execution payload. When a client executes the template, they provide the values for these variables to resolve the final query structure.

Schema-Mixed Encrypted Fields

Because the IS-Model allows dynamic injection of fields (Schema-Mixed Mode), the Resource Registry provides a native Encrypted complex Property Type to handle sensitive dynamic data without relying on external vaults.

The framework employs a “double-encryption” architecture to ensure both data-at-rest security and strict transport isolation:

  1. Write (Storage): When a client submits an Encrypted field, they provide it encrypted with the symmetric key of their operational Context. The backend service receives it, decrypts it using that specific Context key, and then re-encrypts the raw value using the service’s own universal service-managed encryption key before committing it to the database. The data on the database is therefore uniquely encrypted by the service.

  2. Read (Retrieval): Upon retrieval, the backend decrypts the value using its universal service-managed encryption key, and dynamically re-encrypts it on the fly using the symmetric key of the specific Context requested by the client (or the Context tied to the caller’s token).

Multi-Context Sharing & Hierarchical Semantics: This architecture elegantly resolves the complexities of sharing secrets across tenants without cryptographic leakage:

  • Sharing into a new Context (Propagation): Because the actual data at rest is encrypted solely with the universal service-managed encryption key, sharing a secret-bearing instance (e.g., propagating a Facet instance to a new Context) requires zero payload mutation. The backend simply adds the new Context to the instance’s visibility. Propagation automatically grants the new Context access.

  • Hierarchical Reads: If a manager performs a hierarchical read spanning multiple Contexts (?hierarchical=true), the system dynamically re-encrypts all returned secrets using the symmetric key of the Context bound to the caller’s operational token, ensuring the caller can seamlessly decrypt the entire payload with their single key.

(Note: How the upstream API Gateway, such as SmartGears, provisions or retrieves these symmetric Context keys to decrypt the incoming payload from the client is an infrastructure concern handled by the Gateway itself, and falls outside the Resource Registry API contract. Similarly, it is explicitly out of scope for this API guide to document the mechanisms for Context key issuance, cryptographic key rotation protocols, and the subsequent batch re-encryption of persisted data).

⚠️ Roadmap Warning: While effective, this double-encryption mechanism represents an interim architectural pattern. In future iterations, secret management will be offloaded to a dedicated Vault service via reference pointers. Client integrators should encapsulate their encryption/decryption routines to minimize refactoring when this transition occurs.

Operation Envelope Representation

When performing membership operations (such as Add to Context or Remove from Current Context), the system returns an Operation Envelope. This response describes the set of instances affected by the “avalanche effect”. The density of this envelope depends on the Prefer: return HTTP header.

Minimal Operation Envelope (Prefer: return=minimal)

A minimal operation envelope returns a flat array of instances, containing only their type and id (along with the strictly essential structural pointers source and target for Relation instances). It strictly omits metadata, contexts, supertypes, and any custom data fields, providing a highly optimized payload for bulk synchronization checks.

(Note: Unlike the full representation which is hierarchically normalized around top-level Resource and IsRelatedTo instances, the minimal envelope is a strictly flat list containing all individually affected graph elements, explicitly including Facet and ConsistsOf instances).

[
    {
        "type": "EService",
        "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
    },
    {
        "type": "IsIdentifiedBy",
        "id": "a8353fdf-9daf-4791-9ca7-02f068153ad0",
        "source": {
            "type": "EService",
            "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
        },
        "target": {
            "type": "SoftwareFacet",
            "id": "e32275d1-1da1-4f47-8c7d-e34a23f4330a"
        }
    },
    {
        "type": "SoftwareFacet",
        "id": "e32275d1-1da1-4f47-8c7d-e34a23f4330a"
    },
    {
        "type": "ConsistsOf",
        "id": "6ca7ee85-19d1-4f5d-8fd7-f2f399a6beeb",
        "source": {
            "type": "EService",
            "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
        },
        "target": {
            "type": "EventFacet",
            "id": "c3a8bf2a-788c-486f-949f-2f72be56b479"
        }
    },
    {
        "type": "EventFacet",
        "id": "c3a8bf2a-788c-486f-949f-2f72be56b479"
    },
    {
        "type": "ConsistsOf",
        "id": "78696361-0d73-4762-8b7b-c4bb203f52dc",
        "source": {
            "type": "EService",
            "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
        },
        "target": {
            "type": "StateFacet",
            "id": "0037c9b9-e75b-4f62-9400-234b902823e2"
        }
    },
    {
        "type": "StateFacet",
        "id": "0037c9b9-e75b-4f62-9400-234b902823e2"
    },
    {
        "type": "ConsistsOf",
        "id": "c616b059-0677-4628-9f7d-f01a44b54069",
        "source": {
            "type": "EService",
            "id": "1a50a46d-2210-4a17-bd2f-22450b109264"
        },
        "target": {
            "type": "AccessPointFacet",
            "id": "52b45cb3-f691-4f30-952e-0bfa875ad7a8"
        }
    },
    {
        "type": "AccessPointFacet",
        "id": "52b45cb3-f691-4f30-952e-0bfa875ad7a8"
    }
]

Full Representation Operation Envelope (Prefer: return=representation)

A full operation envelope returns the affected instances in their complete structural representation. Following the design rules of the API, the envelope payload is typically a flat array at the Infrastructure Topology level containing only the Resource instances and IsRelatedTo instances (with ConsistsOf and Facet instances properly nested inside their parent Resource). Resource instances are returned in full, meaning their attached ConsistsOf instances and Facet instances are nested inside the Resource object. IsRelatedTo instances are returned in full, but their source and target fields are serialized as reference pointers containing structurally only "type" and "id". However, as per the standard API enrichment rules, these pointers will include "contexts" when includeContexts=true, while "metadata" is included only when metadataPolicy=all (with metadataPolicy=root, metadata remains limited to top-level envelope elements). They do not return the full target representation (e.g., nested Facets are omitted). (Note: If an operation directly targets a Facet or ConsistsOf instance, such as deleting a specific Facet, those specific instances will be returned directly in the array, as the avalanche was not triggered by a source Resource instance).

(Example showcasing a fully enriched response shape. The exact mechanisms to govern this enrichment are detailed in the REST API reference).

[
    {
        "type": "EService",
        "supertypes": [ "Service", "GCubeResource", "Resource" ],
        "id": "1a50a46d-2210-4a17-bd2f-22450b109264",
        "metadata": {
            "createdBy": "luca.frosini",
            "creationTime": "2026-04-13 16:06:42.959 +0200",
            "lastUpdateBy": "luca.frosini",
            "lastUpdateTime": "2026-04-13 16:06:57.298 +0200"
        },
        "contexts": {
            "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
            "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
        },
        "consistsOf": [
            {
                "type": "IsIdentifiedBy",
                "supertypes": [ "ConsistsOf" ],
                "id": "a8353fdf-9daf-4791-9ca7-02f068153ad0",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-13 16:06:42.884 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-13 16:06:57.269 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                    "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                },
                "propagationConstraint": {
                    "type": "PropagationConstraint",
                    "add": "propagate",
                    "remove": "cascade"
                },
                "target": {
                    "type": "SoftwareFacet",
                    "supertypes": [ "Facet" ],
                    "id": "e32275d1-1da1-4f47-8c7d-e34a23f4330a",
                    "metadata": {
                        "createdBy": "luca.frosini",
                        "creationTime": "2026-04-13 16:06:42.881 +0200",
                        "lastUpdateBy": "luca.frosini",
                        "lastUpdateTime": "2026-04-13 16:06:57.264 +0200"
                    },
                    "contexts": {
                        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                        "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                    },
                    "name": "test",
                    "version": "1.0.0",
                    "group": "test"
                }
            },
            {
                "type": "ConsistsOf",
                "id": "c616b059-0677-4628-9f7d-f01a44b54069",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-13 16:06:42.915 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-13 16:06:57.278 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                    "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                },
                "propagationConstraint": {
                    "type": "PropagationConstraint",
                    "add": "propagate",
                    "remove": "cascade"
                },
                "target": {
                    "type": "AccessPointFacet",
                    "supertypes": [ "Facet" ],
                    "id": "52b45cb3-f691-4f30-952e-0bfa875ad7a8",
                    "metadata": {
                        "createdBy": "luca.frosini",
                        "creationTime": "2026-04-13 16:06:42.898 +0200",
                        "lastUpdateBy": "luca.frosini",
                        "lastUpdateTime": "2026-04-13 16:06:57.275 +0200"
                    },
                    "contexts": {
                        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                        "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                    },
                    "endpoint": "https://www.d4science.org"
                }
            },
            {
                "type": "ConsistsOf",
                "id": "78696361-0d73-4762-8b7b-c4bb203f52dc",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-13 16:06:42.938 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-13 16:06:57.287 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                    "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                },
                "propagationConstraint": {
                    "type": "PropagationConstraint",
                    "add": "propagate",
                    "remove": "cascade"
                },
                "target": {
                    "type": "StateFacet",
                    "supertypes": [ "Facet" ],
                    "id": "0037c9b9-e75b-4f62-9400-234b902823e2",
                    "metadata": {
                        "createdBy": "luca.frosini",
                        "creationTime": "2026-04-13 16:06:42.935 +0200",
                        "lastUpdateBy": "luca.frosini",
                        "lastUpdateTime": "2026-04-13 16:06:57.284 +0200"
                    },
                    "contexts": {
                        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                        "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                    },
                    "date": "2026-04-13 16:06:32.935 +0200",
                    "value": "ready"
                }
            },
            {
                "type": "ConsistsOf",
                "id": "6ca7ee85-19d1-4f5d-8fd7-f2f399a6beeb",
                "metadata": {
                    "createdBy": "luca.frosini",
                    "creationTime": "2026-04-13 16:06:42.955 +0200",
                    "lastUpdateBy": "luca.frosini",
                    "lastUpdateTime": "2026-04-13 16:06:57.296 +0200"
                },
                "contexts": {
                    "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                    "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                },
                "propagationConstraint": {
                    "type": "PropagationConstraint",
                    "add": "propagate",
                    "remove": "cascade"
                },
                "target": {
                    "type": "EventFacet",
                    "supertypes": [ "Facet" ],
                    "id": "c3a8bf2a-788c-486f-949f-2f72be56b479",
                    "metadata": {
                        "createdBy": "luca.frosini",
                        "creationTime": "2026-04-13 16:06:42.952 +0200",
                        "lastUpdateBy": "luca.frosini",
                        "lastUpdateTime": "2026-04-13 16:06:57.292 +0200"
                    },
                    "contexts": {
                        "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                        "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
                    },
                    "event": {
                        "type": "Event",
                        "supertypes": [ "Property" ],
                        "what": "ready",
                        "when": "2026-04-13 16:06:32.952 +0200"
                    }
                }
            }
        ]
    },
    {
        "type": "Uses",
        "supertypes": [ "IsRelatedTo" ],
        "id": "8b3fdfaa-9daf-4791-9ca7-02f068153abc",
        "metadata": {
            "createdBy": "luca.frosini",
            "creationTime": "2026-04-13 16:06:42.959 +0200",
            "lastUpdateBy": "luca.frosini",
            "lastUpdateTime": "2026-04-13 16:06:57.298 +0200"
        },
        "contexts": {
            "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
            "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
        },
        "propagationConstraint": {
            "type": "PropagationConstraint",
            "add": "propagate",
            "remove": "cascade"
        },
        "source": {
            "type": "EService",
            "id": "1a50a46d-2210-4a17-bd2f-22450b109264",
            "metadata": {
                "createdBy": "luca.frosini",
                "creationTime": "2026-04-13 16:06:42.959 +0200",
                "lastUpdateBy": "luca.frosini",
                "lastUpdateTime": "2026-04-13 16:06:57.298 +0200"
            },
            "contexts": {
                "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
            }
        },
        "target": {
            "type": "EService",
            "id": "2b99a46d-1111-4a17-bd2f-33450b109299",
            "metadata": {
                "createdBy": "luca.frosini",
                "creationTime": "2026-04-13 16:06:42.959 +0200",
                "lastUpdateBy": "luca.frosini",
                "lastUpdateTime": "2026-04-13 16:06:57.298 +0200"
            },
            "contexts": {
                "4eb849d5-efbb-4430-9eb6-1968123921b4": "/gcube",
                "a7bc333f-84df-498d-ae9d-748b358267b5": "/gcube/devsec"
            }
        }
    }
]

(Note on StateFacet vs EventFacet: In the examples throughout this document, StateFacet uses a simple value field to represent a scalar state, whereas EventFacet uses an event field. This is an intentional schema difference: EventFacet is designed to be backed by the complex Event property schema (which can encompass the “Five Ws” tracking fields), while StateFacet represents a simplified enumeration).