From 35910f80a4e929093a42e23ef6ed808eabb236ca Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 16 Apr 2024 04:48:42 -0700 Subject: [PATCH 01/17] docs(arc42): update arc42 to R24.05 state --- README.md | 13 ++++ docs/arc42/02_architecture_constraints.md | 1 + docs/arc42/03_system_scope_and_context.md | 11 ++- docs/arc42/04_solution_strategy.md | 17 ++++- docs/arc42/05_building_block_view.md | 34 ++++++--- docs/arc42/08_concepts.md | 85 +++++++++++++++++++---- docs/arc42/puml/03-technical-context.puml | 2 + docs/arc42/puml/05-level-0.puml | 5 ++ docs/arc42/puml/05-level-1-backend.puml | 16 +++-- docs/arc42/puml/05-level-1-frontend.puml | 12 ++-- docs/arc42/puml/07-deployment-argo.puml | 4 +- docs/arc42/puml/07-deployment.puml | 6 +- 12 files changed, 165 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 79d1dba6..34c87bb6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,19 @@ The project is made of a backend and a frontend. Look into the respective folders and their documentation to get information about prerequirements and getting started guides. +## Known Knows + +### Data Sovereignty + +Currently, edc assets are always configured to match exactly one kind policy. These policies can be defined during +deployment (see [Admin Guide](./docs/adminGuide/Admin_Guide.md)). Data is offered to each partner, who has been added to +the PURIS FOSS's master data pool depending on the business relationship (partner is a customer / supplier). + +For productive use, the following features should be implemented: + +- configuration of contracts including accepting and refusing contracts via UI +- more user-friendly configuration of contracts including bi-lateral contracts + ## License The project is licensed under the [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/docs/arc42/02_architecture_constraints.md b/docs/arc42/02_architecture_constraints.md index cb2b00ac..d00088f2 100644 --- a/docs/arc42/02_architecture_constraints.md +++ b/docs/arc42/02_architecture_constraints.md @@ -10,3 +10,4 @@ PURIS FOSS follows the following constraints: | Managed Identity Wallet (MIW) | MIW is a central Catena-X Service, which allows storing credentials to prove claims in the Catena-X data space. | | Interoperability between Data Applications | Data exchange MUST follow standards so that different vendors applications may exchange data. This allows to reduce the risk of vendor-lock-ins. | | Semantic Aspect Meta Model (SAMM) | Tooling used in Catena-X to semantically describe data. | +| Digital Twins in Catena-X & Industry Core | Standards CX-0002 and CX-0126 describe how Digital Twins following with the Asset Administration Shell shall be used. PURIS standards are built on these foundations | diff --git a/docs/arc42/03_system_scope_and_context.md b/docs/arc42/03_system_scope_and_context.md index 549153e1..8550725c 100644 --- a/docs/arc42/03_system_scope_and_context.md +++ b/docs/arc42/03_system_scope_and_context.md @@ -63,7 +63,7 @@ Catena-X specific implementation of the [Eclipse Dataspace Components Connector (EDC)](https://github.com/eclipse-edc/Connector) is an open-source framework which can be used to participate within an International Data Space (IDS). -*Sovereign Data exchange* +*Sovereign Data Exchange* To ensure data sovereignty, access and usage policies (prohibitions, permissions, obligations) may be attached as a machine readable defintion by data owners before sharing their data. The data consumer has to accept the policies before @@ -71,3 +71,12 @@ processing the data (human readable, machine readable). Connectors (and the unde technically enforce usage policies while there is also legal governance. An access and usage contract can be negotiated beforehand along with access and usage policies to ensure parties agree upon. It is necessary that data apps are compliant to the usage policies, since the policies define data processing rules. +Within Catena-X an odrl policy profile has been defined. The implementation of sovereign data exchange is explained in +the [concepts section](./08_concepts.md). + +**Digital Twins & Industry Core** +The Industry Core defines a layer on top of the combination of IDS and Digital Twin platform capabilities. It defines +the Part Type Twin as a "catalog item" representing a material that has not yet been built (serialized) but sourced. The +[Digital Twin KIT](https://eclipse-tractusx.github.io/docs-kits/kits/Digital%20Twin%20Kit/Adoption%20View%20Digital%20Twin%20Kit) +describes the shared asset pattern used by puris to distribute Digital Twins between the two partners. +For more information refer to the [concepts section](./08_concepts.md).. diff --git a/docs/arc42/04_solution_strategy.md b/docs/arc42/04_solution_strategy.md index b08a33ec..cb4aef19 100644 --- a/docs/arc42/04_solution_strategy.md +++ b/docs/arc42/04_solution_strategy.md @@ -3,18 +3,29 @@ **Organization** PURIS FOSS + - follows the related standardization candidates or even published standards (CX-0112). - is developed parallel to the consortial SAFe project. **Up-to-dateness / real-time** - Stock information has always the latest amount. E.g. at 6 a.m. there is a stock of 60 parts of material and at 8 a.m. -there is a stock of 80 parts of material. + there is a stock of 80 parts of material. - Demand and Production Output are measured "per day" e.g., today's demand and next thursday's demand. **Interoperable Data Exchange and Pattern** + - Use SAMM aspect models to exchange PURIS data (see domain model). - Use the EDC to participate in Catena-X. - - Data Providers can offer their data or data providing API as a _Data Asset_. - - Data Consumers can consume a Data Provider's _Data Asset_. + - Data Providers can offer their data or data providing API as a _Data Asset_. + - Data Consumers can consume a Data Provider's _Data Asset_. - Data is exchanged using an asynchronous pull and push mechanism. + +**Management of EDC and Digital Twins** + +PURIS FOSS + +- creates contract offers for partners itself +- registers digital twins depending on the relationship of partners for a specific material +- implements value-only submodel interfaces for information objects exchanged based on Digital Twin and Industry Core + standards. diff --git a/docs/arc42/05_building_block_view.md b/docs/arc42/05_building_block_view.md index d653a191..17f38281 100644 --- a/docs/arc42/05_building_block_view.md +++ b/docs/arc42/05_building_block_view.md @@ -5,19 +5,26 @@ been omitted for readability. ![Level 0 - Blackbox View](img/05-level-0.svg) -| Component / system | Descriptions | -|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Data Provisioning & Transformation | The Data Provisioning & Transformation Building Block handles the upload of data from internal systems into PURIS and provides capabilities for data transformation. **This component is not part of this repository**. | -| PURIS FOSS Backend | This system represents the PURIS FOSS application's logic. It handles the data exchange. | -| PURIS FOSS Frontend | This system represents the PURIS FOSS user interface. It handles the data visualization. | -| EDC | The Eclipse Dataspace Components Connector (EDC) is the component allowing PURIS FOSS to participate in the IDS. It is used to provide and consume data assets following policy information. Any data transfer is routed through the EDC. | -| Keycloak | Keycloak is an identity provider that can manage multiple clients (applications). Catena-X allows the usage of a shared identity provider. | -| Postgresql DB | Database used by Backend to persist data | +TODO check if plant uml can work directly + +![05-level-0.puml](./puml/05-level-0.puml) + +| Component / system | Descriptions | +|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Data Provisioning & Transformation | The Data Provisioning & Transformation Building Block handles the upload of data from internal systems into PURIS and provides capabilities for data transformation. **This component is not part of this repository**. | +| PURIS FOSS Backend | This system represents the PURIS FOSS application's logic. It handles the data exchange. | +| PURIS FOSS Frontend | This system represents the PURIS FOSS user interface. It handles the data visualization. | +| EDC | The Eclipse Dataspace Components Connector (EDC) is the component allowing PURIS FOSS to participate in the IDS. It is used to provide and consume data assets following policy information. Any data transfer is routed through the EDC. | +| Keycloak | Keycloak is an identity provider that can manage multiple clients (applications). Catena-X allows the usage of a shared identity provider. | +| Postgresql DB | Database used by Backend to persist data | +| Digital Twin Registry | Software Service that implements the AAS Discovery and Registry Interfaces. PURIS FOSS registers materials as ShellDescriptors with the respective information as Submodels. These SubmodelDescriptors do have a DSP endpoint linking to the EDC to contract the usage and how to get the submodel. | ## Level 1 White Boxes **PURIS FOSS Frontend** +For readability reasons, the building block view shows summarized interfaces. + ![Level 1 - Whitebox View - PURIS FOSS Frontend](img/05-level-1-frontend.svg) The Frontend only handles visualization logic. The remaining logic is handled in the backend. @@ -27,10 +34,18 @@ The Frontend only handles visualization logic. The remaining logic is handled in | Stock View | Allows to manually add or update stock information that is allocated to partners. Also latest stock information for partners may be requested (via backend). | | Dashboard | The dashboard allows to compare material-related demands, production outputs and stocks in a mocked way. Only Stock information is currently implements. | | Authentication Service | Encapsulates keycloak authentication and session management to be used by the main app. | -| Access Service | Steers based on the roles (see [Admin Guide](../../adminGuide/Admin_Guide.md)) which views may be visited by the user. | **PURIS FOSS Backend** +For readability reasons, the building block view shows only the stock related information. The strucutre for the other +information objects is the same: + +- planed production output +- short-term material demand (demand) +- delivery information + +The building block view describes only the responsibilities of the components/ packages. + ![Level 1 - Whitebox View - PURIS FOSS Backend](img/05-level-1-backend.svg) | Component / system | Descriptions | @@ -38,3 +53,4 @@ The Frontend only handles visualization logic. The remaining logic is handled in | EDC | The EDC component provides the EDC implementations to create assets, negotiate contracts and intialize transfers. | | MAD | Stores the partner and material related information. They may only be added via REST interfaces. | | Stock | Stores and handles stock related data. It provides interfaces to create and read stock data. Also it allows to exchange stock information via the EDC. | +| DTR | The DTR component provides the DTR implementations to manage ShellDescriptors, query partners' DTR and consume Submodel data. | diff --git a/docs/arc42/08_concepts.md b/docs/arc42/08_concepts.md index d2559345..8d3524e5 100644 --- a/docs/arc42/08_concepts.md +++ b/docs/arc42/08_concepts.md @@ -4,7 +4,7 @@ Within the supply network there may be materials / parts that are produced for multiple partners or customers that share the same material number. -A partner asking for information may not receive any information that are not meant for him. Therefor the PURIS concept +A partner asking for information may not receive any information that are not meant for him. Therefore the PURIS concept is, that exchanged information MUST be allocated to a partner to not leak any partner relationships in the vertical direction. @@ -20,36 +20,97 @@ the respective material number of a partner leading to the following constellati - own material number = material number supplier - material number partner = material number customer -Furthermore, as of ItemStockSAMM v2.0.0 the supplier CX ID is the sole identifier for a material of a respective partner. +Furthermore, as of ItemStockSAMM v2.0.0 the supplier CX ID is the sole identifier for a material of a respective +partner. This leads to two scenarios, within the shared asset approach: -- when acting as a customer, the supplier's global asset id (Catena-X ID) is leading and taken from the PartTypeInformation of the supplier's twin. +- when acting as a customer, the supplier's global asset id (Catena-X ID) is leading and taken from the + PartTypeInformation of the supplier's twin. - when acting as a supplier, the initially generated global asset id (Catena-X ID) is handed over to the customers. Within PURIS this results in the following steps: -- when creating a material (independent of the role) a global asset id (Catena-X ID) is defined on the material, which is used for the supplier twin. +- when creating a material (independent of the role) a global asset id (Catena-X ID) is defined on the material, which + is used for the supplier twin. - when creating a mpr, the global asset id (Catena-X ID), initially left null - is usually not set (acting as supplier) - is set to the supplier's material's catena-X id (acting as customer) ## Data Sovereignty -The application only provides assets (API usage) based on a Business Partner Number Legal Entity (BPNL) based access -policy via the [Tractus-X EDC](https://github.com/eclipse-tractusx/tractusx-edc). All traffic to exchange -information is routed through the EDC data plane using the proxy pull mechanism. +Following the standard, the following measures have been taken: -Whenever a partner is created, all exchanged information APIs that comply to a Catena-X standard are registered as -contract offer for the partner's BPNL. +Access Policies in charge: + +- Business Partner Number Legal Entity (BPNL) +- Membership Credential + +Usage Policies in charge: + +- Framework Agreement credential (partner signed the Framework Agreement) +- Purpose credential (partner is member of Catena-X) + +TODO: Example policies + +_Note: see configuration of usage policies in [AdminGuide](../adminGuide/Admin_Guide.md)._ -Additionally, the application is configured to demand several policies to be fulfilled when accessing or exchanging data, that is: +All traffic to exchange information is routed through the EDC data plane using the proxy pull mechanism. -- the application requires the BPNL of the partner as part of the access policy when accessing any asset. -- the application requires the membership credential as part of the access policy when accessing any asset. +Whenever a partner is created, a contract offer for the DTR is registered for the partner's BPNL. +Whenever a material partner relation (partner buys material, partner suppliers material), + +- the contract offers for the submodels are created for the partner +- the submodel descriptors are added to the twin + +Additionally, the administrator may configure the application to use a framework agreement policy for data offers (see +[Administration Guide](../adminGuide/Admin_Guide.md)). When activated, + +- the application requires the respective credential to be active for the partner. - the application requires the framework agreement credential as contract policy when contracting a partner's offer as a consumer. +## Reusing Contracts & Caching DTR information + +Following the Digital Twin KIT, assets in the EDC can be cut as follows: + +1. one asset per material and submodel +1. one asset per submodel (implicitly emphasized by R24.05 standards) +1. one asset per material (excluded by R24.05 standards) + +**NOTE: the PURIS FOSS assumes the second and can only optimize and cache the information for the second case.** + +There are two kind of assets, the PURIS FOSS application works with: + +- Application Programming Interfaces (currently only the DTR) +- Submodel Endpoints (value-only serialization) + +When contracting, the following information (`ContractMapping`) is stored: + +- asset id +- contract id +- protocol url of edc +- href url per material (submodel only) + +When a new transfer is needed, the system checks if a `ContractMapping` for the resource in question exists. + +- If yes, + - use this information to get the data directly via the EDC by initializing a transfer. + - if anything fails, go the whole way to get the data (contract DTR, contract submodel, save ContractMapping) +- if no, + - go the whole way to get the data (contract DTR, contract submodel, save ContractMapping) + +Whenever a partner is created, all exchanged information APIs that comply to a Catena-X standard are registered as +contract offer for the partner's BPNL. + ## Security Backend APIs are secured by an API Key. The Frontend may be configured to be accessed based on keycloak authentication. Refer to the [Admin Guide](../adminGuide/Admin_Guide.md) for further information. + +Access to respective resources is always granted based on the actual relationships as stated in section 'Multi-Partner +Information'. Means there are two levels of security: + +1. The partner is maintained and access has been granted via the EDC. +2. The partner is routed through the EDC. + +To do the second, the Connector in use needs the extension [additional headers](TODO). diff --git a/docs/arc42/puml/03-technical-context.puml b/docs/arc42/puml/03-technical-context.puml index b10e5367..8d3994fc 100644 --- a/docs/arc42/puml/03-technical-context.puml +++ b/docs/arc42/puml/03-technical-context.puml @@ -3,9 +3,11 @@ [Tractus-X EDC] as edc [Sovereign Data Exchange] as sov [PURIS FOSS] as puris +[Digital Twins &\n Industry Core] as dt samm -- puris edc - puris puris - sov +puris -- dt @enduml diff --git a/docs/arc42/puml/05-level-0.puml b/docs/arc42/puml/05-level-0.puml index 760c0790..1c08b964 100644 --- a/docs/arc42/puml/05-level-0.puml +++ b/docs/arc42/puml/05-level-0.puml @@ -3,9 +3,11 @@ [Eclipse DataSpace Components Connector] as edc [Postgresql DB] as postgres [Keycloak] as idp +[Digital Twin Registry] as dtr data_prov -( "Interface internal systems" edc -- "EDC APIs" +dtr - "Registration &\n Discovery Interfaces" package "<> PURIS"{ @@ -18,6 +20,9 @@ package "<> PURIS"{ puris_frontend -- idp puris_backend --> postgres + puris_backend --( "Registration &\n Discovery Interfaces" } +puris_backend - "Submodel value-only interfaces" + @enduml diff --git a/docs/arc42/puml/05-level-1-backend.puml b/docs/arc42/puml/05-level-1-backend.puml index 2176b97c..0ba71ab1 100644 --- a/docs/arc42/puml/05-level-1-backend.puml +++ b/docs/arc42/puml/05-level-1-backend.puml @@ -3,20 +3,22 @@ skinparam linetype ortho package "<> PURIS FOSS Backend"{ + [DTR] as dtr [EDC] as edc - edc - "EDC Client Interface" - [Stock] as stock - stock - "Stock Interface" - "Stock Request &\n Response Interfaces\n(through EDC)" - stock + [MAD] as mad + edc - "EDC Client Interface" + "Registry & Discovery Interfaces" - dtr + + dtr -- "Register and discover twins\n& submodesls" stock +' TODO make look great edc -- "query catalog &\nrequest data (via edc)" stock - [MAD] as mad mad - "MAD Interface" - stock -- mad - } +stock - "Stock Submodel \n& internalInterface" +stock -- mad @enduml diff --git a/docs/arc42/puml/05-level-1-frontend.puml b/docs/arc42/puml/05-level-1-frontend.puml index 3ee5d357..9be88e0e 100644 --- a/docs/arc42/puml/05-level-1-frontend.puml +++ b/docs/arc42/puml/05-level-1-frontend.puml @@ -6,9 +6,6 @@ package "<> PURIS FOSS Frontend"{ [Stock View] as stock_view [Dashboard] as dashboard [Authentication Service] as auth_service - [Access Service] as access_service - - auth_service <-- access_service } @@ -16,10 +13,11 @@ package "<> PURIS FOSS Frontend"{ idp - auth_service -stock_view --> "Stock Interface" -stock_view --> "MAD interface" +stock_view --( "Stock Interface" +stock_view --( "MAD interface" -dashboard --> "Stock Interface" -dashboard --> "MAD interface" +dashboard --( "Stock Interface" +dashboard --( "MAD interface" +dashboard -( "Interfaces for\n- Planned Production Output\n-Short-Term Material Demand\n-Delivery Information" @enduml diff --git a/docs/arc42/puml/07-deployment-argo.puml b/docs/arc42/puml/07-deployment-argo.puml index 7deb8991..61345de3 100644 --- a/docs/arc42/puml/07-deployment-argo.puml +++ b/docs/arc42/puml/07-deployment-argo.puml @@ -3,13 +3,15 @@ package "PURIS"{ - [Tractus-X Connector Customer] as edc + [Tractus-X Connector] as edc + [Digital Twin Registry] as dtr [Postgresql DB] as postgres [PURIS FOSS Backend] as puris_backend [PURIS FOSS Frontend] as puris_frontend puris_backend - edc + dtr -- puris_backend postgres -- puris_backend "Interface internal systems\n" - puris_backend puris_backend -- puris_frontend diff --git a/docs/arc42/puml/07-deployment.puml b/docs/arc42/puml/07-deployment.puml index 4957443b..a18208e1 100644 --- a/docs/arc42/puml/07-deployment.puml +++ b/docs/arc42/puml/07-deployment.puml @@ -4,11 +4,13 @@ package "Customer"{ [Tractus-X Connector Customer] as edc_cus + [Digital Twin Registry Customer] as dtr_cus [Postgresql DB] as postgres_cus [PURIS FOSS Backend] as puris_backend_cus [PURIS FOSS Frontend] as puris_frontend_cus + dtr_cus - puris_backend_cus puris_backend_cus - edc_cus postgres_cus -- puris_backend_cus "Interface internal systems\n(Customer)" - puris_backend_cus @@ -27,12 +29,14 @@ package "CX" { package "Supplier"{ [Tractus-X Connector Supplier] as edc_sup + [Digital Twin Registry Supplier] as dtr_sup [Postgresql DB] as postgres_sup [PURIS FOSS Backend] as puris_backend_sup [PURIS FOSS Frontend] as puris_frontend_sup - edc_sup - puris_backend_sup + dtr_sup - puris_backend_sup + puris_backend_sup - edc_sup postgres_sup -- puris_backend_sup puris_backend_sup - "Interface internal systems\n(Supplier)" puris_backend_sup -- puris_frontend_sup From c7407dca62785ebd9909cc0ab827c54c65baab8c Mon Sep 17 00:00:00 2001 From: --show-origin Date: Mon, 13 May 2024 10:12:00 -0700 Subject: [PATCH 02/17] docs(arc42): updated puml for runtime view and building block view --- docs/arc42/06_runtime_view.md | 9 ++ docs/arc42/puml/05-level-0.puml | 23 +++-- docs/arc42/puml/05-level-1-backend.puml | 23 ++--- docs/arc42/puml/05-level-1-frontend.puml | 7 +- docs/arc42/puml/06-api-flow-detailed.puml | 115 +++++++++++++++------- docs/arc42/puml/06-twin-creation.puml | 53 ++++++++++ 6 files changed, 172 insertions(+), 58 deletions(-) create mode 100644 docs/arc42/puml/06-twin-creation.puml diff --git a/docs/arc42/06_runtime_view.md b/docs/arc42/06_runtime_view.md index cab7426d..0b18ed35 100644 --- a/docs/arc42/06_runtime_view.md +++ b/docs/arc42/06_runtime_view.md @@ -34,6 +34,15 @@ ommitted. ![Overview of request and response with EDC](img/06-api-flow-detailed.svg) +## Scenario: Create Digital Twins for Material or Product + +A Digital Twin is created for partners as soon as at least one buyer or supplier is known. +Following the Digital Twin Shared Asset Approach, each partner needs his view on the digital twin. +Following the Industry Core, the Supplier Twin dictates the Catena-X ID. Thus, the Customer needs to lookup and use this +Catena-X ID as the `globalAssetId` and during data exchange scenarios. + +The following Diagram illustrates the registration (create and update) process for digital twins: + ## Scenario: Interact with data in web-ui When reloading the UI, the latest data is pulled from the backend. Whenever an update on the information is performed, diff --git a/docs/arc42/puml/05-level-0.puml b/docs/arc42/puml/05-level-0.puml index 1c08b964..14f3c7d1 100644 --- a/docs/arc42/puml/05-level-0.puml +++ b/docs/arc42/puml/05-level-0.puml @@ -1,28 +1,33 @@ @startuml -[Data Provisioning & Transformation] as data_prov -[Eclipse DataSpace Components Connector] as edc +skinparam linetype polyline +skinparam nodesep 100 +skinparam ranksep 50 +[Data Provisioning\n& Transformation] as data_prov +[Eclipse Dataspace\nComponents Connector] as edc [Postgresql DB] as postgres [Keycloak] as idp -[Digital Twin Registry] as dtr +[Digital Twin\nRegistry] as dtr data_prov -( "Interface internal systems" -edc -- "EDC APIs" -dtr - "Registration &\n Discovery Interfaces" +"EDC Management\nAPI" - edc +dtr - "Registration &\nDiscovery Interfaces" package "<> PURIS"{ [PURIS FOSS Backend] as puris_backend [PURIS FOSS Frontend] as puris_frontend - "EDC APIs" )-- "provide and pull data\naccording to standards" puris_backend + puris_backend "provide and pull data\naccording to standards" --( "EDC Management\nAPI" "Interface internal systems" - puris_backend puris_backend <-- puris_frontend puris_frontend -- idp - puris_backend --> postgres + puris_backend -> postgres - puris_backend --( "Registration &\n Discovery Interfaces" + puris_backend --( "Registration &\nDiscovery Interfaces" } -puris_backend - "Submodel value-only interfaces" +"Submodel value-only interfaces" -- puris_backend +dtr --> idp +edc --> idp @enduml diff --git a/docs/arc42/puml/05-level-1-backend.puml b/docs/arc42/puml/05-level-1-backend.puml index 0ba71ab1..6fd72c2a 100644 --- a/docs/arc42/puml/05-level-1-backend.puml +++ b/docs/arc42/puml/05-level-1-backend.puml @@ -1,24 +1,25 @@ @startuml -skinparam linetype ortho +skinparam linetype polyline +skinparam nodesep 150 +skinparam ranksep 50 package "<> PURIS FOSS Backend"{ [DTR] as dtr [EDC] as edc - [Stock] as stock + [Stock, Production, Demand,\nDelivery Information] as stock [MAD] as mad +} - edc - "EDC Client Interface" - "Registry & Discovery Interfaces" - dtr +"Registry & Discovery Interfaces" )-- dtr +"MAD Interface" - mad +edc -( "EDC Client Interface" +stock --( "Submodel \n& internal interface" - dtr -- "Register and discover twins\n& submodesls" stock -' TODO make look great - edc -- "query catalog &\nrequest data (via edc)" stock +dtr -- "Register and discover twins\n& submodels" stock +stock - "query catalog &\nget data (via edc)" edc +mad - stock - mad - "MAD Interface" -} -stock - "Stock Submodel \n& internalInterface" -stock -- mad @enduml diff --git a/docs/arc42/puml/05-level-1-frontend.puml b/docs/arc42/puml/05-level-1-frontend.puml index 9be88e0e..d7598e33 100644 --- a/docs/arc42/puml/05-level-1-frontend.puml +++ b/docs/arc42/puml/05-level-1-frontend.puml @@ -1,5 +1,7 @@ @startuml -skinparam linetype ortho +skinparam linetype polyline +skinparam nodesep 20 +skinparam ranksep 50 package "<> PURIS FOSS Frontend"{ @@ -8,7 +10,7 @@ package "<> PURIS FOSS Frontend"{ [Authentication Service] as auth_service } - +"Interfaces for\n- Planned Production Output\n- Short-Term Material Demand\n- Delivery Information" -- dashboard [Keycloak] as idp idp - auth_service @@ -18,6 +20,5 @@ stock_view --( "MAD interface" dashboard --( "Stock Interface" dashboard --( "MAD interface" -dashboard -( "Interfaces for\n- Planned Production Output\n-Short-Term Material Demand\n-Delivery Information" @enduml diff --git a/docs/arc42/puml/06-api-flow-detailed.puml b/docs/arc42/puml/06-api-flow-detailed.puml index f804537b..ebeda45f 100644 --- a/docs/arc42/puml/06-api-flow-detailed.puml +++ b/docs/arc42/puml/06-api-flow-detailed.puml @@ -4,54 +4,99 @@ skinparam sequenceMessageAlign center box "Data Consumer" participant "Business\nApplication" as app_cons -participant "EDC Consumer" as edc_cons +participant "EDC\nConsumer" as edc_cons end box box "Data Provider" -participant "EDC Provider" as edc_prov -participant "Business\nApplication" as app_prov +participant "EDC\nProvider" as edc_prov +participant "DT\nProvider" as dtr_prov +participant "Submodel\nEndpoint" as se_prov end box -app_cons -> edc_cons: search for request assets at partner +=== Identify Data via Digital Twin Registry of Provider == +== Contract DTR Usage == +app_cons -> edc_cons: search for DTR assets at partner +activate edc_cons edc_cons <-> edc_prov: catalog communication edc_cons --> app_cons: catalog +deactivate edc_cons -app_cons -> app_cons: identify Information Object\nExchange Request asset +app_cons -> app_cons: identify DTR Offer\n(filter by dcat:type, cx:version) -app_cons -> edc_cons: negotiate contract for Information\n Object Exchange Request API +app_cons -> edc_cons: negotiate contract for DTR usage +activate edc_cons edc_cons <-> edc_prov: negotiation edc_cons --> app_cons: contract agreement +deactivate edc_cons -note left: Define Endpoint Data Reference Endpoint = \n Business Application +note over app_cons, edc_cons: Define Transfer Callback url = \n Business Application app_cons -> edc_cons: initialize transfer +activate edc_cons edc_cons <-> edc_prov: initialize transfer -edc_prov --> app_cons: transfer completed, EDR sent - -app_cons -> app_cons: prepare request based on\nEDR endpoint and auth - -note right: Request against Endpoint via EDC -app_cons -> edc_prov: Request Information Object Exchange (via EDC) -edc_prov -> app_prov: proxy request -activate app_prov -app_prov --> edc_prov: Accepted -edc_prov --> app_cons: Accepted - -app_prov -> app_prov: Determine requested Information Object - -note right: simplified communication with EDC, same as above -app_prov -> edc_prov: EDC communication -edc_prov <-> edc_cons: EDC communication -edc_cons --> app_prov: transfer completed, EDR sent - -note right: Send requested Information Objectvia EDC -app_prov -> edc_cons: Response Information Object Exchange (via EDC) -edc_cons -> app_cons: proxy request -activate app_cons -app_cons --> edc_cons: Accepted -edc_cons --> app_prov: Accepted -deactivate app_prov - -app_cons -> app_cons: use data -deactivate app_cons +edc_cons --> app_cons: transfer completed, EDR sent +deactivate edc_cons + +== Lookup and Determine ShellDescriptor for Material in Question == +app_cons -> app_cons: prepare material identification\nas specific asset ids +app_cons -> app_cons: prepare dtr lookup based on\nEDR endpoint and auth + +note over app_cons, edc_cons: Lookup request against DTR via EDC +app_cons -> edc_prov: Lookup Material Twin at partner (via EDC) +activate edc_prov +edc_prov -> dtr_prov: proxy request +activate dtr_prov +dtr_prov --> edc_prov: lookup result +deactivate dtr_prov +edc_prov --> app_cons: lookup result +deactivate edc_prov +app_cons -> app_cons: base64 encode\nreturned shell-id + +note over app_cons, edc_cons: Shell Descriptors request against DTR via EDC +app_cons -> edc_prov: Query Shell-Descriptor of \nMaterial Twin at partner (via EDC) +activate edc_prov +edc_prov -> dtr_prov: proxy request +activate dtr_prov +dtr_prov --> edc_prov: found shellDescriptors +deactivate dtr_prov +edc_prov --> app_cons: found shellDescriptors +deactivate edc_prov + +== Determine Submodel Endpoint of Submodel Type of Interest == +app_cons -> app_cons: lookup submodel "DSP" endpoint\nfor semantic id of interest +app_cons -> app_cons: check if contract is given +app_cons -> app_cons: extract submodel data\n(edc endpoints, asset id, href) + +=== Query Submodel Data at Provider EDC == +== Contract Submodel Usage == +app_cons -> edc_cons: search for submodel asset at partner\n(request with asset id) +activate edc_cons +edc_cons <-> edc_prov: catalog communication +edc_cons --> app_cons: catalog +deactivate edc_cons + +app_cons -> app_cons: filter offers by\ndata sovereignty criteria\n(framework agreement & purpose) + +app_cons -> edc_cons: negotiate contract for submodel data +activate edc_cons +edc_cons <-> edc_prov: negotiation +edc_cons --> app_cons: contract agreement +deactivate edc_cons + +note over app_cons, edc_cons: Define Transfer Callback url = \n Business Application +app_cons -> edc_cons: initialize transfer +activate edc_cons +edc_cons <-> edc_prov: initialize transfer +edc_cons --> app_cons: transfer completed, EDR sent +deactivate edc_cons + +== Request Submodel via EDC == +app_cons -> edc_prov: Query submodel endpoint with href from\nSubmodelDescriptor.endpoint +activate edc_prov +edc_prov -> se_prov: proxy request +activate se_prov +se_prov --> edc_prov: found submodel +deactivate se_prov +edc_prov --> app_cons: found submodel +deactivate edc_prov @enduml diff --git a/docs/arc42/puml/06-twin-creation.puml b/docs/arc42/puml/06-twin-creation.puml new file mode 100644 index 00000000..d54293f3 --- /dev/null +++ b/docs/arc42/puml/06-twin-creation.puml @@ -0,0 +1,53 @@ +@startuml +autonumber +skinparam sequenceMessageAlign center + +box "PURIS backend" +participant "MaterialController" as m_c +participant "MaterialPartner\nRelationsController" as mpr_c +participant "MaterialServiceImpl" as m_s +participant "MaterialPartner\nRelationServiceImpl" as mpr_s +participant "EdcAdapterService" as edc_s +participant "DtrAdapterService" as dtr_s +end box + + +=== Create Material or Product == +m_c -> m_s: Create Material or Product +activate m_s +m_s -> m_s: Generate or take\nCatena-X ID\n(save on material) +m_s --> m_c: OK +deactivate m_s + +mpr_c -> mpr_s: Create MPR for partner\nand material / product +activate mpr_s +mpr_s -> mpr_s: Create DtrRegistrationTask +mpr_s -> mpr_s: Determine Partners who\nbuy material and supply product + +group DtrRegistrationTask + alt at least one Partner who buys (We're the supplier) + mpr_s -> dtr_s: Create ShellDescriptor with access rights for buying\npartners and all submodels + activate dtr_s + return OK + else at least one Partner who sells (We're the customer) + alt MPR does not yet have the CX-ID + mpr_s -> edc_s: Lookup DigitalTwin at Supplier\nto extract Catena-X ID + activate edc_s + edc_s -> edc_s: Lookup and Contract DTR + edc_s -> edc_s: Determine ShellDescriptor and\nSubmodel "DSP" Endpoint for\nPartTypeInformation from\npartner DTR + edc_s -> edc_s: Query PartTypeInformation Submodel\nat partner + edc_s -> edc_s: Extract Catena-X ID from Submodel + edc_s --> mpr_s: Catena-X ID + deactivate edc_s + mpr_s -> mpr_s: Set Partner Catena-X ID + mpr_s -> mpr_s: Save MaterialPartnerRelationship + end + mpr_s -> dtr_s: Create or Update ShellDescriptor with access rights for selling\npartners and all submodels + activate dtr_s + return OK + end +end +mpr_s --> mpr_c: OK +deactivate mpr_s + +@enduml From b0d42fa737cdaaf688ed392ccd1845f2bfe0793a Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 05:57:40 -0700 Subject: [PATCH 03/17] docs(arc42/runtimeView): updated GET Submodel workflow --- docs/arc42/06_runtime_view.md | 96 ++++++++++-------- docs/arc42/img/06-api-flow-detailed.svg | 6 +- docs/arc42/img/06-api-flow.svg | 117 ---------------------- docs/arc42/puml/06-api-flow-detailed.puml | 52 ++++++++-- docs/arc42/puml/06-api-flow.puml | 26 ----- 5 files changed, 102 insertions(+), 195 deletions(-) delete mode 100755 docs/arc42/img/06-api-flow.svg delete mode 100644 docs/arc42/puml/06-api-flow.puml diff --git a/docs/arc42/06_runtime_view.md b/docs/arc42/06_runtime_view.md index 0b18ed35..fbd1bcdd 100644 --- a/docs/arc42/06_runtime_view.md +++ b/docs/arc42/06_runtime_view.md @@ -1,55 +1,69 @@ # Runtime View -The runtime view mainly focuses on two separate scenarios. One can either interact with the data or pull it. +The runtime view mainly focuses on the following scenarios: -## Scenario: Update partner-related data - -The information exchange in PURIS follows a response and request pattern. Requests are directly answered based on -existing data as soon as they arrive. The diagram does not integrate the EDC to explain the overall flow. - -![Overview of request and response](img/06-api-flow.svg) - -The request and response flow both implement a message header and a content section in the exchanged data. +- Update partner-related data +- Create Digital Twins for Material or Product +- Interact with Data in the Web-UI -- the message header contains information about the message. -- the content contains either the request (material numbers) or the response (respective SAMM model as json payload). - -The API implementations are provided and consumed via the EDC. - -1. A data asset is created on Startup by the `AssetCreatedCommandLineRunner`. -1. To request new data - 1. the partners' catalog is queried to search for the request api. - 1. the contract is negotiated. - 1. the transfer is initialized using - the [dynamic http receiver EDC extension](https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/transfer/transfer-pull-http-dynamic-receiver). - 1. the "consumer pull" flow is used ( - see [sample](https://github.com/eclipse-edc/Samples/tree/main/transfer/transfer-06-consumer-pull-http)) - 1. Provider receives EDR token by `EndpointDataReferenceReceiver`. - 1. Provider queries API for information of interest based on the standardized API description. - 1. Consumer receives request, determines data for response and starts with step 2 for the response interface. - -The workflow with simplified EDC communication may be seen in the following sequence diagram. -EDC flow is the same to use the request and response api. Central Services, such as the Managed Identity Wallet are -ommitted. +## Scenario: Update partner-related data -![Overview of request and response with EDC](img/06-api-flow-detailed.svg) +The information exchange in PURIS follows a shared asset approach of the Digital Twin KIT and the Industry Core KIT. +This means: + +- A Digital Twin Registry is needed to lookup the data and know how to pull data +- Information is exchanges as Submodel in Form of Submodel JSON-only serializations +- All traffic is routed through EDCs + +Following the PURIS standards, currently one asset per Submodel Type is wanted. + +Roughly said the following steps need to be achieved to lookup a Submodel Y for a Material X of a Partner Z: + +1. Contract `Digital Twin Registry (DTR)` of Partner Z at `EDC` + 1. Query Catalog of `EDC` of Partner Z (filter by `dcat:type` and `cx-common:version`) + 2. Contract usage of `DTR` of Partner Z (no consumer-side check of policy) + 3. Initialize Transfer to query `DTR` + 4. Get Endpoint Data Reference (EDR, auth token for Data Plane request for `DTR` of Partner Z) +2. Determine Twin of Partner Z for Material X via proxy call through `EDC`: + 1. Lookup Material Twin by specificAssetIds (`manufacturerId`, `manufacturerPartId`, `digialTwinType`) which returns + ShellDescriptor ID + 2. Get ShellDescriptor by ID (base 64 encoded ID) + 3. Terminate Transfer for `DTR` +3. From result, extract needed information to get `Submodel Y` + 1. Determine the `SubmodelDescriptor` by Semantic ID of the Submodel Type in question. + 2. Determine the endpoint of that `SubmodelDescriptor` of type `DSP` + 3. Extract href, assetId (`Submodel Asset`), dspUrl +7. Contract `Submodel Asset` same as `DTR` but with following differences + 1. For communication, use the dspUrl extracted from `SubmodelDescriptor` + 2. Catalog query filters by `assetId` extracted from `SubmodelDescriptor` + 3. Prior to usage the catalog offers are filtered for an offer your application supports: + PURIS FOSS only allows policies with Exactly one `FrameworkAgreement` and one `UsagePurpose`. It only accepts the + same Policy it offers (see [Admin Guide](../adminGuide/Admin_Guide.md)) +4. Query `Submodel Y` trough `EDC` +5. Terminate Transfer for `Submodel Y` + +The workflow with simplified EDC and DTR communication may be seen in the following sequence diagram. +Central Services, such as the `Credential Service` and `Secure Token Service` are ommitted as these are handled by the +`EDC`. + +![Overview of Submodel Request through the EDC including Digital Twin determination](img/06-api-flow-detailed.svg) ## Scenario: Create Digital Twins for Material or Product A Digital Twin is created for partners as soon as at least one buyer or supplier is known. -Following the Digital Twin Shared Asset Approach, each partner needs his view on the digital twin. -Following the Industry Core, the Supplier Twin dictates the Catena-X ID. Thus, the Customer needs to lookup and use this -Catena-X ID as the `globalAssetId` and during data exchange scenarios. +Following the Digital Twin Shared Asset Approach, each partner needs his view on the Digital Twin. +Following the Industry Core, the Supplier Twin dictates the Catena-X ID (also set as globalAssetId). Thus, the Customer +needs to lookup and use this Catena-X ID as the `globalAssetId` -The following Diagram illustrates the registration (create and update) process for digital twins: +- during data exchange scenarios and +- to register his Digital Twin -## Scenario: Interact with data in web-ui +The following diagram illustrates the registration (create and update) process for digital twins. It is always triggered +as soon as a MaterialPartnerRelation is changed. The Digital Twin is always recreated fully. -When reloading the UI, the latest data is pulled from the backend. Whenever an update on the information is performed, -then the frontend hands over the data to the backend to perform the action. +## Scenario: Interact with Data in the Web-UI -The web-ui allows the following interactions: +When reloading the UI, the latest data is pulled from the backend. Whenever a partner-related update on the information +is performed, then the frontend hands over the request to the backend to perform the action. -- create or update stocks for a partner. -- select a specific stock to see the related partner stocks. -- Trigger an update for all partner's data for a specific material (see previous Scenario). +Details on the Web-Ui can be found in the [User Guide](../userGuide/User_Guide.md). diff --git a/docs/arc42/img/06-api-flow-detailed.svg b/docs/arc42/img/06-api-flow-detailed.svg index a45b8bbd..2754e74c 100644 --- a/docs/arc42/img/06-api-flow-detailed.svg +++ b/docs/arc42/img/06-api-flow-detailed.svg @@ -1,4 +1,4 @@ -Data ConsumerData ProviderBusinessApplicationBusinessApplicationEDC ConsumerEDC ConsumerEDC ProviderEDC ProviderBusinessApplicationBusinessApplication1search for request assets at partner2catalog communication3catalog4identify Information ObjectExchange Request asset5negotiate contract for InformationObject Exchange Request API6negotiation7contract agreementDefine Endpoint Data Reference Endpoint =Business Application8initialize transfer9initialize transfer10transfer completed, EDR sent11prepare request based onEDR endpoint and authRequest against Endpoint via EDC12Request Information Object Exchange (via EDC)13proxy request14Accepted15Accepted16Determine requested Information Objectsimplified communication with EDC, same as above17EDC communication18EDC communication19transfer completed, EDR sentSend requested Information Objectvia EDC20Response Information Object Exchange (via EDC)21proxy request22Accepted23Accepted24use data +Data ConsumerData ProviderBusinessApplicationBusinessApplicationEDCConsumerEDCConsumerEDCProviderEDCProviderDTProviderDTProviderSubmodelEndpointSubmodelEndpointIdentify Data via Digital Twin Registry of ProviderContract DTR Usage1search for DTR assets at partner2catalog communication3catalog4identify DTR Offer(filter by dcat:type, cx:version)5negotiate contract for DTR usage6negotiation7contract agreement (contractAgreementId)8initialize transfer9initialize transfer10transfer completed (transferProcessId)11get EDR for transferProcessId12get EDR for transfer13EDR (refreshed)Lookup and Determine ShellDescriptor for Material in Question14prepare material identificationas specific asset ids15prepare dtr lookup based onEDR endpoint and authLookup request against DTR via EDCusing EDR for authentication16Lookup Material Twin at partner (via EDC)lookup uses base64-encoded parameters for- manufacturerId- manufacturerPartId- digitalTwinType = "PartType"17proxy request18lookup result19lookup result20base64 encodereturned shell-idShell Descriptors request against DTR via EDCusing EDR for authentication21Query Shell-Descriptor ofMaterial Twin at partner (via EDC)22proxy request23found shellDescriptors24found shellDescriptors25terminate transfer by transferProcessId26terminate transfer27transfer terminatedDetermine Submodel Endpoint of Submodel Type of Interest28lookup submodel "DSP" endpointfor semantic id of interest29check if contract is given30extract submodel data(edc endpoints, asset id, href)Query Submodel Data at Provider EDCContract Submodel Usage31search for submodel asset at partner(request with asset id)32catalog communication33catalog34filter offers bydata sovereignty criteria(framework agreement & purpose)35negotiate contract for submodel data36negotiation37contract agreement (contractAgreementId)38remember Contract for future usage39initialize transfer40initialize transfer41transfer completed (transferProcessId)42get EDR for transferProcessId43get EDR for transfer44EDR (refreshed)Request Submodel via EDCrequest submodel via EDC using EDR for authentication45Query submodel endpoint with href fromSubmodelDescriptor.endpoint46proxy request47found submodel48found submodel49terminate transfer by transferProcessId50terminate transfer51transfer terminated diff --git a/docs/arc42/img/06-api-flow.svg b/docs/arc42/img/06-api-flow.svg deleted file mode 100755 index 1cf39a34..00000000 --- a/docs/arc42/img/06-api-flow.svg +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - Data Consumer - - - Data Provider - - - - - - Business - - Application - - - Business - - Application - - - Business - - Application - - - Business - - Application - - - - - 1 - - Request Information Object Exchange - - - - Request Endpoint - - - - 2 - - Accepted - - - - - - 3 - - Determine requested Information Object - - - - 4 - - Send requested Information Object - - - - Response Endpoint - - - - 5 - - Accepted - - - diff --git a/docs/arc42/puml/06-api-flow-detailed.puml b/docs/arc42/puml/06-api-flow-detailed.puml index ebeda45f..e3c60f73 100644 --- a/docs/arc42/puml/06-api-flow-detailed.puml +++ b/docs/arc42/puml/06-api-flow-detailed.puml @@ -26,22 +26,36 @@ app_cons -> app_cons: identify DTR Offer\n(filter by dcat:type, cx:version) app_cons -> edc_cons: negotiate contract for DTR usage activate edc_cons edc_cons <-> edc_prov: negotiation -edc_cons --> app_cons: contract agreement +edc_cons --> app_cons: contract agreement (contractAgreementId) deactivate edc_cons -note over app_cons, edc_cons: Define Transfer Callback url = \n Business Application app_cons -> edc_cons: initialize transfer activate edc_cons edc_cons <-> edc_prov: initialize transfer -edc_cons --> app_cons: transfer completed, EDR sent +edc_cons --> app_cons: transfer completed (transferProcessId) +deactivate edc_cons + +app_cons -> edc_cons: get EDR for transferProcessId +activate edc_cons +edc_cons <-> edc_prov: get EDR for transfer +edc_cons --> app_cons: EDR (refreshed) deactivate edc_cons == Lookup and Determine ShellDescriptor for Material in Question == app_cons -> app_cons: prepare material identification\nas specific asset ids app_cons -> app_cons: prepare dtr lookup based on\nEDR endpoint and auth -note over app_cons, edc_cons: Lookup request against DTR via EDC +note over app_cons, edc_cons +Lookup request against DTR via EDC +using EDR for authentication +end note app_cons -> edc_prov: Lookup Material Twin at partner (via EDC) +note right +lookup uses base64-encoded parameters for +- manufacturerId +- manufacturerPartId +- digitalTwinType = "PartType" +end note activate edc_prov edc_prov -> dtr_prov: proxy request activate dtr_prov @@ -51,7 +65,10 @@ edc_prov --> app_cons: lookup result deactivate edc_prov app_cons -> app_cons: base64 encode\nreturned shell-id -note over app_cons, edc_cons: Shell Descriptors request against DTR via EDC +note over app_cons, edc_cons +Shell Descriptors request against DTR via EDC +using EDR for authentication +end note app_cons -> edc_prov: Query Shell-Descriptor of \nMaterial Twin at partner (via EDC) activate edc_prov edc_prov -> dtr_prov: proxy request @@ -61,6 +78,12 @@ deactivate dtr_prov edc_prov --> app_cons: found shellDescriptors deactivate edc_prov +app_cons -> edc_cons: terminate transfer by transferProcessId +activate edc_cons +edc_cons <-> edc_prov: terminate transfer +edc_cons --> app_cons: transfer terminated +deactivate edc_cons + == Determine Submodel Endpoint of Submodel Type of Interest == app_cons -> app_cons: lookup submodel "DSP" endpoint\nfor semantic id of interest app_cons -> app_cons: check if contract is given @@ -79,17 +102,25 @@ app_cons -> app_cons: filter offers by\ndata sovereignty criteria\n(framework ag app_cons -> edc_cons: negotiate contract for submodel data activate edc_cons edc_cons <-> edc_prov: negotiation -edc_cons --> app_cons: contract agreement +edc_cons --> app_cons: contract agreement (contractAgreementId) deactivate edc_cons -note over app_cons, edc_cons: Define Transfer Callback url = \n Business Application +app_cons -> app_cons: remember Contract for future usage + app_cons -> edc_cons: initialize transfer activate edc_cons edc_cons <-> edc_prov: initialize transfer -edc_cons --> app_cons: transfer completed, EDR sent +edc_cons --> app_cons: transfer completed (transferProcessId) +deactivate edc_cons + +app_cons -> edc_cons: get EDR for transferProcessId +activate edc_cons +edc_cons <-> edc_prov: get EDR for transfer +edc_cons --> app_cons: EDR (refreshed) deactivate edc_cons == Request Submodel via EDC == +note over app_cons, edc_cons: request submodel via EDC using EDR for authentication app_cons -> edc_prov: Query submodel endpoint with href from\nSubmodelDescriptor.endpoint activate edc_prov edc_prov -> se_prov: proxy request @@ -99,4 +130,9 @@ deactivate se_prov edc_prov --> app_cons: found submodel deactivate edc_prov +app_cons -> edc_cons: terminate transfer by transferProcessId +activate edc_cons +edc_cons <-> edc_prov: terminate transfer +edc_cons --> app_cons: transfer terminated +deactivate edc_cons @enduml diff --git a/docs/arc42/puml/06-api-flow.puml b/docs/arc42/puml/06-api-flow.puml deleted file mode 100644 index c8241fac..00000000 --- a/docs/arc42/puml/06-api-flow.puml +++ /dev/null @@ -1,26 +0,0 @@ -@startuml -autonumber -skinparam sequenceMessageAlign center - -box "Data Consumer" -participant "Business\nApplication" as app_cons -end box - -box "Data Provider" -participant "Business\nApplication" as app_prov -end box - - -app_cons -> app_prov: Request Information Object Exchange -note right: Request Endpoint -return Accepted - -activate app_prov -app_prov -> app_prov: Determine requested Information Object - -app_prov -> app_cons: Send requested Information Object -note left: Response Endpoint -deactivate app_prov -return Accepted - -@enduml From 33ea453f5c89625b039a0f1d6fda647d295b9350 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 06:12:28 -0700 Subject: [PATCH 04/17] docs(arc42/runtimeView): updated Digital Twin creation --- docs/arc42/06_runtime_view.md | 2 ++ docs/arc42/img/06-twin-creation.svg | 1 + docs/arc42/puml/06-twin-creation.puml | 8 +++++--- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 docs/arc42/img/06-twin-creation.svg diff --git a/docs/arc42/06_runtime_view.md b/docs/arc42/06_runtime_view.md index fbd1bcdd..023beaf7 100644 --- a/docs/arc42/06_runtime_view.md +++ b/docs/arc42/06_runtime_view.md @@ -61,6 +61,8 @@ needs to lookup and use this Catena-X ID as the `globalAssetId` The following diagram illustrates the registration (create and update) process for digital twins. It is always triggered as soon as a MaterialPartnerRelation is changed. The Digital Twin is always recreated fully. +![Overview of Digital Twin Creation](img/06-twin-creation.svg) + ## Scenario: Interact with Data in the Web-UI When reloading the UI, the latest data is pulled from the backend. Whenever a partner-related update on the information diff --git a/docs/arc42/img/06-twin-creation.svg b/docs/arc42/img/06-twin-creation.svg new file mode 100644 index 00000000..5938a55a --- /dev/null +++ b/docs/arc42/img/06-twin-creation.svg @@ -0,0 +1 @@ +PURIS backendMaterialControllerMaterialControllerMaterialPartnerRelationsControllerMaterialPartnerRelationsControllerMaterialServiceImplMaterialServiceImplMaterialPartnerRelationServiceImplMaterialPartnerRelationServiceImplEdcAdapterServiceEdcAdapterServiceDtrAdapterServiceDtrAdapterServiceCreate or Update Material or Product1Create or Update Material or Productalt[create material or product]2Generate or takeCatena-X ID(save on material)3OK4Create or Updae MPR for partnerand material / product5Create DtrRegistrationTask6Determine Partners whobuy material and supply productDtrRegistrationTaskalt[at least one Partner who buys (We're the supplier)]7Create ShellDescriptor with access rights for buyingpartners and all submodels8OK[at least one Partner who sells (We're the customer)]alt[MPR does not yet have the CX-ID]9Lookup DigitalTwin at Supplierto extract Catena-X ID10Lookup and Contract DTR11Determine ShellDescriptor andSubmodel "DSP" Endpoint forPartTypeInformation frompartner DTR12Query PartTypeInformation Submodelat partner13Extract Catena-X ID from Submodel14Catena-X ID15Set Partner Catena-X ID16Save MaterialPartnerRelationship17Create or Update ShellDescriptor with access rights for sellingpartners and all submodels18OK19OK \ No newline at end of file diff --git a/docs/arc42/puml/06-twin-creation.puml b/docs/arc42/puml/06-twin-creation.puml index d54293f3..50da1c0b 100644 --- a/docs/arc42/puml/06-twin-creation.puml +++ b/docs/arc42/puml/06-twin-creation.puml @@ -12,14 +12,16 @@ participant "DtrAdapterService" as dtr_s end box -=== Create Material or Product == -m_c -> m_s: Create Material or Product +=== Create or Update Material or Product == +m_c -> m_s: Create or Update Material or Product activate m_s +alt create material or product m_s -> m_s: Generate or take\nCatena-X ID\n(save on material) +end m_s --> m_c: OK deactivate m_s -mpr_c -> mpr_s: Create MPR for partner\nand material / product +mpr_c -> mpr_s: Create or Updae MPR for partner\nand material / product activate mpr_s mpr_s -> mpr_s: Create DtrRegistrationTask mpr_s -> mpr_s: Determine Partners who\nbuy material and supply product From 52f664f3f30396f48dcbb5a6f28990f4a6dcb7ec Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 07:02:23 -0700 Subject: [PATCH 05/17] docs(arc42,adminGuide): updated data sovereignty handling and configuration --- CHANGELOG.md | 47 +++++++++++ docs/adminGuide/Admin_Guide.md | 65 +++++++++++---- docs/arc42/08_concepts.md | 143 +++++++++++++++++++++++++++++---- 3 files changed, 224 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 887a5f0f..1dd0e6ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v2.0.0](https://github.com/eclipse-tractusx/puris/releases/tag/v2.0.0) + +### Added + +- Implementation of the following standards relying on Digital Twins and Industry Core + - Delivery Information Exchange CX-0118, version 2.0.0 + - Short-Term Material Demand Exchange CX-0120, version 2.0.0 + - Planned Production Output Exchange CX-0121, version 2.0.0 + - Item Stock Exchange CX-0122, version 2.0.0 +- Data Sovereignty + - Added Usage Purpose as mandatory for Submodel +- Infrastructure + - Digital Twin Registry is mandatory (app version) + - Update to Tractus-x EDC Version 0.7.3 (app version) + - Mock version of IATP compliant MIW for local deployment + +### Changed + +- Framework Credential now is mandatory (removed `backend.frameworkagreement.use`) + +### Removed + +- Implementation of CX-0122 version 1.0.0 + +### Security + +- Identity Provider (IDP) support for DTR + - One user for EDC (read) + - One user for PURIS (manage) + +### Known Knowns + +#### Data Sovereignty + +For productive use the following enhancements are encouraged + +- UI to create and manage contract offers and contracts +- possibility to add contract references +- possibility to use multiple Framework or Usage Purpose Constraints in contract policies +- possibility to define contract policies per partner +- user feedback on why negotiations failed (currently refresh runs asynchronously and the admin may only get sufficient + insights from the logs) + +#### Styleguide + +To be checked + ## [v1.0.0](https://github.com/eclipse-tractusx/puris/releases/tag/v1.0.0) ### Added diff --git a/docs/adminGuide/Admin_Guide.md b/docs/adminGuide/Admin_Guide.md index 7fe60383..b4ec76c6 100644 --- a/docs/adminGuide/Admin_Guide.md +++ b/docs/adminGuide/Admin_Guide.md @@ -78,29 +78,61 @@ To host an example keycloak instance, configure the following: _Note: The application does NOT make use of the `Client Authentication` (private) feature of Keycloak Clients._ -## Configure Framework Agreement Credential Usage +## Data Sovereignty related configuration -To configure the usage of a framework agreement credential, that is automatically enforced by the EDC during contracting -(see further details in [ARC42 - Chapter 8](../arc42/08_concepts.md)), the following property needs to be configured: +With R24.05, always Framework Agreement and Usage Purpose Contract Policies need to be used. Refer to +[ARC42 - Chapter 8](../arc42/08_concepts.md) for the influence of these configurations. +TLDR; you define the definition of the policy you want to use and that you'll accept. PURIS FOSS only handles one policy +that is templated. You can only configure the name and version of the Framework Agreement Credential and the Usage +Purpose. -- `backend.frameworkagreement.credential` (docker `PURIS_FRAMEWORKAGREEMENT_CREDENTIAL`) = 'puris' (NOTE: not available - for R24.03) +### Framework Agreement -_**ATTENTION**: If the credential is NOT listed in the Connector Standard (CX-0018) of the current release, then the -Tractus-X EDC will NOT technically enforce the credential by checking the availability in the Managed Identity Wallet. -Thus, it may seem that the Credential is available, but isn't. Same applies to typos._ +To configure the Framework Agreement credential, that is automatically enforced by the EDC during contracting +(see further details in [ARC42 - Chapter 8](../arc42/08_concepts.md)), the following properties need to be configured. +The table contains +the puris defaults for release R24.05. + +| Helm | Docker | Configuration | +|---------------------------------------------|-------------------------------------|---------------| +| backend.puris.frameworkagreement.credential | PURIS_FRAMEWORKAGREEMENT_CREDENTIAL | Puris | +| backend.puris.frameworkagreement.version | PURIS_FRAMEWORKAGREEMENT_VERSION | 1.0 | + +_**ATTENTION**: If the credential is NOT listed in +the [odrl profile](https://github.com/catenax-eV/cx-odrl-profile/blob/main/profile.md) +of the current release, then the Tractus-X EDC will NOT technically enforce the credential by checking the availability +in the Credential Service. Thus, it may seem that the Credential is available, but isn't. Same applies to typos._ _Note: Please refer to the [Portal's documentation on how to sign use case agreements](https://github.com/eclipse-tractusx/portal-assets/blob/main/docs/user/06.%20Certificates/01.%20UseCase%20Participation.md)._ +### Usage Purpose + +To configure the Usage Purpose under which the assets may be used (see further details +in [ARC42 - Chapter 8](../arc42/08_concepts.md)), +the following properties need to be configured. The table contains the puris defaults for release R24.05. + +| Helm | Docker | Configuration | +|-------------------------------|-----------------------|---------------| +| backend.puris.purpose.name | PURIS_PURPOSE_NAME | cx.puris.base | +| backend.puris.purpose.version | PURIS_PURPOSE_VERSION | 1 | + +_**ATTENTION**: Usage Purposes are no credentials than can be enforced technically. See a list of supported purposes +supported within Catena-X in the [odrl profile](https://github.com/catenax-eV/cx-odrl-profile/blob/main/profile.md) +of the current release._ + ## Rate Limiting using nginx Rate limiting is by default enabled in the puris frontend served by nginx and can be dynamically configured. -In order to adjust any variables of nginx's rate limiting or disable it, one has to modify the respective variables in either the -local docker deployment by setting the necessary environment variables, or by modifying the variables in the helm chart values.yaml. - -These variables then get dynamically injected in the nginx.conf file, which is then copied to the docker image to be used by nginx. -That means that the rate limiting can be disabled by modifying the nginx.conf file in the frontend folder. This is also the place +In order to adjust any variables of nginx's rate limiting or disable it, one has to modify the respective variables in +either the +local docker deployment by setting the necessary environment variables, or by modifying the variables in the helm chart +values.yaml. + +These variables then get dynamically injected in the nginx.conf file, which is then copied to the docker image to be +used by nginx. +That means that the rate limiting can be disabled by modifying the nginx.conf file in the frontend folder. This is also +the place to insert and override any other nginx configurations. ## Serving with HTTPS / SSL @@ -264,11 +296,11 @@ You can use this collection as an example for the REST API calls. Please note that since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. -If a CatenaX-Id was not assigned to your Material so far, then by having the ```puris.generatematerialcatenaxid``` set to ```true``` you can auto-generate one randomly (this is the default-setting, by the way). +If a CatenaX-Id was not assigned to your Material so far, then by having the ```puris.generatematerialcatenaxid``` set +to ```true``` you can auto-generate one randomly (this is the default-setting, by the way). In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. - ### Onboard Stock Information One may use the `StockView` related interfaces to add stocks after adding the master data to e.g. regularly update / @@ -287,5 +319,6 @@ the chart. Optionally it may be disabled to use your own installation. Refer to ## Encryption of confidential data at rest -Encryption at rest for databases works. It has been tested by either encrypting the docker folder or encrypting the whole +Encryption at rest for databases works. It has been tested by either encrypting the docker folder or encrypting the +whole filesystem of the machine running. diff --git a/docs/arc42/08_concepts.md b/docs/arc42/08_concepts.md index 8d3524e5..18739e84 100644 --- a/docs/arc42/08_concepts.md +++ b/docs/arc42/08_concepts.md @@ -40,34 +40,147 @@ Within PURIS this results in the following steps: Following the standard, the following measures have been taken: -Access Policies in charge: +- Access Policies and Access Restrictions +- Contract Policies +- Consumer Side Validation +- Views in Frontend (admin access, see [User Guide](../userGuide/User_Guide.md), not handled in this chapter) to + overview negotiations and transfers. + +### Access Policies and Access Restrictions + +Each Contract Offer has the same access policies. When creating a partner, for all potential assets a contract offer +is created using the following constraints: - Business Partner Number Legal Entity (BPNL) - Membership Credential -Usage Policies in charge: +Example Access Policy creation request used: + +```json +{ + "@context": [ + "http://www.w3.org/ns/odrl.jsonld", + { + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "cx-policy": "https://w3id.org/catenax/policy/" + } + ], + "@type": "PolicyDefinitionRequestDto", + "@id": "BPNL1234567890ZZ_policy", + "edc:policy": { + "@type": "Set", + "permission": [ + { + "action": "use", + "constraint": { + "@type": "LogicalConstraint", + "and": [ + { + "@type": "LogicalConstraint", + "leftOperand": "BusinessPartnerNumber", + "operator": "eq", + "rightOperand": "BPNL1234567890ZZ" + }, + { + "@type": "LogicalConstraint", + "leftOperand": "Membership", + "operator": "eq", + "rightOperand": "active" + } + ] + } + } + ] + } +} +``` + +**Digital Twin Registry Configuration** + +Additionally, when creating the Digital Twins in the Digital Twin Registry, the `ShellDescriptors` are restricted in +access using +the [classic Access Control](https://github.com/eclipse-tractusx/sldt-digital-twin-registry/tree/main/docs#classic-implementation) +which restricts the `specificAssetIds` based on BPNLs. + +### Contract Policies + +Two different policies are used depending on the Asset Type: + +- Digital Twin Registry: Use Access Policy also as Contract Policy +- Submodels: Use Contract Policy as defined below + +_Note: The submodel `PartTypeInformation` is also registered with the same Contract Policy as the other Submodels._ + +The Constraints used for the Submodel Contract Policies are the following: - Framework Agreement credential (partner signed the Framework Agreement) -- Purpose credential (partner is member of Catena-X) - -TODO: Example policies +- Usage Purpose (for what can the data be used) + +Example for Submodels based on following configurations: + +| Property (helm) | Value | +|---------------------------------------------|---------------| +| backend.puris.frameworkagreement.credential | Puris | +| backend.puris.frameworkagreement.version | 1.0 | +| backend.puris.purpose.name | cx.puris.base | +| backend.puris.purpose.version | 1 | + +```json +{ + "@context": [ + "http://www.w3.org/ns/odrl.jsonld", + { + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "cx-policy": "https://w3id.org/catenax/policy/" + } + ], + "@type": "PolicyDefinitionRequestDto", + "@id": "Contract_Policy", + "edc:policy": { + "@type": "Set", + "profile": "cx-policy:profile2405", + "permission": [ + { + "action": "use", + "constraint": { + "@type": "LogicalConstraint", + "and": [ + { + "@type": "LogicalConstraint", + "leftOperand": "https://w3id.org/catenax/policy/FrameworkAgreement", + "operator": "eq", + "rightOperand": "Puris:1.0" + }, + { + "@type": "LogicalConstraint", + "leftOperand": "https://w3id.org/catenax/policy/UsagePurpose", + "operator": "eq", + "rightOperand": "cx.puris.base:1" + } + ] + } + } + ] + } +} +``` _Note: see configuration of usage policies in [AdminGuide](../adminGuide/Admin_Guide.md)._ -All traffic to exchange information is routed through the EDC data plane using the proxy pull mechanism. +### Consumer Side Validation -Whenever a partner is created, a contract offer for the DTR is registered for the partner's BPNL. -Whenever a material partner relation (partner buys material, partner suppliers material), +Following +the [Digital Twin KIT R24.05](https://eclipse-tractusx.github.io/docs-kits/kits/Digital%20Twin%20Kit/Software%20Development%20View/dt-kit-software-development-view#usage-policies) +an empty contract policy shall be used for the DRR. This application does **NOT** check the contract policy of the +Digital Twin Registry, and uses an Access Policy on its own. -- the contract offers for the submodels are created for the partner -- the submodel descriptors are added to the twin +For Submodel assets a validation is performed: Whenever the catalog is queried for a Submodel Asset, the returned +catalog is filtered to the same policy that has been configured for the PURIS FOSS. -Additionally, the administrator may configure the application to use a framework agreement policy for data offers (see -[Administration Guide](../adminGuide/Admin_Guide.md)). When activated, +- if none matches, no negotiation is started +- if at least one matching definition is found, the first is taken to start the negotiation. -- the application requires the respective credential to be active for the partner. -- the application requires the framework agreement credential as contract policy when contracting a partner's offer as a - consumer. +The Contract Policy definition can be found above. ## Reusing Contracts & Caching DTR information From d602a4d5243710d1b93912190349165879aba2a8 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 09:23:35 -0700 Subject: [PATCH 06/17] docs(arc42): updated deployment view and security concept --- docs/arc42/07_deployment_view.md | 22 ++++++++++++- docs/arc42/08_concepts.md | 19 +++++++++-- docs/arc42/img/07-deployment-argo.png | Bin 0 -> 30295 bytes docs/arc42/img/07-deployment.png | Bin 0 -> 63539 bytes docs/arc42/puml/07-deployment-argo.puml | 14 ++++++-- docs/arc42/puml/07-deployment.puml | 42 +++++++++++++++++------- 6 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 docs/arc42/img/07-deployment-argo.png create mode 100644 docs/arc42/img/07-deployment.png diff --git a/docs/arc42/07_deployment_view.md b/docs/arc42/07_deployment_view.md index da8e65c0..e92ba72c 100644 --- a/docs/arc42/07_deployment_view.md +++ b/docs/arc42/07_deployment_view.md @@ -7,18 +7,38 @@ graphic. ![Local Deployment of two PURIS clients with MVD](img/07-deployment.svg) +The local deployment includes a mock of the dim service acting as a Central Wallet following IATP flow. Please refer to +[Mock IAM documentation](../../local/iam-mock/README.md) for further information. + +It uses one `Keycloak` (IDP) for everything except the PURIS Frontend (needs an external keycloak, not included in local +deployment). It has three realms (Customer, Supplier, MIW). + +_Note: MIW is currently commented out and the mock iam is used instead. With R24.08 hopefully the MIW can be used again. +_ + +It uses one DBMS (`Postgres DB MIW`) for the MIW and one for the rest (`Postgresql DB` for both `DTR`, `EDC`, +`PURIS Backend`) with each a separate Database. + **Helm / Kubernetes** One can configure the two local helm environments using the product helm chart and the [mxd tutorial](https://github.com/eclipse-tractusx/tutorial-resources/tree/main/mxd). +_Note: For Release R24.05 currently not possible._ + ## ArgoCD Deployment (e.g. INT) The very basic deployment for one PURIS FOSS looks as follows: ![Argo CD Deployment of one PURIS client](img/07-deployment-argo.svg) -The keycloak may be configured to be used. Also a decentral instance may be connected to the frontend. Refer to the +The keycloak may be configured to be used. Also, a decentral instance may be connected to the frontend. Refer to the [helm docs](../../charts/puris/README.md) for further information. +The following components are not part of the [puris helm chart](../../charts/puris/README.md) but need to be deployed +per partner: + +- `DTR` including `Postgres` and `Keycloak / IDP` +- `Connector` including `Postgres` + The chart allows also to either install the database as a dependency or bring your own. diff --git a/docs/arc42/08_concepts.md b/docs/arc42/08_concepts.md index 18739e84..9bf25497 100644 --- a/docs/arc42/08_concepts.md +++ b/docs/arc42/08_concepts.md @@ -197,12 +197,11 @@ There are two kind of assets, the PURIS FOSS application works with: - Application Programming Interfaces (currently only the DTR) - Submodel Endpoints (value-only serialization) -When contracting, the following information (`ContractMapping`) is stored: +When contracting, the following information (`ContractMapping`) is stored per partner (bpnl): - asset id - contract id - protocol url of edc -- href url per material (submodel only) When a new transfer is needed, the system checks if a `ContractMapping` for the resource in question exists. @@ -212,6 +211,9 @@ When a new transfer is needed, the system checks if a `ContractMapping` for the - if no, - go the whole way to get the data (contract DTR, contract submodel, save ContractMapping) +Sidenote: Edc information and hrefs for submodels are always taken from the `ShellDescriptor`. That means that whenever +a submodel is requested, the DTR of a partner is queried. + Whenever a partner is created, all exchanged information APIs that comply to a Catena-X standard are registered as contract offer for the partner's BPNL. @@ -226,4 +228,15 @@ Information'. Means there are two levels of security: 1. The partner is maintained and access has been granted via the EDC. 2. The partner is routed through the EDC. -To do the second, the Connector in use needs the extension [additional headers](TODO). +To do the second, the Connector in use needs the +extension [provision additional headers](https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/provision-additional-headers). + +Beside that the Backend can be configured to use the DTR with an IDP. The PURIS application could differentiate two +users. For configuration, please refer to the [Admin Guide](../adminGuide/Admin_Guide.md). + +- read access client for the EDC: added to the `dataAddress` of the DTR Asset +- manage access client for the PURIS application: used to create and manage the ShellDescriptors + +_Note: The reference +implementation [Digital Twin Registry](https://github.com/eclipse-tractusx/sldt-digital-twin-registry) +currently only works with one client._ diff --git a/docs/arc42/img/07-deployment-argo.png b/docs/arc42/img/07-deployment-argo.png new file mode 100644 index 0000000000000000000000000000000000000000..c693434c4e6b1270c4e0e118cbfb92c619a8f500 GIT binary patch literal 30295 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 literal 0 HcmV?d00001 diff --git a/docs/arc42/img/07-deployment.png b/docs/arc42/img/07-deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..8115bcc719b81add391e3a8d2632903a4c7d8930 GIT binary patch literal 63539 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 NI$8#rH@4WG{vVlrU{C-6 literal 0 HcmV?d00001 diff --git a/docs/arc42/puml/07-deployment-argo.puml b/docs/arc42/puml/07-deployment-argo.puml index 61345de3..71372e55 100644 --- a/docs/arc42/puml/07-deployment-argo.puml +++ b/docs/arc42/puml/07-deployment-argo.puml @@ -3,18 +3,26 @@ package "PURIS"{ + [Postgres TXC] as edc_pg [Tractus-X Connector] as edc [Digital Twin Registry] as dtr + [DTR IDP] as dtr_idp + [Postgres DTR] as dtr_pg [Postgresql DB] as postgres [PURIS FOSS Backend] as puris_backend [PURIS FOSS Frontend] as puris_frontend - puris_backend - edc - dtr -- puris_backend + puris_backend -- edc + edc - edc_pg + dtr_idp - edc + dtr - puris_backend + puris_backend -- dtr_idp + dtr_pg - dtr + dtr -- dtr_idp postgres -- puris_backend "Interface internal systems\n" - puris_backend - puris_backend -- puris_frontend + puris_backend - puris_frontend } diff --git a/docs/arc42/puml/07-deployment.puml b/docs/arc42/puml/07-deployment.puml index a18208e1..e9a7af6a 100644 --- a/docs/arc42/puml/07-deployment.puml +++ b/docs/arc42/puml/07-deployment.puml @@ -1,52 +1,72 @@ @startuml +skinparam linetype polyline +skinparam nodesep 75 +skinparam ranksep 50 -package "Customer"{ +package "Shared" { + [Postgresql DB] as postgres_shared + [Keycloak] as keycloak +} + + +package "Customer" { [Tractus-X Connector Customer] as edc_cus [Digital Twin Registry Customer] as dtr_cus - [Postgresql DB] as postgres_cus [PURIS FOSS Backend] as puris_backend_cus [PURIS FOSS Frontend] as puris_frontend_cus dtr_cus - puris_backend_cus + dtr_cus -- keycloak + dtr_cus -- postgres_shared + edc_cus -- postgres_shared puris_backend_cus - edc_cus - postgres_cus -- puris_backend_cus + puris_backend_cus -- postgres_shared + puris_backend_cus -- keycloak + puris_frontend_cus -- puris_backend_cus "Interface internal systems\n(Customer)" - puris_backend_cus - puris_backend_cus -- puris_frontend_cus } package "CX" { - [Keycloak] as keycloak - [Managed Identity Wallet] as miw + [Postgresql DB MIW] as pg_miw + [Managed Identity Wallet\nMock IAM] as miw + [BPNL Did Resolution Service] as bdrs -} + keycloak - pg_miw + pg_miw - miw +} -package "Supplier"{ +package "Supplier" { [Tractus-X Connector Supplier] as edc_sup [Digital Twin Registry Supplier] as dtr_sup - [Postgresql DB] as postgres_sup [PURIS FOSS Backend] as puris_backend_sup [PURIS FOSS Frontend] as puris_frontend_sup dtr_sup - puris_backend_sup + keycloak -- dtr_sup + keycloak -- puris_backend_sup + postgres_shared -- dtr_sup + postgres_shared -- edc_sup puris_backend_sup - edc_sup - postgres_sup -- puris_backend_sup - puris_backend_sup - "Interface internal systems\n(Supplier)" + postgres_shared -- puris_backend_sup + "Interface internal systems\n(Supplier)" - puris_backend_sup puris_backend_sup -- puris_frontend_sup } edc_cus -- keycloak edc_cus -- miw +edc_cus -- bdrs keycloak -- edc_sup miw -- edc_sup +bdrs -- edc_sup @enduml From 7067cafde6dbc5ad5c5a6d8f137d75484ee5c020 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 10:00:55 -0700 Subject: [PATCH 07/17] docs(adminGuide): updated endoints and added new configuration for dtr and idp --- docs/adminGuide/Admin_Guide.md | 73 +++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/docs/adminGuide/Admin_Guide.md b/docs/adminGuide/Admin_Guide.md index b4ec76c6..1a02442f 100644 --- a/docs/adminGuide/Admin_Guide.md +++ b/docs/adminGuide/Admin_Guide.md @@ -44,7 +44,34 @@ _Note: The API key header is hard coded to `X-API-KEY`._ Configuration of EDC, see e.g. [Tractus-EDC repository](https://github.com/eclipse-tractusx/tractusx-edc). Refer to the [local deployment with docker compose](../../local/docker-compose.yaml) for an example configuration. -Configure EDC addresses in the Backend with prefix `edc.`. Refer to the respective deployments for more information. +Configure EDC addresses in the Backend with prefix `backend.puris.edc.`. Refer to the respective deployments for more +information. + +## Configure DTR in Backend + +Configuration of the DTR , see +e.g. [Digital Twin Registry repository](https://github.com/eclipse-tractusx/sldt-digital-twin-registry). Refer to the +[local deployment with docker compose](../../local/docker-compose.yaml) for an example configuration. + +Configure teh dtr url in the Backend via prefix `backend.puris.dtr.url`. Refer to the respective deployments for more +information. + +### DTR - IDP configuration + +The DTR can be used with together with an IDP. The IDP can be configured in the Backend with prefix +`backend.puris.dtr.idp`. It can be enabled via the flag `enabled`. Beside the `tokenurl` two clients need to be +configured. + +In theory the PURIS FOSS application allows to have one read-only client to be used for queries through the EDC and one +manage (all rights) client used by PURIS FOSS to create and manage digital twins. +In practice, the DTR reference implementation allows only one user, resulting in the following configuration: + +| Helm | Value to set | +|----------------------------|---------------------------------------------------------------------------| +| `clients.puris.id ` | ID of the manage client | +| `clients.puris.secret` | Secret of the manage client | +| `clients.edc.id` | ID of the manage client | +| `clients.edc.secret.alias` | **Path to secret in the vault** accessed by the edc for the manage client | ## Integrate Keycloak into Frontend @@ -125,15 +152,15 @@ of the current release._ Rate limiting is by default enabled in the puris frontend served by nginx and can be dynamically configured. In order to adjust any variables of nginx's rate limiting or disable it, one has to modify the respective variables in -either the -local docker deployment by setting the necessary environment variables, or by modifying the variables in the helm chart -values.yaml. +either + +- the local docker deployment by setting the necessary environment variables, or +- by modifying the variables in the helm chart values.yaml (prefix `frontend.puris.rateLimiting`). These variables then get dynamically injected in the nginx.conf file, which is then copied to the docker image to be used by nginx. That means that the rate limiting can be disabled by modifying the nginx.conf file in the frontend folder. This is also -the place -to insert and override any other nginx configurations. +the place to insert and override any other nginx configurations. ## Serving with HTTPS / SSL @@ -280,6 +307,14 @@ production related information. _Note: The routes in the following always need to be used based on your backend address configuration including the context path._ +### Identity Configuration + +Your main information is added via the deployment. On Startup the application creates a partner for your own company. + +The company data can be set via helm variables with prefix `backend.puris.own`. It will create one partner with one +site and one address. The data should be your company's legal entity. The legal entity can then be enrichted same as +other partners using the "Onboarding Master Data" interfaces. + ### Onboard Master Data The application provides the following endpoints to update master data for your partner. This data may not be entered @@ -301,15 +336,24 @@ to ```true``` you can auto-generate one randomly (this is the default-setting, b In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. -### Onboard Stock Information +**ATTENTION:** please wait some time after updating master data prior to create or update operational data because the +Twins are registered asynchronously when creating / updating material partner relationships (see +[runtime view](../arc42/06_runtime_view.md) for more details). + +### Onboard operational data + +One may use the `StockView` related respectively the operational interfaces listed below to add operational data after +adding the master data to e.g. regularly update / overwrite the existing data. -One may use the `StockView` related interfaces to add stocks after adding the master data to e.g. regularly update / -overwrite the existing stocks. +| Interface | Route | Purpose | +|----------------------------|----------------------------|-------------------------------------------------------------------------------| +| Product Stock | /stockView/product-stocks | Add stocks allocated to your customer | +| Material Stock | /stockView/material-stocks | Add stocks allocated to your supplier | +| Short-Term Material Demand | /demand | Add allocated demands for your supplier | +| Planned Production Output | /production | Add allocated production outputs planned for your customer | +| Delivery Information | /delivery | Add delivery information for your customer or supplier (depends on inco term) | -| Interface | Route | Purpose | -|----------------|----------------------------|---------------------------------------| -| Product Stock | /stockView/product-stocks | Add stocks allocated to your customer | -| Material Stock | /stockView/material-stocks | Add stocks allocated to your supplier | +Please refer to the [Interface Documentation](../interfaceDoc) and the implementation for further information. ## Postgres @@ -320,5 +364,4 @@ the chart. Optionally it may be disabled to use your own installation. Refer to ## Encryption of confidential data at rest Encryption at rest for databases works. It has been tested by either encrypting the docker folder or encrypting the -whole -filesystem of the machine running. +whole filesystem of the machine running. From c3349057cac5a24632f83ec23182956e3daac9a5 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 10:23:43 -0700 Subject: [PATCH 08/17] docs(interface): added open API specification --- docs/api/openAPI.yaml | 2709 ++++++++++++++++++++++++++++ docs/interfaceDoc/Interface_Doc.md | 9 +- 2 files changed, 2715 insertions(+), 3 deletions(-) create mode 100644 docs/api/openAPI.yaml diff --git a/docs/api/openAPI.yaml b/docs/api/openAPI.yaml new file mode 100644 index 00000000..a7917878 --- /dev/null +++ b/docs/api/openAPI.yaml @@ -0,0 +1,2709 @@ +components: + schemas: + AddressDto: + properties: + bpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + country: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + streetAndNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + zipCodeAndCity: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + type: object + AllocatedPlannedProductionOutput: + properties: + estimatedTimeOfCompletion: + format: date-time + type: string + lastUpdatedOnDateTime: + format: date-time + type: string + plannedProductionQuantity: + $ref: '#/components/schemas/ItemQuantityEntity' + productionSiteBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + required: + - estimatedTimeOfCompletion + - lastUpdatedOnDateTime + - plannedProductionQuantity + - productionSiteBpns + type: object + DeliveryDto: + properties: + arrivalType: + enum: + - estimated-departure + - actual-departure + - estimated-arrival + - actual-arrival + type: string + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + dateOfArrival: + format: date-time + type: string + dateOfDeparture: + format: date-time + type: string + departureType: + enum: + - estimated-departure + - actual-departure + - estimated-arrival + - actual-arrival + type: string + destinationBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + destinationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + incoterm: + enum: + - EXW + - FCA + - FAS + - FOB + - CFR + - CIF + - DAP + - DPU + - CPT + - CIP + - DDP + type: string + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + originBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + originBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + ownMaterialNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + partnerBpnl: + pattern: ^BPNL[0-9a-zA-Z]{12}$ + type: string + quantity: + format: double + type: number + reported: + type: boolean + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + trackingNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + DeliveryInformation: + properties: + materialGlobalAssetId: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + positions: + items: + $ref: '#/components/schemas/Position' + type: array + uniqueItems: true + required: + - materialGlobalAssetId + - positions + type: object + Demand: + properties: + day: + format: date-time + type: string + demand: + $ref: '#/components/schemas/ItemQuantityEntity' + required: + - day + - demand + type: object + DemandDto: + properties: + day: + format: date-time + type: string + demandCategoryCode: + enum: + - '0001' + - A1S1 + - SR99 + - PI01 + - PO01 + - OS01 + - OI01 + - ED01 + type: string + demandLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + ownMaterialNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + partnerBpnl: + pattern: ^BPNL[0-9a-zA-Z]{12}$ + type: string + quantity: + format: double + type: number + supplierLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + uuid: + format: uuid + type: string + type: object + DemandSeries: + properties: + customerLocationBpns: + pattern: ^BPNS[a-zA-Z0-9]{12}$ + type: string + demandCategory: + enum: + - DemandCategoryType(demandCategoryCode=0001, demandCategoryName=Default) + - DemandCategoryType(demandCategoryCode=A1S1, demandCategoryName=After-Sales) + - DemandCategoryType(demandCategoryCode=SR99, demandCategoryName=Series) + - DemandCategoryType(demandCategoryCode=PI01, demandCategoryName=Phase-In + Period) + - DemandCategoryType(demandCategoryCode=OS01, demandCategoryName=Single + Order) + - DemandCategoryType(demandCategoryCode=OI01, demandCategoryName=Small Series) + - DemandCategoryType(demandCategoryCode=ED01, demandCategoryName=Extraordinary + Demand) + - DemandCategoryType(demandCategoryCode=PO01, demandCategoryName=Phase-Out + Period) + type: string + demands: + items: + $ref: '#/components/schemas/Demand' + type: array + uniqueItems: true + expectedSupplierLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + lastUpdatedOnDateTime: + format: date-time + type: string + required: + - customerLocationBpns + - demandCategory + - demands + - lastUpdatedOnDateTime + type: object + FrontendMaterialDto: + properties: + description: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + ownMaterialNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + type: object + ItemQuantityEntity: + properties: + unit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + value: + format: double + type: number + required: + - unit + - value + type: object + ItemStockSamm: + properties: + direction: + enum: + - INBOUND + - OUTBOUND + type: string + materialGlobalAssetId: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + positions: + items: + $ref: '#/components/schemas/Position' + type: array + uniqueItems: true + required: + - direction + - positions + type: object + JsonNode: + type: object + MaterialDto: + properties: + materialFlag: + type: boolean + materialNumberCustomer: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + materialNumberCx: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + materialNumberSupplier: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + name: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + productFlag: + type: boolean + uuid: + format: uuid + type: string + type: object + MaterialEntityDto: + properties: + materialFlag: + type: boolean + materialNumberCx: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + name: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + ownMaterialNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + productFlag: + type: boolean + type: object + MaterialStockDto: + properties: + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + isBlocked: + type: boolean + lastUpdatedOn: + format: date-time + type: string + material: + $ref: '#/components/schemas/MaterialDto' + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + partner: + $ref: '#/components/schemas/PartnerDto' + quantity: + format: double + type: number + stockLocationBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + stockLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + OrderPositionReference: + properties: + customerOrderId: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionId: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + supplierOrderId: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + required: + - customerOrderId + - customerOrderPositionId + type: object + PartnerDto: + properties: + addresses: + items: + $ref: '#/components/schemas/AddressDto' + type: array + uniqueItems: true + bpnl: + pattern: ^BPNL[0-9a-zA-Z]{12}$ + type: string + edcUrl: + pattern: ^http[s]?://([a-z0-9][a-z0-9\-]+[a-z0-9])(\.[a-z0-9\-]+)*(:[0-9]{1,4})?(/[a-z0-9\-]+)*[/]?$ + type: string + name: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + sites: + items: + $ref: '#/components/schemas/SiteDto' + type: array + uniqueItems: true + uuid: + format: uuid + type: string + type: object + PlannedProductionOutput: + properties: + materialGlobalAssetId: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + positions: + items: + $ref: '#/components/schemas/Position' + type: array + uniqueItems: true + required: + - materialGlobalAssetId + - positions + type: object + Position: + properties: + allocatedPlannedProductionOutputs: + items: + $ref: '#/components/schemas/AllocatedPlannedProductionOutput' + type: array + uniqueItems: true + lastUpdatedOnDateTime: + format: date-time + type: string + writeOnly: true + orderPositionReference: + $ref: '#/components/schemas/OrderPositionReference' + required: + - allocatedPlannedProductionOutputs + type: object + ProductStockDto: + properties: + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + isBlocked: + type: boolean + lastUpdatedOn: + format: date-time + type: string + material: + $ref: '#/components/schemas/MaterialDto' + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + partner: + $ref: '#/components/schemas/PartnerDto' + quantity: + format: double + type: number + stockLocationBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + stockLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + ProductionDto: + properties: + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + estimatedTimeOfCompletion: + format: date-time + type: string + material: + $ref: '#/components/schemas/MaterialDto' + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + partner: + $ref: '#/components/schemas/PartnerDto' + productionSiteBpns: + type: string + quantity: + format: double + type: number + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + ReportedMaterialStockDto: + properties: + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + isBlocked: + type: boolean + lastUpdatedOn: + format: date-time + type: string + material: + $ref: '#/components/schemas/MaterialDto' + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + partner: + $ref: '#/components/schemas/PartnerDto' + quantity: + format: double + type: number + stockLocationBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + stockLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + ReportedProductStockDto: + properties: + customerOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + customerOrderPositionNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + isBlocked: + type: boolean + lastUpdatedOn: + format: date-time + type: string + material: + $ref: '#/components/schemas/MaterialDto' + measurementUnit: + enum: + - unit:piece + - unit:set + - unit:pair + - unit:page + - unit:cycle + - unit:kilowattHour + - unit:gram + - unit:kilogram + - unit:tonneMetricTon + - unit:tonUsOrShortTonUkorus + - unit:ounceAvoirdupois + - unit:pound + - unit:metre + - unit:centimetre + - unit:kilometre + - unit:inch + - unit:foot + - unit:yard + - unit:squareCentimetre + - unit:squareMetre + - unit:squareInch + - unit:squareFoot + - unit:squareYard + - unit:cubicCentimetre + - unit:cubicMetre + - unit:cubicInch + - unit:cubicFoot + - unit:cubicYard + - unit:litre + - unit:millilitre + - unit:hectolitre + - unit:secondUnitOfTime + - unit:minuteUnitOfTime + - unit:hourUnitOfTime + - unit:day + type: string + partner: + $ref: '#/components/schemas/PartnerDto' + quantity: + format: double + type: number + stockLocationBpna: + pattern: ^BPNA[0-9a-zA-Z]{12}$ + type: string + stockLocationBpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + supplierOrderNumber: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + uuid: + format: uuid + type: string + type: object + ShortTermMaterialDemand: + properties: + demandSeries: + items: + $ref: '#/components/schemas/DemandSeries' + type: array + uniqueItems: true + materialGlobalAssetId: + pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) + type: string + required: + - demandSeries + type: object + SiteDto: + properties: + addresses: + items: + $ref: '#/components/schemas/AddressDto' + type: array + uniqueItems: true + bpns: + pattern: ^BPNS[0-9a-zA-Z]{12}$ + type: string + name: + pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ + type: string + type: object + securitySchemes: + X-API-KEY: + in: header + name: X-API-KEY + type: apiKey +info: + title: PURIS FOSS Open API + version: 1.0.0 +openapi: 3.0.1 +paths: + /delivery: + get: + description: Get all planned deliveries for the given material number. Optionally + a bpns and partner bpnl can be provided to filter the deliveries further. + operationId: getAllDeliveries + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + - in: query + name: bpns + required: false + schema: + type: string + - in: query + name: bpnl + required: false + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/DeliveryDto' + type: array + description: OK + summary: Get all planned deliveries for the given Material + tags: + - delivery-controller + post: + operationId: createDelivery + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DeliveryDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Delivery was created. + '201': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Created + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Delivery already exists. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Internal Server Error. + summary: Creates a new delivery + tags: + - delivery-controller + put: + operationId: updateDelivery + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DeliveryDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: OK + '204': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Delivery was updated. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Malformed or invalid request body. + '404': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Delivery does not exist. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryDto' + description: Internal Server Error. + summary: Updates a delivery by its UUID + tags: + - delivery-controller + /delivery-information/request/{materialNumberCx}/{representation}: + get: + operationId: getDeliveryMapping + parameters: + - in: header + name: edc-bpn + required: true + schema: + type: string + - in: path + name: materialNumberCx + required: true + schema: + type: string + - in: path + name: representation + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryInformation' + description: Ok + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryInformation' + description: Bad Request + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryInformation' + description: Internal Server Error + '501': + content: + '*/*': + schema: + $ref: '#/components/schemas/DeliveryInformation' + description: Unsupported representation + summary: This endpoint receives the Delivery Information Submodel 2.0.0 requests + tags: + - delivery-request-api-controller + /delivery/reported/refresh: + get: + description: Refreshes all reported deliveries from the delivery request API. + operationId: refreshReportedDeliveries + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + summary: Refreshes all reported deliveries + tags: + - delivery-controller + /delivery/{id}: + delete: + operationId: deleteDelivery + parameters: + - in: path + name: id + required: true + schema: + format: uuid + type: string + responses: + '204': + description: Delivery was deleted. + '400': + description: Malformed or invalid request body. + '404': + description: Delivery does not exist. + '500': + description: Internal Server Error. + summary: Deletes a delivery by its UUID + tags: + - delivery-controller + /demand: + get: + description: Get all own demands for the given material number. Optionally the + demanding site can be filtered by its bpns. + operationId: getAllDemands + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + - in: query + name: site + required: false + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/DemandDto' + type: array + description: OK + summary: Get all own demands for the given Material + tags: + - demand-controller + post: + operationId: createDemand + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DemandDto' + required: true + responses: + '201': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Demand was created. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Demand already exists. Use PUT instead. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Internal Server Error. + summary: Creates a new demand + tags: + - demand-controller + put: + operationId: updateDemand + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DemandDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Demand was updated. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Malformed or invalid request body. + '404': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Demand does not exist. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/DemandDto' + description: Internal Server Error. + summary: Updates a demand by its UUID + tags: + - demand-controller + /demand/reported: + get: + description: Get all demands of partners for a material number. Optionally the + partners can be filtered by their bpnl and the demanding site can be filtered + by its bpns. + operationId: getAllDemandsForPartner + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + - in: query + name: bpnl + required: false + schema: + type: string + - in: query + name: site + required: false + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/DemandDto' + type: array + description: OK + summary: Get all demands of partners for a material + tags: + - demand-controller + /demand/reported/refresh: + get: + description: Refreshes all reported demands from the demand request API. + operationId: refreshReportedProductions_1 + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + summary: Refreshes all reported demands + tags: + - demand-controller + /demand/{id}: + delete: + operationId: deleteDemand + parameters: + - in: path + name: id + required: true + schema: + format: uuid + type: string + responses: + '204': + description: Demand was deleted. + '400': + description: Malformed or invalid request body. + '404': + description: Demand does not exist. + '500': + description: Internal Server Error. + summary: Deletes a demand by its UUID + tags: + - demand-controller + /edc/assets: + get: + operationId: getAssets + parameters: + - in: query + name: assetId + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + type: string + description: OK + tags: + - edc-controller + /edc/catalog: + get: + operationId: getCatalog + parameters: + - in: query + name: dspUrl + required: true + schema: + type: string + - in: query + name: partnerBpnl + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + type: string + description: OK + tags: + - edc-controller + /edc/contractnegotiations: + get: + operationId: getContractNegotiations + responses: + '200': + content: + '*/*': + schema: + type: string + description: OK + tags: + - edc-controller + /edc/transfers: + get: + operationId: getTransfers + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/JsonNode' + description: OK + tags: + - edc-controller + /edrendpoint: + post: + operationId: authCodeReceivingEndpoint + requestBody: + content: + application/json: + examples: + EDR Token: + description: EDR Token + value: + at: 1699446240954 + id: 3b603c3e-0f1a-4989-90b7-a4b024496d04 + payload: + callbackAddresses: + - authCodeId: null + authKey: null + events: + - contract.negotiation + - transfer.process + transactional: false + uri: http://host.docker.internal:4000 + dataAddress: + properties: + https://w3id.org/edc/v0.0.1/ns/authCode: eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE2OTk0NDY4NDAsImRhZCI6ImMvMnFYVThaemVRTnJ5WDloUjhFZytONXpaWjhaUnc5dHpDOWRPcDlQNnpQQUhxZE9XN0pyN3JIWk94R0k0dFBXMmUxZVZ6elRJNlA5dUZXREpVVWtvRjJpWm93aXp6UEhmbGF4YTdsY0JIcWNISThhZWlEcm5MYiswM1ZXemRtMEZqLzNYYVdUa3VGYzM4VGtWS1lMaEViOVRNRUV4UGhqbEM5WFplamc0ZWJHNUZ6QldDQXZ2bmlMaWpFMjA4ZDhOcE80M0w5cG4xWXBpUThkZ2IrYjhkcEsyMDZObDNzTFhyS1hsU09ZaERHR2tLM2dSYkxBRHpiRjl3RWlCd3Z6SjFvSzFXbllzMVJwTVNOY1ZPc1ZseDJ6YS9mT1J6M29NYnh4TGdsSzMxU1c3NjVNWlVyWWlLK3JDOFhFaHNNa2JMSlNIcXhKYlFWYnZtL3dic1FyQWoxbUVsajhjbk9FY1p2NUhJOHJoUElyaTQyeU1hbXpWSXhXWW9hWU5PV0x4WHk1SUhZc3ZKcUJMc1cwaWs4eDlOZDhTcDduUGhqempLYjlQeFVVbCthS3BZQWVJaE9XZnNGT2pSMFFHM3lYcmJDalM0S1ZlaHhZbW1MZ0ZIczhyeWNsd1h2VUJzRkk4bzVLZUVwSll2U2RPSjlTQ0dNODB5a1lNczFxK0dTRVZmN2VrTUZRU2pjeGRSMElncUtFRk92OE5Ra3ZXZHAxbVpXc25IbnZNY2E0MFYxTm5nQWFVRndtRDhEeGVyc3k4R0IiLCJjaWQiOiJNUT09OlptVjBZMmhCYzNObGRBPT06T0dWbE4yWmhZelV0WlRjek15MDBPR0prTFRneFl6a3RaV1kzTkRsbFlXSTVNMll6In0.z9Nm_csmyHGBPGdEGgiyUV7pLWes0KE2IK82BHtCOS8XBerJrGb_wqNCgcgph6Zx7j84FwaVSH190FQ98FhJORgVCQ8u187hz1iPjXne9GEclR5Xr9_fSb9ZNK8VNTJvCdevJO5uT7Jkkc_-2U8DKUDDOj_Wqby8uStoSSs0P0idQ4pAazFYTy_Dbl0ltJsz6xc3YxwXk3yk0P1Ys5zYN0ueBznUMEJ6-YXpafAS5kn_iN8zU3It3Q2AgS0ER_M9AzeBHXZmST2MkaXXo3s_kuVxCZEtGRWkv8gmI3XZ5dprJ6x6keQSZ2ApSrxtmhswq2hPcqSQXF1gIFTTSSzg8A + https://w3id.org/edc/v0.0.1/ns/authKey: Authorization + https://w3id.org/edc/v0.0.1/ns/endpoint: http://supplier-data-plane:9285/api/public/ + https://w3id.org/edc/v0.0.1/ns/id: e5c59912-b88a-4c42-9766-9fa593b72603 + https://w3id.org/edc/v0.0.1/ns/type: EDR + transferProcessId: e5c59912-b88a-4c42-9766-9fa593b72603 + type: TransferProcessStarted + schema: + $ref: '#/components/schemas/JsonNode' + required: true + responses: + '200': + content: + '*/*': + schema: + type: string + description: Ok + '400': + content: + '*/*': + schema: + type: string + description: Invalid message body + summary: Endpoint for receiving the authCodes from the counterparty's connector + tags: + - endpoint-data-reference-receiver + /health/: + get: + operationId: getHealth + responses: + '200': + content: + '*/*': + schema: + type: object + description: OK + tags: + - health-controller + /item-stock/request/{materialnumber}/{direction}/{representation}: + get: + operationId: getMappingItemStock2 + parameters: + - in: header + name: edc-bpn + required: true + schema: + type: string + - in: path + name: materialnumber + required: true + schema: + type: string + - in: path + name: direction + required: true + schema: + enum: + - INBOUND + - OUTBOUND + type: string + - in: path + name: representation + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/ItemStockSamm' + description: Ok + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ItemStockSamm' + description: Bad Request + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ItemStockSamm' + description: Internal Server Error + '501': + content: + '*/*': + schema: + $ref: '#/components/schemas/ItemStockSamm' + description: Unsupported representation + summary: This endpoint receives the ItemStock Submodel 2.0.0 requests + tags: + - item-stock-request-api-controller + /material-demand/request/{materialnumbercx}/{representation}: + get: + operationId: getDemandMapping + parameters: + - in: header + name: edc-bpn + required: true + schema: + type: string + - in: path + name: materialnumbercx + required: true + schema: + type: string + - in: path + name: representation + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/ShortTermMaterialDemand' + description: Ok + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ShortTermMaterialDemand' + description: Bad Request + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ShortTermMaterialDemand' + description: Internal Server Error + '501': + content: + '*/*': + schema: + $ref: '#/components/schemas/ShortTermMaterialDemand' + description: Unsupported representation + summary: This endpoint receives the ShortTermMaterialDemand Submodel 1.0.0 requests + tags: + - demand-request-api-controller + /materialpartnerrelations: + post: + description: 'Creates a new MaterialPartnerRelation with the given parameter + data. Please note that this is only possible, if the designated Material and + Partner entities have already been created before this request. ' + operationId: createMaterialPartnerRelation + parameters: + - description: The Material Number that is used in your own company to identify + the Material. + example: MNR-7307-AU340474.002 + in: query + name: ownMaterialNumber + required: true + schema: + type: string + - description: The unique BPNL that was assigned to that Partner. + example: BPNL2222222222RR + in: query + name: partnerBpnl + required: true + schema: + type: string + - description: The Material Number that this Partner is using in his own company + to identify the Material. + example: MNR-8101-ID146955.001 + in: query + name: partnerMaterialNumber + required: true + schema: + type: string + - description: The CatenaX Number that this Partner uses + example: 860fb504-b884-4009-9313-c6fb6cdc776b + in: query + name: partnerCXNumber + required: false + schema: + type: string + - description: The informal name that this Partner uses + example: Semiconductor + in: query + name: nameAtManufacturer + required: false + schema: + type: string + - description: This boolean flag indicates whether this Partner is a potential + supplier of the given Material. + example: true + in: query + name: partnerSupplies + required: true + schema: + type: boolean + - description: This boolean flag indicates whether this Partner is a potential + customer of this Material. + example: true + in: query + name: partnerBuys + required: true + schema: + type: boolean + responses: + '200': + content: + '*/*': + schema: + type: object + description: Successfully created a new MaterialPartnerRelationEntity. + '400': + content: + '*/*': + schema: + type: object + description: Material and/or Partner do not exist or invalid parameters + '409': + content: + '*/*': + schema: + type: object + description: Relation for given Material and Partner does already exist. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server Error. + tags: + - material-partner-relations-controller + put: + description: 'Updates an existing MaterialPartnerRelation. You have to specify + the ownMaterialNumber and the partnerBpnl. The other three parameters are + genuinely optional. Provide them only if you want to change their values. ' + operationId: updateMaterialPartnerRelation + parameters: + - description: The Material Number that is used in your own company to identify + the Material. + example: MNR-7307-AU340474.002 + in: query + name: ownMaterialNumber + required: true + schema: + type: string + - description: The unique BPNL that was assigned to that Partner. + example: BPNL2222222222RR + in: query + name: partnerBpnl + required: true + schema: + type: string + - description: The Material Number that this Partner is using in his own company + to identify the Material. + example: MNR-8101-ID146955.001 + in: query + name: partnerMaterialNumber + required: false + schema: + type: string + - description: The CatenaX Number that this Partner uses + example: 860fb504-b884-4009-9313-c6fb6cdc776b + in: query + name: partnerCXNumber + required: false + schema: + type: string + - description: The informal name that this Partner uses + example: Semiconductor + in: query + name: nameAtManufacturer + required: false + schema: + type: string + - description: This boolean flag indicates whether this Partner is a potential + supplier of the given Material. + example: true + in: query + name: partnerSupplies + required: false + schema: + type: boolean + - description: This boolean flag indicates whether this Partner is a potential + customer of this Material. + example: true + in: query + name: partnerBuys + required: false + schema: + type: boolean + responses: + '200': + content: + '*/*': + schema: + type: object + description: Update was accepted. + '400': + content: + '*/*': + schema: + type: object + description: Invalid parameters + '404': + content: + '*/*': + schema: + type: object + description: No existing entity was found. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server Error. + tags: + - material-partner-relations-controller + /materials: + get: + description: Returns the requested Material dto, specified by the given ownMaterialNumber. + operationId: getMaterial + parameters: + - description: The Material Number that is used in your own company to identify + the Material. + example: MNR-7307-AU340474.002 + in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialEntityDto' + description: Returns the requested Material. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialEntityDto' + description: Invalid parameter + '404': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialEntityDto' + description: Requested Material was not found. + tags: + - material-controller + post: + description: Creates a new Material entity with the data given in the request + body. As a bare minimum, it must contain a new, unique ownMaterialNumber. + operationId: createMaterial + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MaterialEntityDto' + required: true + responses: + '200': + content: + '*/*': + schema: + type: object + description: Successfully created a new Material entity. + '400': + content: + '*/*': + schema: + type: object + description: Malformed request body. + '409': + content: + '*/*': + schema: + type: object + description: Material with the given ownMaterialNumber already exists. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server error. + tags: + - material-controller + put: + description: Updates an existing Material entity with the data given in the + request body. + operationId: updateMaterial + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MaterialEntityDto' + required: true + responses: + '200': + content: + '*/*': + schema: + type: object + description: Update was accepted. + '400': + content: + '*/*': + schema: + type: object + description: Malformed request body. + '404': + content: + '*/*': + schema: + type: object + description: No existing Material Entity found, no update was performed. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server Error. + tags: + - material-controller + /materials/all: + get: + description: Returns a list of all Materials and Products. + operationId: listMaterials + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/MaterialEntityDto' + type: array + description: OK + tags: + - material-controller + /partners: + get: + description: Returns the requested PartnerDto. + operationId: getPartner + parameters: + - description: The unique BPNL that was assigned to that Partner. + example: BPNL2222222222RR + in: query + name: partnerBpnl + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/PartnerDto' + description: Found Partner, returning it in response body. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/PartnerDto' + description: Invalid parameter. + '404': + content: + '*/*': + schema: + $ref: '#/components/schemas/PartnerDto' + description: Requested Partner not found. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/PartnerDto' + description: Internal Server Error. + tags: + - partner-controller + post: + description: Creates a new Partner entity with the data given in the request + body. Please note that no UUID can be assigned to a Partner that wasn't created + before. So the request body must not contain a UUID. + operationId: createPartner + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PartnerDto' + required: true + responses: + '200': + content: + '*/*': + schema: + type: object + description: Partner created successfully. + '400': + content: + '*/*': + schema: + type: object + description: Request body was malformed, didn't meet the minimum constraints + or wrongfully contained a UUID. + '409': + content: + '*/*': + schema: + type: object + description: 'The BPNL specified in the request body is already assigned. ' + tags: + - partner-controller + /partners/all: + get: + description: 'Returns a list of all Partners. ' + operationId: listPartners + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + tags: + - partner-controller + /partners/ownSites: + get: + description: Returns all sites of the puris partner using the puris system. + operationId: getOwnSites + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/SiteDto' + type: array + description: OK + tags: + - partner-controller + /partners/putAddress: + put: + description: 'Updates an existing Partner by adding a new Address. If that Partner + already has an Address with the BPNA given in the request body, that existing + Address will be overwritten. ' + operationId: addAddress + parameters: + - description: The unique BPNL that was assigned to that Partner. + example: BPNL2222222222RR + in: query + name: partnerBpnl + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AddressDto' + required: true + responses: + '200': + content: + '*/*': + schema: + type: object + description: Update accepted. + '400': + content: + '*/*': + schema: + type: object + description: Invalid Address data or invalid partnerBpnl. + '404': + content: + '*/*': + schema: + type: object + description: Partner not found. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server Error. + tags: + - partner-controller + /partners/putSite: + put: + description: 'Updates an existing Partner by adding a new Site. If that Partner + already has a Site with the BPNS given in the request body, that existing + Site will be overwritten. ' + operationId: addSite + parameters: + - description: The unique BPNL that was assigned to that Partner. + example: BPNL2222222222RR + in: query + name: partnerBpnl + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SiteDto' + required: true + responses: + '200': + content: + '*/*': + schema: + type: object + description: Update accepted. + '400': + content: + '*/*': + schema: + type: object + description: Invalid Address data or invalid partnerBpnl. + '404': + content: + '*/*': + schema: + type: object + description: Partner not found. + '500': + content: + '*/*': + schema: + type: object + description: Internal Server Error. + tags: + - partner-controller + /parttypeinformation/{materialnumber}/{representation}: + get: + description: Endpoint that delivers PartTypeInformation of own products to customer + partners. 'materialnumber' must be set to the ownMaterialNumber of the party, + that receives the request + operationId: getMapping + parameters: + - in: header + name: edc-bpn + required: true + schema: + type: string + - description: The material number that the request receiving party uses for + the material in question + in: path + name: materialnumber + required: true + schema: + type: string + - description: Must be set to '$value' + in: path + name: representation + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + type: object + description: Ok + '400': + content: + '*/*': + schema: + type: object + description: 'Invalid request parameters. ' + '401': + content: + '*/*': + schema: + type: object + description: 'Access forbidden. ' + '404': + content: + '*/*': + schema: + type: object + description: 'Product not found for given parameters. ' + '501': + content: + '*/*': + schema: + type: object + description: 'Unsupported representation requested. ' + tags: + - part-type-information-controller + /planned-production/request/{materialnumbercx}/{representation}: + get: + operationId: getProductionMapping + parameters: + - in: header + name: edc-bpn + required: true + schema: + type: string + - in: path + name: materialnumbercx + required: true + schema: + type: string + - in: path + name: representation + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/PlannedProductionOutput' + description: Ok + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/PlannedProductionOutput' + description: Bad Request + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/PlannedProductionOutput' + description: Internal Server Error + '501': + content: + '*/*': + schema: + $ref: '#/components/schemas/PlannedProductionOutput' + description: Unsupported representation + summary: This endpoint receives the PlannedProduction Submodel 2.0.0 requests + tags: + - production-request-api-controller + /production: + get: + description: Get all planned productions for the given material number. Optionally + the production site can be filtered by its bpns. + operationId: getAllProductions + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + - in: query + name: site + required: false + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: OK + summary: Get all planned productions for the given Material + tags: + - production-controller + post: + operationId: createProduction + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductionDto' + required: true + responses: + '201': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Planned Production was created. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Planned Production already exists. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Internal Server Error. + summary: Creates a new planned production + tags: + - production-controller + put: + operationId: updateProduction + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductionDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Planned Productions was updated. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Malformed or invalid request body. + '404': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Planned Production does not exist. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductionDto' + description: Internal Server Error. + summary: Updates a planned production by its UUID + tags: + - production-controller + /production/range: + post: + operationId: createProductionRange + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + required: true + responses: + '201': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: Planned Productions were created. + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: Planned Productions already exist. + '500': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: Internal Server Error. + summary: Creates a range of planned productions + tags: + - production-controller + /production/reported: + get: + description: Get all productions of partners for a material number. Optionally + the partners can be filtered by their bpnl and the production site can be + filtered by its bpns. + operationId: getAllProductionsForPartner + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + - in: query + name: bpnl + required: false + schema: + type: string + - in: query + name: site + required: false + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductionDto' + type: array + description: OK + summary: Get all productions of partners for a material + tags: + - production-controller + /production/reported/refresh: + get: + description: Refreshes all reported productions from the production request + API. + operationId: refreshReportedProductions + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + summary: Refreshes all reported productions + tags: + - production-controller + /production/{id}: + delete: + operationId: deleteProduction + parameters: + - in: path + name: id + required: true + schema: + format: uuid + type: string + responses: + '204': + description: Planned Productions was deleted. + '400': + description: Malformed or invalid request body. + '404': + description: Planned Production does not exist. + '500': + description: Internal Server Error. + summary: Deletes a planned production by its UUID + tags: + - production-controller + /stockView/customer: + get: + description: Returns a list of all Partners that are ordering the given material + operationId: getCustomerPartnersOrderingMaterial + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller + /stockView/material-stocks: + get: + description: Returns a list of all material-stocks + operationId: getMaterialStocks + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/MaterialStockDto' + type: array + description: OK + tags: + - stock-view-controller + post: + description: Creates a new material-stock + operationId: createMaterialStocks + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MaterialStockDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Material Stock was created. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Material Stock does already exist. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Internal Server Error. + tags: + - stock-view-controller + put: + description: Updates an existing material-stock + operationId: updateMaterialStocks + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MaterialStockDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Material Stock was updated. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Malformed request body. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/MaterialStockDto' + description: Internal Server Error. + tags: + - stock-view-controller + /stockView/materialnumbers-mapping: + get: + description: Returns a mapping of all material numbers, that others partners + are usingfor the material given in the request parameter. + operationId: getMaterialNumbers + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + examples: + Basic sample: + description: Basic sample + value: + BPNL1234567890ZZ: MNR-8101-ID146955.001 + BPNL4444444444XX: MNR-7307-AU340474.002 + description: OK + '400': + content: + '*/*': + schema: + additionalProperties: + type: string + type: object + description: Invalid parameter + tags: + - stock-view-controller + /stockView/materials: + get: + description: Returns a list of all materials (excluding products) + operationId: getMaterials + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/FrontendMaterialDto' + type: array + description: OK + tags: + - stock-view-controller + /stockView/product-stocks: + get: + description: Returns a list of all product-stocks + operationId: getProductStocks + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ProductStockDto' + type: array + description: OK + tags: + - stock-view-controller + post: + description: Creates a new product-stock + operationId: createProductStocks + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductStockDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Product Stock was created. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Malformed or invalid request body. + '409': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Product Stock does already exist. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Internal Server Error. + tags: + - stock-view-controller + put: + description: Updates an existing productstock + operationId: updateProductStocks + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductStockDto' + required: true + responses: + '200': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Product Stock was updated. + '400': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Malformed request body. + '500': + content: + '*/*': + schema: + $ref: '#/components/schemas/ProductStockDto' + description: Internal Server Error. + tags: + - stock-view-controller + /stockView/products: + get: + description: Returns a list of all products (excluding materials) + operationId: getProducts + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/FrontendMaterialDto' + type: array + description: OK + tags: + - stock-view-controller + /stockView/reported-material-stocks: + get: + description: Returns a list of all materials the partner (supplier) reported + he has at his site. Only stocks for the given material number are returned. + operationId: getSupplierMaterialStocks + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ReportedMaterialStockDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ReportedMaterialStockDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller + /stockView/reported-product-stocks: + get: + description: Returns a list of all products the partner (customer) reported + he has at his site. Only stocks for the given material number are returned. + operationId: getCustomerProductStocks + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ReportedProductStockDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/ReportedProductStockDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller + /stockView/supplier: + get: + description: Returns a list of all Partners that are supplying the given material + operationId: getSupplierPartnersSupplyingMaterial + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller + /stockView/update-reported-material-stocks: + get: + description: For the given material, all known suppliers will be requested to + report theircurrent stocks for our input material. The response body contains + a list of those supplier partners that were sent a request.Please note that + these requests are handled asynchronously by the partners, so there are no + guarantees, if and when the corresponding responses will be available. As + soon as a response arrives, it will be available via a call to the GET reported-material-stocks + endpoint. + operationId: triggerReportedMaterialStockUpdateForMaterialNumber + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller + /stockView/update-reported-product-stocks: + get: + description: For the given material, all known customers will be requested to + report theircurrent stocks for our output material. The response body contains + a list of those customer partners that were sent a request.Please note that + these requests are handled asynchronously by the partners, so there are no + guarantees, if and when the corresponding responses will be available. As + soon as a response arrives, it will be available via a call to the GET reported-material-stocks + endpoint. + operationId: triggerReportedProductStockUpdateForMaterialNumber + parameters: + - in: query + name: ownMaterialNumber + required: true + schema: + type: string + responses: + '200': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: OK + '400': + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PartnerDto' + type: array + description: Invalid parameter + tags: + - stock-view-controller +security: +- X-API-KEY: [] +servers: +- description: Generated server url + url: http://localhost:8081/catena diff --git a/docs/interfaceDoc/Interface_Doc.md b/docs/interfaceDoc/Interface_Doc.md index d015f4cc..6332c824 100644 --- a/docs/interfaceDoc/Interface_Doc.md +++ b/docs/interfaceDoc/Interface_Doc.md @@ -13,14 +13,17 @@ The [arc42 documentation](../arc42/Index.md) provides an overview based on the f ## Swagger documentation -You can refer to the INT environment application to view the swagger ui. +Please refer to the open API specification provided in `docs/api/openAPI.yaml`. + +To have a running swagger ui, feel free to check out the INT environment. ``` http://puris-customer.int.demo.catena-x.net/swagger-ui/index.html ``` -If not reachable, you can also deploy the backend application according to the [Install.md](../../backend/INSTALL.md) in -the backend and use the following path. +To have a running and executable swagger ui, feel free to also deploy the backend application according to the +[Install.md](../../backend/INSTALL.md) in the backend and use the following path. +To authorize requests copy the value of key `CUSTOMER_BACKEND_API_KEY` in `local/.env`. ``` http://localhost:8081/catena/swagger-ui/index.html From 8c8328f65c02e02323a497f07990b193175bf4a6 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 10:30:26 -0700 Subject: [PATCH 09/17] docs(./README.md): added non-chart dependencies --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 34c87bb6..5179a733 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,15 @@ The project is made of a backend and a frontend. Look into the respective folders and their documentation to get information about prerequirements and getting started guides. +## Dependencies + +Beside the dependencies provided in the Helm Chart, the following dependencies have been tested for R24.05 to run PURIS: + +| Application | App Version | Chart Version | +|-------------------------------------------------------------------------------------------------------------------|-------------|---------------| +| [Tractus-X Connector](https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector) | 0.7.2 | 0.7.2 | +| [Digital Twin Registry](https://github.com/eclipse-tractusx/sldt-digital-twin-registry/tree/main/charts/registry) | 0.4.3 | 0.4.11 | + ## Known Knows ### Data Sovereignty From cd4ea0cb6b136e2cf7974fdbf67a213a5cf90e96 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 10:34:42 -0700 Subject: [PATCH 10/17] docs: updated docs folder structure to TRG 1.08 --- README.md | 2 +- docs/README.md | 16 ++++++++-------- docs/{adminGuide => admin}/Admin_Guide.md | 9 +++++---- docs/{interfaceDoc => api}/Interface_Doc.md | 6 +++--- docs/arc42/img/06-twin-creation.svg | 1 - .../01_introduction_and_goals.md | 0 .../02_architecture_constraints.md | 0 .../03_system_scope_and_context.md | 0 .../04_solution_strategy.md | 0 .../05_building_block_view.md | 0 docs/{arc42 => architecture}/06_runtime_view.md | 4 ++-- .../07_deployment_view.md | 0 docs/{arc42 => architecture}/08_concepts.md | 8 ++++---- .../09_architecture_decisions.md | 0 .../10_quality_requirements.md | 0 .../11_technical_risks.md | 0 docs/{arc42 => architecture}/12_glossary.md | 0 docs/{arc42 => architecture}/Index.md | 0 .../img/03-business-context.svg | 0 .../img/03-technical-context.svg | 0 docs/{arc42 => architecture}/img/05-level-0.svg | 0 .../img/05-level-1-backend.svg | 0 .../img/05-level-1-frontend.svg | 0 .../img/06-api-flow-detailed.svg | 0 docs/architecture/img/06-twin-creation.svg | 4 ++++ .../img/07-deployment-argo.png | Bin .../img/07-deployment-argo.svg | 0 .../img/07-deployment.png | Bin .../img/07-deployment.svg | 0 .../puml/03-business-context.puml | 0 .../puml/03-technical-context.puml | 0 .../puml/05-level-0.puml | 0 .../puml/05-level-1-backend.puml | 0 .../puml/05-level-1-frontend.puml | 0 .../puml/06-api-flow-detailed.puml | 0 .../puml/06-twin-creation.puml | 0 .../puml/07-deployment-argo.puml | 0 .../puml/07-deployment.puml | 0 docs/{userGuide => user}/User_Guide.md | 0 docs/{userGuide => user}/img/catalog_view.png | Bin .../img/catalog_view_list.png | Bin docs/{userGuide => user}/img/dashboard_view.png | Bin .../img/dashboard_view_list.png | Bin .../img/negotiations_view.png | Bin .../img/negotiations_view_list.png | Bin docs/{userGuide => user}/img/stock_view.png | Bin .../img/stock_view_added_material_stock.png | Bin .../img/stock_view_selected_material_stock.png | Bin docs/{userGuide => user}/img/transfers_view.png | Bin .../img/transfers_view_list.png | Bin 50 files changed, 27 insertions(+), 23 deletions(-) rename docs/{adminGuide => admin}/Admin_Guide.md (98%) rename docs/{interfaceDoc => api}/Interface_Doc.md (76%) delete mode 100644 docs/arc42/img/06-twin-creation.svg rename docs/{arc42 => architecture}/01_introduction_and_goals.md (100%) rename docs/{arc42 => architecture}/02_architecture_constraints.md (100%) rename docs/{arc42 => architecture}/03_system_scope_and_context.md (100%) rename docs/{arc42 => architecture}/04_solution_strategy.md (100%) rename docs/{arc42 => architecture}/05_building_block_view.md (100%) rename docs/{arc42 => architecture}/06_runtime_view.md (95%) rename docs/{arc42 => architecture}/07_deployment_view.md (100%) rename docs/{arc42 => architecture}/08_concepts.md (97%) rename docs/{arc42 => architecture}/09_architecture_decisions.md (100%) rename docs/{arc42 => architecture}/10_quality_requirements.md (100%) rename docs/{arc42 => architecture}/11_technical_risks.md (100%) rename docs/{arc42 => architecture}/12_glossary.md (100%) rename docs/{arc42 => architecture}/Index.md (100%) rename docs/{arc42 => architecture}/img/03-business-context.svg (100%) rename docs/{arc42 => architecture}/img/03-technical-context.svg (100%) rename docs/{arc42 => architecture}/img/05-level-0.svg (100%) rename docs/{arc42 => architecture}/img/05-level-1-backend.svg (100%) rename docs/{arc42 => architecture}/img/05-level-1-frontend.svg (100%) rename docs/{arc42 => architecture}/img/06-api-flow-detailed.svg (100%) create mode 100644 docs/architecture/img/06-twin-creation.svg rename docs/{arc42 => architecture}/img/07-deployment-argo.png (100%) rename docs/{arc42 => architecture}/img/07-deployment-argo.svg (100%) rename docs/{arc42 => architecture}/img/07-deployment.png (100%) rename docs/{arc42 => architecture}/img/07-deployment.svg (100%) rename docs/{arc42 => architecture}/puml/03-business-context.puml (100%) rename docs/{arc42 => architecture}/puml/03-technical-context.puml (100%) rename docs/{arc42 => architecture}/puml/05-level-0.puml (100%) rename docs/{arc42 => architecture}/puml/05-level-1-backend.puml (100%) rename docs/{arc42 => architecture}/puml/05-level-1-frontend.puml (100%) rename docs/{arc42 => architecture}/puml/06-api-flow-detailed.puml (100%) rename docs/{arc42 => architecture}/puml/06-twin-creation.puml (100%) rename docs/{arc42 => architecture}/puml/07-deployment-argo.puml (100%) rename docs/{arc42 => architecture}/puml/07-deployment.puml (100%) rename docs/{userGuide => user}/User_Guide.md (100%) rename docs/{userGuide => user}/img/catalog_view.png (100%) rename docs/{userGuide => user}/img/catalog_view_list.png (100%) rename docs/{userGuide => user}/img/dashboard_view.png (100%) rename docs/{userGuide => user}/img/dashboard_view_list.png (100%) rename docs/{userGuide => user}/img/negotiations_view.png (100%) rename docs/{userGuide => user}/img/negotiations_view_list.png (100%) rename docs/{userGuide => user}/img/stock_view.png (100%) rename docs/{userGuide => user}/img/stock_view_added_material_stock.png (100%) rename docs/{userGuide => user}/img/stock_view_selected_material_stock.png (100%) rename docs/{userGuide => user}/img/transfers_view.png (100%) rename docs/{userGuide => user}/img/transfers_view_list.png (100%) diff --git a/README.md b/README.md index 5179a733..c8d229d7 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Beside the dependencies provided in the Helm Chart, the following dependencies h ### Data Sovereignty Currently, edc assets are always configured to match exactly one kind policy. These policies can be defined during -deployment (see [Admin Guide](./docs/adminGuide/Admin_Guide.md)). Data is offered to each partner, who has been added to +deployment (see [Admin Guide](docs/admin/Admin_Guide.md)). Data is offered to each partner, who has been added to the PURIS FOSS's master data pool depending on the business relationship (partner is a customer / supplier). For productive use, the following features should be implemented: diff --git a/docs/README.md b/docs/README.md index 3f107abd..c867c0ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,14 +1,14 @@ # Introduction -This repository provides the frontend and backend of the puris demonstrator. +This repository provides the frontend and backend of the puris demonstrator. It allows to exchange data according to puris related standards to fulfill short-term information needs. The following table links you to the respective documentations. -| Documentation | Purpose | -|------------------------------------------------------------|-----------------------------------------------------------------| -| [Arc42](./arc42/Index.md) | Architecture Documentation of Frontend and Backend. | -| [DEVELOPMENT.MD](./DEVELOPMENT.md) | Information relevant, if you contribute in PURIS development. | -| [Administration Guide](./adminGuide/Admin_Guide.md) | Information relevant, if you want to use the PURIS application. | -| [Interface Documentation](./interfaceDoc/Interface_Doc.md) | Information about the interfaces. | -| [User Manual](./userGuide/User_Guide.md) | Explanation of the views and how to use them. | +| Documentation | Purpose | +|-------------------------------------------------|-----------------------------------------------------------------| +| [Arc42](architecture/Index.md) | Architecture Documentation of Frontend and Backend. | +| [DEVELOPMENT.MD](./DEVELOPMENT.md) | Information relevant, if you contribute in PURIS development. | +| [Administration Guide](admin/Admin_Guide.md) | Information relevant, if you want to use the PURIS application. | +| [Interface Documentation](api/Interface_Doc.md) | Information about the interfaces. | +| [User Manual](user/User_Guide.md) | Explanation of the views and how to use them. | diff --git a/docs/adminGuide/Admin_Guide.md b/docs/admin/Admin_Guide.md similarity index 98% rename from docs/adminGuide/Admin_Guide.md rename to docs/admin/Admin_Guide.md index 1a02442f..ea7cf71b 100644 --- a/docs/adminGuide/Admin_Guide.md +++ b/docs/admin/Admin_Guide.md @@ -108,7 +108,7 @@ _Note: The application does NOT make use of the `Client Authentication` (private ## Data Sovereignty related configuration With R24.05, always Framework Agreement and Usage Purpose Contract Policies need to be used. Refer to -[ARC42 - Chapter 8](../arc42/08_concepts.md) for the influence of these configurations. +[ARC42 - Chapter 8](../architecture/08_concepts.md) for the influence of these configurations. TLDR; you define the definition of the policy you want to use and that you'll accept. PURIS FOSS only handles one policy that is templated. You can only configure the name and version of the Framework Agreement Credential and the Usage Purpose. @@ -116,7 +116,8 @@ Purpose. ### Framework Agreement To configure the Framework Agreement credential, that is automatically enforced by the EDC during contracting -(see further details in [ARC42 - Chapter 8](../arc42/08_concepts.md)), the following properties need to be configured. +(see further details in [ARC42 - Chapter 8](../architecture/08_concepts.md)), the following properties need to be +configured. The table contains the puris defaults for release R24.05. @@ -136,7 +137,7 @@ the [Portal's documentation on how to sign use case agreements](https://github.c ### Usage Purpose To configure the Usage Purpose under which the assets may be used (see further details -in [ARC42 - Chapter 8](../arc42/08_concepts.md)), +in [ARC42 - Chapter 8](../architecture/08_concepts.md)), the following properties need to be configured. The table contains the puris defaults for release R24.05. | Helm | Docker | Configuration | @@ -338,7 +339,7 @@ Material entity. **ATTENTION:** please wait some time after updating master data prior to create or update operational data because the Twins are registered asynchronously when creating / updating material partner relationships (see -[runtime view](../arc42/06_runtime_view.md) for more details). +[runtime view](../architecture/06_runtime_view.md) for more details). ### Onboard operational data diff --git a/docs/interfaceDoc/Interface_Doc.md b/docs/api/Interface_Doc.md similarity index 76% rename from docs/interfaceDoc/Interface_Doc.md rename to docs/api/Interface_Doc.md index 6332c824..b0084d61 100644 --- a/docs/interfaceDoc/Interface_Doc.md +++ b/docs/api/Interface_Doc.md @@ -5,10 +5,10 @@ documentations. ## Overview of Data Exchange Interfaces -The [arc42 documentation](../arc42/Index.md) provides an overview based on the following chapters: +The [arc42 documentation](../architecture/Index.md) provides an overview based on the following chapters: -- [Building Block View](../arc42/05_building_block_view.md) shows which kind of interfaces are present -- [Runtime View](../arc42/06_runtime_view.md) shows how data with participants is exchanged (implementation of +- [Building Block View](../architecture/05_building_block_view.md) shows which kind of interfaces are present +- [Runtime View](../architecture/06_runtime_view.md) shows how data with participants is exchanged (implementation of standardization candidate) ## Swagger documentation diff --git a/docs/arc42/img/06-twin-creation.svg b/docs/arc42/img/06-twin-creation.svg deleted file mode 100644 index 5938a55a..00000000 --- a/docs/arc42/img/06-twin-creation.svg +++ /dev/null @@ -1 +0,0 @@ -PURIS backendMaterialControllerMaterialControllerMaterialPartnerRelationsControllerMaterialPartnerRelationsControllerMaterialServiceImplMaterialServiceImplMaterialPartnerRelationServiceImplMaterialPartnerRelationServiceImplEdcAdapterServiceEdcAdapterServiceDtrAdapterServiceDtrAdapterServiceCreate or Update Material or Product1Create or Update Material or Productalt[create material or product]2Generate or takeCatena-X ID(save on material)3OK4Create or Updae MPR for partnerand material / product5Create DtrRegistrationTask6Determine Partners whobuy material and supply productDtrRegistrationTaskalt[at least one Partner who buys (We're the supplier)]7Create ShellDescriptor with access rights for buyingpartners and all submodels8OK[at least one Partner who sells (We're the customer)]alt[MPR does not yet have the CX-ID]9Lookup DigitalTwin at Supplierto extract Catena-X ID10Lookup and Contract DTR11Determine ShellDescriptor andSubmodel "DSP" Endpoint forPartTypeInformation frompartner DTR12Query PartTypeInformation Submodelat partner13Extract Catena-X ID from Submodel14Catena-X ID15Set Partner Catena-X ID16Save MaterialPartnerRelationship17Create or Update ShellDescriptor with access rights for sellingpartners and all submodels18OK19OK \ No newline at end of file diff --git a/docs/arc42/01_introduction_and_goals.md b/docs/architecture/01_introduction_and_goals.md similarity index 100% rename from docs/arc42/01_introduction_and_goals.md rename to docs/architecture/01_introduction_and_goals.md diff --git a/docs/arc42/02_architecture_constraints.md b/docs/architecture/02_architecture_constraints.md similarity index 100% rename from docs/arc42/02_architecture_constraints.md rename to docs/architecture/02_architecture_constraints.md diff --git a/docs/arc42/03_system_scope_and_context.md b/docs/architecture/03_system_scope_and_context.md similarity index 100% rename from docs/arc42/03_system_scope_and_context.md rename to docs/architecture/03_system_scope_and_context.md diff --git a/docs/arc42/04_solution_strategy.md b/docs/architecture/04_solution_strategy.md similarity index 100% rename from docs/arc42/04_solution_strategy.md rename to docs/architecture/04_solution_strategy.md diff --git a/docs/arc42/05_building_block_view.md b/docs/architecture/05_building_block_view.md similarity index 100% rename from docs/arc42/05_building_block_view.md rename to docs/architecture/05_building_block_view.md diff --git a/docs/arc42/06_runtime_view.md b/docs/architecture/06_runtime_view.md similarity index 95% rename from docs/arc42/06_runtime_view.md rename to docs/architecture/06_runtime_view.md index 023beaf7..8c7dcb42 100644 --- a/docs/arc42/06_runtime_view.md +++ b/docs/architecture/06_runtime_view.md @@ -38,7 +38,7 @@ Roughly said the following steps need to be achieved to lookup a Submodel Y for 2. Catalog query filters by `assetId` extracted from `SubmodelDescriptor` 3. Prior to usage the catalog offers are filtered for an offer your application supports: PURIS FOSS only allows policies with Exactly one `FrameworkAgreement` and one `UsagePurpose`. It only accepts the - same Policy it offers (see [Admin Guide](../adminGuide/Admin_Guide.md)) + same Policy it offers (see [Admin Guide](../admin/Admin_Guide.md)) 4. Query `Submodel Y` trough `EDC` 5. Terminate Transfer for `Submodel Y` @@ -68,4 +68,4 @@ as soon as a MaterialPartnerRelation is changed. The Digital Twin is always recr When reloading the UI, the latest data is pulled from the backend. Whenever a partner-related update on the information is performed, then the frontend hands over the request to the backend to perform the action. -Details on the Web-Ui can be found in the [User Guide](../userGuide/User_Guide.md). +Details on the Web-Ui can be found in the [User Guide](../user/User_Guide.md). diff --git a/docs/arc42/07_deployment_view.md b/docs/architecture/07_deployment_view.md similarity index 100% rename from docs/arc42/07_deployment_view.md rename to docs/architecture/07_deployment_view.md diff --git a/docs/arc42/08_concepts.md b/docs/architecture/08_concepts.md similarity index 97% rename from docs/arc42/08_concepts.md rename to docs/architecture/08_concepts.md index 9bf25497..ee9900da 100644 --- a/docs/arc42/08_concepts.md +++ b/docs/architecture/08_concepts.md @@ -43,7 +43,7 @@ Following the standard, the following measures have been taken: - Access Policies and Access Restrictions - Contract Policies - Consumer Side Validation -- Views in Frontend (admin access, see [User Guide](../userGuide/User_Guide.md), not handled in this chapter) to +- Views in Frontend (admin access, see [User Guide](../user/User_Guide.md), not handled in this chapter) to overview negotiations and transfers. ### Access Policies and Access Restrictions @@ -165,7 +165,7 @@ Example for Submodels based on following configurations: } ``` -_Note: see configuration of usage policies in [AdminGuide](../adminGuide/Admin_Guide.md)._ +_Note: see configuration of usage policies in [AdminGuide](../admin/Admin_Guide.md)._ ### Consumer Side Validation @@ -220,7 +220,7 @@ contract offer for the partner's BPNL. ## Security Backend APIs are secured by an API Key. The Frontend may be configured to be accessed based on keycloak authentication. -Refer to the [Admin Guide](../adminGuide/Admin_Guide.md) for further information. +Refer to the [Admin Guide](../admin/Admin_Guide.md) for further information. Access to respective resources is always granted based on the actual relationships as stated in section 'Multi-Partner Information'. Means there are two levels of security: @@ -232,7 +232,7 @@ To do the second, the Connector in use needs the extension [provision additional headers](https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/provision-additional-headers). Beside that the Backend can be configured to use the DTR with an IDP. The PURIS application could differentiate two -users. For configuration, please refer to the [Admin Guide](../adminGuide/Admin_Guide.md). +users. For configuration, please refer to the [Admin Guide](../admin/Admin_Guide.md). - read access client for the EDC: added to the `dataAddress` of the DTR Asset - manage access client for the PURIS application: used to create and manage the ShellDescriptors diff --git a/docs/arc42/09_architecture_decisions.md b/docs/architecture/09_architecture_decisions.md similarity index 100% rename from docs/arc42/09_architecture_decisions.md rename to docs/architecture/09_architecture_decisions.md diff --git a/docs/arc42/10_quality_requirements.md b/docs/architecture/10_quality_requirements.md similarity index 100% rename from docs/arc42/10_quality_requirements.md rename to docs/architecture/10_quality_requirements.md diff --git a/docs/arc42/11_technical_risks.md b/docs/architecture/11_technical_risks.md similarity index 100% rename from docs/arc42/11_technical_risks.md rename to docs/architecture/11_technical_risks.md diff --git a/docs/arc42/12_glossary.md b/docs/architecture/12_glossary.md similarity index 100% rename from docs/arc42/12_glossary.md rename to docs/architecture/12_glossary.md diff --git a/docs/arc42/Index.md b/docs/architecture/Index.md similarity index 100% rename from docs/arc42/Index.md rename to docs/architecture/Index.md diff --git a/docs/arc42/img/03-business-context.svg b/docs/architecture/img/03-business-context.svg similarity index 100% rename from docs/arc42/img/03-business-context.svg rename to docs/architecture/img/03-business-context.svg diff --git a/docs/arc42/img/03-technical-context.svg b/docs/architecture/img/03-technical-context.svg similarity index 100% rename from docs/arc42/img/03-technical-context.svg rename to docs/architecture/img/03-technical-context.svg diff --git a/docs/arc42/img/05-level-0.svg b/docs/architecture/img/05-level-0.svg similarity index 100% rename from docs/arc42/img/05-level-0.svg rename to docs/architecture/img/05-level-0.svg diff --git a/docs/arc42/img/05-level-1-backend.svg b/docs/architecture/img/05-level-1-backend.svg similarity index 100% rename from docs/arc42/img/05-level-1-backend.svg rename to docs/architecture/img/05-level-1-backend.svg diff --git a/docs/arc42/img/05-level-1-frontend.svg b/docs/architecture/img/05-level-1-frontend.svg similarity index 100% rename from docs/arc42/img/05-level-1-frontend.svg rename to docs/architecture/img/05-level-1-frontend.svg diff --git a/docs/arc42/img/06-api-flow-detailed.svg b/docs/architecture/img/06-api-flow-detailed.svg similarity index 100% rename from docs/arc42/img/06-api-flow-detailed.svg rename to docs/architecture/img/06-api-flow-detailed.svg diff --git a/docs/architecture/img/06-twin-creation.svg b/docs/architecture/img/06-twin-creation.svg new file mode 100644 index 00000000..fa4b2953 --- /dev/null +++ b/docs/architecture/img/06-twin-creation.svg @@ -0,0 +1,4 @@ + +PURIS backendMaterialControllerMaterialControllerMaterialPartnerRelationsControllerMaterialPartnerRelationsControllerMaterialServiceImplMaterialServiceImplMaterialPartnerRelationServiceImplMaterialPartnerRelationServiceImplEdcAdapterServiceEdcAdapterServiceDtrAdapterServiceDtrAdapterServiceCreate or Update Material or Product1Create or Update Material or Productalt[create material or product]2Generate or takeCatena-X ID(save on material)3OK4Create or Updae MPR for partnerand material / product5Create DtrRegistrationTask6Determine Partners whobuy material and supply productDtrRegistrationTaskalt[at least one Partner who buys (We're the supplier)]7Create ShellDescriptor with access rights for buyingpartners and all submodels8OK[at least one Partner who sells (We're the customer)]alt[MPR does not yet have the CX-ID]9Lookup DigitalTwin at Supplierto extract Catena-X ID10Lookup and Contract DTR11Determine ShellDescriptor andSubmodel "DSP" Endpoint forPartTypeInformation frompartner DTR12Query PartTypeInformation Submodelat partner13Extract Catena-X ID from Submodel14Catena-X ID15Set Partner Catena-X ID16Save MaterialPartnerRelationship17Create or Update ShellDescriptor with access rights for sellingpartners and all submodels18OK19OK diff --git a/docs/arc42/img/07-deployment-argo.png b/docs/architecture/img/07-deployment-argo.png similarity index 100% rename from docs/arc42/img/07-deployment-argo.png rename to docs/architecture/img/07-deployment-argo.png diff --git a/docs/arc42/img/07-deployment-argo.svg b/docs/architecture/img/07-deployment-argo.svg similarity index 100% rename from docs/arc42/img/07-deployment-argo.svg rename to docs/architecture/img/07-deployment-argo.svg diff --git a/docs/arc42/img/07-deployment.png b/docs/architecture/img/07-deployment.png similarity index 100% rename from docs/arc42/img/07-deployment.png rename to docs/architecture/img/07-deployment.png diff --git a/docs/arc42/img/07-deployment.svg b/docs/architecture/img/07-deployment.svg similarity index 100% rename from docs/arc42/img/07-deployment.svg rename to docs/architecture/img/07-deployment.svg diff --git a/docs/arc42/puml/03-business-context.puml b/docs/architecture/puml/03-business-context.puml similarity index 100% rename from docs/arc42/puml/03-business-context.puml rename to docs/architecture/puml/03-business-context.puml diff --git a/docs/arc42/puml/03-technical-context.puml b/docs/architecture/puml/03-technical-context.puml similarity index 100% rename from docs/arc42/puml/03-technical-context.puml rename to docs/architecture/puml/03-technical-context.puml diff --git a/docs/arc42/puml/05-level-0.puml b/docs/architecture/puml/05-level-0.puml similarity index 100% rename from docs/arc42/puml/05-level-0.puml rename to docs/architecture/puml/05-level-0.puml diff --git a/docs/arc42/puml/05-level-1-backend.puml b/docs/architecture/puml/05-level-1-backend.puml similarity index 100% rename from docs/arc42/puml/05-level-1-backend.puml rename to docs/architecture/puml/05-level-1-backend.puml diff --git a/docs/arc42/puml/05-level-1-frontend.puml b/docs/architecture/puml/05-level-1-frontend.puml similarity index 100% rename from docs/arc42/puml/05-level-1-frontend.puml rename to docs/architecture/puml/05-level-1-frontend.puml diff --git a/docs/arc42/puml/06-api-flow-detailed.puml b/docs/architecture/puml/06-api-flow-detailed.puml similarity index 100% rename from docs/arc42/puml/06-api-flow-detailed.puml rename to docs/architecture/puml/06-api-flow-detailed.puml diff --git a/docs/arc42/puml/06-twin-creation.puml b/docs/architecture/puml/06-twin-creation.puml similarity index 100% rename from docs/arc42/puml/06-twin-creation.puml rename to docs/architecture/puml/06-twin-creation.puml diff --git a/docs/arc42/puml/07-deployment-argo.puml b/docs/architecture/puml/07-deployment-argo.puml similarity index 100% rename from docs/arc42/puml/07-deployment-argo.puml rename to docs/architecture/puml/07-deployment-argo.puml diff --git a/docs/arc42/puml/07-deployment.puml b/docs/architecture/puml/07-deployment.puml similarity index 100% rename from docs/arc42/puml/07-deployment.puml rename to docs/architecture/puml/07-deployment.puml diff --git a/docs/userGuide/User_Guide.md b/docs/user/User_Guide.md similarity index 100% rename from docs/userGuide/User_Guide.md rename to docs/user/User_Guide.md diff --git a/docs/userGuide/img/catalog_view.png b/docs/user/img/catalog_view.png similarity index 100% rename from docs/userGuide/img/catalog_view.png rename to docs/user/img/catalog_view.png diff --git a/docs/userGuide/img/catalog_view_list.png b/docs/user/img/catalog_view_list.png similarity index 100% rename from docs/userGuide/img/catalog_view_list.png rename to docs/user/img/catalog_view_list.png diff --git a/docs/userGuide/img/dashboard_view.png b/docs/user/img/dashboard_view.png similarity index 100% rename from docs/userGuide/img/dashboard_view.png rename to docs/user/img/dashboard_view.png diff --git a/docs/userGuide/img/dashboard_view_list.png b/docs/user/img/dashboard_view_list.png similarity index 100% rename from docs/userGuide/img/dashboard_view_list.png rename to docs/user/img/dashboard_view_list.png diff --git a/docs/userGuide/img/negotiations_view.png b/docs/user/img/negotiations_view.png similarity index 100% rename from docs/userGuide/img/negotiations_view.png rename to docs/user/img/negotiations_view.png diff --git a/docs/userGuide/img/negotiations_view_list.png b/docs/user/img/negotiations_view_list.png similarity index 100% rename from docs/userGuide/img/negotiations_view_list.png rename to docs/user/img/negotiations_view_list.png diff --git a/docs/userGuide/img/stock_view.png b/docs/user/img/stock_view.png similarity index 100% rename from docs/userGuide/img/stock_view.png rename to docs/user/img/stock_view.png diff --git a/docs/userGuide/img/stock_view_added_material_stock.png b/docs/user/img/stock_view_added_material_stock.png similarity index 100% rename from docs/userGuide/img/stock_view_added_material_stock.png rename to docs/user/img/stock_view_added_material_stock.png diff --git a/docs/userGuide/img/stock_view_selected_material_stock.png b/docs/user/img/stock_view_selected_material_stock.png similarity index 100% rename from docs/userGuide/img/stock_view_selected_material_stock.png rename to docs/user/img/stock_view_selected_material_stock.png diff --git a/docs/userGuide/img/transfers_view.png b/docs/user/img/transfers_view.png similarity index 100% rename from docs/userGuide/img/transfers_view.png rename to docs/user/img/transfers_view.png diff --git a/docs/userGuide/img/transfers_view_list.png b/docs/user/img/transfers_view_list.png similarity index 100% rename from docs/userGuide/img/transfers_view_list.png rename to docs/user/img/transfers_view_list.png From 889101ae929308b52a35088e32555aa24410576b Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 10:37:37 -0700 Subject: [PATCH 11/17] docs(architecture): updated deployment svgs --- docs/architecture/img/07-deployment-argo.png | Bin 30295 -> 0 bytes docs/architecture/img/07-deployment-argo.svg | 4 ++-- docs/architecture/img/07-deployment.png | Bin 63539 -> 0 bytes docs/architecture/img/07-deployment.svg | 8 ++++---- 4 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 docs/architecture/img/07-deployment-argo.png delete mode 100644 docs/architecture/img/07-deployment.png diff --git a/docs/architecture/img/07-deployment-argo.png b/docs/architecture/img/07-deployment-argo.png deleted file mode 100644 index c693434c4e6b1270c4e0e118cbfb92c619a8f500..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30295 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 diff --git a/docs/architecture/img/07-deployment-argo.svg b/docs/architecture/img/07-deployment-argo.svg index 69e778e5..cb1a39c0 100644 --- a/docs/architecture/img/07-deployment-argo.svg +++ b/docs/architecture/img/07-deployment-argo.svg @@ -1,4 +1,4 @@ PURISCXTractus-X Connector CustomerPostgresql DBPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems KeycloakManaged Identity Wallet + style="width:968px;height:443px;background:#FFFFFF;" version="1.1" viewBox="0 0 968 443" width="968px" + zoomAndPan="magnify">PURISCXPostgres TXCTractus-X ConnectorDigital Twin RegistryDTR IDPPostgres DTRPostgresql DBPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems KeycloakManaged Identity Wallet diff --git a/docs/architecture/img/07-deployment.png b/docs/architecture/img/07-deployment.png deleted file mode 100644 index 8115bcc719b81add391e3a8d2632903a4c7d8930..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63539 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 NI$8#rH@4WG{vVlrU{C-6 diff --git a/docs/architecture/img/07-deployment.svg b/docs/architecture/img/07-deployment.svg index 7648abe9..000912c4 100644 --- a/docs/architecture/img/07-deployment.svg +++ b/docs/architecture/img/07-deployment.svg @@ -1,4 +1,4 @@ - -CustomerCXSupplierTractus-X Connector CustomerPostgresql DBPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems(Customer)KeycloakManaged Identity WalletTractus-X Connector SupplierPostgresql DBPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems(Supplier) + +SharedCustomerCXSupplierPostgresql DBKeycloakTractus-X Connector CustomerDigital Twin Registry CustomerPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems(Customer)Postgresql DB MIWManaged Identity WalletMock IAMBPNL Did Resolution ServiceTractus-X Connector SupplierDigital Twin Registry SupplierPURIS FOSS BackendPURIS FOSS FrontendInterface internal systems(Supplier) From 3d609047ddaecae722fdfc5201c4fbc4c3263143 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Sat, 18 May 2024 04:35:48 -0700 Subject: [PATCH 12/17] docs(Changelog.md): updated for R24.05 release --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dd0e6ca..cfd1095c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v2.0.0](https://github.com/eclipse-tractusx/puris/releases/tag/v2.0.0) +The following Changelog lists the changes. Please refer to the [documentation](docs/README.md) for configuration needs +and understanding the concept changes. + +The **need for configuration updates** is **marked bold**. + ### Added - Implementation of the following standards relying on Digital Twins and Industry Core @@ -14,28 +19,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Short-Term Material Demand Exchange CX-0120, version 2.0.0 - Planned Production Output Exchange CX-0121, version 2.0.0 - Item Stock Exchange CX-0122, version 2.0.0 -- Data Sovereignty - - Added Usage Purpose as mandatory for Submodel +- Added submodel PartTypeInformation + pull flow of the Catena-X ID for shared assets pattern of the Digital Twin / + Industry Core KIT. +- Implementation of Digital Twins. **Added Digital Twin Registry (DTR) as dependency**. Used to + - create and update digital twins for partners + - query partner materials and determine submodels +- Added Identity Provider (IDP) support for DTR + - One user for EDC (read) + - One user for PURIS (manage) +- Frontend updates + - Reworked whole frontend to use React instead of Vue -> better Styleguide conformity as cx components are used. + - Updated Dashboard + - Customer view shows own demand, stock and incoming deliveries. You can select customer partner sites to see + planned production, stocks and outgoing deliveries. + - Supplier view shows own planned production, stock and outgoing deliveries. You can select supplier partner + sites + to see demand, stocks and incoming deliveries. + - Added manual create / delete for production, deliveries and demand (stock still separate ui). + - Added projection of stock from latest stock. + - Added possibility to pull data from partner for demand, planned production and deliveries. + - Catalog now uses partners and their EDC url (no freehand check possible anymore) +- **Data Sovereignty** + - Added Membership Credential to all access policies. + - **Added Usage Purpose as mandatory for submodel.** + - **Added version to usage purpose and framework agreement.** + - Added consumer side verification of contracts. - Infrastructure - - Digital Twin Registry is mandatory (app version) - - Update to Tractus-x EDC Version 0.7.3 (app version) + - **Digital Twin Registry version 0.4.3 is mandatory** + - **Update to Tractus-x EDC version 0.7.3** - Mock version of IATP compliant MIW for local deployment ### Changed -- Framework Credential now is mandatory (removed `backend.frameworkagreement.use`) +- Data Sovereignty + - Updated to be compliant to cx odrl:profile. (No Schema-Validation) + - **Framework Credential now is mandatory** (removed `backend.frameworkagreement.use`) +- Bump supported EDC version from 0.5.x to 0.7.x + - Update of EDR flow: Don't use the Http Dynamic Receiver extension anymore as it was removed from EDC 0.7.x. Now + uses + Tractus-X EDC EDR v2 version getting a fresh token synchronously. EDR Controller to be removed. + - Terminate transfers after opening. + - Enhanced reusage of contracts - but still not always possible. +- Local deployment updated. + - Version bumps for EDC + switched from in-memory to postgres version. + - Use one postgres for PURIS, EDC and DTR. + - Updated keycloak to have a Customer and Supplier realm for DTR IDP configuration. + - Updated MIW to 0.4.0. Then outcommented MIW as it doesn't support Identity and Trust Protocol (IATP, needed for TX + EDC 0.7.x) and added Mock-IAM mocking the needed services. +- Integration test postman suite + - Updated test for EDC > new syntax and models. + - Added tests for new information (demand, planned production, delivery). + - Added tests for SubmodelDescriptor Setup in DTR. + - Refatorings for tests. +- **Master Data handling**: + - Store Catena-X ID for product twins of the partner in material partner relationship. Needed due to Digital Twin + shared asset approach. + - Configuration to either let the backend generate your Catena-X ID or to ship it via interface. ### Removed -- Implementation of CX-0122 version 1.0.0 +- Implementation of CX-0122 version 1.0.0 (Request and Response Endpoint) +- CI: Veracode as license expired -### Security +### Known Knowns -- Identity Provider (IDP) support for DTR - - One user for EDC (read) - - One user for PURIS (manage) +#### Upgradeability -### Known Knowns +As currently no active user was known migrations of data are not yet supported. The chart technically is upgradeable. #### Data Sovereignty From dc527636d143f36ede9b39eeb4366786efbe98a5 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Sat, 18 May 2024 07:38:06 -0700 Subject: [PATCH 13/17] fix(openApi): resolve KICS --- docs/api/openAPI.yaml | 444 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) diff --git a/docs/api/openAPI.yaml b/docs/api/openAPI.yaml index a7917878..2951db47 100644 --- a/docs/api/openAPI.yaml +++ b/docs/api/openAPI.yaml @@ -1,31 +1,40 @@ components: schemas: AddressDto: + additionalProperties: false properties: bpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string country: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string streetAndNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string zipCodeAndCity: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string type: object AllocatedPlannedProductionOutput: + additionalProperties: false properties: estimatedTimeOfCompletion: format: date-time + maxItems: 50 type: string lastUpdatedOnDateTime: format: date-time + maxItems: 50 type: string plannedProductionQuantity: $ref: '#/components/schemas/ItemQuantityEntity' productionSiteBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string required: @@ -35,6 +44,7 @@ components: - productionSiteBpns type: object DeliveryDto: + additionalProperties: false properties: arrivalType: enum: @@ -42,18 +52,23 @@ components: - actual-departure - estimated-arrival - actual-arrival + maxItems: 50 type: string customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string dateOfArrival: format: date-time + maxItems: 50 type: string dateOfDeparture: format: date-time + maxItems: 50 type: string departureType: enum: @@ -61,11 +76,14 @@ components: - actual-departure - estimated-arrival - actual-arrival + maxItems: 50 type: string destinationBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string destinationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string incoterm: @@ -81,6 +99,7 @@ components: - CPT - CIP - DDP + maxItems: 50 type: string measurementUnit: enum: @@ -119,17 +138,22 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string originBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string originBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string ownMaterialNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string partnerBpnl: + maxItems: 50 pattern: ^BPNL[0-9a-zA-Z]{12}$ type: string quantity: @@ -138,23 +162,29 @@ components: reported: type: boolean supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string trackingNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object DeliveryInformation: + additionalProperties: false properties: materialGlobalAssetId: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string positions: items: $ref: '#/components/schemas/Position' + maxItems: 50 type: array uniqueItems: true required: @@ -162,9 +192,11 @@ components: - positions type: object Demand: + additionalProperties: false properties: day: format: date-time + maxItems: 50 type: string demand: $ref: '#/components/schemas/ItemQuantityEntity' @@ -173,9 +205,11 @@ components: - demand type: object DemandDto: + additionalProperties: false properties: day: format: date-time + maxItems: 50 type: string demandCategoryCode: enum: @@ -187,8 +221,10 @@ components: - OS01 - OI01 - ED01 + maxItems: 50 type: string demandLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string measurementUnit: @@ -228,26 +264,33 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string ownMaterialNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string partnerBpnl: + maxItems: 50 pattern: ^BPNL[0-9a-zA-Z]{12}$ type: string quantity: format: double type: number supplierLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string uuid: format: uuid + maxItems: 50 type: string type: object DemandSeries: + additionalProperties: false properties: customerLocationBpns: + maxItems: 50 pattern: ^BPNS[a-zA-Z0-9]{12}$ type: string demandCategory: @@ -264,17 +307,21 @@ components: Demand) - DemandCategoryType(demandCategoryCode=PO01, demandCategoryName=Phase-Out Period) + maxItems: 50 type: string demands: items: $ref: '#/components/schemas/Demand' + maxItems: 50 type: array uniqueItems: true expectedSupplierLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string lastUpdatedOnDateTime: format: date-time + maxItems: 50 type: string required: - customerLocationBpns @@ -283,15 +330,19 @@ components: - lastUpdatedOnDateTime type: object FrontendMaterialDto: + additionalProperties: false properties: description: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string ownMaterialNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string type: object ItemQuantityEntity: + additionalProperties: false properties: unit: enum: @@ -330,6 +381,7 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string value: format: double @@ -339,18 +391,22 @@ components: - value type: object ItemStockSamm: + additionalProperties: false properties: direction: enum: - INBOUND - OUTBOUND + maxItems: 50 type: string materialGlobalAssetId: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string positions: items: $ref: '#/components/schemas/Position' + maxItems: 50 type: array uniqueItems: true required: @@ -360,55 +416,69 @@ components: JsonNode: type: object MaterialDto: + additionalProperties: false properties: materialFlag: type: boolean materialNumberCustomer: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string materialNumberCx: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string materialNumberSupplier: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string name: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string productFlag: type: boolean uuid: format: uuid + maxItems: 50 type: string type: object MaterialEntityDto: + additionalProperties: false properties: materialFlag: type: boolean materialNumberCx: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string name: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string ownMaterialNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string productFlag: type: boolean type: object MaterialStockDto: + additionalProperties: false properties: customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string isBlocked: type: boolean lastUpdatedOn: format: date-time + maxItems: 50 type: string material: $ref: '#/components/schemas/MaterialDto' @@ -449,6 +519,7 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string partner: $ref: '#/components/schemas/PartnerDto' @@ -456,27 +527,35 @@ components: format: double type: number stockLocationBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string stockLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object OrderPositionReference: + additionalProperties: false properties: customerOrderId: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionId: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string supplierOrderId: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string required: @@ -484,38 +563,48 @@ components: - customerOrderPositionId type: object PartnerDto: + additionalProperties: false properties: addresses: items: $ref: '#/components/schemas/AddressDto' + maxItems: 50 type: array uniqueItems: true bpnl: + maxItems: 50 pattern: ^BPNL[0-9a-zA-Z]{12}$ type: string edcUrl: + maxItems: 50 pattern: ^http[s]?://([a-z0-9][a-z0-9\-]+[a-z0-9])(\.[a-z0-9\-]+)*(:[0-9]{1,4})?(/[a-z0-9\-]+)*[/]?$ type: string name: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string sites: items: $ref: '#/components/schemas/SiteDto' + maxItems: 50 type: array uniqueItems: true uuid: format: uuid + maxItems: 50 type: string type: object PlannedProductionOutput: + additionalProperties: false properties: materialGlobalAssetId: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string positions: items: $ref: '#/components/schemas/Position' + maxItems: 50 type: array uniqueItems: true required: @@ -523,14 +612,17 @@ components: - positions type: object Position: + additionalProperties: false properties: allocatedPlannedProductionOutputs: items: $ref: '#/components/schemas/AllocatedPlannedProductionOutput' + maxItems: 50 type: array uniqueItems: true lastUpdatedOnDateTime: format: date-time + maxItems: 50 type: string writeOnly: true orderPositionReference: @@ -539,17 +631,21 @@ components: - allocatedPlannedProductionOutputs type: object ProductStockDto: + additionalProperties: false properties: customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string isBlocked: type: boolean lastUpdatedOn: format: date-time + maxItems: 50 type: string material: $ref: '#/components/schemas/MaterialDto' @@ -590,6 +686,7 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string partner: $ref: '#/components/schemas/PartnerDto' @@ -597,28 +694,36 @@ components: format: double type: number stockLocationBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string stockLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object ProductionDto: + additionalProperties: false properties: customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string estimatedTimeOfCompletion: format: date-time + maxItems: 50 type: string material: $ref: '#/components/schemas/MaterialDto' @@ -659,33 +764,41 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string partner: $ref: '#/components/schemas/PartnerDto' productionSiteBpns: + maxItems: 50 type: string quantity: format: double type: number supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object ReportedMaterialStockDto: + additionalProperties: false properties: customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string isBlocked: type: boolean lastUpdatedOn: format: date-time + maxItems: 50 type: string material: $ref: '#/components/schemas/MaterialDto' @@ -726,6 +839,7 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string partner: $ref: '#/components/schemas/PartnerDto' @@ -733,30 +847,38 @@ components: format: double type: number stockLocationBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string stockLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object ReportedProductStockDto: + additionalProperties: false properties: customerOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string customerOrderPositionNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string isBlocked: type: boolean lastUpdatedOn: format: date-time + maxItems: 50 type: string material: $ref: '#/components/schemas/MaterialDto' @@ -797,6 +919,7 @@ components: - unit:minuteUnitOfTime - unit:hourUnitOfTime - unit:day + maxItems: 50 type: string partner: $ref: '#/components/schemas/PartnerDto' @@ -804,42 +927,53 @@ components: format: double type: number stockLocationBpna: + maxItems: 50 pattern: ^BPNA[0-9a-zA-Z]{12}$ type: string stockLocationBpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string supplierOrderNumber: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string uuid: format: uuid + maxItems: 50 type: string type: object ShortTermMaterialDemand: + additionalProperties: false properties: demandSeries: items: $ref: '#/components/schemas/DemandSeries' + maxItems: 50 type: array uniqueItems: true materialGlobalAssetId: + maxItems: 50 pattern: (^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)|(^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$) type: string required: - demandSeries type: object SiteDto: + additionalProperties: false properties: addresses: items: $ref: '#/components/schemas/AddressDto' + maxItems: 50 type: array uniqueItems: true bpns: + maxItems: 50 pattern: ^BPNS[0-9a-zA-Z]{12}$ type: string name: + maxItems: 50 pattern: ^[^\n\x0B\f\r\x85\u2028\u2029]+$ type: string type: object @@ -863,24 +997,32 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: bpns required: false schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: bpnl required: false schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/DeliveryDto' + maxItems: 50 type: array description: OK summary: Get all planned deliveries for the given Material @@ -893,6 +1035,7 @@ paths: application/json: schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false required: true responses: '200': @@ -900,30 +1043,35 @@ paths: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Delivery was created. '201': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Created '400': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Malformed or invalid request body. '409': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Delivery already exists. '500': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Internal Server Error. summary: Creates a new delivery tags: @@ -935,6 +1083,7 @@ paths: application/json: schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false required: true responses: '200': @@ -942,30 +1091,35 @@ paths: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: OK '204': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Delivery was updated. '400': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Malformed or invalid request body. '404': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Delivery does not exist. '500': content: '*/*': schema: $ref: '#/components/schemas/DeliveryDto' + additionalProperties: false description: Internal Server Error. summary: Updates a delivery by its UUID tags: @@ -978,16 +1132,22 @@ paths: name: edc-bpn required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: materialNumberCx required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: representation required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -995,24 +1155,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/DeliveryInformation' + additionalProperties: false description: Ok '400': content: '*/*': schema: $ref: '#/components/schemas/DeliveryInformation' + additionalProperties: false description: Bad Request '500': content: '*/*': schema: $ref: '#/components/schemas/DeliveryInformation' + additionalProperties: false description: Internal Server Error '501': content: '*/*': schema: $ref: '#/components/schemas/DeliveryInformation' + additionalProperties: false description: Unsupported representation summary: This endpoint receives the Delivery Information Submodel 2.0.0 requests tags: @@ -1026,14 +1190,18 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK summary: Refreshes all reported deliveries @@ -1047,7 +1215,9 @@ paths: name: id required: true schema: + additionalProperties: false format: uuid + maxItems: 50 type: string responses: '204': @@ -1071,19 +1241,25 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: site required: false schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/DemandDto' + maxItems: 50 type: array description: OK summary: Get all own demands for the given Material @@ -1096,6 +1272,7 @@ paths: application/json: schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false required: true responses: '201': @@ -1103,24 +1280,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Demand was created. '400': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Malformed or invalid request body. '409': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Demand already exists. Use PUT instead. '500': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Internal Server Error. summary: Creates a new demand tags: @@ -1132,6 +1313,7 @@ paths: application/json: schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false required: true responses: '200': @@ -1139,24 +1321,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Demand was updated. '400': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Malformed or invalid request body. '404': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Demand does not exist. '500': content: '*/*': schema: $ref: '#/components/schemas/DemandDto' + additionalProperties: false description: Internal Server Error. summary: Updates a demand by its UUID tags: @@ -1172,24 +1358,32 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: bpnl required: false schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: site required: false schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/DemandDto' + maxItems: 50 type: array description: OK summary: Get all demands of partners for a material @@ -1204,14 +1398,18 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK summary: Refreshes all reported demands @@ -1225,7 +1423,9 @@ paths: name: id required: true schema: + additionalProperties: false format: uuid + maxItems: 50 type: string responses: '204': @@ -1247,12 +1447,16 @@ paths: name: assetId required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false + maxItems: 50 type: string description: OK tags: @@ -1265,17 +1469,23 @@ paths: name: dspUrl required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false + maxItems: 50 type: string description: OK tags: @@ -1288,6 +1498,8 @@ paths: content: '*/*': schema: + additionalProperties: false + maxItems: 50 type: string description: OK tags: @@ -1301,6 +1513,7 @@ paths: '*/*': schema: $ref: '#/components/schemas/JsonNode' + additionalProperties: false description: OK tags: - edc-controller @@ -1336,18 +1549,23 @@ paths: type: TransferProcessStarted schema: $ref: '#/components/schemas/JsonNode' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false + maxItems: 50 type: string description: Ok '400': content: '*/*': schema: + additionalProperties: false + maxItems: 50 type: string description: Invalid message body summary: Endpoint for receiving the authCodes from the counterparty's connector @@ -1361,6 +1579,7 @@ paths: content: '*/*': schema: + additionalProperties: false type: object description: OK tags: @@ -1373,24 +1592,32 @@ paths: name: edc-bpn required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: materialnumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: direction required: true schema: + additionalProperties: false enum: - INBOUND - OUTBOUND + maxItems: 50 type: string - in: path name: representation required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -1398,24 +1625,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/ItemStockSamm' + additionalProperties: false description: Ok '400': content: '*/*': schema: $ref: '#/components/schemas/ItemStockSamm' + additionalProperties: false description: Bad Request '500': content: '*/*': schema: $ref: '#/components/schemas/ItemStockSamm' + additionalProperties: false description: Internal Server Error '501': content: '*/*': schema: $ref: '#/components/schemas/ItemStockSamm' + additionalProperties: false description: Unsupported representation summary: This endpoint receives the ItemStock Submodel 2.0.0 requests tags: @@ -1428,16 +1659,22 @@ paths: name: edc-bpn required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: materialnumbercx required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: representation required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -1445,24 +1682,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/ShortTermMaterialDemand' + additionalProperties: false description: Ok '400': content: '*/*': schema: $ref: '#/components/schemas/ShortTermMaterialDemand' + additionalProperties: false description: Bad Request '500': content: '*/*': schema: $ref: '#/components/schemas/ShortTermMaterialDemand' + additionalProperties: false description: Internal Server Error '501': content: '*/*': schema: $ref: '#/components/schemas/ShortTermMaterialDemand' + additionalProperties: false description: Unsupported representation summary: This endpoint receives the ShortTermMaterialDemand Submodel 1.0.0 requests tags: @@ -1481,6 +1722,8 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The unique BPNL that was assigned to that Partner. example: BPNL2222222222RR @@ -1488,6 +1731,8 @@ paths: name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The Material Number that this Partner is using in his own company to identify the Material. @@ -1496,6 +1741,8 @@ paths: name: partnerMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The CatenaX Number that this Partner uses example: 860fb504-b884-4009-9313-c6fb6cdc776b @@ -1503,6 +1750,8 @@ paths: name: partnerCXNumber required: false schema: + additionalProperties: false + maxItems: 50 type: string - description: The informal name that this Partner uses example: Semiconductor @@ -1510,6 +1759,8 @@ paths: name: nameAtManufacturer required: false schema: + additionalProperties: false + maxItems: 50 type: string - description: This boolean flag indicates whether this Partner is a potential supplier of the given Material. @@ -1518,6 +1769,7 @@ paths: name: partnerSupplies required: true schema: + additionalProperties: false type: boolean - description: This boolean flag indicates whether this Partner is a potential customer of this Material. @@ -1526,30 +1778,35 @@ paths: name: partnerBuys required: true schema: + additionalProperties: false type: boolean responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Successfully created a new MaterialPartnerRelationEntity. '400': content: '*/*': schema: + additionalProperties: false type: object description: Material and/or Partner do not exist or invalid parameters '409': content: '*/*': schema: + additionalProperties: false type: object description: Relation for given Material and Partner does already exist. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server Error. tags: @@ -1567,6 +1824,8 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The unique BPNL that was assigned to that Partner. example: BPNL2222222222RR @@ -1574,6 +1833,8 @@ paths: name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The Material Number that this Partner is using in his own company to identify the Material. @@ -1582,6 +1843,8 @@ paths: name: partnerMaterialNumber required: false schema: + additionalProperties: false + maxItems: 50 type: string - description: The CatenaX Number that this Partner uses example: 860fb504-b884-4009-9313-c6fb6cdc776b @@ -1589,6 +1852,8 @@ paths: name: partnerCXNumber required: false schema: + additionalProperties: false + maxItems: 50 type: string - description: The informal name that this Partner uses example: Semiconductor @@ -1596,6 +1861,8 @@ paths: name: nameAtManufacturer required: false schema: + additionalProperties: false + maxItems: 50 type: string - description: This boolean flag indicates whether this Partner is a potential supplier of the given Material. @@ -1604,6 +1871,7 @@ paths: name: partnerSupplies required: false schema: + additionalProperties: false type: boolean - description: This boolean flag indicates whether this Partner is a potential customer of this Material. @@ -1612,30 +1880,35 @@ paths: name: partnerBuys required: false schema: + additionalProperties: false type: boolean responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Update was accepted. '400': content: '*/*': schema: + additionalProperties: false type: object description: Invalid parameters '404': content: '*/*': schema: + additionalProperties: false type: object description: No existing entity was found. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server Error. tags: @@ -1652,6 +1925,8 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -1659,18 +1934,21 @@ paths: '*/*': schema: $ref: '#/components/schemas/MaterialEntityDto' + additionalProperties: false description: Returns the requested Material. '400': content: '*/*': schema: $ref: '#/components/schemas/MaterialEntityDto' + additionalProperties: false description: Invalid parameter '404': content: '*/*': schema: $ref: '#/components/schemas/MaterialEntityDto' + additionalProperties: false description: Requested Material was not found. tags: - material-controller @@ -1683,30 +1961,35 @@ paths: application/json: schema: $ref: '#/components/schemas/MaterialEntityDto' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Successfully created a new Material entity. '400': content: '*/*': schema: + additionalProperties: false type: object description: Malformed request body. '409': content: '*/*': schema: + additionalProperties: false type: object description: Material with the given ownMaterialNumber already exists. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server error. tags: @@ -1720,30 +2003,35 @@ paths: application/json: schema: $ref: '#/components/schemas/MaterialEntityDto' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Update was accepted. '400': content: '*/*': schema: + additionalProperties: false type: object description: Malformed request body. '404': content: '*/*': schema: + additionalProperties: false type: object description: No existing Material Entity found, no update was performed. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server Error. tags: @@ -1757,8 +2045,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/MaterialEntityDto' + maxItems: 50 type: array description: OK tags: @@ -1774,6 +2064,8 @@ paths: name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -1781,24 +2073,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/PartnerDto' + additionalProperties: false description: Found Partner, returning it in response body. '400': content: '*/*': schema: $ref: '#/components/schemas/PartnerDto' + additionalProperties: false description: Invalid parameter. '404': content: '*/*': schema: $ref: '#/components/schemas/PartnerDto' + additionalProperties: false description: Requested Partner not found. '500': content: '*/*': schema: $ref: '#/components/schemas/PartnerDto' + additionalProperties: false description: Internal Server Error. tags: - partner-controller @@ -1812,18 +2108,21 @@ paths: application/json: schema: $ref: '#/components/schemas/PartnerDto' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Partner created successfully. '400': content: '*/*': schema: + additionalProperties: false type: object description: Request body was malformed, didn't meet the minimum constraints or wrongfully contained a UUID. @@ -1831,6 +2130,7 @@ paths: content: '*/*': schema: + additionalProperties: false type: object description: 'The BPNL specified in the request body is already assigned. ' tags: @@ -1844,8 +2144,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK tags: @@ -1859,8 +2161,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/SiteDto' + maxItems: 50 type: array description: OK tags: @@ -1878,36 +2182,43 @@ paths: name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/AddressDto' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Update accepted. '400': content: '*/*': schema: + additionalProperties: false type: object description: Invalid Address data or invalid partnerBpnl. '404': content: '*/*': schema: + additionalProperties: false type: object description: Partner not found. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server Error. tags: @@ -1925,36 +2236,43 @@ paths: name: partnerBpnl required: true schema: + additionalProperties: false + maxItems: 50 type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/SiteDto' + additionalProperties: false required: true responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Update accepted. '400': content: '*/*': schema: + additionalProperties: false type: object description: Invalid Address data or invalid partnerBpnl. '404': content: '*/*': schema: + additionalProperties: false type: object description: Partner not found. '500': content: '*/*': schema: + additionalProperties: false type: object description: Internal Server Error. tags: @@ -1970,6 +2288,8 @@ paths: name: edc-bpn required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: The material number that the request receiving party uses for the material in question @@ -1977,42 +2297,51 @@ paths: name: materialnumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - description: Must be set to '$value' in: path name: representation required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false type: object description: Ok '400': content: '*/*': schema: + additionalProperties: false type: object description: 'Invalid request parameters. ' '401': content: '*/*': schema: + additionalProperties: false type: object description: 'Access forbidden. ' '404': content: '*/*': schema: + additionalProperties: false type: object description: 'Product not found for given parameters. ' '501': content: '*/*': schema: + additionalProperties: false type: object description: 'Unsupported representation requested. ' tags: @@ -2025,16 +2354,22 @@ paths: name: edc-bpn required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: materialnumbercx required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: path name: representation required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -2042,24 +2377,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/PlannedProductionOutput' + additionalProperties: false description: Ok '400': content: '*/*': schema: $ref: '#/components/schemas/PlannedProductionOutput' + additionalProperties: false description: Bad Request '500': content: '*/*': schema: $ref: '#/components/schemas/PlannedProductionOutput' + additionalProperties: false description: Internal Server Error '501': content: '*/*': schema: $ref: '#/components/schemas/PlannedProductionOutput' + additionalProperties: false description: Unsupported representation summary: This endpoint receives the PlannedProduction Submodel 2.0.0 requests tags: @@ -2074,19 +2413,25 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: site required: false schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: OK summary: Get all planned productions for the given Material @@ -2099,6 +2444,7 @@ paths: application/json: schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false required: true responses: '201': @@ -2106,24 +2452,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Planned Production was created. '400': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Malformed or invalid request body. '409': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Planned Production already exists. '500': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Internal Server Error. summary: Creates a new planned production tags: @@ -2135,6 +2485,7 @@ paths: application/json: schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false required: true responses: '200': @@ -2142,24 +2493,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Planned Productions was updated. '400': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Malformed or invalid request body. '404': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Planned Production does not exist. '500': content: '*/*': schema: $ref: '#/components/schemas/ProductionDto' + additionalProperties: false description: Internal Server Error. summary: Updates a planned production by its UUID tags: @@ -2171,8 +2526,10 @@ paths: content: application/json: schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array required: true responses: @@ -2180,32 +2537,40 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: Planned Productions were created. '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: Malformed or invalid request body. '409': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: Planned Productions already exist. '500': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: Internal Server Error. summary: Creates a range of planned productions @@ -2222,24 +2587,32 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: bpnl required: false schema: + additionalProperties: false + maxItems: 50 type: string - in: query name: site required: false schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductionDto' + maxItems: 50 type: array description: OK summary: Get all productions of partners for a material @@ -2255,14 +2628,18 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK summary: Refreshes all reported productions @@ -2276,7 +2653,9 @@ paths: name: id required: true schema: + additionalProperties: false format: uuid + maxItems: 50 type: string responses: '204': @@ -2299,22 +2678,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: Invalid parameter tags: @@ -2328,8 +2713,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/MaterialStockDto' + maxItems: 50 type: array description: OK tags: @@ -2342,6 +2729,7 @@ paths: application/json: schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false required: true responses: '200': @@ -2349,24 +2737,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Material Stock was created. '400': content: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Malformed or invalid request body. '409': content: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Material Stock does already exist. '500': content: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Internal Server Error. tags: - stock-view-controller @@ -2378,6 +2770,7 @@ paths: application/json: schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false required: true responses: '200': @@ -2385,18 +2778,21 @@ paths: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Material Stock was updated. '400': content: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Malformed request body. '500': content: '*/*': schema: $ref: '#/components/schemas/MaterialStockDto' + additionalProperties: false description: Internal Server Error. tags: - stock-view-controller @@ -2410,6 +2806,8 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': @@ -2427,6 +2825,7 @@ paths: '*/*': schema: additionalProperties: + maxItems: 50 type: string type: object description: Invalid parameter @@ -2441,8 +2840,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/FrontendMaterialDto' + maxItems: 50 type: array description: OK tags: @@ -2456,8 +2857,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ProductStockDto' + maxItems: 50 type: array description: OK tags: @@ -2470,6 +2873,7 @@ paths: application/json: schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false required: true responses: '200': @@ -2477,24 +2881,28 @@ paths: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Product Stock was created. '400': content: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Malformed or invalid request body. '409': content: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Product Stock does already exist. '500': content: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Internal Server Error. tags: - stock-view-controller @@ -2506,6 +2914,7 @@ paths: application/json: schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false required: true responses: '200': @@ -2513,18 +2922,21 @@ paths: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Product Stock was updated. '400': content: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Malformed request body. '500': content: '*/*': schema: $ref: '#/components/schemas/ProductStockDto' + additionalProperties: false description: Internal Server Error. tags: - stock-view-controller @@ -2537,8 +2949,10 @@ paths: content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/FrontendMaterialDto' + maxItems: 50 type: array description: OK tags: @@ -2553,22 +2967,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ReportedMaterialStockDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ReportedMaterialStockDto' + maxItems: 50 type: array description: Invalid parameter tags: @@ -2583,22 +3003,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ReportedProductStockDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/ReportedProductStockDto' + maxItems: 50 type: array description: Invalid parameter tags: @@ -2612,22 +3038,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: Invalid parameter tags: @@ -2647,22 +3079,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: Invalid parameter tags: @@ -2682,22 +3120,28 @@ paths: name: ownMaterialNumber required: true schema: + additionalProperties: false + maxItems: 50 type: string responses: '200': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: OK '400': content: '*/*': schema: + additionalProperties: false items: $ref: '#/components/schemas/PartnerDto' + maxItems: 50 type: array description: Invalid parameter tags: From 5723e5aaab3fa4a2ab24b6ecb289cd248a8bdc2b Mon Sep 17 00:00:00 2001 From: --show-origin Date: Mon, 20 May 2024 03:40:49 -0700 Subject: [PATCH 14/17] chore: added notice suffix to markdown documentations (TRG 7.07) --- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 2 +- INSTALL.md | 8 ++++++++ README.md | 8 ++++++++ backend/INSTALL.md | 8 ++++++++ backend/README.md | 8 ++++++++ backend/docs/documentation.md | 1 - charts/puris/README.md | 8 ++++++++ docs/DEVELOPMENT.md | 8 ++++++++ docs/README.md | 8 ++++++++ docs/admin/Admin_Guide.md | 8 ++++++++ docs/api/Interface_Doc.md | 8 ++++++++ docs/architecture/01_introduction_and_goals.md | 8 ++++++++ docs/architecture/02_architecture_constraints.md | 8 ++++++++ docs/architecture/03_system_scope_and_context.md | 8 ++++++++ docs/architecture/04_solution_strategy.md | 8 ++++++++ docs/architecture/05_building_block_view.md | 8 ++++++++ docs/architecture/06_runtime_view.md | 8 ++++++++ docs/architecture/07_deployment_view.md | 8 ++++++++ docs/architecture/08_concepts.md | 8 ++++++++ docs/architecture/09_architecture_decisions.md | 8 ++++++++ docs/architecture/10_quality_requirements.md | 8 ++++++++ docs/architecture/11_technical_risks.md | 8 ++++++++ docs/architecture/12_glossary.md | 8 ++++++++ docs/architecture/Index.md | 8 ++++++++ docs/security-assessment.md | 8 ++++++++ docs/user/User_Guide.md | 8 ++++++++ frontend/INSTALL.md | 8 ++++++++ frontend/README.md | 8 ++++++++ frontend/docs/documentation.md | 1 - local/INSTALL.md | 8 ++++++++ local/keycloak/INSTALL.md | 8 ++++++++ local/postman/README.md | 8 ++++++++ 33 files changed, 234 insertions(+), 4 deletions(-) delete mode 100644 backend/docs/documentation.md delete mode 100644 frontend/docs/documentation.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index faa735b3..b097564d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -90,4 +90,4 @@ The Eclipse Foundation Board of Directors may amend this Code from time to time This Code was inspired by the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available [here](https://www.contributor-covenant.org/version/1/4/code-of-conduct/). -[^1]: Capitalized terms used herein without definition shall have the meanings assigned to them in the Bylaws. \ No newline at end of file +[^1]: Capitalized terms used herein without definition shall have the meanings assigned to them in the Bylaws. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2084b6ea..1915f50a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,4 +55,4 @@ https://www.eclipse.org/projects/handbook/#resources-commit Contact the project developers via the project's "dev" list. -* https://accounts.eclipse.org/mailing-list/tractusx-dev \ No newline at end of file +* https://accounts.eclipse.org/mailing-list/tractusx-dev diff --git a/INSTALL.md b/INSTALL.md index 1b4f5c75..efe6dfe4 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -64,3 +64,11 @@ sudo vim /etc/hosts 5. Done! The applications should be available at: - (frontend) `http://your-frontend-host-address.com` - (backend) `http://your-backend-host-address.com` + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/README.md b/README.md index c8d229d7..bba0ff36 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,11 @@ Below you can find the information regarding Docker Notice for this frontend. - [Frontend](./frontend/DOCKER_NOTICE.md) - [Backend](./backend/DOCKER_NOTICE.md) + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/backend/INSTALL.md b/backend/INSTALL.md index 67d48592..c176016f 100644 --- a/backend/INSTALL.md +++ b/backend/INSTALL.md @@ -55,3 +55,11 @@ helm install backend --namespace puris --create-namespace . --set ingress.enable - (Java & Docker) `http://YOURIP:8081/catena/swagger-ui/index.html` - (Kubernetes) `http://CLUSTERIP:30001/catena/swagger-ui/index.html` 3. It is highly suggested to install and run the PURIS frontend afterward + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/backend/README.md b/backend/README.md index a7822c03..f75d176a 100644 --- a/backend/README.md +++ b/backend/README.md @@ -31,3 +31,11 @@ For details on the licensing terms, see the `LICENSE` file. Below you can find the information regarding Docker Notice for this frontend. [Backend](./DOCKER_NOTICE.md) + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/backend/docs/documentation.md b/backend/docs/documentation.md deleted file mode 100644 index d3fe277a..00000000 --- a/backend/docs/documentation.md +++ /dev/null @@ -1 +0,0 @@ -# PURIS Backend Documentation diff --git a/charts/puris/README.md b/charts/puris/README.md index 31c5e44a..25a413d1 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -191,3 +191,11 @@ $ helm install puris --namespace puris --create-namespace . | postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | | postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | | postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 593eeb10..4e7918f6 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -125,3 +125,11 @@ ocker ps docker exec -it {container-id} crictl rmi puris-backend:dev docker exec -it {container-id} crictl rmi puris-frontend:dev ``` + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/README.md b/docs/README.md index c867c0ab..cea124ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,3 +12,11 @@ The following table links you to the respective documentations. | [Administration Guide](admin/Admin_Guide.md) | Information relevant, if you want to use the PURIS application. | | [Interface Documentation](api/Interface_Doc.md) | Information about the interfaces. | | [User Manual](user/User_Guide.md) | Explanation of the views and how to use them. | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/admin/Admin_Guide.md b/docs/admin/Admin_Guide.md index ea7cf71b..30ed9716 100644 --- a/docs/admin/Admin_Guide.md +++ b/docs/admin/Admin_Guide.md @@ -366,3 +366,11 @@ the chart. Optionally it may be disabled to use your own installation. Refer to Encryption at rest for databases works. It has been tested by either encrypting the docker folder or encrypting the whole filesystem of the machine running. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/api/Interface_Doc.md b/docs/api/Interface_Doc.md index b0084d61..3eb0b4ec 100644 --- a/docs/api/Interface_Doc.md +++ b/docs/api/Interface_Doc.md @@ -35,3 +35,11 @@ _Note: The port and the path depend on the configuration of the spring backend ( There is a [postman collection](../../local/postman/README.md) containing information on how to provide master data and some basic data to test the application. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/01_introduction_and_goals.md b/docs/architecture/01_introduction_and_goals.md index d64e6805..2d2777fd 100644 --- a/docs/architecture/01_introduction_and_goals.md +++ b/docs/architecture/01_introduction_and_goals.md @@ -45,3 +45,11 @@ Key stakehoders for puris are: | Politics and Companies | more resilient supply networks | | SME | less efforts for integration | | Disposition | Knowledge about supply and demand situation | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/02_architecture_constraints.md b/docs/architecture/02_architecture_constraints.md index d00088f2..9d6da301 100644 --- a/docs/architecture/02_architecture_constraints.md +++ b/docs/architecture/02_architecture_constraints.md @@ -11,3 +11,11 @@ PURIS FOSS follows the following constraints: | Interoperability between Data Applications | Data exchange MUST follow standards so that different vendors applications may exchange data. This allows to reduce the risk of vendor-lock-ins. | | Semantic Aspect Meta Model (SAMM) | Tooling used in Catena-X to semantically describe data. | | Digital Twins in Catena-X & Industry Core | Standards CX-0002 and CX-0126 describe how Digital Twins following with the Asset Administration Shell shall be used. PURIS standards are built on these foundations | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/03_system_scope_and_context.md b/docs/architecture/03_system_scope_and_context.md index 8550725c..d74f0c38 100644 --- a/docs/architecture/03_system_scope_and_context.md +++ b/docs/architecture/03_system_scope_and_context.md @@ -80,3 +80,11 @@ the Part Type Twin as a "catalog item" representing a material that has not yet [Digital Twin KIT](https://eclipse-tractusx.github.io/docs-kits/kits/Digital%20Twin%20Kit/Adoption%20View%20Digital%20Twin%20Kit) describes the shared asset pattern used by puris to distribute Digital Twins between the two partners. For more information refer to the [concepts section](./08_concepts.md).. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/04_solution_strategy.md b/docs/architecture/04_solution_strategy.md index cb4aef19..09158e60 100644 --- a/docs/architecture/04_solution_strategy.md +++ b/docs/architecture/04_solution_strategy.md @@ -29,3 +29,11 @@ PURIS FOSS - registers digital twins depending on the relationship of partners for a specific material - implements value-only submodel interfaces for information objects exchanged based on Digital Twin and Industry Core standards. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/05_building_block_view.md b/docs/architecture/05_building_block_view.md index 17f38281..abda329e 100644 --- a/docs/architecture/05_building_block_view.md +++ b/docs/architecture/05_building_block_view.md @@ -54,3 +54,11 @@ The building block view describes only the responsibilities of the components/ p | MAD | Stores the partner and material related information. They may only be added via REST interfaces. | | Stock | Stores and handles stock related data. It provides interfaces to create and read stock data. Also it allows to exchange stock information via the EDC. | | DTR | The DTR component provides the DTR implementations to manage ShellDescriptors, query partners' DTR and consume Submodel data. | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/06_runtime_view.md b/docs/architecture/06_runtime_view.md index 8c7dcb42..ab4f3e8c 100644 --- a/docs/architecture/06_runtime_view.md +++ b/docs/architecture/06_runtime_view.md @@ -69,3 +69,11 @@ When reloading the UI, the latest data is pulled from the backend. Whenever a pa is performed, then the frontend hands over the request to the backend to perform the action. Details on the Web-Ui can be found in the [User Guide](../user/User_Guide.md). + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/07_deployment_view.md b/docs/architecture/07_deployment_view.md index e92ba72c..7ea460c0 100644 --- a/docs/architecture/07_deployment_view.md +++ b/docs/architecture/07_deployment_view.md @@ -42,3 +42,11 @@ per partner: - `Connector` including `Postgres` The chart allows also to either install the database as a dependency or bring your own. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/08_concepts.md b/docs/architecture/08_concepts.md index ee9900da..32ff587a 100644 --- a/docs/architecture/08_concepts.md +++ b/docs/architecture/08_concepts.md @@ -240,3 +240,11 @@ users. For configuration, please refer to the [Admin Guide](../admin/Admin_Guide _Note: The reference implementation [Digital Twin Registry](https://github.com/eclipse-tractusx/sldt-digital-twin-registry) currently only works with one client._ + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/09_architecture_decisions.md b/docs/architecture/09_architecture_decisions.md index d4653a81..cc16ecc1 100644 --- a/docs/architecture/09_architecture_decisions.md +++ b/docs/architecture/09_architecture_decisions.md @@ -1,3 +1,11 @@ # Architecture Decisions _None have been documented yet._ + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/10_quality_requirements.md b/docs/architecture/10_quality_requirements.md index 53099f4f..ca813840 100644 --- a/docs/architecture/10_quality_requirements.md +++ b/docs/architecture/10_quality_requirements.md @@ -1,3 +1,11 @@ # Quality Requirements PURIS FOSS is compliant to the [Tractus-X Release Guidelines](https://eclipse-tractusx.github.io/docs/release). + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/11_technical_risks.md b/docs/architecture/11_technical_risks.md index 9d099e1b..07c563c4 100644 --- a/docs/architecture/11_technical_risks.md +++ b/docs/architecture/11_technical_risks.md @@ -4,3 +4,11 @@ This application started as a demonstrator and is enhanced to become an applicat debts that need to be resolved later. Until now, automated test coverage is low to medium. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/12_glossary.md b/docs/architecture/12_glossary.md index d916afec..0c794663 100644 --- a/docs/architecture/12_glossary.md +++ b/docs/architecture/12_glossary.md @@ -33,3 +33,11 @@ | Semantic Aspect Meta Model | SAMM | A formal, machine-readable semantic description (expressed with RDF/turtle) of data accessible from an Aspect. Note 1 to entry: An Aspect Model must adhere to the Semantic Aspect Meta Model (SAMM), i.e., it utilizes elements and relations defined in the Semantic Aspect Meta Model and is compliant to the validity rules defined by the Semantic Aspect Meta Model. Note 2 to entry: Aspect model are logical data models which can be used to detail a conceptual model in order to describe the semantics of runtime data related to a concept. Further, elements of an Aspect model can/should refer to terms of a standardized Business Glossary (if existing). [Source: Catena-X, CX-0002](https://catena-x.net/de/standard-library) | | Digital Twin | DT | Digital representation of an asset (concept, physical device, process, etc.). Realized using the Asset Administration Shell. Used synonymously with the term "Asset Administration Shell". | | Managed Identity Wallet | MIW | Service providing verifieable credentials to be proof claims. | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/architecture/Index.md b/docs/architecture/Index.md index ab649db7..7352fc50 100644 --- a/docs/architecture/Index.md +++ b/docs/architecture/Index.md @@ -13,3 +13,11 @@ - [10. Quality Requirements](10_quality_requirements.md) - [11. Technical Risks](11_technical_risks.md) - [12. Glossary](12_glossary.md) + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/security-assessment.md b/docs/security-assessment.md index 21257a65..4a8705db 100644 --- a/docs/security-assessment.md +++ b/docs/security-assessment.md @@ -191,3 +191,11 @@ B | Before Mitigation | Impact: High, Likelihood: Medium, Risk: High | | After Mitigation | Impact: Low, Likelihood: Low, Risk: Low | | Mitigation | PostgreSQL DB has been implemented to the product. Status of implementation is already completed. Additionally: We don't include it in compile, but in test scope so that we have easy testing but security when deploying. | + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/docs/user/User_Guide.md b/docs/user/User_Guide.md index 99dfd21c..e3cb1077 100644 --- a/docs/user/User_Guide.md +++ b/docs/user/User_Guide.md @@ -148,3 +148,11 @@ Per Transfer the following information is listed: _**Note**: Per data request per partner, there are two Transfers as one contracts the partner's request asset and the partner contracts your response asset._ + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/frontend/INSTALL.md b/frontend/INSTALL.md index 884c8f3f..ad690961 100644 --- a/frontend/INSTALL.md +++ b/frontend/INSTALL.md @@ -45,3 +45,11 @@ cd charts/puris/charts/frontend helm install frontend --namespace puris --create-namespace . --set ingress.enabled=true --values ../../values.yaml ``` 4. Done! The frontend should be available at `http://YOURIP:30000/` + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/frontend/README.md b/frontend/README.md index 2ca46227..c8803490 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -30,3 +30,11 @@ For details on the licensing terms, see the `LICENSE` file. Below you can find the information regarding Docker Notice for this frontend. [Frontend](./DOCKER_NOTICE.md) + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/frontend/docs/documentation.md b/frontend/docs/documentation.md deleted file mode 100644 index 2001af6b..00000000 --- a/frontend/docs/documentation.md +++ /dev/null @@ -1 +0,0 @@ -# PURIS Frontend Documentation \ No newline at end of file diff --git a/local/INSTALL.md b/local/INSTALL.md index 4228351e..5d209ca5 100644 --- a/local/INSTALL.md +++ b/local/INSTALL.md @@ -84,3 +84,11 @@ cd local sh cleanup.sh ``` Then start your containers again with the aforementioned commands. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/local/keycloak/INSTALL.md b/local/keycloak/INSTALL.md index fe6ed687..c7c3b4c0 100644 --- a/local/keycloak/INSTALL.md +++ b/local/keycloak/INSTALL.md @@ -52,3 +52,11 @@ docker volume rm kc-temp-data # make sure to remove the array "org.keycloak.keys.KeyProvider" (contains unneeded credentials) # from realm file ``` + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris diff --git a/local/postman/README.md b/local/postman/README.md index ad66bc10..985747c7 100644 --- a/local/postman/README.md +++ b/local/postman/README.md @@ -200,3 +200,11 @@ environment file. ## Run the integration test You can run the integration tests on per folder level using right click > run folder. + +## NOTICE + +This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). + +- SPDX-License-Identifier: Apache-2.0 +- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation +- Source URL: https://github.com/eclipse-tractusx/puris From c0d0138654d222796f05087e273610ff95e2419a Mon Sep 17 00:00:00 2001 From: --show-origin Date: Mon, 20 May 2024 03:42:11 -0700 Subject: [PATCH 15/17] chore(helm): version bump to release version 3.0.0 --- charts/puris/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index 06142577..bcd3579a 100644 --- a/charts/puris/Chart.yaml +++ b/charts/puris/Chart.yaml @@ -35,7 +35,7 @@ dependencies: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.3.0 +version: 3.0.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to From 4074b61ac19a81967e112f17a43acb9b2aaef547 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 21 May 2024 07:50:53 -0700 Subject: [PATCH 16/17] docs(architecture/05): updated images and smaller fixes --- backend/pom.xml | 370 +++++++++--------- .../02_architecture_constraints.md | 2 +- .../03_system_scope_and_context.md | 2 +- docs/architecture/05_building_block_view.md | 19 +- docs/architecture/img/05-level-0.svg | 206 ++++++---- docs/architecture/img/05-level-1-backend.svg | 199 ++++++---- .../architecture/puml/05-level-1-backend.puml | 2 +- 7 files changed, 453 insertions(+), 347 deletions(-) diff --git a/backend/pom.xml b/backend/pom.xml index 566d847d..1b026611 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -24,191 +24,191 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.2.5 - - - org.eclipse.tractusx.puris - puris-backend - 1.0.0 - puris-backend - PURIS Backend - - 21 - 2.5.0 - 8.0.1.Final - 2.2 - 4.12.0 - 3.2.0 - 2.7.2 - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.session - spring-session-core - - - org.hsqldb - hsqldb - ${hsqldb.version} - runtime - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.postgresql - postgresql - 42.7.2 - runtime - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc.version} - - - com.squareup.okhttp3 - okhttp - ${okhttp.version} - - - com.squareup.okhttp3 - mockwebserver - ${okhttp.version} - test - - - - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} - - - - org.modelmapper - modelmapper - ${modelmapper.version} - - + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + org.eclipse.tractusx.puris + puris-backend + 2.0.0 + puris-backend + PURIS Backend + + 21 + 2.5.0 + 8.0.1.Final + 2.2 + 4.12.0 + 3.2.0 + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.session + spring-session-core + + + org.hsqldb + hsqldb + ${hsqldb.version} + runtime + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.postgresql + postgresql + 42.7.2 + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + com.squareup.okhttp3 + mockwebserver + ${okhttp.version} + test + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + + org.modelmapper + modelmapper + ${modelmapper.version} + + - - - dash-licenses - https://repo.eclipse.org/content/repositories/dash-licenses - - + + + dash-licenses + https://repo.eclipse.org/content/repositories/dash-licenses + + - - - - org.eclipse.dash - license-tool-plugin - 1.0.2 - - automotive.tractusx - - DEPENDENCIES - - test - - - - license-check - - license-check - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - org.hsqldb - hsqldb - - - - - - com.mycila - license-maven-plugin - 4.2 - - - -
scripts/license/header.txt
- - **/README - src/test/resources/** - src/main/resources/** - -
-
-
-
-
- - - - ${project.basedir}/src/main/resources - - application.properties - - BOOT-INF/classes/ - - - - ${project.basedir}/ - - README.md - LICENSE - NOTICE.md - DEPENDENCIES - SECURITY.md - - META-INF - - -
+ + + + org.eclipse.dash + license-tool-plugin + 1.0.2 + + automotive.tractusx + + DEPENDENCIES + + test + + + + license-check + + license-check + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + org.hsqldb + hsqldb + + + + + + com.mycila + license-maven-plugin + 4.2 + + + +
scripts/license/header.txt
+ + **/README + src/test/resources/** + src/main/resources/** + +
+
+
+
+
+ + + + ${project.basedir}/src/main/resources + + application.properties + + BOOT-INF/classes/ + + + + ${project.basedir}/ + + README.md + LICENSE + NOTICE.md + DEPENDENCIES + SECURITY.md + + META-INF + + +
diff --git a/docs/architecture/02_architecture_constraints.md b/docs/architecture/02_architecture_constraints.md index 9d6da301..7cc31074 100644 --- a/docs/architecture/02_architecture_constraints.md +++ b/docs/architecture/02_architecture_constraints.md @@ -10,7 +10,7 @@ PURIS FOSS follows the following constraints: | Managed Identity Wallet (MIW) | MIW is a central Catena-X Service, which allows storing credentials to prove claims in the Catena-X data space. | | Interoperability between Data Applications | Data exchange MUST follow standards so that different vendors applications may exchange data. This allows to reduce the risk of vendor-lock-ins. | | Semantic Aspect Meta Model (SAMM) | Tooling used in Catena-X to semantically describe data. | -| Digital Twins in Catena-X & Industry Core | Standards CX-0002 and CX-0126 describe how Digital Twins following with the Asset Administration Shell shall be used. PURIS standards are built on these foundations | +| Digital Twins in Catena-X & Industry Core | Standards CX-0002 and CX-0126 describe how Digital Twins following with the Asset Administration Shell shall be used. PURIS standards are built on these foundations. | ## NOTICE diff --git a/docs/architecture/03_system_scope_and_context.md b/docs/architecture/03_system_scope_and_context.md index d74f0c38..ee3d940b 100644 --- a/docs/architecture/03_system_scope_and_context.md +++ b/docs/architecture/03_system_scope_and_context.md @@ -16,7 +16,7 @@ steers the allocation of material within the production. PURIS supports the disp providing relevant information regarding the material flow. **Production (Process)** -Production is the actually value-adding process of a manufacturer. It's demand is derived by outer factors such as +Production is the actually value-adding process of a manufacturer. Its demand is derived by outer factors such as orders. A lack of material in supply chains leads to shortages. The production process has to be seen as a consumer of data provided by PURIS (Catena-X data consumer) and as a provider of data to PURIS (Catena-X data provider). In that way PURIS is able to fulfill the disposition's information need. diff --git a/docs/architecture/05_building_block_view.md b/docs/architecture/05_building_block_view.md index abda329e..3f67bf47 100644 --- a/docs/architecture/05_building_block_view.md +++ b/docs/architecture/05_building_block_view.md @@ -5,17 +5,13 @@ been omitted for readability. ![Level 0 - Blackbox View](img/05-level-0.svg) -TODO check if plant uml can work directly - -![05-level-0.puml](./puml/05-level-0.puml) - | Component / system | Descriptions | |------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Data Provisioning & Transformation | The Data Provisioning & Transformation Building Block handles the upload of data from internal systems into PURIS and provides capabilities for data transformation. **This component is not part of this repository**. | | PURIS FOSS Backend | This system represents the PURIS FOSS application's logic. It handles the data exchange. | | PURIS FOSS Frontend | This system represents the PURIS FOSS user interface. It handles the data visualization. | | EDC | The Eclipse Dataspace Components Connector (EDC) is the component allowing PURIS FOSS to participate in the IDS. It is used to provide and consume data assets following policy information. Any data transfer is routed through the EDC. | -| Keycloak | Keycloak is an identity provider that can manage multiple clients (applications). Catena-X allows the usage of a shared identity provider. | +| Keycloak | Keycloak is an identity provider that can manage multiple clients (applications). Catena-X allows the usage of a shared identity provider. Also the DTR can use a keycloak that allows manage access to the PURIS backend and Read access through the EDC | | Postgresql DB | Database used by Backend to persist data | | Digital Twin Registry | Software Service that implements the AAS Discovery and Registry Interfaces. PURIS FOSS registers materials as ShellDescriptors with the respective information as Submodels. These SubmodelDescriptors do have a DSP endpoint linking to the EDC to contract the usage and how to get the submodel. | @@ -34,6 +30,7 @@ The Frontend only handles visualization logic. The remaining logic is handled in | Stock View | Allows to manually add or update stock information that is allocated to partners. Also latest stock information for partners may be requested (via backend). | | Dashboard | The dashboard allows to compare material-related demands, production outputs and stocks in a mocked way. Only Stock information is currently implements. | | Authentication Service | Encapsulates keycloak authentication and session management to be used by the main app. | +| Access Service | Use to give control the access to views. | **PURIS FOSS Backend** @@ -48,12 +45,12 @@ The building block view describes only the responsibilities of the components/ p ![Level 1 - Whitebox View - PURIS FOSS Backend](img/05-level-1-backend.svg) -| Component / system | Descriptions | -|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| -| EDC | The EDC component provides the EDC implementations to create assets, negotiate contracts and intialize transfers. | -| MAD | Stores the partner and material related information. They may only be added via REST interfaces. | -| Stock | Stores and handles stock related data. It provides interfaces to create and read stock data. Also it allows to exchange stock information via the EDC. | -| DTR | The DTR component provides the DTR implementations to manage ShellDescriptors, query partners' DTR and consume Submodel data. | +| Component / system | Descriptions | +|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| EDC | The EDC component provides the EDC implementations to create assets, negotiate contracts and intialize transfers. query partners' DTR and consume Submodel data. | +| MAD | Stores the partner and material related information. They may only be added via REST interfaces. | +| Stock | Stores and handles stock related data. It provides interfaces to create and read stock data. Also it allows to exchange stock information via the EDC. | +| DTR | The DTR component provides the DTR implementations to manage ShellDescriptors. May first need to get a OAuth 2 token for authentication. | ## NOTICE diff --git a/docs/architecture/img/05-level-0.svg b/docs/architecture/img/05-level-0.svg index 3b638d95..92ed9fd9 100644 --- a/docs/architecture/img/05-level-0.svg +++ b/docs/architecture/img/05-level-0.svg @@ -1,134 +1,200 @@ - - - + «system» PURIS + textLength="127" x="377.5" y="81.4951">«system» PURIS - - - + x="390.5" y="101.5"/> + + + PURIS FOSS Backend + x="405.5" y="134.4951">PURIS FOSS Backend - - - + x="389.5" y="214.5"/> + + + PURIS FOSS Frontend + x="404.5" y="247.4951">PURIS FOSS Frontend - - - - - Data Provisioning & Transformation + + + + + Data Provisioning + + & Transformation - - - - - Eclipse DataSpace Components Connector + + + + + Eclipse Dataspace + + Components Connector - - - + x="678.5" y="101.5"/> + + + Postgresql DB + x="693.5" y="134.4951">Postgresql DB - - - + x="432.5" y="319"/> + + + Keycloak + x="447.5" y="351.9951">Keycloak + + + + + + + + Digital Twin + + Registry - + Interface internal systems + x="189.5" y="154.4951">Interface internal systems + + + + + EDC Management + + API + + + + + Registration & + + Discovery Interfaces - - - - EDC APIs + + + + Submodel value-only interfaces - - + - - - + + + + + - - - - + + + provide and pull data + x="375.4404" y="167.6424">provide and pull data according to standards + x="370.4404" y="182.7752">according to standards - + - - - - + + + + + + + + + + + + + + + + - + diff --git a/docs/architecture/img/05-level-1-backend.svg b/docs/architecture/img/05-level-1-backend.svg index b5286216..40116d3c 100755 --- a/docs/architecture/img/05-level-1-backend.svg +++ b/docs/architecture/img/05-level-1-backend.svg @@ -1,108 +1,151 @@ - - + «system» PURIS FOSS Backend + textLength="246" x="203.5" y="73.9951">«system» PURIS FOSS Backend + + + + + + + + DTR - - - + x="825.5" y="198.5"/> + + + EDC - - - - - EDC Client Interface + x="840.5" y="231.4951">EDC - - - - - Stock - - - - - Stock Interface - - - - - Stock Request & - - Response Interfaces - - (through EDC) + + + + + Stock, Production, Demand, + + Delivery Information - - - - - MAD + + + + + MAD + + + + + Registry & Discovery Interfaces - - MAD Interface + + MAD Interface + + + + + EDC Client Interface + + + + + Submodel + + & internal interface + + + + OAuth2 + + + + + + + + - - - - - - - - - - + + + + + + + + - query catalog & + Register and discover twins - request data (via edc) + & submodels - - - - - - - + + + + query catalog & + + get data (via edc) + + + + + + + + + uses for authentication of DTR + + diff --git a/docs/architecture/puml/05-level-1-backend.puml b/docs/architecture/puml/05-level-1-backend.puml index 6fd72c2a..04d6df19 100644 --- a/docs/architecture/puml/05-level-1-backend.puml +++ b/docs/architecture/puml/05-level-1-backend.puml @@ -20,6 +20,6 @@ dtr -- "Register and discover twins\n& submodels" stock stock - "query catalog &\nget data (via edc)" edc mad - stock - +"OAuth2" )- "uses for authentication of DTR" dtr @enduml From 34896fd9a23d385ad2f22c36514f8ede33debffb Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 21 May 2024 07:57:54 -0700 Subject: [PATCH 17/17] chore(helm): update readme and chart version --- charts/puris/Chart.yaml | 2 +- charts/puris/README.md | 348 ++++++++++++++++++++-------------------- 2 files changed, 175 insertions(+), 175 deletions(-) diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index e07ae3f2..d0f0c11f 100644 --- a/charts/puris/Chart.yaml +++ b/charts/puris/Chart.yaml @@ -41,4 +41,4 @@ version: 2.5.1 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.0.0" +appVersion: "2.0.0" diff --git a/charts/puris/README.md b/charts/puris/README.md index 779ff1aa..e36d3220 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -1,6 +1,6 @@ # puris -![Version: 2.3.0](https://img.shields.io/badge/Version-2.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +![Version: 2.5.1](https://img.shields.io/badge/Version-2.5.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.0.0](https://img.shields.io/badge/AppVersion-2.0.0-informational?style=flat-square) A helm chart for Kubernetes deployment of PURIS @@ -29,179 +29,179 @@ $ helm install puris --namespace puris --create-namespace . ## Values -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | -| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | -| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | -| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| backend.imagePullSecrets | list | `[]` | List of used secrets | -| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | -| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | -| backend.ingress.enabled | bool | `false` | Enable the Ingress | -| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | -| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | -| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| backend.nameOverride | string | `""` | Possibility to override the name | -| backend.nodeSelector | object | `{}` | Constrains for the node selector | -| backend.podAnnotations | object | `{}` | Annotations added to a running pod | -| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | -| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | -| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | -| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | -| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | -| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | -| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | -| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | -| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | -| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | -| backend.puris.dtr.idp.clients.edc.id | string | `"FOSS-EDC-CLIENT"` | id of the client that has a service account with roles to view the DTR. Used by the application to create DTR asset in the edc with read only access. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.edc.secret.alias | string | `"path/secret-name"` | alias for the vault used by the EDC in which the secret is stored. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.puris.id | string | `"FOSS-PURIS-CLIENT"` | id of the client that has a service account with roles to manage the DTR. Used by the application to create and update digital twins. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.puris.secret | string | `nil` | secret of the client with write access (no vault alias). No default value will be created if empty. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.enabled | bool | `true` | enables the usage of the IDP for the DTR. | -| backend.puris.dtr.idp.tokenurl | string | `"https://keycloak-service.com/realms/your-realm/openid-connect/token"` | token url of the idp for your specific realm. May be different to other idp token url in this config. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | -| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | -| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | -| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | -| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | -| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | -| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | -| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | -| backend.puris.frameworkagreement.credential | string | `"Puris"` | The name of the framework agreement. Starting with Uppercase and using CamelCase. | -| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | -| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | -| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | -| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | -| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | -| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | -| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | -| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | -| backend.puris.own.country | string | `"Germany"` | Own country | -| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | -| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | -| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | -| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | -| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | -| backend.puris.purpose.name | string | `"cx.puris.base"` | The name of the purpose to use for submodel contracts | -| backend.puris.purpose.version | string | `"1"` | The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! | -| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | -| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | -| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | -| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | -| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | -| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | -| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | -| backend.service.port | int | `8081` | The port of the service | -| backend.service.type | string | `"ClusterIP"` | Type of the service | -| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| backend.tolerations | list | `[]` | Constrains for tolerations | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | -| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | -| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | -| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | -| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | -| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | -| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| frontend.imagePullSecrets | list | `[]` | List of used secrets | -| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | -| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | -| frontend.ingress.enabled | bool | `false` | Enable the Ingress | -| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | -| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | -| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| frontend.nameOverride | string | `""` | Possibility to override the name | -| frontend.nodeSelector | object | `{}` | Constrains for the node selector | -| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | -| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | -| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | -| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointDelivery | string | `"delivery"` | The endpoint for the delivery submodel | -| frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel | -| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | -| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | -| frontend.puris.endpointPartner | string | `"partner"` | The endpoint for the partners BPNS | -| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | -| frontend.puris.endpointProduction | string | `"production"` | The endpoint for the production submodel | -| frontend.puris.endpointProductionRange | string | `"production/range"` | The endpoint for the production range of the production submodel | -| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | -| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | -| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | -| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | -| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | -| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | -| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | -| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | -| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | -| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | -| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | -| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | -| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | -| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | -| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | -| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| frontend.replicaCount | int | `1` | | -| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | -| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | -| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | -| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | -| frontend.service.port | int | `8080` | The port of the service | -| frontend.service.type | string | `"ClusterIP"` | Type of the service | -| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| frontend.tolerations | list | `[]` | Constrains for tolerations | -| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | -| postgresql.auth.database | string | `"postgres"` | Name of the database. | -| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | -| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | -| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | -| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | -| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | -| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | -| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | +| Key | Type | Default | Description | +|-------------------------------------------------------------------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | +| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | +| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | +| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| backend.imagePullSecrets | list | `[]` | List of used secrets | +| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | +| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | +| backend.ingress.enabled | bool | `false` | Enable the Ingress | +| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | +| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | +| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| backend.nameOverride | string | `""` | Possibility to override the name | +| backend.nodeSelector | object | `{}` | Constrains for the node selector | +| backend.podAnnotations | object | `{}` | Annotations added to a running pod | +| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | +| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | +| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | +| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | +| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | +| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | +| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | +| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | +| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | +| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | +| backend.puris.dtr.idp.clients.edc.id | string | `"FOSS-EDC-CLIENT"` | id of the client that has a service account with roles to view the DTR. Used by the application to create DTR asset in the edc with read only access. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.edc.secret.alias | string | `"path/secret-name"` | alias for the vault used by the EDC in which the secret is stored. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.puris.id | string | `"FOSS-PURIS-CLIENT"` | id of the client that has a service account with roles to manage the DTR. Used by the application to create and update digital twins. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.puris.secret | string | `nil` | secret of the client with write access (no vault alias). No default value will be created if empty. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.enabled | bool | `true` | enables the usage of the IDP for the DTR. | +| backend.puris.dtr.idp.tokenurl | string | `"https://keycloak-service.com/realms/your-realm/openid-connect/token"` | token url of the idp for your specific realm. May be different to other idp token url in this config. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | +| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | +| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | +| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | +| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | +| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | +| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | +| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | +| backend.puris.frameworkagreement.credential | string | `"Puris"` | The name of the framework agreement. Starting with Uppercase and using CamelCase. | +| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | +| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | +| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | +| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | +| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | +| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | +| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | +| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | +| backend.puris.own.country | string | `"Germany"` | Own country | +| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | +| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | +| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | +| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | +| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | +| backend.puris.purpose.name | string | `"cx.puris.base"` | The name of the purpose to use for submodel contracts | +| backend.puris.purpose.version | string | `"1"` | The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! | +| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | +| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | +| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | +| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | +| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | +| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | +| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | +| backend.service.port | int | `8081` | The port of the service | +| backend.service.type | string | `"ClusterIP"` | Type of the service | +| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| backend.tolerations | list | `[]` | Constrains for tolerations | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | +| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | +| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | +| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | +| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | +| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | +| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| frontend.imagePullSecrets | list | `[]` | List of used secrets | +| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | +| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | +| frontend.ingress.enabled | bool | `false` | Enable the Ingress | +| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | +| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | +| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| frontend.nameOverride | string | `""` | Possibility to override the name | +| frontend.nodeSelector | object | `{}` | Constrains for the node selector | +| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | +| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | +| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | +| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointDelivery | string | `"delivery"` | The endpoint for the delivery submodel | +| frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel | +| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | +| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | +| frontend.puris.endpointPartner | string | `"partner"` | The endpoint for the partners BPNS | +| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | +| frontend.puris.endpointProduction | string | `"production"` | The endpoint for the production submodel | +| frontend.puris.endpointProductionRange | string | `"production/range"` | The endpoint for the production range of the production submodel | +| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | +| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | +| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | +| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | +| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | +| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | +| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | +| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | +| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | +| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | +| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | +| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | +| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | +| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | +| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | +| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| frontend.replicaCount | int | `1` | | +| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | +| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | +| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | +| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | +| frontend.service.port | int | `8080` | The port of the service | +| frontend.service.type | string | `"ClusterIP"` | Type of the service | +| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| frontend.tolerations | list | `[]` | Constrains for tolerations | +| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | +| postgresql.auth.database | string | `"postgres"` | Name of the database. | +| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | +| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | +| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | +| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | +| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | +| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | +| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | ## NOTICE