diff --git a/archetypes/releases.md b/archetypes/releases.md index 80b08c222..f2898b39d 100644 --- a/archetypes/releases.md +++ b/archetypes/releases.md @@ -15,23 +15,18 @@ _Release date:_ The following sections document the changes this release brings to each service. -### Admin - -### BPMN engine - -### Schema -### BAAS - -### Core +### Admin ### Agent -### Audit +### BaaS + +### ISA-95 -### Keycloak Theme +### Typescript host service -### Router +### Workflow ## Compatibility diff --git a/content/_index.md b/content/_index.md index 0b9cd02f0..053655240 100644 --- a/content/_index.md +++ b/content/_index.md @@ -1,10 +1,9 @@ --- -title: ##Leave only home page without title description: User guides, deploy docs, references, and deep dives about the Rhize manufacturing data hub. +type: "docs" cascade: - type: docs - v: "3.2.1" + v: "4.2.0" --- diff --git a/content/deploy/cluster-sizing.md b/content/deploy/cluster-sizing.md index e657e6b1c..3f5ad022d 100644 --- a/content/deploy/cluster-sizing.md +++ b/content/deploy/cluster-sizing.md @@ -16,19 +16,18 @@ The following tables are the minimum recommended sizes to provision your cluster For high availability, Rhize recommends a **minimum of three nodes** with the following specifications. - | Property | Value | |-----------------------|-------------------| | Number of nodes | 3 | | CPU Speed (GHz) | 3.3 | | vCPU per Node | 16 | | Memory per node (GiB) | 32 (64 is better) | -| Persisted volumes | 12 | +| Persisted volumes | 16 | | Persisted Volume IOPS | 5000 | | PV Throughput (MBps) | 500 | | Total Disk Space (TB) | 3 | | Disk IOPS | 5000 | -| Disk MBps | 500MBps | +| Disk MBps | 500 | ### Rhize agent @@ -47,24 +46,25 @@ For the Rhize Agent, the minimum recommended specifications are as follows: The following table lists the **minimum** recommended specifications for the main services. Services with stateful PV have a persistent volume per pod. +>![Warn] +> Avoid NFS or SMB filesystems. These are known to lead to file corruption in BaaS and do not work at all with various other services. + | Service | Pods for HA (replica count) | vCPU per Pod | Memory Per Pod | Stateful PV | DiskSize (GiB) | Comments | |------------------------|-----------------------------|--------------|----------------|-------------|----------------|----------------------------------------------------------------------| | `baas-alpha` | 3 | 8 | 16 (at least) | Yes | 750 | High throughput and IOPS | -| `baas-zero` | 3 | 2 | 2 | Yes | 350 | High throughput and IOPS | -| `libre-core` | 3 | 1 | 2 | No | N/A | HA requires 2 pods, but 3 is to avoid hotkey issues and balance load | -| `bpmn-engine` | 3 | 1 | 2 | No | N/A | HA requires 2 pods, but 3 is to avoid hotkey issues and balance load | -| `nats` | 3 | 1 | 2 | Yes | 100 | High IOPS | -| `nats-box` | 1 | 0.25 | 0.25 | No | N/A | | -| `libre-audit` | 2 | 1 | 1 | No | N/A | | +| `baas-zero` | 3 | 2 | 2 | Yes | 300 | High throughput and IOPS | +| `workflow` | 3 | 1 | 2 | No | N/A | HA requires 2 pods, but 3 is to avoid hotkey issues and balance load | +| `isa95` | 2 | 2 | 1 | NO | N/A | | +| `keycloak-postgres` | 2 | 1 | 2 | No | 200 | Runs in pod with `keycloak` | +| `keycloak` | 2 | 1 | 2 | No | N/A | | | `libre-audit-postgres` | 2 | 1 | 2 | Yes | 250 | Runs in pod with `libre-audit` | | `libre-ui` | 3 | 0.25 | 0.25 | No | N/A | | -| `keycloak` | 2 | 1 | 2 | No | N/A | | -| `keycloak-postgres` | 2 | 1 | 2 | No | 200 | Runs in pod with `keycloak` | -| `router` | 2 | 1 | 2 | Yes | <1 | Requires volume to compose supergraph | -| `grafana`* | 3 | 0.5 | 2 | No | 20-50 | Storage can be in host or in object bucket. | +| `quest-db` | 1 | 4 | 8 | Yes | 250 | High Throughput and IPOS | +| `redpanda` | 3 | | | Yes | 100 | High IOPS | +| `restate` | 3 | | | Yes | 50 | High Throughput and IPOS | +| `appsmith` | 3 | 4 | | Yes | 50 | High Throughput and IPOS | - * May run [in separate cluster](#monitoring-stack) ### Monitoring stack @@ -90,3 +90,9 @@ However, some deployments prefer to separate monitoring to its own cluster. | `tempo-distributor` | 1 | 0.25 | 0.5 | 0.25 | | `tempo-query-frontend` | 1 | 0.25 | 0.5 | 0.25 | | `temp-memcache` | 1 | 0.25 | 0.1 | 0.25 | + +## Back up + +You can [back up Rhize to S3](/deploy/backup/binary/) . +Consider including an S3 bucket as part of your deployment. + diff --git a/content/deploy/install/keycloak.md b/content/deploy/install/keycloak.md index bb97b5d84..052835991 100644 --- a/content/deploy/install/keycloak.md +++ b/content/deploy/install/keycloak.md @@ -49,7 +49,7 @@ To create your Rhize realm, follow these steps. 1. In the side menu, select **Realm Settings**. 1. Enter the following values: | Field | value | - |--------------|-----------------------| + | ------------ | --------------------- | | Frontend URL | Keycloak frontend URL | | Require SSL | External requests | @@ -141,9 +141,9 @@ Create a client for the UI as follows: 1. Configure the **Access Settings**: - - **Root URL**: `.` without trailing slashes - - **Home URL**: `.` without trailing slashes - - **Web Origins**: `.` without trailing slashes + - **Root URL**: `` without trailing slashes + - **Home URL**: `` without trailing slashes + - **Web Origins**: `` without trailing slashes 1. Select **Next**, then **Save**. @@ -168,8 +168,8 @@ Create a client for the UI as follows: 1. Configure the **Access Settings**: - - **Root URL**: `.` without trailing slashes - - **Home URL**: `.` without trailing slashes + - **Root URL**: `` without trailing slashes + - **Home URL**: `` without trailing slashes - **Valid redirect URIs**: `/login/generic_oauth` without trailing slashes - **Valid post logout redirect URIs**: `+` without trailing slashes - **Web origins**: `.` without trailing slashes @@ -181,22 +181,26 @@ Create a client for the UI as follows: The other services do not need authorization but do need client authentication. By default you need to add only the client ID. -For example, to create the BPMN engine client: +For example, to create the Workflow client: 1. In the side menu, select **Clients > create client**. -1. For **Client ID**, enter `{{< param application_name >}}Bpmn` +1. For **Client ID**, enter `{{< param application_name >}}Workflow` +1. **Name**: `{{< param brand_name >}} Workflow Engine` +1. **Description**: `{{< param brand_name >}} Workflow Engine` 1. Configure the **Capability config**: - **Client Authentication**: On 1. Select **Next**, then **Save**. -**Repeat this process for each of the following services:** +Repeat the preceding process for each of the following services with the corresponding values in the table. -| Client ID | Description | -|----------------------------------------|-----------------------| -| `{{< param application_name >}}Audit` | The audit log service | -| `{{< param application_name >}}Core` | The edge agent | -| `{{< param application_name >}}Router` | API router | +| Client ID | Name | Description | +| --------------------------------------- | --------------------------------------- | --------------------------- | +| `{{< param application_name >}}Agent` | {{< param brand_name >}} Agent | The agent data service | +| `{{< param application_name >}}Audit`* | {{< param brand_name >}} Audit Log | The audit log service | +| `{{< param application_name >}}ISA95` | {{< param brand_name >}} ISA-95 Model | The ISA-95 model service | +| `{{< param application_name >}}KPI`* | {{< param brand_name >}} KPI Calculator | The ISO22400 KPI calculator | +| `{{< param application_name >}}Router`* | {{< param brand_name >}} API Router | The API router | -Based on your architecture, repeat for any Libre Edge Agents, `{{< param application_name >}}Agent`. +*- Optional based on your architecture. ### Scope services @@ -216,31 +220,28 @@ To create a scope for your Rhize services, follow these steps: - **Display on consent screen**: `On` - **Include in token scope**: `On` 1. **Create**. -1. Select the **Mappers** tab, then **Configure new mapper**. Add an audience mapper for the DB client: - - **Mapper Type**: `Audience` - - **Name**: `{{< param db >}}AudienceMapper` - - **Include Client Audience**: `{{< param db >}}` - - **Add to ID Token**: `On` - - **Add to access token**: `On` -1. Repeat the preceding step for a mapper for the UI client: - - **Mapper Type**: `Audience` - - **Name**: `{{< param application_name >}}UIAudienceMapper` - - **Include Client Audience**: `{{< param application_name >}}UI` - - **Add to ID Token**: `On` - - **Add to access token**: `Off` -1. Repeat the preceding step for a mapper for the BPMN client: - - **Mapper Type**: `Audience` - - **Name**: `{{< param application_name >}}BpmnAudienceMapper` - - **Include Client Audience**: `{{< param application_name >}}Bpmn` - - **Add to ID Token**: `On` - - **Add to access token**: `On` -1. If using the Rhize Audit microservice, repeat the preceding step for an Audit scope and audience mapper: - - **Mapper Type**: `Audience` - - **Name**: `{{< param application_name >}}AuditAudienceMapper` - - **Include Client Audience**: - - **Included Custom Audience**: `audit` - - **Add to ID Token**: `On` - - **Add to access token**: `On` + +#### Create audience mappers +Select the **Mappers** tab, then **Configure new mapper**. Add an audience mapper for the DB client: + - **Mapper Type**: `Audience` + - **Name**: `{{< param db >}}AudienceMapper` + - **Include Client Audience**: `{{< param db >}}` + - **Add to ID Token**: `On` + - **Add to access token**: `On` + +Repeat the preceding process for each of the following services with the corresponding values in the table. + +| Name | Include Client Audience | ID Token | Access Token | +| ------------------------------------------------------ | ---------------------------------------- | :------: | :----------: | +| `{{< param application_name >}}AuditAudienceMapper`* | `audit`** | `On` | `On` | +| `{{< param application_name >}}AgentAudienceMapper` | `{{< param application_name >}}Agent` | `On` | `On` | +| `{{< param application_name >}}ISA95AudienceMapper` | `{{< param application_name >}}ISA95` | `On` | `On` | +| `{{< param application_name >}}KPIAudienceMapper`* | `{{< param application_name >}}KPI` | `On` | `On` | +| `{{< param application_name >}}UIAudienceMapper` | `{{< param application_name >}}UI` | `On` | `Off` | +| `{{< param application_name >}}WorkflowAudienceMapper` | `{{< param application_name >}}Workflow` | `On` | `On` | + +*- Optional based on your architecture.
+**- Included as a Custom Audience. #### Add services to the scope @@ -250,14 +251,24 @@ To create a scope for your Rhize services, follow these steps: 1. Select `{{< param application_name >}}ClientScope` from the list. 1. **Add > Default**. -Repeat this process for the `dashboard`, `{{< param application_name >}}UI`, `{{< param application_name >}}Bpmn`, `{{< param application_name >}}Core`, `{{< param application_name >}}Router`, `{{< param application_name >}}Audit` (if applicable). Based on your architecture repeat for any Libre Edge Agent clients. +Repeat the preceding process above for each of the following services: + +- `dashboard` +- `{{< param application_name >}}Audit`* +- `{{< param application_name >}}Agent` +- `{{< param application_name >}}ISA95` +- `{{< param application_name >}}KPI`* +- `{{< param application_name >}}Router`* +- `{{< param application_name >}}UI` +- `{{< param application_name >}}Workflow` + +*- Optional based on your architecture. ### Create roles and groups In Keycloak, _roles_ identify a category or type of user. _Groups_ are a common set of attributes for a set of users. - #### Add the Admin Group 1. In the left hand menu, select **Groups > Create group**. @@ -305,7 +316,7 @@ Now map the scope: 1. Select the **Client scopes** tab. 1. **Add client scope**. 1. Select `groups`. -1. **Add > Default**. +1. **Add Default**. ### Add Client Policy @@ -314,7 +325,7 @@ Rhize requires authorization for the database service. 1. In the left hand menu, select **Clients**, and then `{{< param db >}}`. 1. Select the **Authorization** tab. -1. Select the **Policies** sub-tab. +1. Select the **Policies** subtab. 1. Select **Create Policy > Group**. 1. Name the policy `{{< param application_name >}}AdminGroupPolicy`. 1. Select **Add Groups**. @@ -342,43 +353,18 @@ Now create a user password: 1. For **Temporary**, choose `Off`. 1. **Save**. -Repeat this process for the following accounts: - -- Audit: - - **Username**: `{{< param application_name >}}Audit@{{< param domain_name >}}` - - **Email**: `{{< param application_name >}}Audit@{{< param domain_name >}}` - - **Email Verified**: `On` - - **First name**: `Audit` - - **Last name**: `{{< param brand_name >}}` - - **Join Groups**: `{{< param application_name >}}AdminGroup` -- Core: - - **Username**: `{{< param application_name >}}Core@{{< param domain_name >}}` - - **Email**: `{{< param application_name >}}Core@{{< param domain_name >}}` - - **Email Verified**: `On` - - **First name**: `Core` - - **Last name**: `{{< param brand_name >}}` - - **Join Groups**: `{{< param application_name >}}AdminGroup` -- BPMN - - **Username**: `{{< param application_name >}}Bpmn@{{< param domain_name >}}` - - **Email**: `{{< param application_name >}}Bpmn@{{< param domain_name >}}` - - **Email Verified**: `On` - - **First name**: `Bpmn` - - **Last name**: `{{< param brand_name >}}` - - **Join Groups**: `{{< param application_name >}}AdminGroup` -- Router - - **Username**: `{{< param application_name >}}Router@{{< param domain_name >}}` - - **Email**: `{{< param application_name >}}Router@{{< param domain_name >}}` - - **Email Verified**: `On` - - **First name**: `Router` - - **Last name**: `{{< param brand_name >}}` - - **Join Groups**: `{{< param application_name >}}AdminGroup` -- Agent - - **Username**: `{{< param application_name >}}Agent@{{< param domain_name >}}` - - **Email**: `{{< param application_name >}}Agent@{{< param domain_name >}}` - - **Email Verified**: `On` - - **First name**: `Agent` - - **Last name**: `{{< param brand_name >}}` - - **Join Groups**: `{{< param application_name >}}AdminGroup` +Repeat the preceding process for each of the following services with the corresponding values in the table. + +| Username | First name | +| ------------------------------------------------------------------ | ---------- | +| `{{< param application_name >}}Audit@{{< param domain_name >}}`* | Audit | +| `{{< param application_name >}}Agent@{{< param domain_name >}}` | Agent | +| `{{< param application_name >}}ISA95@{{< param domain_name >}}` | ISA95 | +| `{{< param application_name >}}KPI@{{< param domain_name >}}`* | KPI | +| `{{< param application_name >}}Router@{{< param domain_name >}}`* | Router | +| `{{< param application_name >}}Workflow@{{< param domain_name >}}` | Workflow | + +*- Optional based on your architecture. {{% /steps %}} diff --git a/content/deploy/install/row-level-access-control.md b/content/deploy/install/row-level-access-control.md index 9c52208e7..84091fe2f 100644 --- a/content/deploy/install/row-level-access-control.md +++ b/content/deploy/install/row-level-access-control.md @@ -23,7 +23,7 @@ Consider the following scenario: Acme Inc. contracts part of its supply chain to 1. Create an OIDC Role: Define a role called `cmoAccess` in your OIDC provider (e.g., Keycloak). 2. Define a Hierarchy Scope. Create a hierarchy scope in Rhize called `CMO`. This scope is applied to objects or nodes in the graph that relate to the CMO. -3. Add a Rule to the Scope Map: Define a rule in the `scopemap.json` file as follows: +3. Add a Rule to the Scope Map. Define a rule in the `scopemap.scopemap.json` file as follows: ```json { diff --git a/content/deploy/install/services.md b/content/deploy/install/services.md index 6cc3fad43..ab1729a04 100644 --- a/content/deploy/install/services.md +++ b/content/deploy/install/services.md @@ -8,9 +8,6 @@ categories: "how-to" The final installation step is to install the Rhize services in your Kubernetes cluster. -> [!NOTE] -> For the recommended compute per pod for each service, refer to [Cluster sizing]({{< relref "../cluster-sizing" >}}) - ## Prerequisites This topic assumes you have done the following: @@ -37,6 +34,7 @@ Common values that are changed include: Client secrets are necessary for Rhize services to authenticate with Keycloak. These secrets are stored with Kubernetes secrets. 1. Go to Keycloak and get the secrets for each client you've created. + 1. Create Kubernetes secrets for each service. You can either create a secret file, or pass raw data from the command line. {{< callout type="caution" >}} @@ -47,20 +45,30 @@ Client secrets are necessary for Rhize services to authenticate with Keycloak. T With raw data, the command might look something like this: ```bash - kubectl create secret generic {{< param application_name >}}-client-secrets -n {{< param application_name >}} \ - --from-literal=dashboard=VKIZ6zkQYyPutDzWqIZ9uIEnQRviyqsS \ - --from-literal={{< param application_name >}}Audit=q8JBjuEefWTmhv9IX4KKYxNtXXnYtDPD \ - --from-literal={{< param application_name >}}Baas=KYbMHlRLhXwiDNFuDCl3qtPj1cNdeMSl \ - --from-literal={{< param application_name >}}Bpmn=7OrjB7FhOdsNeb819xzEDBbMyVb6kNdr \ - --from-literal={{< param application_name >}}Core=SH28Wlx2uEXcgf1NffStbmSuruxvrpi6 \ - --from-literal={{< param application_name >}}UI=0qQ7c1EtOKvwsAcpd0xYIvle4zsMcGRq \ - --from-literal={{< param application_name >}}Router=0qQ7c1EtOKvwsAcpd0xYIvle4zsMcGRq + kubectl create secret generic {{< param application_name >}}-client-secrets \ + -n {{< param application_name >}} \ + --from-literal=dashboard=G4hoxIL37F5S9DQgeDYGQejcJ6oJhOPA \ + --from-literal={{< param application_name >}}Workflow=GTy1x64U0IHAUTWizugEAnN47a9kWgX8 \ + --from-literal={{< param application_name >}}ISA95=Yvtx1tZWCPFayvDCzHTTInEz9gnuLyLc \ + --from-literal={{< param application_name >}}Baas=KYbMHlRLhXwiDNFuDCl3qtPj1cNdeMSl \ + --from-literal={{< param application_name >}}UI=54yUQqmvgcxoKPaIbPZTQGlEs8Xu2qH0 ``` 1. Create secrets for login passwords. Each service with its own user in Keycloak can have its password supplied through Kubernetes secrets. As you install services through Helm, their respective YAML files reference these secrets. +## Add the Rhize Helm Chart Repository + +You must add the helm chart repository for Rhize. + +1. Add the Helm Chart Repository + + ```bash + helm repo add {{< param application_name >}} https://gitlab.com/api/v4/projects/42214456/packages/helm/stable + helm repo update + ``` + ## Install and add roles for the DB {#db} You must install the {{< param db >}} database service first. @@ -87,23 +95,21 @@ If you need Row Level Access Control, [configure your scope map]({{< relref "row All statuses should be `RUNNING`. - 1. Return to the Keycloak UI and add all `{{< param application_name >}}` roles to the admin group. 1. Proxy the `http:8080` port on `{{< param application_name >}}-baas-dgraph-alpha`. - ``` + ```bash kubectl port-forward -n {{< param application_name >}} pod/baas-baas-alpha-0 8080:8080 ``` 1. Get a token using the credentials. With `curl`, it looks like this: ```bash - curl --location --request POST 'https://- - auth.{{< param application_name >}}/realms/{{< param application_name >}}/protocol/openid-connect/token' \ + curl --location --request POST '/realms/{{< param application_name >}}/protocol/openid-connect/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=password' \ - --data-urlencode 'username=system@{{< param application_name >}}.com' \ + --data-urlencode 'username=' \ --data-urlencode 'password=' \ --data-urlencode 'client_id={{< param application_name >}}Baas' \ --data-urlencode 'client_secret=' @@ -112,7 +118,7 @@ If you need Row Level Access Control, [configure your scope map]({{< relref "row 1. Post the schema: ```bash - curl --location --request POST 'http://localhost:/admin/schema' \ + curl --location --request POST '/admin/schema' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/octet-stream' \ --data-binary '@' @@ -120,7 +126,7 @@ If you need Row Level Access Control, [configure your scope map]({{< relref "row This creates more roles. -1. Go to Keycloak UI and add all new {{< param db >}} roles to the `ADMIN` group. +1. Go to Keycloak UI and add all new {{< param db >}} roles to the `libreAdminGroup`. If the install is successful, the Keycloak UI is available on its [default port]({{< relref "../../reference/default-ports" >}}). @@ -148,193 +154,250 @@ helm install \ For the full configuration options, read the official [Helm `install` reference](https://helm.sh/docs/helm/helm_install/). - -### NATS {#nats} - - +### Redpanda -[NATS](https://nats.io) is the message broker that powers Rhize's event-driven architecture. +Rhize uses Redpanda to buffer requests to Restate and connect to Agent. -Install NATS with these steps: +Install Redpanda with these steps: -1. If it doesn't exist, add the NATS repository: +1. If the Redpanda repository doesn't exist, add it: ```bash - helm repo add nats https://nats-io.github.io/k8s/helm/charts/ + helm repo add redpanda https://charts.redpanda.com + helm repo update ``` -1. Modify the NATS Helm file with your code editor. Edit any necessary overrides. +1. Modify the Redpanda Helm overrides as needed. + 1. Install with Helm: - ``` - helm install nats -f nats.yaml nats/nats -n {{< param application_name >}} + ```bash + helm install redpanda -f redpanda.yaml redpanda/redpanda -n {{< param application_name >}} ``` +### Alloy -### Tempo +Install Alloy with these steps: -Rhize uses [Tempo](https://grafana.com/oss/tempo/) to trace BPMN processes. +1. If the Grafana repository doesn't exist, add it: -Install Tempo with these steps: + ```bash + helm repo add grafana https://grafana.github.io/helm-charts + helm repo update + ``` + +1. Modify the Alloy Helm overrides as needed. -1. If it doesn't exist, add the Tempo repository: +1. Install with Helm: ```bash - helm repo add grafana https://grafana.github.io/helm-charts + helm install alloy -f alloy.yaml grafana/alloy -n {{< param application_name >}} ``` -1. Modify the Helm file as needed. +### Grafana LGTM + +Grafana LGTM includes Tempo and Grafana. Rhize uses [Tempo](https://grafana.com/oss/tempo/) to trace BPMN processes. + +Install Grafana LGTM with these steps: + +1. Modify the Grafana LGTM Helm overrides as needed. + 1. Install with Helm: ```bash - helm install tempo -f tempo.yaml grafana/tempo -n {{< param application_name >}} + helm install lgtm-distributed -f lgtm-distributed.yaml grafana/lgtm-distributed -n {{< param application_name >}} ``` -### Core +If the install is successful, the Grafana service is available on its +[default port]({{< relref "../../reference/default-ports" >}}). + +### Restate -The {{< param brand_name >}} Core service is the custom edge agent that monitors data sources, like OPC-UA servers, and publishes and subscribes topics to NATS. +Rhize uses Restate as a platform for orchestrating other services. -> **Requirements**: Core requires the [{{< param db >}}](#db) and [NATS](#nats) services. +Install Restate with these steps: -Install the Core agent with these steps: +1. Modify the Restate Helm overrides as needed. -1. In the `core.yaml` Helm file, edit the `clientSecret` and `password` with settings from the Keycloak client. -1. Override any other values, as needed. 1. Install with Helm: ```bash - helm install core -f core.yaml {{< param application_name >}}/core -n {{< param application_name >}} + helm install restate -f restate.yaml oci://ghcr.io/restatedev/restate-helm -n {{< param application_name >}} ``` -### BPMN +So that you can register certain services with Restate, proxy the Restate port: + + ```bash + kubectl port-forward -n {{< param application_name >}} pod/restate-0 9070:9070 + ``` -The BPMN service is the custom engine Rhize uses to process low-code workflows modeled in the BPMN UI. +### Workflow -> **Requirements**: The BPMN service requires the [{{< param db >}}](#db), [NATS](#nats), and [Tempo](#tempo) services. +The Workflow service is the custom engine Rhize uses to process low-code workflows modeled in the Workflow UI. -Install the BPMN engine with these steps: +> **Requirements**: The Workflow service requires the [{{< param db >}}](#db), [Restate](#restate), and [Tempo](#tempo) services. + +Install Workflow with these steps: + +1. Modify the Workflow Helm overrides as needed. -1. Open `bpmn.yaml` Update the `clientSecret` and `password` for your BPMN Keycloak credentials. -1. Modify any other values, as needed. 1. Install with Helm: ```bash - helm install bpmn -f bpmn.yaml {{< param application_name >}}/bpmn -n {{< param application_name >}} + helm install workflow -f workflow.yaml {{< param application_name >}}/workflow -n {{< param application_name >}} ``` -### Router +1. When the Workflow service starts, it should register with Restate. Verify this with: + + ```bash + curl localhost:9070/deployments | jq '.deployments[].uri' + ``` -Rhize uses the [Apollo router](https://www.apollographql.com/docs/router) to unite queries for different services in a single endpoint. + This will show the URL of each registered service. If Workflow's URL is not present, register it with: -> **Requirements:** Router requires the [GraphDB](#db), [BPMN](#bpmn), and [Core](#core) services. + ```bash + curl --location 'http://localhost:9070/deployments' \ + --header 'Content-Type: application/json' \ + --data '{"uri":"http://workflow.{{< param application_name >}}.svc.cluster.local:29080", "force":true}' + ``` -Install the router with these steps: +### Typescript Host Service + +Install Typescript Host Service with these steps: + +1. Modify the Typescript Host Service Helm overrides as needed. -1. Modify the router Helm YAML file as needed. 1. Install with Helm: + ```bash + helm install typescript-host-service -f typescript-host-service.yaml {{< param application_name >}}/typescript-host-service -n {{< param application_name >}} + ``` + +1. When the Typescript Host Service starts, it should register with Restate. Verify this with: + ```bash - helm install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} + curl localhost:9070/deployments | jq '.deployments[].uri' ``` -If the install is successful, the Router explorer is available on its -[default port]({{< relref "../../reference/default-ports" >}}). + This will show the URL of each registered service. If Typescript Host Service's URL is not present, register it with: + + ```bash + curl --location 'http://localhost:9070/deployments' \ + --header 'Content-Type: application/json' \ + --data '{"uri":"http://typescript-host-service.{{< param application_name >}}.svc.cluster.local:9081", "force":true}' + ``` -### Grafana +### QuestDB -Rhize uses [Grafana](https://grafana.com) for its dashboard to monitor real time data. +QuestDB is used by Rhize to store timeseries data, however it can be substitude for another historian. -Install Grafana with these steps: +Install QuestDB with these steps: -1. Modify the Grafana Helm YAML file as needed. +1. If it doesn't exist, add the QuestDB repository: -1. Add the Helm repository ```bash - helm repo add grafana https://grafana.github.io/helm-charts + helm repo add questdb https://helm.questdb.io/ + helm repo update ``` +1. Modify the QuestDB Helm overrides as needed. + 1. Install with Helm: ```bash - helm install grafana -f grafana.yaml grafana/grafana -n {{< param application_name >}} + helm install questdb -f questdb.yaml questdb/questdb -n {{< param application_name >}} ``` -If the install is successful, the Grafana service is available on its -[default port]({{< relref "../../reference/default-ports" >}}). +### ISA-95 -### Agent +Install ISA-95 with these steps: -The Rhize agent bridges your plant processes with the Rhize data hub. -It collects data emitted from the plant and publishes it to the NATS message broker. +1. Modify the ISA-95 Helm overrides as needed. -> **Requirements:** Agent requires the [Graph DB](#db), [Nats](#nats), and [Tempo](#tempo) services. +1. Install with Helm: -Install the agent with these steps: + ```bash + helm install isa95 -f isa95.yaml {{< param application_name >}}/isa95 -n {{< param application_name >}} + ``` -1. Modify the Agent Helm file as needed. +1. When the ISA-95 service starts, it should register with Restate. Verify this with: -1. In the Rhize UI, add a Data Source for Agent to interact with: - - In the lefthand menu, open **Master Data > Data Sources > + Create Data Source**. - - Input a name for the Data Source. - - Add a Connection String and Create. - - Add any relevant Topics. - - Activate the Data Source. + ```bash + curl localhost:9070/deployments | jq '.deployments[].uri' + ``` -1. Install with Helm: + This will show the URL of each registered service. If ISA-95's URL is not present, register it with: ```bash - helm install agent -f agent.yaml {{< param application_name >}}/agent -n {{< param application_name >}} + curl --location 'http://localhost:9070/deployments' \ + --header 'Content-Type: application/json' \ + --data '{"uri":"http://isa95.{{< param application_name >}}.svc.cluster.local:29080", "force":true}' ``` ## Install Admin UI -The Admin UI is the graphical frontend to [handle events]({{< relref "../../how-to/bpmn" >}}) and [define work masters]({{< relref "../../how-to/model" >}}). +The Rhize agent bridges your plant processes with the Rhize data hub. + +The Admin UI is the graphical frontend to [handle events]({{< relref "/how-to/bpmn" >}}) and [define work masters]({{< relref "/how-to/model" >}}). -> **Requirements:** The UI requires the [GraphDB](#db), [BPMN](#bpmn), [Core](#core), and [Router](#router) services. +> **Requirements:** The Admin UI requires the [Workflow](#workflow) services. After installing all other services, install the UI with these steps: -1. Forward the port from the Router API. In the example, this forwards Router traffic to port `4000` on `localhost`. +1. Modify the UI Helm overrides as needed. + +1. Install with Helm: ```bash - kubectl port-forward svc/router 4000:4000 -n {{< param application_name >}} + helm install admin-ui -f admin-ui.yaml {{< param application_name >}}/admin-ui -n {{< param application_name >}} ``` -1. Open the Admin UI Helm file. Update the `envVars` object to reflect the URL for Router and Keycloak. If following the prior examples for port-forwarding, it will look something like this: +If the install is successful, the UI is available on its +[default port]({{< relref "../../reference/default-ports" >}}). - ```yaml - envVars: - APP_APOLLO_CLIENT: "http://localhost:4000" - APP_APOLLO_CLIENT_ADMIN: "http://localhost:4000" - APP_AUTH_KEYCLOAK_SERVER_URL: "http://localhost:8080" - ``` +### Agent + +The Rhize agent bridges your plant processes with the Rhize data hub. +It collects data emitted from the plant and publishes it to the message broker. + +> **Requirements:** Agent requires the [Graph DB](#db), [Tempo](#tempo), Redpanda, and an event broker service to communicate with. + +Install Agent with these steps: + +1. Modify the Agent Helm overrides as needed. + +1. In the Rhize UI, add a Data Source for Agent to interact with: + - In the lefthand menu, open **Master Data > Data Sources > + Create Data Source**. + - Input a name for the Data Source. + - Add a Connection String and Create. + - Add any relevant Topics. + - Activate the Data Source. -1. Modify any other values, as needed. 1. Install with Helm: ```bash - helm install admin-ui -f admin-ui.yaml {{< param application_name >}}/admin-ui -n {{< param application_name >}} + helm install agent -f agent.yaml {{< param application_name >}}/agent -n {{< param application_name >}} ``` -If the install is successful, Admin UI is available on its -[default port]({{< relref "../../reference/default-ports" >}}). +To verify that Agent is working, check the Redpanda UI. -## Optional: Audit Trail service +## Optional Services +### Audit Trail -The Rhize [Audit]({{< relref "../../how-to/audit" >}}) service provides an audit trail for database changes to install. The Audit service uses PostgreSQL for storage. +The Rhize [Audit]({{< relref "/how-to/audit" >}}) service provides an audit trail for database changes. The Audit service uses PostgreSQL for storage. -Install Audit Service with these steps: +Install Audit with these steps: 1. Modify the Audit trail Helm YAML file. It is *recommended* to change the PostgreSQL username and password values. -2. Install with Helm: +1. Install with Helm: ```bash helm install audit -f audit.yaml {{< param application_name >}}/audit -n {{< param application_name >}} ``` -3. Create partition tables in the PostgreSQL database: +1. Create partition tables in the PostgreSQL database: ```sql create table public.audit_log_partition( like public.audit_log ); @@ -343,7 +406,7 @@ Install Audit Service with these steps: For details about maintaining the Audit trail, read [Archive the PostgresQL Audit trail]({{< relref "../maintain/audit/" >}}). -### Enable change data capture +#### Enable change data capture The Audit trail requires [change data capture (CDC)]({{< relref "../../how-to/publish-subscribe/track-changes" >}}) to function. To enable CDC in {{< param application_name >}} BAAS, include the following values for the Helm chart overrides: @@ -359,123 +422,61 @@ alpha: replicas: 1 ``` -### Enable Audit subgraph +### KPI -To use the Audit trail in the UI, you must add the Audit trail subgraph into the router. To enable router to use and compose the subgraph: +The Rhize KPI service is a GraphQL service which calcualtes ISO22400 KPIs using timseries tables. -1. Update the Router Helm chart overrides, `router.yaml`, to include: +Install KPI with these steps: - ```yaml - # Add Audit to the router subgraph url override - router: - configuration: - override_subgraph_url: - AUDIT: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query +1. Modify the KPI Helm overrides as needed. - # If supergraph compose is enabled - supergraphCompose: - supergraphConfig: - subgraphs: - AUDIT: - routing_url: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query - schema: - subgraph_url: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query - ``` +1. Install with Helm: -2. Update the Router deployment + ```bash + helm install kpi -f kpi.yaml {{< param application_name >}}/kpi -n {{< param application_name >}} + ``` -```shell -$ helm upgrade --install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} -``` +### Solace -## Optional: calendar service +Solace is an event broker that can be used alongside Agent, though it can be substituted for any other event broker. -The [{{< param brand_name >}} calendar service]({{< relref "../../how-to/work-calendars">}}) monitors work calendar definitions and creates work calendar entries in real time, both in the [Graph](#db) and time-series databases. +1. Add the Solace Charts Helm repo. -> **Requirements:** The calendar service requires the [GraphDB](#db), [Keycloak](#keycloak), and [NATS](#nats) services. + ```bash + helm repo add solacecharts https://solaceproducts.github.io/pubsubplus-kubernetes-helm-quickstart/helm-charts + helm repo update + ``` -{{% callout type="info" %}} -The work calendar requires a time-series DB installed such as [InfluxDB](https://influxdata.com/), [QuestDB](https://questdb.io) or [TimescaleDB](https://www.timescale.com/). The following instructions are specific to QuestDB. -{{% /callout %}} +1. Modify the Solace Helm overrides as needed. -Install the calendar service with these steps: +1. Install with Helm: -1. Create tables in the time series. For example: + ```bash + helm install solace -f solace.yaml solacecharts/pubsubplus -n {{< param application_name >}} + ``` +> [!NOTE] +> Solace can be installed in high availability by using `pubsubplus-ha` instead of `pubsubplus`. +> See detailed instructions on [github](https://github.com/SolaceProducts/pubsubplus-kubernetes-helm-quickstart). - ```sql - CREATE TABLE IF NOT EXISTS PSDT_POT( - EquipmentId SYMBOL, - EquipmentVersion STRING, - WorkCalendarId STRING, - WorkCalendarIid STRING, - WorkCalendarDefinitionId STRING, - WorkCalendarDefinitionEntryId STRING, - WorkCalendarDefinitionEntryIid STRING, - WorkCalendarEntryId STRING, - WorkCalendarEntryIid SYMBOL, - HierarchyScopeId STRING, - EntryType STRING, - ISO22400CalendarState STRING, - isDeleted boolean, - updatedAt TIMESTAMP, - time TIMESTAMP, - lockerCount INT, - lockers STRING - ) TIMESTAMP(time) PARTITION BY month - DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); - - CREATE TABLE IF NOT EXISTS PDOT_PBT( - EquipmentId SYMBOL, - EquipmentVersion STRING, - WorkCalendarId STRING, - WorkCalendarIid STRING, - WorkCalendarDefinitionId STRING, - WorkCalendarDefinitionEntryId STRING, - WorkCalendarDefinitionEntryIid STRING, - WorkCalendarEntryId STRING, - WorkCalendarEntryIid SYMBOL, - HierarchyScopeId STRING, - EntryType STRING, - ISO22400CalendarState STRING, - isDeleted boolean, - updatedAt TIMESTAMP, - time TIMESTAMP, - lockerCount INT, - lockers STRING - ) TIMESTAMP(time) PARTITION BY month - DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); - - CREATE TABLE IF NOT EXISTS Calendar_AdHoc( - EquipmentId SYMBOL, - EquipmentVersion STRING, - WorkCalendarId STRING, - WorkCalendarIid STRING, - WorkCalendarDefinitionId STRING, - WorkCalendarDefinitionEntryId STRING, - WorkCalendarDefinitionEntryIid STRING, - WorkCalendarEntryId STRING, - WorkCalendarEntryIid SYMBOL, - HierarchyScopeId STRING, - EntryType STRING, - ISO22400CalendarState STRING, - isDeleted boolean, - updatedAt TIMESTAMP, - time TIMESTAMP, - lockerCount INT, - lockers STRING - ) TIMESTAMP(time) PARTITION BY month - DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); - ``` +### Apollo Router + +While Rhize provides a built in GraphQL Playground using Apollo's Sandobx, [Apollo Router](https://www.apollographql.com/docs/router) can be installed to unite queries for different services in a single endpoint outside of Rhize's interface. -1. Modify the calendar YAML file as needed. +> **Requirements:** Router requires the [GraphDB](#db) service. -1. Deploy with helm +Install Router with these steps: + +1. Modify the Router Helm overrides as needed. + +1. Install with Helm: ```bash - helm install calendar-service -f calendar-service.yaml {{< param application_name >}}/calendar-service -n {{< param application_name >}} + helm install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} ``` +If the install is successful, the Router explorer is available on its [default port]({{< relref "../../reference/default-ports" >}}). + ## Optional: change service configuration The services installed in the previous step have many parameters that you can configure for your performance and deployment requirements. diff --git a/content/deploy/install/setup-kubernetes.md b/content/deploy/install/setup-kubernetes.md index 6e4048e83..248335eba 100644 --- a/content/deploy/install/setup-kubernetes.md +++ b/content/deploy/install/setup-kubernetes.md @@ -100,15 +100,13 @@ Then, follow these steps. 1. Update overrides to `keycloak.yaml`. Then install with this command: ```bash - helm install keycloak -f ./keycloak.yaml bitnami/keycloak -n libre + helm install keycloak -f ./keycloak.yaml bitnami/keycloak -n {{< param application_name >}} ``` -> Note: Version may have to be specified by appending on `--version` and the desired chart version. - -1. Set up port forwarding from Keycloak. For example, this forwards traffic to port `8080` on `localhost`. +1. Set up port forwarding from Keycloak. For example, this forwards traffic to port `5101` on `localhost`: ```bash - kubectl port-forward svc/keycloak 8080:80 -n libre + kubectl port-forward svc/keycloak 5101:80 ``` ## Next steps diff --git a/content/versions/v4.0.0/how-to/seeq.md b/content/how-to/seeq.md similarity index 100% rename from content/versions/v4.0.0/how-to/seeq.md rename to content/how-to/seeq.md diff --git a/content/releases/4-2-0.md b/content/releases/4-2-0.md new file mode 100644 index 000000000..d32725b50 --- /dev/null +++ b/content/releases/4-2-0.md @@ -0,0 +1,506 @@ +--- +title: 4.2.0 +date: '2025-12-04T13:18:53-03:00' +description: Release notes for v4.2.0 of the Rhize application +categories: ["releases"] +weight: 1653202285 ## auto-generated, don't change +--- + +Release notes for version 4.2.0 of the Rhize application. + +_Release date:_ +4 Dec 2025 + +## Changes by service + +### Admin + +#### Add + + - Add action payload expression to start message event + - Add AG Grid Transaction Support for WorkMaster UI + - Add amplitude auto-capture for UI usage research in docker + - Add asset mapping tab to equipment + - Add BPMN task for SQL query + - Add bulk version management to Work Master grid + - Add class/instance filtering to selection to work master specifications + - Add copy functionality to work master grid + - Add copy/paste functionality in material specifications grid + - Add datasource topic import from excel + - Add default Mapbox API key + - Add default work type of Production to newly created work masters + - Add dynamic vars to CI/CD pipeline + - Add equipment property mutation and refactor properties component + - Add event tracking to amplitude + - Add import / export of Work Masters to support project lifecycles enabled with environmental variable + - Add inactive filter to data access in specification editors + - Add inline property type editing for equipment class properties + - Add hierarchical view for work masters to improve visual representation + - Add missing description field for Physical Assets + - Add nested properties to Equipment properties page + - Add option to create a work master instance from a pattern + - Add pages for defining Workflow Connection types and Workflow Node Types + - Add persistence to work master editor react flow node locations + - Add restate admin page for subscriptions + - Add sensible defaults for new specifications + - Add storage location to material specifications + - Add support for adding nested properties to Equipment properties + - Add task template for google BigQuery + - Add test specifications to specification + - Add timerange to audit tag query + - Add tooltip to options in select where tooltip data is available + - Add Work Master Editor user interface + - Add work master versioning support + +#### Change + + - Change @bpmn-io/element-template-chooser to ^2.0.0 from ^0.1.0 + - Change a work master's related Operations Segment to be mutually exclusive with Process Segment and Operations Definition + - Change authentication flow to remove client secret from Libre-UI + - Change BPMN view instance list default to last 1 day + - Change builds to use yarn cache for faster pipeline builds + - Change color scheme of work master library to align with site + - Change css for better layout and responsiveness + - Change default work master grid to active work masters + - Change download BPMN to allow for foreign characters + - Change Equipment Asset Mapping to use label as primary display and show ID as subtitle + - Change equipment management page to align with existing resource pages + - Change equipment properties table to use AG-Grid + - Change equipment property binding modal to limit search to the first 100 data source topics + - Change equipment property binding to use the propertyPath instead of propertyLabel + - Change equipment tree component to improve loading of large equipment trees in a reasonable time + - Change equipment tree query to default sort ascending + - + - Change grid component from a Rhize Grid to AG Grid for Equipment, Material Specifications & Material Specification Properties + - Change grid component from a Rhize Grid to AG Grid for Equipment Specification & Equipment Specification Properties + - Change grid component from a Rhize Grid to AG Grid for Personnel Specification & Personnel Specification Properties + - Change grid component from a Rhize Grid to AG Grid for Physical Asset Specification & Physical Asset Specification Properties + - Change hierarchy scope to optional field in workflow specifications + - Change location of the save/reset buttons to the top of specification editors + - Change name to mandatory when creating a new Person by disabling create button when no name provided + - Change node selection dropdowns specification editors + - Change page page title based on the screen + - Change parameter specification to use icons instead of text + - Change Physical Asset to allow update when optional fields are left blank + - Change preact to version 10.19.3 + - Change property type custom cell type and use in other class and operations event definition pages + - Change property type to mandatory in the user interface + - Change project to typescript to 5.8.3 + - Change schema to align with latest ISA-95 Schema + - Change sort order of process segments to show the newly created one at the top of the list instead of bottom + - Change specification property components to use apollo client directly + - Change specification table to synchronize with unified editor tab access + - Change specification tables to show edit control on left + - Change state management to persist selected workflow nodes across sessions + - Change titles from resource name to resource name Specification + - Change to the confirm type modal for cancel and delete material specifications actions + - Change Work Master Editor to reset tabs on initial navigation to page + - Change Work Master Editor to show select popup if selected node or workflow has no link + - Change Work Master Editor page by refactoring tab management logic into dedicated component for more maintainable interface + - Change Work Master grid to allow orphaned Work Master records to be edited + - Change Work Master Editor to support Workflows and Specifications + +#### Fix + - Fix adding new equipment class properties not adding parent property relationship + - Fix asset mapping selection defaulting to the top item instead of the selected equipment object + - Fix assets disappear from equipment asset mapping table when changing version state + - Fix async handling in Workflow Specification updates + - Fix attempts to add equipment parent even if none required + - Fix automatic navigation on newly created version instead of having to manually select it + - Fix BPMN Instance list showing the start-time minute as the month + - Fix BPMN SaveNewVersion not updating the selected version + - Fix display of no data available in Restate Admin page of Services + - Fix equipment general tab drop downs cache values and not updating on page load with most recent + - Fix caching of existing fields when creating new equipment for the second time + - Fix caching of Workflow Connection Types requiring refresh to see newly created in the list + - Fix caching of Workflow Connection Types requiring refresh to see newly created in the list + - Fix changing equipment state hiding child equipment with equipment tree refactor + - Fix clipping of datasource names in equipment property binding modal + - Fix clone of work master without a workflow specification + - Fix deployment bugs + - Fix dirty check on Spatial Definition & Operational Location if undefined + - Fix disable operational location property disable + - Fix disabled equipment showing when searching using the search bar when inactive toggle is off +- Fix double pagination of dataSourceTopics + - Fix duplicate storage or operational locations in specification selection + - Fix editing operations event definition version + - Fix equipment asset mapping being added on deprecated Equipment Versions + - Fix equipment asset mapping asset dropdown pre-selection option not saving + - Fix equipment class caching when adding a new equipment class and immediately want to select it in equipment + - Fix equipment class property change throwing 422 error + - Fix equipment class rule race condition when adding an equipment class rule immediately after creating equipment class + - Fix equipment hierarchy scrolling down halfway through equipment when only a small equipment set present + - Fix equipment hierarchy unknown scrolling depth with large equipment hierarchies + - Fix equipment sidebar search is case sensitive when searching + - Fix equipment tree sorting not persisting upon reload + - Fix for Physical Asset page issue with using 'Enter' to submit variable + - Fix icon clipping in select component by padding + - Fix inability to close expanded view in restate subscription admin page + - Fix inability to set infinite date on equipment asset mapping + - Fix infinite scroll loading/spinner issue in Material Definition sidebar + - Fix inherited equipment class properties not nesting + - Fix issue in Work Master UI where editors were not always showing existing object values + - Fix issue where a workflow specification connection is not refreshed + - Fix issue where Add Workflow button causes loss of node selection in WorkMaster UI + - Fix long data source topic names truncating in equipment property binding modal + - Fix Material Class Property Select all button causing enable/disable function to fail + - Fix mismatch between Equipment Asset Mapping fields when editing to what was persisted + - Fix missing meta data in operational location property meta data detail panel + - Fix missing newly added unit of measures in selection for material class properties after being added + - Fix multiple select placeholder text in Unit Of Measure page showing wrong text string + - Fix Operations Event Definitions failing to load due to introduction of Work Master Versions + - Fix pagination across all table cell components using LibreTable component + - Fix person version optional fields not maintained after version creation + - Fix Physical Asset Fixed assed it being limited to numbers only + - Fix popup elements rendering too narrow of an aspect ratio + - Fix Process Segment page inverted 'See inactive' toggle + - Fix route parameter for work master to iid in route slugs and navigation + - Fix save not persisting on equipment class version + - Fix SaveAsNewVersion failing for secret variables + - Fix sidebar add equipment + - Fix situation where a user could link a work master to an existing node and appending to the list of work masters for a node instead of replacing it + - Fix specification table's version stub causing navbar failure on other pages + - Fix three dot menu obfuscating version number and status, disabling the save and change version state modal + - Fix tree expansion in Equipment hierarchy page + - Fix unlinking of a datasource topic from a bound equipment property + - Fix view instance restate OOM by adding limit to BPMN view instance query + - Fix work master specification table performance issue related to effect loop use + - Fix work master definition values not persisting when edited and saved + - Fix workflow auto-save updating a draft version in the backend + +#### Remove + - Remove ability to edit a physical asset version when the version failed to create in the first place + - Remove reset button from resource specification tree + - Remove unused queries + - Remove unused specification search boxes + + + +### Agent + +#### Add + + - Add OPC UA adapter configuration parameters + - Add check for non-empty password before setting password presence flag + - Add check for non-empty username before setting username presence flag + - Add govulncheck + - Add kakfa egress topic patterns to route data source topics to specific kafka topics + - Add restate handlers + - Add support for custom certificate authorities with keycloak + - Add MQTT qos as a configuration parameter + +#### Change + + - Change build binary to rhize-agent from main + - Change deprecated golang.org/x/exp/rand library to math/rand/v2 + - Change go version to 1.23.9 from 1.23.4 + - Change golang libraries to align with release + - Change library github.com/eclipse/paho.golang to v0.22.0 from v0.12.0 + - Change library github.com/gopcua/opcua to v0.8.0 from v0.5.3 + - Change library gitlab.com/libremfg/rhize-go/v4 to v4.0.1-rc.3 + - Change NATS to optional instead of hard requirement + - Change Rhize service versions to align with release + +#### Fix + + - Fix golangci-lint errors + - Fix kafka message egress memory leak + - Fix parsing OPC-UA topics into NATs subjects + - Fix vulnerabilities + - Fix race conditions in CI/CD MQTT Tests + +### BaaS + +#### Add + + - Add @local directive for dgraph @Remote type resolution + - Add `skipReplacement` option to `@custom` directive to allow for custom resolves not implemented by Runtime + - Add additional error message context to Transaction Too Big errors + - Add admin auth to dql & debug paths + - Add admin resolver for query:lookup, mutation:rollup, mutation:recoverSplitList & mutation:indexRebuild + - Add authentication token propegation for websocket subscriptions + - Add BAAS console to facilitate easier administration of BAAS + - Add custom timeout support to the GraphQL Superflag used for restate calls (default: 1m) + - Add dgraphtest package + - Add getPostingAndLengthNoSort for performance improvements when no-sort is required + - Add graphql subflag flag federation [apollo, restate] to swap federation types (default: restate) + - Add Graphiql playground to console + - Add kafka producer maximum message size + - Add http change-data-capture sink + - Add ISO8601DateTime data type support + - Add logging to badger ErrTooBig + - Add option for custom CA certs to be used when connecting to Keycloak + - Add resource cleanup + - Add support for defining single entities in rules + - Add support for function macros within authorization rules to enable dynamic evalution of permssions of runtime context + - Add support for Regexp Comparison [no Indexes] in GraphQL Queries and Filters + - Add websocket transport to allow for to GraphQL Subscriptions + +#### Change + + - Change @local field resolution to use a queries alias over the field name where present + - Change badger to v4 from v3 + - Change benchmark files to use hypermode repo (was dgraph) + - Change default federation to restate and _Any type to JSONObject + - Change default scopemap to align with latest ISA-95 structure + - Change docker images to 28.4.0 in pipeline + - Change error message for txn too big to give more context + - Change gqlgen and gqlparser to latest versions + - Change ioutil to os library equivalents due to library deprecation + - Change log level of auth rule evaluation to require higher logging level + - Change NATS Sink handler to support new CDC Format + - Change postings cache to align with generic declaration in ristretto v2 + - Change postinglistCountAndLength function to improve performance + - CH-29) Change protobuf for badger and regenerate + - Change resource evaluator not expanding and matching wildcards under all scenarios + - Change ristretto to v2 from v1 + - Change scalar _Any to JSONObject + - Change span trace library to use opentelemetry was opencensus + +#### Fix + + - Fix auth query variable names conflicts with user-defined variable names mutations + - Fix cascade directive field arguments not being coerced to lists + - Fix compatability issues with Rhize OIDC authentication and dgraphtest package + - Fix CSRF vulnerability in the apollo playground fetch/render + - Fix deadlock that happens due to timeout during proposal + - Fix debug tool for schema keys + - Fix debug tool to read WAL entries correctly + - Fix deleteBelowTs rollup issue + - Fix export for any s3 endpoint + - Fix golangci-lint, go-vet & go-vuln issues + - Fix inconsistent time units and prevent erroneous cleanup in incrRollupi Process + - Fix leaking transactions and file descriptors + - Fix memory leak in readMIMEHeader by no longer storing call info, context or complexity into an append only in-memory data structure + - Fix performance issue in type filter + - Fix raft join failure introduced in raft/v3, RestartNode used instead of StartNode + - Fix resolution of _Any scalar type by moving from apolloSchemaExtrase to schemaInputs + - Fix RLAC resources not evaluated correctly + - Fix search operation by list intersection not subset + - Fix snapshot to use updated confstate before sending to prevent stale configuration causing errors + - Fix the conflict in accessing split parts during a rollUp + - Fix validation panic on type check + - Fix wal replay issue during rollup + - Fix wget urls for large datasets in testing pipeline + +#### Remove + +- Remove ACL and legacy login requirement from dgraphtest package +- Remove Ludicrous mode from postings + +### ISA-95 + +#### Add + + - Add `/debug/ingress/cache` handler to get and delete cache when running with debug on + - Add `overfetch` option to history query, that allows for querying a certain number of records outside the given time range while still respecting the `limit` + - Add Audit handlers to ISA-95 + - Add bypass for Ingress to go direct to Kafka + - Add build information to startup + - Add check mandatory fields when creating a new version of an object + - Add comment syncEquipmentDBtoKV to indicate cache update + - Add concurrency to Kafka.ValueDirect Consumer + - Add configuration option `RHIZE_ISA95_KAFKA_CONSUMER_COUNT` to run ingress with multiple consumers per topic + - Add configuration option `RHIZE_ISA95_LUDICROUS_MODE` to run ingress with common comiter goroutine + - Add configuration option `RHIZE_ISA95_VALUECHANGE_TOPIC` to run multiple go-routines per ingress topic + - Add context to rule evaluation call + - Add default order by when none provided and overfetching + - Add default timeouts to restate http2 client to prevent running indefinitely + - Add default timeouts to server http handler to prevent running indefinitely + - Add Equipment IID to historical records + - Add golang pprof port enabled with `RHIZE_ISA95_PPROF_LISTEN` + - Add goroutine labels to assist debugging + - Add ISO8601DateTime data type scalar to schema definition + - Add histogram metric for time spent waiting for ingress to read and commit messages + - Add ludicrous mode to ingress that uses a channels and a goroutine to commit multiple in the background + - Add metrics to IngressValueChange + - Add migration for Equipment.equipmentAssetMapping + - Add missing permission to MutationStatus + - Add move/rename mutations + - Add nested equipment property inheritance and bindings + - Add OIDC Token to restate calls when bypassing restate + - Add Operations Parameter, Operations Data, Work Parameter and Work Data to schema + - Add option to bypass saving restate state on every BPMN task execution when calling a BPMN + - Add otel tracing to ISA-95 microservice + - Add resolver to bypass restate for equipment history queries to increase performance + - Add restate handler metrics for observability + - Add search by equipment level to graph + - Add search to equipment asset mapping date times + - Add syncEquipment mutation + - Add Test Specification Fields to PhysicalAssetSpecification + - Add TTL to cloud event ingress Value Bindings and Equipment Version cache (10min) + - Add `update` auth rule to schema + - Add update bpmn method + - Add version to schema generation + - Add work master version references across multiple schemas + - Add Work Master versioning as per other master data entities + - Add workflow synchronization mutation + - Add WorkMasterVersion Service Implementation + +#### Change + + - Change BAAS container to v4.2.0-rc2 + - Change cached values to allow nil to prevent constant lookups on value changes without bindings + - Change CDC Processing to batch changes for performance enhancement + - Change CI/CD pipeline keycloak to sslRequired=NONE + - Change CI/CD to use golangci-lint v2 + - Change CreateMaterialDefinitionVersionInput to allow creating with base UoM, properties and material classes + - Change default token to work new Keycloak v26.4 seeded database + - Change equipment property history resolver to use ISO8601 datetime (ns support) + - Change exportJSON to use JSONObect instead of string + - Change getInformationObjectData to use JSONObject instead of string + - Change GetInformationObjectDataRequest to return restate terminal error for better restate handling + - Change golang to v1.24 + - Change Grafana LGTM to 0.11.17 + - Change ingress handler to allow to subscribing to multiple topics + - Change strategy to only get equipment state when required and from tsClient + - Change Keycloak to v26.4 + - Change Keycloak seed database to align with Keycloak v26.4 + - Change libraries to latest versions + - Change metric counter library to otel from prometheus + - Change OIDC to use rhize-go Library + - Change queryInstances endpoint for workflow instance log list + - Change questdb equipment property data schema to use SYMBOL type to reduce storage requirements and improve performance + - Chang processing of agent data to restate service rather than virtual objects by default + - Change pipeline services to latest versions + - Change QuestbDB to v9.1.1 + - Change Redpanda to v25.2.10 + - Change Restate to v1.21.1 + - Change to restate restate.UUID from restate.Rand.UUID to align with client upgrade +- Change schema resolution of dgraph types in inherited properties to only return IIds and allow dgraph to resolve + - Change service context span to return new context to allow for nested spans + - Change typescript-host to v4.2.0-rc1 + - Change various golang libraries to latest minor/bugfix release + +#### Fix + + - Fix cache population on map value + - Fix Calendar generation not scheduling itself + - Fix concurrent map read/write + - Fix equipment property data schema for QuestDB to Use SYMBOL Type + - Fix goroutine leak by upgrading restate sdk-go to v0.18.1 + - Fix inconsistent isa95.equipment restate key usage + - Fix Inconsistent Key Usage in Topic Bindings + - Fix memory usage of inherited properties by using @local directive on local return types + - Fix metrics endpoint resolver + - Fix must not query state unless a service_key is provided in the WHERE clause + - Fix non-pointer binding and ensure correct content-type is passed to restate based on body content + - Fix optional fields value missing after version creation of a Person + - Fix restate OOM by changing default schema to use int limits and require datetimes for queryInstances + - Fix several security vulnerabilities in event catalog + +#### Remove + - Remove excess information being stored in equipment active version + - Remove over-fetched data for inherited equipment properties + - Remove tests that are specific to old combined WorkMaster header/version structure + +### Typescript host service + +#### Change + - Change pipeline release step to use docker v29.0 + - Change restate sdk version to 1.9.0 + + +### Workflow + +#### Add + - Add a struct for type Rule Evaluation Payload Context + - Add action payload expressions to workflow definition outputs to allow UI to display the existing value + - Add blank rule expression just to evaluate the struct instead to increase rule evaluation performance (this skips the need for communicating with the type script service for eval) + - Add cache of workflow specifications + - Add debug message for rule evaluation + - Add documentation on `CreateAndRun` function for the `BPMN` restate service + - Add error logging for binding failures + - Add expand env vars to JSONata service task transform & input + - Add foreign character support to BPMNs + - Add function to rebind message start event triggers + - Add instance node logging + - Add instance node log delete function for cleanup of logging + - Add Intermediate catch via message start back in + - Add option to specify BPMN version on CreateAndRun handler + - Add option to run workflow without restate + - Add process documentation as description when marshalling and the inverse when unmarshalling to xml + - Add restate metrics to support debugging and performance analysis + - Add round-robin load balancing for typescript host in HA environments + - Add schema validation function back in + - Add SQL Task Handler for PostgreSQL + - Add support for saving bpmn extension properties as workflow spec properties + - Add task Data Source Method Call back in + - Add task handler for GoogleBigQuery + - Add Update BPMN restate handler + - Add Update Workflow Specification Property handler + - Add validation logic to update BPMN timers + - Add validation to the SQL Playground sql query to prevent full table scans of value or value_utf8 fields + - Add workflow id search in instance query + - Add workflow instance log list as queryInstances end point + +#### Change + +- Change /healthz definition to inline defined for readability +- Change BPMN loading for SQL tasks to accept inputs for `url`, `query`, `args`, and `responseTransformExpression`. +- Change BPMNService to initialize with a query/mutation adapter instead of creating one every time +- Change `buildActionPayload` to always treat expressions as non-constant, due to issues with the UI +- Change completed workflow buffer when equal to or greater than 10 +- Change connection string logging to use slog for consistency +- Change `createAndRunBpmn` strategy to fallback to database query when workflow specification not found +- Change datasource task to route via restate instead of NATS +- Change dependencies to align with release +- Change DQL, GraphQL & RestAPI Task HTTP Clients to use common client with shared Certificate Authority pool to allow for external certificate use +- Change error messages to restate terminalize errors +- Change event message start to trigger off of rule-definition bound to datasource topic instead in restate instead of Kafka Topic +- Change golang libraries to align with release + - Change instance filter to filter out un-versioned, un-started or un-ended instances + - Change JSONata-go to v1.8.8 + - Change JSONata errors to terminalize back to restate instead of panic'ing + - Change JSONata resolution to use typescript microservice implementation instead of golangs +- Change Kafka implementation to allow use of Redpanda + - Change log usage to slog in main.go for consistency + - Change pipeline variables to work with v4 app-config-local +- Change RestateSDK to 0.18.1 +- Change rule evaluation error messages to wrap additional context before erroring + - Change versions of filippo/age + - Change versions of golang.org/x/exp + - Change versions of golang-jwt and golang.org/x/net + - Change workflow to clear token on abort to prevent a loop + - Change workflow to only handle Message/Timer starts on start nodes (i.e. filter out the others) + +#### Fix + + - Fix an issue where `buildActionPayload` would overwrite inputs before sending it to typescript-host-service + - Fix bpmn timer disable + - sts/99) Fix CI pipeline failure due to creating a datasource with curl compressed + - Fix duplicate subscriptions from ever being created on message start events + - Fix error where an end node would be displayed as a failed node + - Fix http protocols served by Workflow + - sts/92) Fix lint issues + - Fix metrics complete not finding any instances due to incorrect key from complete token method + - Fix node errors shown in View Instance UI + - Fix platform state SQL playground error + - Fix sync bpmn service to include case where workflow does not have a virtual object + - Fix workflownode automated delete to use node.NodeID instead of the restate key & NodeID + +#### Remove + + - Remove Ingress BAAS CDC handler from Workflow + - Remove unused duplicated fromBpmnXML + - Remove unused/commented out code + - Remove azure client information in agent test configuration + + + + + +The following sections document the changes this release brings to each service. + + +## Compatibility + +{{< compatible "4.2.0" >}} + +## Checksums + +{{% checksums "v4.2.0-checksums.txt" %}} + +## Upgrade + +To upgrade to v4.2.0, follow the [Upgrade instructions](/deploy/upgrade). diff --git a/content/versions/v4.0.0/_index.md b/content/versions/v3.2.1/_index.md similarity index 95% rename from content/versions/v4.0.0/_index.md rename to content/versions/v3.2.1/_index.md index a2f99a69b..73b7c5039 100644 --- a/content/versions/v4.0.0/_index.md +++ b/content/versions/v3.2.1/_index.md @@ -1,10 +1,10 @@ --- -title: v4.0.0 +title: ##Leave only home page without title description: User guides, deploy docs, references, and deep dives about the Rhize manufacturing data hub. cascade: type: versions - v: "4.0.0" + v: "3.2.1" --- diff --git a/content/versions/v4.0.0/deploy/_index.md b/content/versions/v3.2.1/deploy/_index.md similarity index 100% rename from content/versions/v4.0.0/deploy/_index.md rename to content/versions/v3.2.1/deploy/_index.md diff --git a/content/versions/v4.0.0/deploy/backup/_index.md b/content/versions/v3.2.1/deploy/backup/_index.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/_index.md rename to content/versions/v3.2.1/deploy/backup/_index.md diff --git a/content/versions/v4.0.0/deploy/backup/audit.md b/content/versions/v3.2.1/deploy/backup/audit.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/audit.md rename to content/versions/v3.2.1/deploy/backup/audit.md diff --git a/content/versions/v4.0.0/deploy/backup/binary.md b/content/versions/v3.2.1/deploy/backup/binary.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/binary.md rename to content/versions/v3.2.1/deploy/backup/binary.md diff --git a/content/versions/v4.0.0/deploy/backup/grafana.md b/content/versions/v3.2.1/deploy/backup/grafana.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/grafana.md rename to content/versions/v3.2.1/deploy/backup/grafana.md diff --git a/content/versions/v4.0.0/deploy/backup/graphdb.md b/content/versions/v3.2.1/deploy/backup/graphdb.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/graphdb.md rename to content/versions/v3.2.1/deploy/backup/graphdb.md diff --git a/content/versions/v4.0.0/deploy/backup/influx.md b/content/versions/v3.2.1/deploy/backup/influx.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/influx.md rename to content/versions/v3.2.1/deploy/backup/influx.md diff --git a/content/versions/v4.0.0/deploy/backup/keycloak.md b/content/versions/v3.2.1/deploy/backup/keycloak.md similarity index 100% rename from content/versions/v4.0.0/deploy/backup/keycloak.md rename to content/versions/v3.2.1/deploy/backup/keycloak.md diff --git a/content/versions/v3.2.1/deploy/cluster-sizing.md b/content/versions/v3.2.1/deploy/cluster-sizing.md new file mode 100644 index 000000000..e657e6b1c --- /dev/null +++ b/content/versions/v3.2.1/deploy/cluster-sizing.md @@ -0,0 +1,92 @@ +--- +title: Recommended Kubernetes cluster sizing +description: The recommended number of nodes and compute per pod in your Rhize Kubernetes cluster +--- + +Rhize runs on Kubernetes. + +This document provides compute recommendations for the nodes, pods services of your [Rhize Install]({{< relref "install" >}}). +Some services also have recommended replication factors to increase reliability. + +## Node recommendations + +The following tables are the minimum recommended sizes to provision your cluster for Rhize {{% param v %}}. + +### Rhize nodes + +For high availability, Rhize recommends a **minimum of three nodes** with the following specifications. + + +| Property | Value | +|-----------------------|-------------------| +| Number of nodes | 3 | +| CPU Speed (GHz) | 3.3 | +| vCPU per Node | 16 | +| Memory per node (GiB) | 32 (64 is better) | +| Persisted volumes | 12 | +| Persisted Volume IOPS | 5000 | +| PV Throughput (MBps) | 500 | +| Total Disk Space (TB) | 3 | +| Disk IOPS | 5000 | +| Disk MBps | 500MBps | + +### Rhize agent + +The Rhize agent typically runs on the edge, outside of the cluster entirely. +For the Rhize Agent, the minimum recommended specifications are as follows: + +| Property | Value | +|-----------------------|-------| +| CPU Speed (GHz) | 2.8 | +| vCPU per Node | 2 | +| Memory per node (GiB) | 1 | +| Persisted volumes | 1 | + +## Service-level recommendations + +The following table lists the **minimum** recommended specifications for the main services. +Services with stateful PV have a persistent volume per pod. + + +| Service | Pods for HA (replica count) | vCPU per Pod | Memory Per Pod | Stateful PV | DiskSize (GiB) | Comments | +|------------------------|-----------------------------|--------------|----------------|-------------|----------------|----------------------------------------------------------------------| +| `baas-alpha` | 3 | 8 | 16 (at least) | Yes | 750 | High throughput and IOPS | +| `baas-zero` | 3 | 2 | 2 | Yes | 350 | High throughput and IOPS | +| `libre-core` | 3 | 1 | 2 | No | N/A | HA requires 2 pods, but 3 is to avoid hotkey issues and balance load | +| `bpmn-engine` | 3 | 1 | 2 | No | N/A | HA requires 2 pods, but 3 is to avoid hotkey issues and balance load | +| `nats` | 3 | 1 | 2 | Yes | 100 | High IOPS | +| `nats-box` | 1 | 0.25 | 0.25 | No | N/A | | +| `libre-audit` | 2 | 1 | 1 | No | N/A | | +| `libre-audit-postgres` | 2 | 1 | 2 | Yes | 250 | Runs in pod with `libre-audit` | +| `libre-ui` | 3 | 0.25 | 0.25 | No | N/A | | +| `keycloak` | 2 | 1 | 2 | No | N/A | | +| `keycloak-postgres` | 2 | 1 | 2 | No | 200 | Runs in pod with `keycloak` | +| `router` | 2 | 1 | 2 | Yes | <1 | Requires volume to compose supergraph | +| `grafana`* | 3 | 0.5 | 2 | No | 20-50 | Storage can be in host or in object bucket. | + + * May run [in separate cluster](#monitoring-stack) + +### Monitoring stack + +The following table provides minimal compute recommendations for the monitoring stack. + +The default recommendation is to run your Rhize observability stack in the nodes that also run the Rhize application. +However, some deployments prefer to separate monitoring to its own cluster. + +| Service | Pods for HA (replica count) | vCPU cores per pod | Memory per pod | DiskSize (GiB) | +|-------------------------|-----------------------------|--------------------|----------------|----------------| +| `grafana` | 3 | 0.5 | 2 | 50GB | +| `prometheus-node` | 4 | 0.25 | 0.05 | N/A | +| `prometheus-server` | 1 per pod | 1 | 2 | 1 | +| `promtail` | 4 | 0.25 | 0.2 | N/A | +| `loki` | 1 | 1 | 1 | 1 | +| `loki-logs` | 1 per pod | 0.25 | 0.1 | N/A | +| `loki-canary` | 4 | 0.25 | 0.1 | N/A | +| `loki-gateway` | 1 | 0.25 | 0.05 | 0.25 | +| `loki-grafana-operator` | 1 | 0.25 | 0.1 | 0.25 | +| `tempo-compactor` | 1 | 0.25 | 2 | 0.25 | +| `tempo-ingester` | 3 | 0.5 | 0.75 | 1.5 | +| `tempo-querier` | 1 | 0.25 | 0.5 | 0.25 | +| `tempo-distributor` | 1 | 0.25 | 0.5 | 0.25 | +| `tempo-query-frontend` | 1 | 0.25 | 0.5 | 0.25 | +| `temp-memcache` | 1 | 0.25 | 0.1 | 0.25 | diff --git a/content/versions/v3.2.1/deploy/get-keycloak-token.md b/content/versions/v3.2.1/deploy/get-keycloak-token.md new file mode 100644 index 000000000..006bb674e --- /dev/null +++ b/content/versions/v3.2.1/deploy/get-keycloak-token.md @@ -0,0 +1,46 @@ +--- +title: Get Keycloak Token +description: Get a Keycloak bearer token +--- + +When build applications on Rhize, your clients to need authenticate requests. +To do that, they need to periodically request a bearer token from the Keycloak service. + +## Get token + +With `grant_type` set for client credentials, you can get a bearer token with the following request: + +```shell +curl -X POST "https:///realms//protocol/openid-connect/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=client_credentials" \ + -d "client_id=" \ + -d "client_secret=" +``` + +If the `grant_type` is set for password authentication the request will also require a username and password: + +```shell +curl -X POST "https:///realms//protocol/openid-connect/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=password" \ + -d "client_id=" \ + -d "client_secret=" \ + -d "username=" \ + -d "password=" +``` + +## Response + +An example response returns a JSON object with the following structure. +The `access_token` property has the token value. + +```json +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU...", + "expires_in": 300, + "token_type": "Bearer", + "scope": "email profile" +} +``` + diff --git a/content/versions/v4.0.0/deploy/install/_index.md b/content/versions/v3.2.1/deploy/install/_index.md similarity index 100% rename from content/versions/v4.0.0/deploy/install/_index.md rename to content/versions/v3.2.1/deploy/install/_index.md diff --git a/content/versions/v4.0.0/deploy/install/image.png b/content/versions/v3.2.1/deploy/install/image.png similarity index 100% rename from content/versions/v4.0.0/deploy/install/image.png rename to content/versions/v3.2.1/deploy/install/image.png diff --git a/content/versions/v4.0.0/deploy/install/keycloak.md b/content/versions/v3.2.1/deploy/install/keycloak.md similarity index 67% rename from content/versions/v4.0.0/deploy/install/keycloak.md rename to content/versions/v3.2.1/deploy/install/keycloak.md index 052835991..bb97b5d84 100644 --- a/content/versions/v4.0.0/deploy/install/keycloak.md +++ b/content/versions/v3.2.1/deploy/install/keycloak.md @@ -49,7 +49,7 @@ To create your Rhize realm, follow these steps. 1. In the side menu, select **Realm Settings**. 1. Enter the following values: | Field | value | - | ------------ | --------------------- | + |--------------|-----------------------| | Frontend URL | Keycloak frontend URL | | Require SSL | External requests | @@ -141,9 +141,9 @@ Create a client for the UI as follows: 1. Configure the **Access Settings**: - - **Root URL**: `` without trailing slashes - - **Home URL**: `` without trailing slashes - - **Web Origins**: `` without trailing slashes + - **Root URL**: `.` without trailing slashes + - **Home URL**: `.` without trailing slashes + - **Web Origins**: `.` without trailing slashes 1. Select **Next**, then **Save**. @@ -168,8 +168,8 @@ Create a client for the UI as follows: 1. Configure the **Access Settings**: - - **Root URL**: `` without trailing slashes - - **Home URL**: `` without trailing slashes + - **Root URL**: `.` without trailing slashes + - **Home URL**: `.` without trailing slashes - **Valid redirect URIs**: `/login/generic_oauth` without trailing slashes - **Valid post logout redirect URIs**: `+` without trailing slashes - **Web origins**: `.` without trailing slashes @@ -181,26 +181,22 @@ Create a client for the UI as follows: The other services do not need authorization but do need client authentication. By default you need to add only the client ID. -For example, to create the Workflow client: +For example, to create the BPMN engine client: 1. In the side menu, select **Clients > create client**. -1. For **Client ID**, enter `{{< param application_name >}}Workflow` -1. **Name**: `{{< param brand_name >}} Workflow Engine` -1. **Description**: `{{< param brand_name >}} Workflow Engine` +1. For **Client ID**, enter `{{< param application_name >}}Bpmn` 1. Configure the **Capability config**: - **Client Authentication**: On 1. Select **Next**, then **Save**. -Repeat the preceding process for each of the following services with the corresponding values in the table. +**Repeat this process for each of the following services:** -| Client ID | Name | Description | -| --------------------------------------- | --------------------------------------- | --------------------------- | -| `{{< param application_name >}}Agent` | {{< param brand_name >}} Agent | The agent data service | -| `{{< param application_name >}}Audit`* | {{< param brand_name >}} Audit Log | The audit log service | -| `{{< param application_name >}}ISA95` | {{< param brand_name >}} ISA-95 Model | The ISA-95 model service | -| `{{< param application_name >}}KPI`* | {{< param brand_name >}} KPI Calculator | The ISO22400 KPI calculator | -| `{{< param application_name >}}Router`* | {{< param brand_name >}} API Router | The API router | +| Client ID | Description | +|----------------------------------------|-----------------------| +| `{{< param application_name >}}Audit` | The audit log service | +| `{{< param application_name >}}Core` | The edge agent | +| `{{< param application_name >}}Router` | API router | -*- Optional based on your architecture. +Based on your architecture, repeat for any Libre Edge Agents, `{{< param application_name >}}Agent`. ### Scope services @@ -220,28 +216,31 @@ To create a scope for your Rhize services, follow these steps: - **Display on consent screen**: `On` - **Include in token scope**: `On` 1. **Create**. - -#### Create audience mappers -Select the **Mappers** tab, then **Configure new mapper**. Add an audience mapper for the DB client: - - **Mapper Type**: `Audience` - - **Name**: `{{< param db >}}AudienceMapper` - - **Include Client Audience**: `{{< param db >}}` - - **Add to ID Token**: `On` - - **Add to access token**: `On` - -Repeat the preceding process for each of the following services with the corresponding values in the table. - -| Name | Include Client Audience | ID Token | Access Token | -| ------------------------------------------------------ | ---------------------------------------- | :------: | :----------: | -| `{{< param application_name >}}AuditAudienceMapper`* | `audit`** | `On` | `On` | -| `{{< param application_name >}}AgentAudienceMapper` | `{{< param application_name >}}Agent` | `On` | `On` | -| `{{< param application_name >}}ISA95AudienceMapper` | `{{< param application_name >}}ISA95` | `On` | `On` | -| `{{< param application_name >}}KPIAudienceMapper`* | `{{< param application_name >}}KPI` | `On` | `On` | -| `{{< param application_name >}}UIAudienceMapper` | `{{< param application_name >}}UI` | `On` | `Off` | -| `{{< param application_name >}}WorkflowAudienceMapper` | `{{< param application_name >}}Workflow` | `On` | `On` | - -*- Optional based on your architecture.
-**- Included as a Custom Audience. +1. Select the **Mappers** tab, then **Configure new mapper**. Add an audience mapper for the DB client: + - **Mapper Type**: `Audience` + - **Name**: `{{< param db >}}AudienceMapper` + - **Include Client Audience**: `{{< param db >}}` + - **Add to ID Token**: `On` + - **Add to access token**: `On` +1. Repeat the preceding step for a mapper for the UI client: + - **Mapper Type**: `Audience` + - **Name**: `{{< param application_name >}}UIAudienceMapper` + - **Include Client Audience**: `{{< param application_name >}}UI` + - **Add to ID Token**: `On` + - **Add to access token**: `Off` +1. Repeat the preceding step for a mapper for the BPMN client: + - **Mapper Type**: `Audience` + - **Name**: `{{< param application_name >}}BpmnAudienceMapper` + - **Include Client Audience**: `{{< param application_name >}}Bpmn` + - **Add to ID Token**: `On` + - **Add to access token**: `On` +1. If using the Rhize Audit microservice, repeat the preceding step for an Audit scope and audience mapper: + - **Mapper Type**: `Audience` + - **Name**: `{{< param application_name >}}AuditAudienceMapper` + - **Include Client Audience**: + - **Included Custom Audience**: `audit` + - **Add to ID Token**: `On` + - **Add to access token**: `On` #### Add services to the scope @@ -251,24 +250,14 @@ Repeat the preceding process for each of the following services with the corresp 1. Select `{{< param application_name >}}ClientScope` from the list. 1. **Add > Default**. -Repeat the preceding process above for each of the following services: - -- `dashboard` -- `{{< param application_name >}}Audit`* -- `{{< param application_name >}}Agent` -- `{{< param application_name >}}ISA95` -- `{{< param application_name >}}KPI`* -- `{{< param application_name >}}Router`* -- `{{< param application_name >}}UI` -- `{{< param application_name >}}Workflow` - -*- Optional based on your architecture. +Repeat this process for the `dashboard`, `{{< param application_name >}}UI`, `{{< param application_name >}}Bpmn`, `{{< param application_name >}}Core`, `{{< param application_name >}}Router`, `{{< param application_name >}}Audit` (if applicable). Based on your architecture repeat for any Libre Edge Agent clients. ### Create roles and groups In Keycloak, _roles_ identify a category or type of user. _Groups_ are a common set of attributes for a set of users. + #### Add the Admin Group 1. In the left hand menu, select **Groups > Create group**. @@ -316,7 +305,7 @@ Now map the scope: 1. Select the **Client scopes** tab. 1. **Add client scope**. 1. Select `groups`. -1. **Add Default**. +1. **Add > Default**. ### Add Client Policy @@ -325,7 +314,7 @@ Rhize requires authorization for the database service. 1. In the left hand menu, select **Clients**, and then `{{< param db >}}`. 1. Select the **Authorization** tab. -1. Select the **Policies** subtab. +1. Select the **Policies** sub-tab. 1. Select **Create Policy > Group**. 1. Name the policy `{{< param application_name >}}AdminGroupPolicy`. 1. Select **Add Groups**. @@ -353,18 +342,43 @@ Now create a user password: 1. For **Temporary**, choose `Off`. 1. **Save**. -Repeat the preceding process for each of the following services with the corresponding values in the table. - -| Username | First name | -| ------------------------------------------------------------------ | ---------- | -| `{{< param application_name >}}Audit@{{< param domain_name >}}`* | Audit | -| `{{< param application_name >}}Agent@{{< param domain_name >}}` | Agent | -| `{{< param application_name >}}ISA95@{{< param domain_name >}}` | ISA95 | -| `{{< param application_name >}}KPI@{{< param domain_name >}}`* | KPI | -| `{{< param application_name >}}Router@{{< param domain_name >}}`* | Router | -| `{{< param application_name >}}Workflow@{{< param domain_name >}}` | Workflow | - -*- Optional based on your architecture. +Repeat this process for the following accounts: + +- Audit: + - **Username**: `{{< param application_name >}}Audit@{{< param domain_name >}}` + - **Email**: `{{< param application_name >}}Audit@{{< param domain_name >}}` + - **Email Verified**: `On` + - **First name**: `Audit` + - **Last name**: `{{< param brand_name >}}` + - **Join Groups**: `{{< param application_name >}}AdminGroup` +- Core: + - **Username**: `{{< param application_name >}}Core@{{< param domain_name >}}` + - **Email**: `{{< param application_name >}}Core@{{< param domain_name >}}` + - **Email Verified**: `On` + - **First name**: `Core` + - **Last name**: `{{< param brand_name >}}` + - **Join Groups**: `{{< param application_name >}}AdminGroup` +- BPMN + - **Username**: `{{< param application_name >}}Bpmn@{{< param domain_name >}}` + - **Email**: `{{< param application_name >}}Bpmn@{{< param domain_name >}}` + - **Email Verified**: `On` + - **First name**: `Bpmn` + - **Last name**: `{{< param brand_name >}}` + - **Join Groups**: `{{< param application_name >}}AdminGroup` +- Router + - **Username**: `{{< param application_name >}}Router@{{< param domain_name >}}` + - **Email**: `{{< param application_name >}}Router@{{< param domain_name >}}` + - **Email Verified**: `On` + - **First name**: `Router` + - **Last name**: `{{< param brand_name >}}` + - **Join Groups**: `{{< param application_name >}}AdminGroup` +- Agent + - **Username**: `{{< param application_name >}}Agent@{{< param domain_name >}}` + - **Email**: `{{< param application_name >}}Agent@{{< param domain_name >}}` + - **Email Verified**: `On` + - **First name**: `Agent` + - **Last name**: `{{< param brand_name >}}` + - **Join Groups**: `{{< param application_name >}}AdminGroup` {{% /steps %}} diff --git a/content/versions/v4.0.0/deploy/install/overview.md b/content/versions/v3.2.1/deploy/install/overview.md similarity index 100% rename from content/versions/v4.0.0/deploy/install/overview.md rename to content/versions/v3.2.1/deploy/install/overview.md diff --git a/content/versions/v4.0.0/deploy/install/row-level-access-control.md b/content/versions/v3.2.1/deploy/install/row-level-access-control.md similarity index 95% rename from content/versions/v4.0.0/deploy/install/row-level-access-control.md rename to content/versions/v3.2.1/deploy/install/row-level-access-control.md index 674b2a36c..9c52208e7 100644 --- a/content/versions/v4.0.0/deploy/install/row-level-access-control.md +++ b/content/versions/v3.2.1/deploy/install/row-level-access-control.md @@ -23,7 +23,7 @@ Consider the following scenario: Acme Inc. contracts part of its supply chain to 1. Create an OIDC Role: Define a role called `cmoAccess` in your OIDC provider (e.g., Keycloak). 2. Define a Hierarchy Scope. Create a hierarchy scope in Rhize called `CMO`. This scope is applied to objects or nodes in the graph that relate to the CMO. -3. Add a Rule to the Scope Map: Define a rule in the `scopemap.scopemap.json` file as follows: +3. Add a Rule to the Scope Map: Define a rule in the `scopemap.json` file as follows: ```json { diff --git a/content/versions/v3.2.1/deploy/install/services.md b/content/versions/v3.2.1/deploy/install/services.md new file mode 100644 index 000000000..6cc3fad43 --- /dev/null +++ b/content/versions/v3.2.1/deploy/install/services.md @@ -0,0 +1,512 @@ +--- +title: Install Rhize services +description: >- + Instructions to install services in the Rhize Kubernetes cluster. +weight: 100 +categories: "how-to" +--- + +The final installation step is to install the Rhize services in your Kubernetes cluster. + +> [!NOTE] +> For the recommended compute per pod for each service, refer to [Cluster sizing]({{< relref "../cluster-sizing" >}}) + +## Prerequisites + +This topic assumes you have done the following: +- [Set up Kubernetes]({{< relref "setup-kubernetes" >}}) and [Configured Keycloak]({{< relref "keycloak" >}}). All the prerequisites for those topics apply here. +- Configured load balancing for the following DNS records: + + {{< reusable/default-urls >}} + + _Note that `rhize-` is only the recommended prefix of the subdomain. Your organization may use something else._ + + +### Overrides + +Each service is installed through a Helm YAML file. +For some of these services, you might need to edit this file to add credential information and modify defaults. + +Common values that are changed include: +- URLs and URL links +- The number of replicas running for each pod +- Ingress values for services exposed on the internet + +## Get client secrets + +Client secrets are necessary for Rhize services to authenticate with Keycloak. These secrets are stored with Kubernetes secrets. + +1. Go to Keycloak and get the secrets for each client you've created. +1. Create Kubernetes secrets for each service. You can either create a secret file, or pass raw data from the command line. + + {{< callout type="caution" >}} + How you create Kubernetes secrets **depends on your implementation details and security procedures.** + For guidance, refer to the official Kubernetes topic, [Managing Secrets using `kubectl`](https://kubernetes.io/docs/tasks/configmap-secret/managing-secret-using-kubectl/). + {{< /callout >}} + + With raw data, the command might look something like this: + + ```bash + kubectl create secret generic {{< param application_name >}}-client-secrets -n {{< param application_name >}} \ + --from-literal=dashboard=VKIZ6zkQYyPutDzWqIZ9uIEnQRviyqsS \ + --from-literal={{< param application_name >}}Audit=q8JBjuEefWTmhv9IX4KKYxNtXXnYtDPD \ + --from-literal={{< param application_name >}}Baas=KYbMHlRLhXwiDNFuDCl3qtPj1cNdeMSl \ + --from-literal={{< param application_name >}}Bpmn=7OrjB7FhOdsNeb819xzEDBbMyVb6kNdr \ + --from-literal={{< param application_name >}}Core=SH28Wlx2uEXcgf1NffStbmSuruxvrpi6 \ + --from-literal={{< param application_name >}}UI=0qQ7c1EtOKvwsAcpd0xYIvle4zsMcGRq \ + --from-literal={{< param application_name >}}Router=0qQ7c1EtOKvwsAcpd0xYIvle4zsMcGRq + ``` + +1. Create secrets for login passwords. Each service with its own user in Keycloak can have its password supplied through Kubernetes secrets. + + As you install services through Helm, their respective YAML files reference these secrets. + +## Install and add roles for the DB {#db} + +You must install the {{< param db >}} database service first. +You also need to configure the {{< param db >}} service to have roles in Keycloak. + +If enabling the Audit Trail, also the include the configuration in [Enable change data capture](#enable-change-data-capture). + +If you need Row Level Access Control, [configure your scope map]({{< relref "row-level-access-control.md" >}}). + +1. Modify the DB Helm file with your code editor. Edit any necessary overrides. + + +1. Use Helm to install the database: + + ```bash + helm install -f baas.yaml {{< param application_name >}}-baas {{< param application_name >}}/baas -n {{< param application_name >}} + ``` + + To confirm it works, run the following command: + + ```bash + kubectl get pods + ``` + + All statuses should be `RUNNING`. + + +1. Return to the Keycloak UI and add all `{{< param application_name >}}` roles to the admin group. + +1. Proxy the `http:8080` port on `{{< param application_name >}}-baas-dgraph-alpha`. + + ``` + kubectl port-forward -n {{< param application_name >}} pod/baas-baas-alpha-0 8080:8080 + ``` + +1. Get a token using the credentials. With `curl`, it looks like this: + + ```bash + curl --location --request POST 'https://- + auth.{{< param application_name >}}/realms/{{< param application_name >}}/protocol/openid-connect/token' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=password' \ + --data-urlencode 'username=system@{{< param application_name >}}.com' \ + --data-urlencode 'password=' \ + --data-urlencode 'client_id={{< param application_name >}}Baas' \ + --data-urlencode 'client_secret=' + ``` + +1. Post the schema: + + ```bash + curl --location --request POST 'http://localhost:/admin/schema' \ + --header 'Authorization: Bearer ' \ + --header 'Content-Type: application/octet-stream' \ + --data-binary '@' + ``` + + This creates more roles. + +1. Go to Keycloak UI and add all new {{< param db >}} roles to the `ADMIN` group. + +If the install is successful, the Keycloak UI is available on its +[default port]({{< relref "../../reference/default-ports" >}}). + + +## Install services + +Each of the following procedures installs a service through Helm. + +The syntax to install a Rhize service must have arguments for the following: +- The chart YAML file +- The packaged chart +- The path to the unpackaged chart or directory + +Additionally, use the `-n` flag to ensure that the install is scoped to the correct namespace: + + +``` +helm install \ + -f .yaml \ + \ + -n +``` + +For the full configuration options, +read the official [Helm `install` reference](https://helm.sh/docs/helm/helm_install/). + + +### NATS {#nats} + + + +[NATS](https://nats.io) is the message broker that powers Rhize's event-driven architecture. + +Install NATS with these steps: + +1. If it doesn't exist, add the NATS repository: + + ```bash + helm repo add nats https://nats-io.github.io/k8s/helm/charts/ + ``` + +1. Modify the NATS Helm file with your code editor. Edit any necessary overrides. +1. Install with Helm: + + ``` + helm install nats -f nats.yaml nats/nats -n {{< param application_name >}} + ``` + + +### Tempo + +Rhize uses [Tempo](https://grafana.com/oss/tempo/) to trace BPMN processes. + +Install Tempo with these steps: + +1. If it doesn't exist, add the Tempo repository: + + ```bash + helm repo add grafana https://grafana.github.io/helm-charts + ``` + +1. Modify the Helm file as needed. +1. Install with Helm: + + ```bash + helm install tempo -f tempo.yaml grafana/tempo -n {{< param application_name >}} + ``` + +### Core + +The {{< param brand_name >}} Core service is the custom edge agent that monitors data sources, like OPC-UA servers, and publishes and subscribes topics to NATS. + +> **Requirements**: Core requires the [{{< param db >}}](#db) and [NATS](#nats) services. + +Install the Core agent with these steps: + +1. In the `core.yaml` Helm file, edit the `clientSecret` and `password` with settings from the Keycloak client. +1. Override any other values, as needed. +1. Install with Helm: + + ```bash + helm install core -f core.yaml {{< param application_name >}}/core -n {{< param application_name >}} + ``` + +### BPMN + +The BPMN service is the custom engine Rhize uses to process low-code workflows modeled in the BPMN UI. + +> **Requirements**: The BPMN service requires the [{{< param db >}}](#db), [NATS](#nats), and [Tempo](#tempo) services. + +Install the BPMN engine with these steps: + +1. Open `bpmn.yaml` Update the `clientSecret` and `password` for your BPMN Keycloak credentials. +1. Modify any other values, as needed. +1. Install with Helm: + + ```bash + helm install bpmn -f bpmn.yaml {{< param application_name >}}/bpmn -n {{< param application_name >}} + ``` + +### Router + +Rhize uses the [Apollo router](https://www.apollographql.com/docs/router) to unite queries for different services in a single endpoint. + +> **Requirements:** Router requires the [GraphDB](#db), [BPMN](#bpmn), and [Core](#core) services. + +Install the router with these steps: + +1. Modify the router Helm YAML file as needed. +1. Install with Helm: + + ```bash + helm install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} + ``` + +If the install is successful, the Router explorer is available on its +[default port]({{< relref "../../reference/default-ports" >}}). + +### Grafana + +Rhize uses [Grafana](https://grafana.com) for its dashboard to monitor real time data. + +Install Grafana with these steps: + +1. Modify the Grafana Helm YAML file as needed. + +1. Add the Helm repository + ```bash + helm repo add grafana https://grafana.github.io/helm-charts + ``` + +1. Install with Helm: + + ```bash + helm install grafana -f grafana.yaml grafana/grafana -n {{< param application_name >}} + ``` + +If the install is successful, the Grafana service is available on its +[default port]({{< relref "../../reference/default-ports" >}}). + +### Agent + +The Rhize agent bridges your plant processes with the Rhize data hub. +It collects data emitted from the plant and publishes it to the NATS message broker. + +> **Requirements:** Agent requires the [Graph DB](#db), [Nats](#nats), and [Tempo](#tempo) services. + +Install the agent with these steps: + +1. Modify the Agent Helm file as needed. + +1. In the Rhize UI, add a Data Source for Agent to interact with: + - In the lefthand menu, open **Master Data > Data Sources > + Create Data Source**. + - Input a name for the Data Source. + - Add a Connection String and Create. + - Add any relevant Topics. + - Activate the Data Source. + +1. Install with Helm: + + ```bash + helm install agent -f agent.yaml {{< param application_name >}}/agent -n {{< param application_name >}} + ``` + +## Install Admin UI + +The Admin UI is the graphical frontend to [handle events]({{< relref "../../how-to/bpmn" >}}) and [define work masters]({{< relref "../../how-to/model" >}}). + +> **Requirements:** The UI requires the [GraphDB](#db), [BPMN](#bpmn), [Core](#core), and [Router](#router) services. + +After installing all other services, install the UI with these steps: + +1. Forward the port from the Router API. In the example, this forwards Router traffic to port `4000` on `localhost`. + + ```bash + kubectl port-forward svc/router 4000:4000 -n {{< param application_name >}} + ``` + +1. Open the Admin UI Helm file. Update the `envVars` object to reflect the URL for Router and Keycloak. If following the prior examples for port-forwarding, it will look something like this: + + ```yaml + envVars: + APP_APOLLO_CLIENT: "http://localhost:4000" + APP_APOLLO_CLIENT_ADMIN: "http://localhost:4000" + APP_AUTH_KEYCLOAK_SERVER_URL: "http://localhost:8080" + ``` + +1. Modify any other values, as needed. +1. Install with Helm: + + ```bash + helm install admin-ui -f admin-ui.yaml {{< param application_name >}}/admin-ui -n {{< param application_name >}} + ``` + +If the install is successful, Admin UI is available on its +[default port]({{< relref "../../reference/default-ports" >}}). + +## Optional: Audit Trail service + + +The Rhize [Audit]({{< relref "../../how-to/audit" >}}) service provides an audit trail for database changes to install. The Audit service uses PostgreSQL for storage. + +Install Audit Service with these steps: + +1. Modify the Audit trail Helm YAML file. It is *recommended* to change the PostgreSQL username and password values. + +2. Install with Helm: + + ```bash + helm install audit -f audit.yaml {{< param application_name >}}/audit -n {{< param application_name >}} + ``` + +3. Create partition tables in the PostgreSQL database: + + ```sql + create table public.audit_log_partition( like public.audit_log ); + select partman.create_parent( p_parent_table := 'public.audit_log', p_control := 'time', p_interval := '1 Month', p_template_table := 'public.audit_log_partition'); + ``` + +For details about maintaining the Audit trail, read [Archive the PostgresQL Audit trail]({{< relref "../maintain/audit/" >}}). + +### Enable change data capture + +The Audit trail requires [change data capture (CDC)]({{< relref "../../how-to/publish-subscribe/track-changes" >}}) to function. To enable CDC in {{< param application_name >}} BAAS, include the following values for the Helm chart overrides: + +```yaml +alpha: + # Change Data Capture (CDC) + cdc: + # Enable + enabled: true + # If configured for security, configure in NATS url. For example `nats://username:password@nats:4222` + nats: nats://nats:4222 + # Adjust based on high-availability requirements and cluster size. + replicas: 1 +``` + +### Enable Audit subgraph + +To use the Audit trail in the UI, you must add the Audit trail subgraph into the router. To enable router to use and compose the subgraph: + +1. Update the Router Helm chart overrides, `router.yaml`, to include: + + ```yaml + # Add Audit to the router subgraph url override + router: + configuration: + override_subgraph_url: + AUDIT: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query + + # If supergraph compose is enabled + supergraphCompose: + supergraphConfig: + subgraphs: + AUDIT: + routing_url: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query + schema: + subgraph_url: http://audit.{{< param application_name >}}.svc.cluster.local:8084/query + ``` + +2. Update the Router deployment + +```shell +$ helm upgrade --install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} +``` + +## Optional: calendar service + +The [{{< param brand_name >}} calendar service]({{< relref "../../how-to/work-calendars">}}) monitors work calendar definitions and creates work calendar entries in real time, both in the [Graph](#db) and time-series databases. + +> **Requirements:** The calendar service requires the [GraphDB](#db), [Keycloak](#keycloak), and [NATS](#nats) services. + +{{% callout type="info" %}} +The work calendar requires a time-series DB installed such as [InfluxDB](https://influxdata.com/), [QuestDB](https://questdb.io) or [TimescaleDB](https://www.timescale.com/). The following instructions are specific to QuestDB. +{{% /callout %}} + +Install the calendar service with these steps: + +1. Create tables in the time series. For example: + + + ```sql + CREATE TABLE IF NOT EXISTS PSDT_POT( + EquipmentId SYMBOL, + EquipmentVersion STRING, + WorkCalendarId STRING, + WorkCalendarIid STRING, + WorkCalendarDefinitionId STRING, + WorkCalendarDefinitionEntryId STRING, + WorkCalendarDefinitionEntryIid STRING, + WorkCalendarEntryId STRING, + WorkCalendarEntryIid SYMBOL, + HierarchyScopeId STRING, + EntryType STRING, + ISO22400CalendarState STRING, + isDeleted boolean, + updatedAt TIMESTAMP, + time TIMESTAMP, + lockerCount INT, + lockers STRING + ) TIMESTAMP(time) PARTITION BY month + DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); + + CREATE TABLE IF NOT EXISTS PDOT_PBT( + EquipmentId SYMBOL, + EquipmentVersion STRING, + WorkCalendarId STRING, + WorkCalendarIid STRING, + WorkCalendarDefinitionId STRING, + WorkCalendarDefinitionEntryId STRING, + WorkCalendarDefinitionEntryIid STRING, + WorkCalendarEntryId STRING, + WorkCalendarEntryIid SYMBOL, + HierarchyScopeId STRING, + EntryType STRING, + ISO22400CalendarState STRING, + isDeleted boolean, + updatedAt TIMESTAMP, + time TIMESTAMP, + lockerCount INT, + lockers STRING + ) TIMESTAMP(time) PARTITION BY month + DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); + + CREATE TABLE IF NOT EXISTS Calendar_AdHoc( + EquipmentId SYMBOL, + EquipmentVersion STRING, + WorkCalendarId STRING, + WorkCalendarIid STRING, + WorkCalendarDefinitionId STRING, + WorkCalendarDefinitionEntryId STRING, + WorkCalendarDefinitionEntryIid STRING, + WorkCalendarEntryId STRING, + WorkCalendarEntryIid SYMBOL, + HierarchyScopeId STRING, + EntryType STRING, + ISO22400CalendarState STRING, + isDeleted boolean, + updatedAt TIMESTAMP, + time TIMESTAMP, + lockerCount INT, + lockers STRING + ) TIMESTAMP(time) PARTITION BY month + DEDUP UPSERT KEYS(time, EquipmentId, WorkCalendarEntryIid); + ``` + +1. Modify the calendar YAML file as needed. + +1. Deploy with helm + + ```bash + helm install calendar-service -f calendar-service.yaml {{< param application_name >}}/calendar-service -n {{< param application_name >}} + ``` + +## Optional: change service configuration + +The services installed in the previous step have many parameters that you can configure for your performance and deployment requirements. +Review the full list in the [Service configuration]({{< relref "../../reference/service-config" >}}) reference. + +## Troubleshoot + +For general Kubernetes issues, the [Kubernetes dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/) is great for troubleshooting, and you can configure it to be accessible through the browser. + +For particular problems, try these commands: + +- **Is my service running?** + + To check deployment status, use this command: + + ```bash + kubectl get deployments + ``` + + Look for the pod name and its status. + +- **Access service through browser** + + Some services are accessible through the browser. + To access them, visit local host on the service's [default port]({{< relref "../../reference/default-ports" >}}). + +- **I installed a service too early**. + If you installed a service too early, use Helm to uninstall: + + ```bash + helm uninstall {{< param db >}} + ``` + + Then perform the steps you need and reinstall when ready. diff --git a/content/versions/v4.0.0/deploy/install/setup-kubernetes.md b/content/versions/v3.2.1/deploy/install/setup-kubernetes.md similarity index 93% rename from content/versions/v4.0.0/deploy/install/setup-kubernetes.md rename to content/versions/v3.2.1/deploy/install/setup-kubernetes.md index 248335eba..6e4048e83 100644 --- a/content/versions/v4.0.0/deploy/install/setup-kubernetes.md +++ b/content/versions/v3.2.1/deploy/install/setup-kubernetes.md @@ -100,13 +100,15 @@ Then, follow these steps. 1. Update overrides to `keycloak.yaml`. Then install with this command: ```bash - helm install keycloak -f ./keycloak.yaml bitnami/keycloak -n {{< param application_name >}} + helm install keycloak -f ./keycloak.yaml bitnami/keycloak -n libre ``` -1. Set up port forwarding from Keycloak. For example, this forwards traffic to port `5101` on `localhost`: +> Note: Version may have to be specified by appending on `--version` and the desired chart version. + +1. Set up port forwarding from Keycloak. For example, this forwards traffic to port `8080` on `localhost`. ```bash - kubectl port-forward svc/keycloak 5101:80 + kubectl port-forward svc/keycloak 8080:80 -n libre ``` ## Next steps diff --git a/content/versions/v4.0.0/deploy/maintain/_index.md b/content/versions/v3.2.1/deploy/maintain/_index.md similarity index 100% rename from content/versions/v4.0.0/deploy/maintain/_index.md rename to content/versions/v3.2.1/deploy/maintain/_index.md diff --git a/content/versions/v4.0.0/deploy/maintain/audit.md b/content/versions/v3.2.1/deploy/maintain/audit.md similarity index 100% rename from content/versions/v4.0.0/deploy/maintain/audit.md rename to content/versions/v3.2.1/deploy/maintain/audit.md diff --git a/content/versions/v3.2.1/deploy/maintain/bpmn-nodes.md b/content/versions/v3.2.1/deploy/maintain/bpmn-nodes.md new file mode 100644 index 000000000..e6cfbf47f --- /dev/null +++ b/content/versions/v3.2.1/deploy/maintain/bpmn-nodes.md @@ -0,0 +1,45 @@ +--- +title: "BPMN execution recovery" +weight: 200 +description: >- + If a BPMN node suddenly fails, Rhize has a number of recovery methods to ensure that the workflow finishes executing. +categories: ["concepts"] +--- + +[{{< abbr "BPMN" >}} processes]({{< relref "../../how-to/bpmn" >}}) often have longer execution durations and many steps. +If a BPMN node suddenly fails (for example through a panic or loss of power), +Rhize needs to ensure that the workflow completes. + +To achieve high availability and resiliency, Rhize services run in [Kubernetes nodes](https://kubernetes.io/docs/concepts/architecture/nodes/), and the NATS message broker typically has [data replication](https://docs.nats.io/running-a-nats-service/nats_admin/jetstream_admin/replication). +As long as the remaining BPMN nodes are not already at full processing capacity, +if a BPMN node fails while executing a process, +the Rhize system recovers and finishes the workflow. + +This recovery is automatic, though users may experience an execution gap of up to 30 seconds. + +## BPMN failure and recovery modes + +How Rhize recovers from a halted process depends on where the system failed. + +### BPMN node failure + +If a BPMN container suddenly fails, the process that was currently executing times out after 30 seconds. +As long as the node had not been running for [longer than 10 minutes](#bpmn-age-out), +NATS re-sends the message to another BPMN node and the process finishes. + +### NATS node unavailable + +If the NATS node fails, recovery depends on your replication and backup strategy. + +- If the stream has R3 replication or greater, a new NATS node picks up the process. No noticeable performance issues should occur. + +- If the stream has no replication, everything in the node is lost. However, if you took a snapshot of a stream with `nats stream backup` before the node became unavailable, and the `WorkflowSpecifications` KV is the same at backup and restore sites, then you can use the `nats stream restore` command to replay the stream from when the backup was made. + +To learn more, read the NATS topic on [Disaster recovery](https://docs.nats.io/running-a-nats-service/nats_admin/jetstream_admin/disaster_recovery). + +## All BPMN elements age out after ten minutes {#bpmn-age-out} + +If an element in a BPMN workflow takes longer than 10 minutes, NATS ages the workflow out of the queue. The process continues, but if the pod executing the element dies or is interrupted, that workflow is permanently dropped. + +This ten-minute execution limit should be sufficient for any element in a BPMN process. +Processes that take longer, such as cooling or fermentation periods, should be implemented as [BPMN event triggers]({{ relref "../../how-to/bpmn/bpmn-elements" >}}) or as polls that periodically check data sources between intervals of sleep. diff --git a/content/versions/v4.0.0/deploy/maintain/keycloak-events.md b/content/versions/v3.2.1/deploy/maintain/keycloak-events.md similarity index 100% rename from content/versions/v4.0.0/deploy/maintain/keycloak-events.md rename to content/versions/v3.2.1/deploy/maintain/keycloak-events.md diff --git a/content/versions/v4.0.0/deploy/restore/_index.md b/content/versions/v3.2.1/deploy/restore/_index.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/_index.md rename to content/versions/v3.2.1/deploy/restore/_index.md diff --git a/content/versions/v4.0.0/deploy/restore/audit.md b/content/versions/v3.2.1/deploy/restore/audit.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/audit.md rename to content/versions/v3.2.1/deploy/restore/audit.md diff --git a/content/versions/v4.0.0/deploy/restore/binary.md b/content/versions/v3.2.1/deploy/restore/binary.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/binary.md rename to content/versions/v3.2.1/deploy/restore/binary.md diff --git a/content/versions/v4.0.0/deploy/restore/grafana.md b/content/versions/v3.2.1/deploy/restore/grafana.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/grafana.md rename to content/versions/v3.2.1/deploy/restore/grafana.md diff --git a/content/versions/v4.0.0/deploy/restore/graphdb.md b/content/versions/v3.2.1/deploy/restore/graphdb.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/graphdb.md rename to content/versions/v3.2.1/deploy/restore/graphdb.md diff --git a/content/versions/v4.0.0/deploy/restore/influxdb.md b/content/versions/v3.2.1/deploy/restore/influxdb.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/influxdb.md rename to content/versions/v3.2.1/deploy/restore/influxdb.md diff --git a/content/versions/v4.0.0/deploy/restore/keycloak.md b/content/versions/v3.2.1/deploy/restore/keycloak.md similarity index 100% rename from content/versions/v4.0.0/deploy/restore/keycloak.md rename to content/versions/v3.2.1/deploy/restore/keycloak.md diff --git a/content/versions/v4.0.0/deploy/upgrade.md b/content/versions/v3.2.1/deploy/upgrade.md similarity index 100% rename from content/versions/v4.0.0/deploy/upgrade.md rename to content/versions/v3.2.1/deploy/upgrade.md diff --git a/content/versions/v4.0.0/how-to/_index.md b/content/versions/v3.2.1/how-to/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/_index.md rename to content/versions/v3.2.1/how-to/_index.md diff --git a/content/versions/v4.0.0/how-to/audit.md b/content/versions/v3.2.1/how-to/audit.md similarity index 100% rename from content/versions/v4.0.0/how-to/audit.md rename to content/versions/v3.2.1/how-to/audit.md diff --git a/content/versions/v4.0.0/how-to/bpmn/_index.md b/content/versions/v3.2.1/how-to/bpmn/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/_index.md rename to content/versions/v3.2.1/how-to/bpmn/_index.md diff --git a/content/versions/v4.0.0/how-to/bpmn/bpmn-elements.md b/content/versions/v3.2.1/how-to/bpmn/bpmn-elements.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/bpmn-elements.md rename to content/versions/v3.2.1/how-to/bpmn/bpmn-elements.md diff --git a/content/versions/v4.0.0/how-to/bpmn/create-workflow.md b/content/versions/v3.2.1/how-to/bpmn/create-workflow.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/create-workflow.md rename to content/versions/v3.2.1/how-to/bpmn/create-workflow.md diff --git a/content/versions/v4.0.0/how-to/bpmn/debug-workflows.md b/content/versions/v3.2.1/how-to/bpmn/debug-workflows.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/debug-workflows.md rename to content/versions/v3.2.1/how-to/bpmn/debug-workflows.md diff --git a/content/versions/v4.0.0/how-to/bpmn/learning-resources.md b/content/versions/v3.2.1/how-to/bpmn/learning-resources.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/learning-resources.md rename to content/versions/v3.2.1/how-to/bpmn/learning-resources.md diff --git a/content/versions/v4.0.0/how-to/bpmn/naming-conventions.md b/content/versions/v3.2.1/how-to/bpmn/naming-conventions.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/naming-conventions.md rename to content/versions/v3.2.1/how-to/bpmn/naming-conventions.md diff --git a/content/versions/v4.0.0/how-to/bpmn/screenshot-rhize-flamegraph-json.png b/content/versions/v3.2.1/how-to/bpmn/screenshot-rhize-flamegraph-json.png similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/screenshot-rhize-flamegraph-json.png rename to content/versions/v3.2.1/how-to/bpmn/screenshot-rhize-flamegraph-json.png diff --git a/content/versions/v4.0.0/how-to/bpmn/trigger-workflows.md b/content/versions/v3.2.1/how-to/bpmn/trigger-workflows.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/trigger-workflows.md rename to content/versions/v3.2.1/how-to/bpmn/trigger-workflows.md diff --git a/content/versions/v4.0.0/how-to/bpmn/tune-performance.md b/content/versions/v3.2.1/how-to/bpmn/tune-performance.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/tune-performance.md rename to content/versions/v3.2.1/how-to/bpmn/tune-performance.md diff --git a/content/versions/v4.0.0/how-to/bpmn/use-jsonata.md b/content/versions/v3.2.1/how-to/bpmn/use-jsonata.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/use-jsonata.md rename to content/versions/v3.2.1/how-to/bpmn/use-jsonata.md diff --git a/content/versions/v4.0.0/how-to/bpmn/variables.md b/content/versions/v3.2.1/how-to/bpmn/variables.md similarity index 100% rename from content/versions/v4.0.0/how-to/bpmn/variables.md rename to content/versions/v3.2.1/how-to/bpmn/variables.md diff --git a/content/versions/v4.0.0/how-to/gql/_index.md b/content/versions/v3.2.1/how-to/gql/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/_index.md rename to content/versions/v3.2.1/how-to/gql/_index.md diff --git a/content/versions/v4.0.0/how-to/gql/call-the-graphql-api.md b/content/versions/v3.2.1/how-to/gql/call-the-graphql-api.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/call-the-graphql-api.md rename to content/versions/v3.2.1/how-to/gql/call-the-graphql-api.md diff --git a/content/versions/v4.0.0/how-to/gql/default.md b/content/versions/v3.2.1/how-to/gql/default.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/default.md rename to content/versions/v3.2.1/how-to/gql/default.md diff --git a/content/versions/v4.0.0/how-to/gql/directives.md b/content/versions/v3.2.1/how-to/gql/directives.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/directives.md rename to content/versions/v3.2.1/how-to/gql/directives.md diff --git a/content/versions/v4.0.0/how-to/gql/filter.md b/content/versions/v3.2.1/how-to/gql/filter.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/filter.md rename to content/versions/v3.2.1/how-to/gql/filter.md diff --git a/content/versions/v4.0.0/how-to/gql/generate.md b/content/versions/v3.2.1/how-to/gql/generate.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/generate.md rename to content/versions/v3.2.1/how-to/gql/generate.md diff --git a/content/versions/v4.0.0/how-to/gql/mutate.md b/content/versions/v3.2.1/how-to/gql/mutate.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/mutate.md rename to content/versions/v3.2.1/how-to/gql/mutate.md diff --git a/content/versions/v4.0.0/how-to/gql/query.md b/content/versions/v3.2.1/how-to/gql/query.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/query.md rename to content/versions/v3.2.1/how-to/gql/query.md diff --git a/content/versions/v4.0.0/how-to/gql/subscribe.md b/content/versions/v3.2.1/how-to/gql/subscribe.md similarity index 100% rename from content/versions/v4.0.0/how-to/gql/subscribe.md rename to content/versions/v3.2.1/how-to/gql/subscribe.md diff --git a/content/versions/v4.0.0/how-to/kpi-service/_index.md b/content/versions/v3.2.1/how-to/kpi-service/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/kpi-service/_index.md rename to content/versions/v3.2.1/how-to/kpi-service/_index.md diff --git a/content/versions/v4.0.0/how-to/kpi-service/about-kpi-service.md b/content/versions/v3.2.1/how-to/kpi-service/about-kpi-service.md similarity index 100% rename from content/versions/v4.0.0/how-to/kpi-service/about-kpi-service.md rename to content/versions/v3.2.1/how-to/kpi-service/about-kpi-service.md diff --git a/content/versions/v4.0.0/how-to/kpi-service/configure-kpi-service.md b/content/versions/v3.2.1/how-to/kpi-service/configure-kpi-service.md similarity index 100% rename from content/versions/v4.0.0/how-to/kpi-service/configure-kpi-service.md rename to content/versions/v3.2.1/how-to/kpi-service/configure-kpi-service.md diff --git a/content/versions/v4.0.0/how-to/kpi-service/query-kpi-service.md b/content/versions/v3.2.1/how-to/kpi-service/query-kpi-service.md similarity index 100% rename from content/versions/v4.0.0/how-to/kpi-service/query-kpi-service.md rename to content/versions/v3.2.1/how-to/kpi-service/query-kpi-service.md diff --git a/content/versions/v4.0.0/how-to/model/_index.md b/content/versions/v3.2.1/how-to/model/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/model/_index.md rename to content/versions/v3.2.1/how-to/model/_index.md diff --git a/content/versions/v4.0.0/how-to/model/create-objects-ui.md b/content/versions/v3.2.1/how-to/model/create-objects-ui.md similarity index 100% rename from content/versions/v4.0.0/how-to/model/create-objects-ui.md rename to content/versions/v3.2.1/how-to/model/create-objects-ui.md diff --git a/content/versions/v4.0.0/how-to/model/master-definitions.md b/content/versions/v3.2.1/how-to/model/master-definitions.md similarity index 99% rename from content/versions/v4.0.0/how-to/model/master-definitions.md rename to content/versions/v3.2.1/how-to/model/master-definitions.md index ee24f6acf..a109a889f 100644 --- a/content/versions/v4.0.0/how-to/model/master-definitions.md +++ b/content/versions/v3.2.1/how-to/model/master-definitions.md @@ -16,7 +16,7 @@ All these models are based on the ISA-95 standard, mostly from [Part 2](https:// {{< callout type="info" >}} - For an introduction to the language of ISA-95, read [How to speak ISA-95](/isa-95/how-to-speak-isa-95) - For visual examples of how some of these models relate, -look at our page of [ISA-95 Diagrams]({{< relref "../../isa-95/isa-95-diagrams" >}}). +look at our page of [ISA-95 Diagrams]({{< relref "/isa-95/isa-95-diagrams" >}}). {{< /callout >}} ## Global object fields diff --git a/content/versions/v4.0.0/how-to/publish-subscribe/_index.md b/content/versions/v3.2.1/how-to/publish-subscribe/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/publish-subscribe/_index.md rename to content/versions/v3.2.1/how-to/publish-subscribe/_index.md diff --git a/content/versions/v4.0.0/how-to/publish-subscribe/connect-datasource.md b/content/versions/v3.2.1/how-to/publish-subscribe/connect-datasource.md similarity index 100% rename from content/versions/v4.0.0/how-to/publish-subscribe/connect-datasource.md rename to content/versions/v3.2.1/how-to/publish-subscribe/connect-datasource.md diff --git a/content/versions/v4.0.0/how-to/publish-subscribe/create-equipment-class-rule.md b/content/versions/v3.2.1/how-to/publish-subscribe/create-equipment-class-rule.md similarity index 100% rename from content/versions/v4.0.0/how-to/publish-subscribe/create-equipment-class-rule.md rename to content/versions/v3.2.1/how-to/publish-subscribe/create-equipment-class-rule.md diff --git a/content/versions/v4.0.0/how-to/publish-subscribe/screenshot-rhize-rules-engine.png b/content/versions/v3.2.1/how-to/publish-subscribe/screenshot-rhize-rules-engine.png similarity index 100% rename from content/versions/v4.0.0/how-to/publish-subscribe/screenshot-rhize-rules-engine.png rename to content/versions/v3.2.1/how-to/publish-subscribe/screenshot-rhize-rules-engine.png diff --git a/content/versions/v4.0.0/how-to/publish-subscribe/track-changes.md b/content/versions/v3.2.1/how-to/publish-subscribe/track-changes.md similarity index 100% rename from content/versions/v4.0.0/how-to/publish-subscribe/track-changes.md rename to content/versions/v3.2.1/how-to/publish-subscribe/track-changes.md diff --git a/content/versions/v4.0.0/how-to/work-calendars/_index.md b/content/versions/v3.2.1/how-to/work-calendars/_index.md similarity index 100% rename from content/versions/v4.0.0/how-to/work-calendars/_index.md rename to content/versions/v3.2.1/how-to/work-calendars/_index.md diff --git a/content/versions/v4.0.0/how-to/work-calendars/about-calendars-and-overrides.md b/content/versions/v3.2.1/how-to/work-calendars/about-calendars-and-overrides.md similarity index 100% rename from content/versions/v4.0.0/how-to/work-calendars/about-calendars-and-overrides.md rename to content/versions/v3.2.1/how-to/work-calendars/about-calendars-and-overrides.md diff --git a/content/versions/v4.0.0/how-to/work-calendars/create-work-calendar.md b/content/versions/v3.2.1/how-to/work-calendars/create-work-calendar.md similarity index 100% rename from content/versions/v4.0.0/how-to/work-calendars/create-work-calendar.md rename to content/versions/v3.2.1/how-to/work-calendars/create-work-calendar.md diff --git a/content/versions/v4.0.0/reference/_index.md b/content/versions/v3.2.1/reference/_index.md similarity index 100% rename from content/versions/v4.0.0/reference/_index.md rename to content/versions/v3.2.1/reference/_index.md diff --git a/content/versions/v4.0.0/reference/default-ports.md b/content/versions/v3.2.1/reference/default-ports.md similarity index 100% rename from content/versions/v4.0.0/reference/default-ports.md rename to content/versions/v3.2.1/reference/default-ports.md diff --git a/content/versions/v4.0.0/reference/glossary.md b/content/versions/v3.2.1/reference/glossary.md similarity index 100% rename from content/versions/v4.0.0/reference/glossary.md rename to content/versions/v3.2.1/reference/glossary.md diff --git a/content/versions/v4.0.0/reference/gql-types.md b/content/versions/v3.2.1/reference/gql-types.md similarity index 100% rename from content/versions/v4.0.0/reference/gql-types.md rename to content/versions/v3.2.1/reference/gql-types.md diff --git a/content/versions/v4.0.0/reference/image.png b/content/versions/v3.2.1/reference/image.png similarity index 100% rename from content/versions/v4.0.0/reference/image.png rename to content/versions/v3.2.1/reference/image.png diff --git a/content/versions/v4.0.0/reference/nats-configuration.md b/content/versions/v3.2.1/reference/nats-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/nats-configuration.md rename to content/versions/v3.2.1/reference/nats-configuration.md diff --git a/content/versions/v4.0.0/reference/observability-metrics.md b/content/versions/v3.2.1/reference/observability-metrics.md similarity index 100% rename from content/versions/v4.0.0/reference/observability-metrics.md rename to content/versions/v3.2.1/reference/observability-metrics.md diff --git a/content/versions/v4.0.0/reference/service-config/_index.md b/content/versions/v3.2.1/reference/service-config/_index.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/_index.md rename to content/versions/v3.2.1/reference/service-config/_index.md diff --git a/content/versions/v4.0.0/reference/service-config/adminUI-configuration.md b/content/versions/v3.2.1/reference/service-config/adminUI-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/adminUI-configuration.md rename to content/versions/v3.2.1/reference/service-config/adminUI-configuration.md diff --git a/content/versions/v4.0.0/reference/service-config/agent-configuration.md b/content/versions/v3.2.1/reference/service-config/agent-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/agent-configuration.md rename to content/versions/v3.2.1/reference/service-config/agent-configuration.md diff --git a/content/versions/v4.0.0/reference/service-config/audit-configuration.md b/content/versions/v3.2.1/reference/service-config/audit-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/audit-configuration.md rename to content/versions/v3.2.1/reference/service-config/audit-configuration.md diff --git a/content/versions/v4.0.0/reference/service-config/bpmn-configuration.md b/content/versions/v3.2.1/reference/service-config/bpmn-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/bpmn-configuration.md rename to content/versions/v3.2.1/reference/service-config/bpmn-configuration.md diff --git a/content/versions/v4.0.0/reference/service-config/calendar-configuration.md b/content/versions/v3.2.1/reference/service-config/calendar-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/calendar-configuration.md rename to content/versions/v3.2.1/reference/service-config/calendar-configuration.md diff --git a/content/versions/v4.0.0/reference/service-config/core-configuration.md b/content/versions/v3.2.1/reference/service-config/core-configuration.md similarity index 100% rename from content/versions/v4.0.0/reference/service-config/core-configuration.md rename to content/versions/v3.2.1/reference/service-config/core-configuration.md diff --git a/content/versions/v4.0.0/releases/3-0-1.md b/content/versions/v3.2.1/releases/3-0-1.md similarity index 97% rename from content/versions/v4.0.0/releases/3-0-1.md rename to content/versions/v3.2.1/releases/3-0-1.md index ca27a7b14..3afad9755 100644 --- a/content/versions/v4.0.0/releases/3-0-1.md +++ b/content/versions/v3.2.1/releases/3-0-1.md @@ -46,7 +46,7 @@ The following sections document the changes this release brings to each service. - Work calendar execution is now based on Hierarchy Scope. **Change** -- Reduce number of retries in BPMN recovery, speeding up response times when node does not exist. +- Reduce number of retries in [BPMN recovery]({{< relref "../deploy/maintain/bpmn-nodes/" >}}), speeding up response times when node does not exist. From the user's perspective, the delay was particularly notable on [API BPMN triggers]({{< relref "../how-to/bpmn/trigger-workflows/#start-a-workflow-from-an-api" >}}) when the specified workflow did not exist. **Fixes** diff --git a/content/versions/v4.0.0/releases/3-0-3.md b/content/versions/v3.2.1/releases/3-0-3.md similarity index 100% rename from content/versions/v4.0.0/releases/3-0-3.md rename to content/versions/v3.2.1/releases/3-0-3.md diff --git a/content/versions/v4.0.0/releases/3-0.md b/content/versions/v3.2.1/releases/3-0.md similarity index 96% rename from content/versions/v4.0.0/releases/3-0.md rename to content/versions/v3.2.1/releases/3-0.md index 7045fda7e..ccebe5897 100644 --- a/content/versions/v4.0.0/releases/3-0.md +++ b/content/versions/v3.2.1/releases/3-0.md @@ -105,7 +105,7 @@ As such, Rhize is designed to conform to your operation's IT and manufacturing p Rhize runs on your IT infrastructure. The data model itself is based on a widely recognized standard, ISA-95. -Your teams control its security and access policies, with authentication provided through [OpenID Connect]({{< relref "../explanations/about-openidconnect.md" >}}). +Your teams control its security and access policies, with authentication provided through OpenID. ### High availability and reliability @@ -149,8 +149,4 @@ The following changelogs document the features, fixes, and refactoring that went - [3.0.0rc06]({{< relref "changelog/3-0-0rc06/" >}}) - [3.0.0rc05]({{< relref "changelog/3-0-0rc05/" >}}) -## Read more -- [Get started]({{< relref "../get-started" >}}) introduces Rhize's application and architecture. -- [Manufacturing data hub]({{< relref "../explanations" >}}) explains why Rhize chose its design. -- [Use cases]({{< relref "../use-cases" >}}) explains ways customers use Rhize. diff --git a/content/versions/v4.0.0/releases/3-1-0.md b/content/versions/v3.2.1/releases/3-1-0.md similarity index 100% rename from content/versions/v4.0.0/releases/3-1-0.md rename to content/versions/v3.2.1/releases/3-1-0.md diff --git a/content/versions/v4.0.0/releases/3-2-0.md b/content/versions/v3.2.1/releases/3-2-0.md similarity index 100% rename from content/versions/v4.0.0/releases/3-2-0.md rename to content/versions/v3.2.1/releases/3-2-0.md diff --git a/content/versions/v4.0.0/releases/3-2-1.md b/content/versions/v3.2.1/releases/3-2-1.md similarity index 100% rename from content/versions/v4.0.0/releases/3-2-1.md rename to content/versions/v3.2.1/releases/3-2-1.md diff --git a/content/versions/v4.0.0/releases/_index.md b/content/versions/v3.2.1/releases/_index.md similarity index 100% rename from content/versions/v4.0.0/releases/_index.md rename to content/versions/v3.2.1/releases/_index.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0.md b/content/versions/v3.2.1/releases/changelog/3-0-0.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0.md rename to content/versions/v3.2.1/releases/changelog/3-0-0.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0rc05.md b/content/versions/v3.2.1/releases/changelog/3-0-0rc05.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0rc05.md rename to content/versions/v3.2.1/releases/changelog/3-0-0rc05.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0rc06.md b/content/versions/v3.2.1/releases/changelog/3-0-0rc06.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0rc06.md rename to content/versions/v3.2.1/releases/changelog/3-0-0rc06.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0rc07.md b/content/versions/v3.2.1/releases/changelog/3-0-0rc07.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0rc07.md rename to content/versions/v3.2.1/releases/changelog/3-0-0rc07.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0rc08.md b/content/versions/v3.2.1/releases/changelog/3-0-0rc08.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0rc08.md rename to content/versions/v3.2.1/releases/changelog/3-0-0rc08.md diff --git a/content/versions/v4.0.0/releases/changelog/3-0-0rc09.md b/content/versions/v3.2.1/releases/changelog/3-0-0rc09.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/3-0-0rc09.md rename to content/versions/v3.2.1/releases/changelog/3-0-0rc09.md diff --git a/content/versions/v4.0.0/releases/changelog/_index.md b/content/versions/v3.2.1/releases/changelog/_index.md similarity index 100% rename from content/versions/v4.0.0/releases/changelog/_index.md rename to content/versions/v3.2.1/releases/changelog/_index.md diff --git a/content/versions/v4.0.0/use-cases/_index.md b/content/versions/v3.2.1/use-cases/_index.md similarity index 100% rename from content/versions/v4.0.0/use-cases/_index.md rename to content/versions/v3.2.1/use-cases/_index.md diff --git a/content/versions/v4.0.0/use-cases/calculate-oee.md b/content/versions/v3.2.1/use-cases/calculate-oee.md similarity index 100% rename from content/versions/v4.0.0/use-cases/calculate-oee.md rename to content/versions/v3.2.1/use-cases/calculate-oee.md diff --git a/content/versions/v4.0.0/use-cases/data-collection-ebr.md b/content/versions/v3.2.1/use-cases/data-collection-ebr.md similarity index 100% rename from content/versions/v4.0.0/use-cases/data-collection-ebr.md rename to content/versions/v3.2.1/use-cases/data-collection-ebr.md diff --git a/content/versions/v4.0.0/use-cases/ebr.md b/content/versions/v3.2.1/use-cases/ebr.md similarity index 100% rename from content/versions/v4.0.0/use-cases/ebr.md rename to content/versions/v3.2.1/use-cases/ebr.md diff --git a/content/versions/v4.0.0/use-cases/genealogy.md b/content/versions/v3.2.1/use-cases/genealogy.md similarity index 99% rename from content/versions/v4.0.0/use-cases/genealogy.md rename to content/versions/v3.2.1/use-cases/genealogy.md index 1f09b308b..415d08ab4 100644 --- a/content/versions/v4.0.0/use-cases/genealogy.md +++ b/content/versions/v3.2.1/use-cases/genealogy.md @@ -218,7 +218,7 @@ For an idea of how a more complete query would look, refer to the [Examples](#ex {{< callout >}} :memo: For a more complete introduction to ISA-95 and its terminology, -read [How to speak ISA-95]({{< relref "../isa-95/how-to-speak-isa-95" >}}). +read [How to speak ISA-95]({{< relref "/isa-95/how-to-speak-isa-95" >}}). {{< /callout >}} In ISA-95 terminology, the lineage of each material is expressed through the following entities: diff --git a/content/versions/v4.0.0/use-cases/overview.md b/content/versions/v3.2.1/use-cases/overview.md similarity index 100% rename from content/versions/v4.0.0/use-cases/overview.md rename to content/versions/v3.2.1/use-cases/overview.md diff --git a/content/versions/v4.0.0/deploy/install/services.md b/content/versions/v4.0.0/deploy/install/services.md deleted file mode 100644 index ab1729a04..000000000 --- a/content/versions/v4.0.0/deploy/install/services.md +++ /dev/null @@ -1,513 +0,0 @@ ---- -title: Install Rhize services -description: >- - Instructions to install services in the Rhize Kubernetes cluster. -weight: 100 -categories: "how-to" ---- - -The final installation step is to install the Rhize services in your Kubernetes cluster. - -## Prerequisites - -This topic assumes you have done the following: -- [Set up Kubernetes]({{< relref "setup-kubernetes" >}}) and [Configured Keycloak]({{< relref "keycloak" >}}). All the prerequisites for those topics apply here. -- Configured load balancing for the following DNS records: - - {{< reusable/default-urls >}} - - _Note that `rhize-` is only the recommended prefix of the subdomain. Your organization may use something else._ - - -### Overrides - -Each service is installed through a Helm YAML file. -For some of these services, you might need to edit this file to add credential information and modify defaults. - -Common values that are changed include: -- URLs and URL links -- The number of replicas running for each pod -- Ingress values for services exposed on the internet - -## Get client secrets - -Client secrets are necessary for Rhize services to authenticate with Keycloak. These secrets are stored with Kubernetes secrets. - -1. Go to Keycloak and get the secrets for each client you've created. - -1. Create Kubernetes secrets for each service. You can either create a secret file, or pass raw data from the command line. - - {{< callout type="caution" >}} - How you create Kubernetes secrets **depends on your implementation details and security procedures.** - For guidance, refer to the official Kubernetes topic, [Managing Secrets using `kubectl`](https://kubernetes.io/docs/tasks/configmap-secret/managing-secret-using-kubectl/). - {{< /callout >}} - - With raw data, the command might look something like this: - - ```bash - kubectl create secret generic {{< param application_name >}}-client-secrets \ - -n {{< param application_name >}} \ - --from-literal=dashboard=G4hoxIL37F5S9DQgeDYGQejcJ6oJhOPA \ - --from-literal={{< param application_name >}}Workflow=GTy1x64U0IHAUTWizugEAnN47a9kWgX8 \ - --from-literal={{< param application_name >}}ISA95=Yvtx1tZWCPFayvDCzHTTInEz9gnuLyLc \ - --from-literal={{< param application_name >}}Baas=KYbMHlRLhXwiDNFuDCl3qtPj1cNdeMSl \ - --from-literal={{< param application_name >}}UI=54yUQqmvgcxoKPaIbPZTQGlEs8Xu2qH0 - ``` - -1. Create secrets for login passwords. Each service with its own user in Keycloak can have its password supplied through Kubernetes secrets. - - As you install services through Helm, their respective YAML files reference these secrets. - -## Add the Rhize Helm Chart Repository - -You must add the helm chart repository for Rhize. - -1. Add the Helm Chart Repository - - ```bash - helm repo add {{< param application_name >}} https://gitlab.com/api/v4/projects/42214456/packages/helm/stable - helm repo update - ``` - -## Install and add roles for the DB {#db} - -You must install the {{< param db >}} database service first. -You also need to configure the {{< param db >}} service to have roles in Keycloak. - -If enabling the Audit Trail, also the include the configuration in [Enable change data capture](#enable-change-data-capture). - -If you need Row Level Access Control, [configure your scope map]({{< relref "row-level-access-control.md" >}}). - -1. Modify the DB Helm file with your code editor. Edit any necessary overrides. - - -1. Use Helm to install the database: - - ```bash - helm install -f baas.yaml {{< param application_name >}}-baas {{< param application_name >}}/baas -n {{< param application_name >}} - ``` - - To confirm it works, run the following command: - - ```bash - kubectl get pods - ``` - - All statuses should be `RUNNING`. - -1. Return to the Keycloak UI and add all `{{< param application_name >}}` roles to the admin group. - -1. Proxy the `http:8080` port on `{{< param application_name >}}-baas-dgraph-alpha`. - - ```bash - kubectl port-forward -n {{< param application_name >}} pod/baas-baas-alpha-0 8080:8080 - ``` - -1. Get a token using the credentials. With `curl`, it looks like this: - - ```bash - curl --location --request POST '/realms/{{< param application_name >}}/protocol/openid-connect/token' \ - --header 'Content-Type: application/x-www-form-urlencoded' \ - --data-urlencode 'grant_type=password' \ - --data-urlencode 'username=' \ - --data-urlencode 'password=' \ - --data-urlencode 'client_id={{< param application_name >}}Baas' \ - --data-urlencode 'client_secret=' - ``` - -1. Post the schema: - - ```bash - curl --location --request POST '/admin/schema' \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/octet-stream' \ - --data-binary '@' - ``` - - This creates more roles. - -1. Go to Keycloak UI and add all new {{< param db >}} roles to the `libreAdminGroup`. - -If the install is successful, the Keycloak UI is available on its -[default port]({{< relref "../../reference/default-ports" >}}). - - -## Install services - -Each of the following procedures installs a service through Helm. - -The syntax to install a Rhize service must have arguments for the following: -- The chart YAML file -- The packaged chart -- The path to the unpackaged chart or directory - -Additionally, use the `-n` flag to ensure that the install is scoped to the correct namespace: - - -``` -helm install \ - -f .yaml \ - \ - -n -``` - -For the full configuration options, -read the official [Helm `install` reference](https://helm.sh/docs/helm/helm_install/). - -### Redpanda - -Rhize uses Redpanda to buffer requests to Restate and connect to Agent. - -Install Redpanda with these steps: - -1. If the Redpanda repository doesn't exist, add it: - - ```bash - helm repo add redpanda https://charts.redpanda.com - helm repo update - ``` - -1. Modify the Redpanda Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install redpanda -f redpanda.yaml redpanda/redpanda -n {{< param application_name >}} - ``` - -### Alloy - -Install Alloy with these steps: - -1. If the Grafana repository doesn't exist, add it: - - ```bash - helm repo add grafana https://grafana.github.io/helm-charts - helm repo update - ``` - -1. Modify the Alloy Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install alloy -f alloy.yaml grafana/alloy -n {{< param application_name >}} - ``` - -### Grafana LGTM - -Grafana LGTM includes Tempo and Grafana. Rhize uses [Tempo](https://grafana.com/oss/tempo/) to trace BPMN processes. - -Install Grafana LGTM with these steps: - -1. Modify the Grafana LGTM Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install lgtm-distributed -f lgtm-distributed.yaml grafana/lgtm-distributed -n {{< param application_name >}} - ``` - -If the install is successful, the Grafana service is available on its -[default port]({{< relref "../../reference/default-ports" >}}). - -### Restate - -Rhize uses Restate as a platform for orchestrating other services. - -Install Restate with these steps: - -1. Modify the Restate Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install restate -f restate.yaml oci://ghcr.io/restatedev/restate-helm -n {{< param application_name >}} - ``` - -So that you can register certain services with Restate, proxy the Restate port: - - ```bash - kubectl port-forward -n {{< param application_name >}} pod/restate-0 9070:9070 - ``` - -### Workflow - -The Workflow service is the custom engine Rhize uses to process low-code workflows modeled in the Workflow UI. - -> **Requirements**: The Workflow service requires the [{{< param db >}}](#db), [Restate](#restate), and [Tempo](#tempo) services. - -Install Workflow with these steps: - -1. Modify the Workflow Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install workflow -f workflow.yaml {{< param application_name >}}/workflow -n {{< param application_name >}} - ``` - -1. When the Workflow service starts, it should register with Restate. Verify this with: - - ```bash - curl localhost:9070/deployments | jq '.deployments[].uri' - ``` - - This will show the URL of each registered service. If Workflow's URL is not present, register it with: - - ```bash - curl --location 'http://localhost:9070/deployments' \ - --header 'Content-Type: application/json' \ - --data '{"uri":"http://workflow.{{< param application_name >}}.svc.cluster.local:29080", "force":true}' - ``` - -### Typescript Host Service - -Install Typescript Host Service with these steps: - -1. Modify the Typescript Host Service Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install typescript-host-service -f typescript-host-service.yaml {{< param application_name >}}/typescript-host-service -n {{< param application_name >}} - ``` - -1. When the Typescript Host Service starts, it should register with Restate. Verify this with: - - ```bash - curl localhost:9070/deployments | jq '.deployments[].uri' - ``` - - This will show the URL of each registered service. If Typescript Host Service's URL is not present, register it with: - - ```bash - curl --location 'http://localhost:9070/deployments' \ - --header 'Content-Type: application/json' \ - --data '{"uri":"http://typescript-host-service.{{< param application_name >}}.svc.cluster.local:9081", "force":true}' - ``` - -### QuestDB - -QuestDB is used by Rhize to store timeseries data, however it can be substitude for another historian. - -Install QuestDB with these steps: - -1. If it doesn't exist, add the QuestDB repository: - - ```bash - helm repo add questdb https://helm.questdb.io/ - helm repo update - ``` - -1. Modify the QuestDB Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install questdb -f questdb.yaml questdb/questdb -n {{< param application_name >}} - ``` - -### ISA-95 - -Install ISA-95 with these steps: - -1. Modify the ISA-95 Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install isa95 -f isa95.yaml {{< param application_name >}}/isa95 -n {{< param application_name >}} - ``` - -1. When the ISA-95 service starts, it should register with Restate. Verify this with: - - ```bash - curl localhost:9070/deployments | jq '.deployments[].uri' - ``` - - This will show the URL of each registered service. If ISA-95's URL is not present, register it with: - - ```bash - curl --location 'http://localhost:9070/deployments' \ - --header 'Content-Type: application/json' \ - --data '{"uri":"http://isa95.{{< param application_name >}}.svc.cluster.local:29080", "force":true}' - ``` - -## Install Admin UI - -The Rhize agent bridges your plant processes with the Rhize data hub. - -The Admin UI is the graphical frontend to [handle events]({{< relref "/how-to/bpmn" >}}) and [define work masters]({{< relref "/how-to/model" >}}). - -> **Requirements:** The Admin UI requires the [Workflow](#workflow) services. - -After installing all other services, install the UI with these steps: - -1. Modify the UI Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install admin-ui -f admin-ui.yaml {{< param application_name >}}/admin-ui -n {{< param application_name >}} - ``` - -If the install is successful, the UI is available on its -[default port]({{< relref "../../reference/default-ports" >}}). - -### Agent - -The Rhize agent bridges your plant processes with the Rhize data hub. -It collects data emitted from the plant and publishes it to the message broker. - -> **Requirements:** Agent requires the [Graph DB](#db), [Tempo](#tempo), Redpanda, and an event broker service to communicate with. - -Install Agent with these steps: - -1. Modify the Agent Helm overrides as needed. - -1. In the Rhize UI, add a Data Source for Agent to interact with: - - In the lefthand menu, open **Master Data > Data Sources > + Create Data Source**. - - Input a name for the Data Source. - - Add a Connection String and Create. - - Add any relevant Topics. - - Activate the Data Source. - -1. Install with Helm: - - ```bash - helm install agent -f agent.yaml {{< param application_name >}}/agent -n {{< param application_name >}} - ``` - -To verify that Agent is working, check the Redpanda UI. - -## Optional Services - -### Audit Trail - -The Rhize [Audit]({{< relref "/how-to/audit" >}}) service provides an audit trail for database changes. The Audit service uses PostgreSQL for storage. - -Install Audit with these steps: - -1. Modify the Audit trail Helm YAML file. It is *recommended* to change the PostgreSQL username and password values. - -1. Install with Helm: - - ```bash - helm install audit -f audit.yaml {{< param application_name >}}/audit -n {{< param application_name >}} - ``` - -1. Create partition tables in the PostgreSQL database: - - ```sql - create table public.audit_log_partition( like public.audit_log ); - select partman.create_parent( p_parent_table := 'public.audit_log', p_control := 'time', p_interval := '1 Month', p_template_table := 'public.audit_log_partition'); - ``` - -For details about maintaining the Audit trail, read [Archive the PostgresQL Audit trail]({{< relref "../maintain/audit/" >}}). - -#### Enable change data capture - -The Audit trail requires [change data capture (CDC)]({{< relref "../../how-to/publish-subscribe/track-changes" >}}) to function. To enable CDC in {{< param application_name >}} BAAS, include the following values for the Helm chart overrides: - -```yaml -alpha: - # Change Data Capture (CDC) - cdc: - # Enable - enabled: true - # If configured for security, configure in NATS url. For example `nats://username:password@nats:4222` - nats: nats://nats:4222 - # Adjust based on high-availability requirements and cluster size. - replicas: 1 -``` - -### KPI - -The Rhize KPI service is a GraphQL service which calcualtes ISO22400 KPIs using timseries tables. - -Install KPI with these steps: - -1. Modify the KPI Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install kpi -f kpi.yaml {{< param application_name >}}/kpi -n {{< param application_name >}} - ``` - -### Solace - -Solace is an event broker that can be used alongside Agent, though it can be substituted for any other event broker. - -1. Add the Solace Charts Helm repo. - - ```bash - helm repo add solacecharts https://solaceproducts.github.io/pubsubplus-kubernetes-helm-quickstart/helm-charts - helm repo update - ``` - -1. Modify the Solace Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install solace -f solace.yaml solacecharts/pubsubplus -n {{< param application_name >}} - ``` - -> [!NOTE] -> Solace can be installed in high availability by using `pubsubplus-ha` instead of `pubsubplus`. -> See detailed instructions on [github](https://github.com/SolaceProducts/pubsubplus-kubernetes-helm-quickstart). - -### Apollo Router - -While Rhize provides a built in GraphQL Playground using Apollo's Sandobx, [Apollo Router](https://www.apollographql.com/docs/router) can be installed to unite queries for different services in a single endpoint outside of Rhize's interface. - -> **Requirements:** Router requires the [GraphDB](#db) service. - -Install Router with these steps: - -1. Modify the Router Helm overrides as needed. - -1. Install with Helm: - - ```bash - helm install router -f router.yaml {{< param application_name >}}/router -n {{< param application_name >}} - ``` - -If the install is successful, the Router explorer is available on its [default port]({{< relref "../../reference/default-ports" >}}). - -## Optional: change service configuration - -The services installed in the previous step have many parameters that you can configure for your performance and deployment requirements. -Review the full list in the [Service configuration]({{< relref "../../reference/service-config" >}}) reference. - -## Troubleshoot - -For general Kubernetes issues, the [Kubernetes dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/) is great for troubleshooting, and you can configure it to be accessible through the browser. - -For particular problems, try these commands: - -- **Is my service running?** - - To check deployment status, use this command: - - ```bash - kubectl get deployments - ``` - - Look for the pod name and its status. - -- **Access service through browser** - - Some services are accessible through the browser. - To access them, visit local host on the service's [default port]({{< relref "../../reference/default-ports" >}}). - -- **I installed a service too early**. - If you installed a service too early, use Helm to uninstall: - - ```bash - helm uninstall {{< param db >}} - ``` - - Then perform the steps you need and reinstall when ready. diff --git a/content/versions/v4.0.0/explanations/_index.md b/content/versions/v4.0.0/explanations/_index.md deleted file mode 100644 index 44f7e38eb..000000000 --- a/content/versions/v4.0.0/explanations/_index.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Explanations -description: >- - These topics explain the concepts, architecture, and philosophy that underpin the design of Rhize. -identifier: explanations -weight: 500 -draft: false -cascade: - categories: ["explanations"] - icon: question-mark-circle ---- - - -The design of the Rhize Manufacturing Data Hub comes from decades of work in industrial automation. -Rhize is designed to scale to the largest organizations, integrate with legacy systems, and address the complex reality of manufacturing head on. -These to do this, these are our explicit design goals: - -{{< reusable/design-goals >}} - -These following topics explain the concepts, architecture, and philosophy that underpin the Rhize application: - - -{{< card-list >}} diff --git a/content/versions/v4.0.0/explanations/about-openidconnect.md b/content/versions/v4.0.0/explanations/about-openidconnect.md deleted file mode 100644 index c37c2d2ee..000000000 --- a/content/versions/v4.0.0/explanations/about-openidconnect.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: About OpenID connect -description: The Rhize GraphQL implementation uses OpenIDConnect for - Authentication and role-based access control. This section describes how to - set up Keycloak -weight: 999 -categories: ["concepts"] -db: libreBaas ---- - -Rhize uses [OpenIDConnect](https://openid.net/developers/how-connect-works/) to connect to a [Keycloak](https://www.keycloak.org/) server to authenticate users and manage Role-based access controls. - -Open ID Connect is a security architecture that uses JSON Web Tokens (JWTs) to access secured resources. -JWTs are issued by Keycloak. Users can also be managed in Keycloak. -Or you can manage users in other services such as LDAP, Google, Azure AD, Facebook, etc. - -The general authentication flow is as follows: -1. When a user accesses the user interface, the UI redirects to Keycloak. -1. Depending on how it is configured, Keycloak redirects to the authentication provider so that the user can log in. -1. If the user is successfully authenticated, Keycloak redirects back to the user interface with an authentication code in the URL parameters. -1. The UI calls a secure API to exchange the authentication code for a JWT. -1. The UI then uses that JWT to access secure APIs such as the Rhize GraphQL API. - -The Rhize DB, {{< param db >}}, has the public key from Keycloak, which can be used to verify the JWT. - -```mermaid -sequenceDiagram - actor User - participant UI as Web UI - participant Rhize as Rhize DB - participant KC as Keycloak - participant AP as AuthProvider - Rhize->>KC: Get Public Key - User->>UI: Log In - UI-->>KC: Redirect - KC-->>AP: Redirect - AP->>User: Credentials - AP-->>KC: Auth Result - KC-->>UI: Redirect with Code - UI->>KC: Exchange Code for Token - KC->>UI: Reply with id_token and access_token - UI->>Rhize: Access API with Bearer Token - Rhize->>Rhize: Verify Token with Public Key from Keycloak - -``` - diff --git a/content/versions/v4.0.0/explanations/manufacturing-data-hub.md b/content/versions/v4.0.0/explanations/manufacturing-data-hub.md deleted file mode 100644 index 31bd72534..000000000 --- a/content/versions/v4.0.0/explanations/manufacturing-data-hub.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -title: Manufacturing Data Hub -description: >- - What is a Manufacturing Data Hub? Why is it necessary? - How the design of Rhize meets the needs of modern manufacturing. -weight: 100 -draft: false -images: - - "/images/og/rhize-mdh-graphic.png" ---- - -This article explains the components of a _Manufacturing Data Hub_ (MDH) and why the system must have these particular components to meet the needs of large, modern manufacturing environments. - -In other words, this article explains why Rhize made the choices it did to become the world's first manufacturing data hub. -For introductory explanations about Rhize in particular, -read [What is Rhize?]({{< relref "../get-started/introduction" >}}) and [How Rhize works]({{< relref "../get-started/how-rhize-works" >}}). - -## What is an MDH? - -A manufacturing data hub is a system that collects all manufacturing events, stores them in a standard model, and has a programmable engine that runs user logic to receive, transform, and send messages across different devices in a manufacturing operation. -Since it comes with all the necessary backend components—message handling, logic, and storage—an MDH also serves as a backend for manufacturers to build custom MES and MOM applications. - - -{{< bigFigure -width="75%" -alt="simplified mdh" -src="/images/arch/diagram-rhize-simplified-mdh.png" ->}} - -### Components - -An MDH is not just a storage or message system. -It is a coherent system of interrelated parts and interfaces, whose components include: - -- A high-performance graph database with a standardized schema -- A data model based on manufacturing standards -- An API to interact with the data -- An agent that listens for tag changes from data sources -- A rules engine that monitors tag changes and triggers user workflows when conditions are met -- A message broker that communicates events to and from various systems -- A workflow engine that processes, transforms, and contextualizes tag and event data -- The IT infrastructure that this all runs on, which at a certain scale must be clustered. - -### Technical requirements - -Besides its components and features, Rhize is explicitly designed to meet the needs of manufacturing operations of any scale. -This goal requires a high standard of operational performance, robustness, and extensibility: - -- **Zero Downtime Architecture.** A data hub such as Rhize is used in mission-critical environments that run every hour of every day. Outages are unacceptable. Operators must be able to update every component of the system without taking it offline. -- **Secure.** Users must be able to securely access and integrate with the hub across applications in the enterprise. So the database requires native [OAuth2](https://datatracker.ietf.org/doc/html/rfc6749) security integration for seamless single-sign-on. -- **ACID-compliant.** The critical features of an MES require the guarantee of an [ACID](https://en.wikipedia.org/wiki/ACID) database. Consistency and availability must be maintained even as the system scales horizontally. -- **Headless operation.** Users must be able to use the data hub as a backend to run MES functions, using frameworks or low-code tools to build any frontend on top of these functions. This flexibility is how the MDH can adapt to any manufacturing process: Rhize provides the means to store, standardize, and handle information flows; users build on top of this backend to create the applications, workflows, and interfaces that make sense for their use cases. -- **Type-safe.** Uncontrolled schemas in messages become brittle at scale. Unlike a pure MQTT architecture, which does not check the schema of message payloads, the MDH must enforce that data has a standard structure at the moment that the data is written to the database. -- **Extensible but Standardized.** While the data hub is built on the ISA-95 standard, it must be able to extend to include customer-specific schemas. -- **Process orchestration.** The hub must be able to coordinate tasks handled by multiple systems concurrently and provide a way for users to automate and combine workflows. - - -## Why an MDH needs this design - -Rhize chose its components deliberately, after careful consideration and years of real-world experience. -The following sections describe how these components work together and how this design arose from the landscape of manufacturing automation. - -### Point-to-point reaches scaling issues - -In early efforts to digitize manufacturing, information often flows from _point to point_. -Each node in the system communicates directly with the other nodes that it sends data to or receives data from. -While this form of communication is initially simple to implement, it also tightly couples services. -As the system scales, the complexity of point-to-point communication increases non-linearly. With each node, the system becomes increasingly fragile and unobservable. - -For example, notice how many channels of communication are maintained in this stylized diagram of information -exchange between level-three and level-four systems in a point-to-point topology: - -{{< bigFigure -width="65%" -alt="Diagram simplifying flows depicted in part 1 of ISA-95" -src="/images/arch/diagram-rhize-l3-l4-information-flows.png" -caption="A simplified view of how information might exchange between level 3 and 4 systems in a point-to-point topology." ->}} - -### Pub/sub messaging decouples devices - -When point-to-point communication becomes too difficult to maintain, the _hub-and-spoke_ approach presents the logical next step. -In this topology, a central hub coordinates communication between nodes. - -Some systems achieve a hub and spoke through _polling_, -where each device sends a request to the hub at some interval to check whether resources changed. -However, considering the number of devices and volume of exchange in manufacturing, -polling can create a massive amount of unnecessary traffic. - -Instead of polling, _the publish-subscribe pattern_ can be a more efficient way to decouple communication. -Event producers _publish_ topics to a message broker, and the message broker sends the event to consumers that _subscribe_ to the particular topic. -With the proliferation of IoT devices and the popularity of the MQTT protocol, publish-subscribe messaging has gained widespread adoption in manufacturing. - -{{< bigFigure -width="65%" -alt="Diagram showing event producers and subscribers in decoupled pub-sub communication" -caption="Diagram showing event producers and subscribers in decoupled pub-sub communication" -src="/images/arch/diagram-rhize-pubsub-hubspoke.png" ->}} - - -While publish-subscribe patterns resolve issues of coupled communication and data accessibility, -they don't address how to make this data useful: -- How can users collect and organize the data for analysis? -- How can this data drive further automation? - -An operation with many data sources likely also has many different structures of its in-flight messages. -The MQTT format, for example, has no prescribed payload format: structured JSON and binary blobs are equally valid. -While such flexibility provides excellent convenience for producers, the lack of uniformity can make wider integration efforts convoluted and unmaintainable. - -The philosophy of a data hub is to address these problems without comprising flexibility. -So its central components, the database, schema, and message and event handlers, -can integrate disparate systems while providing a common, standardized storage for the data exchanged between these systems. - - -### A standard graph model provides context - -Every event, person, and object in a manufacturing system is inter-connected. -To adequately process incoming event data, manufacturers need to _contextualize_ it, where each event carries additional information about its context within the larger system. -This context is framed by the information _model_ that represents the system. - -For a coherent model of the system, manufacturers need to be able to store assets and event data according to a standardized schema. -To scale, this model needs to be suitably thorough and generic. -For any organization, it would be an enormous undertaking to write a bespoke model. -Fortunately, decades of collaboration have already generated a suitable standard: ISA-95. - -{{< bigFigure -width="65%" -alt="Diagram showing ISA-95 data model" -src="/images/arch/diagram-rhize-isa95-schema.png" ->}} - - -The ISA-95 standard provides a comprehensive data model for manufacturing. -As it happens, its object-oriented system of attributes and relations has an inherent graph structure. -This harmony of ISA-95 and graph structures makes a graph database a perfect foundation for the manufacturing data hub: -- The schema provides the complete model, suitable to any scale -- The graph database provides the structure that coheres with the inter-related reality of manufacturing - -However, while publish-subscribe messaging decouples communication, and the ISA-95 database provides a sensible way to contextualize the messages of this data, -the system still needs a bridge between the message stream and the long-term, standardized storage. -This gap reveals missing components: -- The system needs to structure raw message data in its ISA-95 representation. -- Users need a way to access the database and message flow to program their own applications. - -{{< bigFigure -width="65%" -alt="Diagram showing how an MDH is incomplete without a bridge between messages and storage" -caption="Without a bridge between messages and storage, an MDH is incomplete" -src="/images/arch/diagram-rhize-incomplete-mdh.png" ->}} - -### The rules engine creates events - -After the hub receives a message, it must evaluate whether the data is significant enough to constitute an event. -This is the function of the _rules engine_: it assesses message values for changes and then evaluates whether these values should be classified as significant _events_. - -{{< bigFigure -width="65%" -alt="Diagram showing how the rules engine turns topics into events." -src="/images/arch/diagram-rhize-rule-engine.png" -caption="The rules converts significant values into manufacturing events." ->}} - -Once the system receives an event, users then need a way to be able to process it. - -### A workflow engine makes the system responsive - -For true "ubiquitous automation" of manufacturing processes, an MDH must provide a way for users to write their own logic to handle events as they happen. -Thus, the hub needs a _workflow engine_ that can send messages, process data, and interact with the database in real-time. - -{{< bigFigure -width="70%" -alt="An example BPMN workflow that receives a job order, evaluates whether maintenance is needed, then stores the data in a standardized database" -caption="An example BPMN workflow that receives a job order, evaluates whether maintenance is needed, then stores the data in a standardized database" -src="/images/arch/diagram-rhize-bpmn-eda.png" ->}} - -The data hub also must be agnostic about the information it receives, so the event handler must have a way to transform incoming events and represent them in the database schema. -Without such transformation, the burden of ISA-95 standardization falls on the event producer. -This is both inconvenient for the user and more architecturally fragile: -a second place where transformation can happen is also a second point of failure. -As long as the producer and consumer can accept and receive the same encoding (for example, JSON), the data hub should be responsible for enforcing standardization. - -With components for data ingestion, processing, and standardized storage, the MDH has all the necessary functionality to serve as a knowledge graph, MES backend, and integrator of legacy systems. -However, this capability cannot be realized unless the system is usable for the widest range of people. - -### Sensible interfaces make it accessible - -For many who work in industrial automation, IT is part of a job, not a job in itself. -So, a well-designed manufacturing data hub should provide high-quality abstractions -and interfaces that minimize the need for thinking about IT systems (instead of manufacturing ones). - -GraphQL, with its single endpoint and precise controls, makes an ideal API interface for the MDH graph database. -Queries resemble the structure of the data itself, requiring no recursive joins or intermediary object-relation models. -GraphQL also pairs perfectly with a data model based on ISA-95, whose object model has a graph structure, itself a model of the interconnected reality of actual manufacturing. - -While GraphQL provides the API to query and transform the data, it cannot execute logic. -So, the rules engine should also provide a graphical interface to make event handling as accessible as possible. - -However, one final piece is missing: the system must be robust enough for the data-intensive world of manufacturing IT. - -### Distributed execution provides robustness - -The final factor is that the components of an MDH must run on distributed systems. -Large manufacturing operations can generate enormous volumes of data. -At some point, scaling vertically (with better hardware on single devices) is impossible. -Besides size constraints, single devices also create single points of failure. - -So, an MDH must scale horizontally, where different nodes share computation responsibilities, -and extra volumes add data replication. - -## Read more - -Our blog has some articles that define what a data hub is: - -- [What is a Manufacturing Data Hub?](https://rhize.com/blog/what-is-a-manufacturing-data-hub/) -- [Data hub vs. Data lake: the difference for manufacturers](https://rhize.com/blog/manufacturing-data-hub-vs-data-lake/) diff --git a/content/versions/v4.0.0/get-started/_index.md b/content/versions/v4.0.0/get-started/_index.md deleted file mode 100644 index fa20784cb..000000000 --- a/content/versions/v4.0.0/get-started/_index.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Get started" -weight: 1 -identifier: get-started -description: A collection of pages to introduce you to Rhize -cascade: - icon: "academic-cap" - ---- - -{{< card-list >}} - diff --git a/content/versions/v4.0.0/get-started/arch-overview.excalidraw b/content/versions/v4.0.0/get-started/arch-overview.excalidraw deleted file mode 100644 index 23fc77014..000000000 --- a/content/versions/v4.0.0/get-started/arch-overview.excalidraw +++ /dev/null @@ -1,10323 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 177, - "versionNonce": 1214071512, - "isDeleted": false, - "id": "nmQqysnmMFkXk1u9K0Wd4", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1003, - "y": 323, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ebfbee", - "width": 853, - "height": 831, - "seed": 33665499, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "Dy0BoTuUc1GtWWmiUiePa", - "type": "arrow" - } - ], - "updated": 1703077397462, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 216, - "versionNonce": 1764685480, - "isDeleted": false, - "id": "hBs1AR-Q_Wepzw5OWxDTX", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1060, - "y": 940, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 785, - "height": 118, - "seed": 527121531, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "BWHofv6wBCzVErNs0WvFf" - }, - { - "id": "JCQIbiZ1YAhj2ywRIZA7w", - "type": "arrow" - }, - { - "id": "NzUOjmCp9A-z7IspYG6IS", - "type": "arrow" - }, - { - "id": "SUzTbAbUdj3Ad2DLmZ6Yo", - "type": "arrow" - }, - { - "id": "6hEAqnwGecJRYDoIgXNyt", - "type": "arrow" - }, - { - "id": "Dy0BoTuUc1GtWWmiUiePa", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 169, - "versionNonce": 1046423512, - "isDeleted": false, - "id": "BWHofv6wBCzVErNs0WvFf", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1337.6999969482422, - "y": 965.4000000000001, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 229.60000610351562, - "height": 67.2, - "seed": 1062872667, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "Message broker\n(NATS)", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "hBs1AR-Q_Wepzw5OWxDTX", - "originalText": "Message broker\n(NATS)", - "lineHeight": 1.2, - "baseline": 61 - }, - { - "type": "rectangle", - "version": 404, - "versionNonce": 946463144, - "isDeleted": false, - "id": "QjAXk0eq9qciL21xR8klr", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 500, - "y": 1300, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 819, - "height": 220, - "seed": 12060149, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "Dy0BoTuUc1GtWWmiUiePa", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 393, - "versionNonce": 1155296472, - "isDeleted": false, - "id": "QpZEn0862fATDOKezUKBM", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 539.6666666666665, - "y": 1450.5333333333335, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 759.5999755859375, - "height": 43.199999999999996, - "seed": 1924552533, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 36, - "fontFamily": 3, - "text": "Operations data (telemetry and docs)", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Operations data (telemetry and docs)", - "lineHeight": 1.2, - "baseline": 35 - }, - { - "type": "rectangle", - "version": 286, - "versionNonce": 1460628648, - "isDeleted": false, - "id": "QNIR5iMK0xBlxtSl6pi8A", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 520, - "y": 1340, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 80, - "seed": 449421813, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 285, - "versionNonce": 1969820120, - "isDeleted": false, - "id": "hmY1NLBpuHwT4GhgDYJAY", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 559, - "y": 1377, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 49.20000076293945, - "height": 33.6, - "seed": 1874840731, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "ERP", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "ERP", - "lineHeight": 1.2, - "baseline": 27 - }, - { - "type": "rectangle", - "version": 300, - "versionNonce": 1053530024, - "isDeleted": false, - "id": "P9Rc0kdAOKraqARRDS4lq", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 680, - "y": 1340, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 80, - "seed": 1694530395, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 309, - "versionNonce": 387520216, - "isDeleted": false, - "id": "Fmz59FWV6LTS2c3ltRbGx", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 700, - "y": 1380, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 98.4000015258789, - "height": 33.6, - "seed": 1672370171, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "OPC UA", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "OPC UA", - "lineHeight": 1.2, - "baseline": 27 - }, - { - "type": "rectangle", - "version": 341, - "versionNonce": 1405772456, - "isDeleted": false, - "id": "2XVM0jfapOfUAQRpNMrnj", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 839.9999999999999, - "y": 1340, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 80, - "seed": 933341819, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 325, - "versionNonce": 1853914072, - "isDeleted": false, - "id": "4yYLOei7PQrwGuuJHW2q7", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 879.9999999999999, - "y": 1380, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 65.5999984741211, - "height": 33.6, - "seed": 614245147, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "MQTT", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "MQTT", - "lineHeight": 1.2, - "baseline": 27 - }, - { - "type": "rectangle", - "version": 319, - "versionNonce": 347590056, - "isDeleted": false, - "id": "EFf-xrdTLhzO9SN3vTNsm", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 999.9999999999999, - "y": 1340, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 80, - "seed": 2122876053, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 349, - "versionNonce": 229851352, - "isDeleted": false, - "id": "GAfdNj3tvY1BoiHFNGlBB", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1040, - "y": 1380, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 65.5999984741211, - "height": 33.6, - "seed": 2023041525, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "LIMS", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "LIMS", - "lineHeight": 1.2, - "baseline": 27 - }, - { - "type": "rectangle", - "version": 331, - "versionNonce": 1254086824, - "isDeleted": false, - "id": "EZ2dxa7YlYBxzlisuMxIM", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1160, - "y": 1340, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 80, - "seed": 1047907189, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 377, - "versionNonce": 608527832, - "isDeleted": false, - "id": "GFpntSB2l6vZiCHVVmnJa", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1200, - "y": 1380, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 49.20000076293945, - "height": 33.6, - "seed": 485922005, - "groupIds": [ - "ydVEdmxSStzllcnTWlAET" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "WMS", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "WMS", - "lineHeight": 1.2, - "baseline": 27 - }, - { - "type": "arrow", - "version": 1099, - "versionNonce": 965641128, - "isDeleted": false, - "id": "JCQIbiZ1YAhj2ywRIZA7w", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 1151.5319609830613, - "y": 826.6219574984165, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 0.08687748427564657, - "height": 101.1223761323838, - "seed": 1128216901, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": { - "elementId": "01jP5L_uql0cNdoJ0YLDE", - "gap": 6.62195749841635, - "focus": -0.07985464094212442 - }, - "endBinding": { - "elementId": "hBs1AR-Q_Wepzw5OWxDTX", - "gap": 12.25566636919973, - "focus": -0.7670758022560904 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -0.08687748427564657, - 101.1223761323838 - ] - ] - }, - { - "type": "rectangle", - "version": 355, - "versionNonce": 1330309848, - "isDeleted": false, - "id": "01jP5L_uql0cNdoJ0YLDE", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1076, - "y": 688, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 140, - "height": 132, - "seed": 2028063199, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "umQTCbsPmLNf-TLbnWKzr" - }, - { - "id": "JCQIbiZ1YAhj2ywRIZA7w", - "type": "arrow" - }, - { - "id": "avGQftH-6xWaiHIUAN7TM", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 362, - "versionNonce": 1330630312, - "isDeleted": false, - "id": "umQTCbsPmLNf-TLbnWKzr", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.599998474121, - "y": 703.6, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 114.80000305175781, - "height": 100.80000000000001, - "seed": 1928670527, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": " BPMN\nengine \n(CEP)", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "01jP5L_uql0cNdoJ0YLDE", - "originalText": " BPMN\nengine (CEP)", - "lineHeight": 1.2, - "baseline": 95 - }, - { - "type": "arrow", - "version": 1023, - "versionNonce": 1767362520, - "isDeleted": false, - "id": "NzUOjmCp9A-z7IspYG6IS", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1299.5653427876846, - "y": 833.8366647843086, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 1.9445299793619597, - "height": 94.12237613238392, - "seed": 1255572635, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": { - "elementId": "8Qo930v2IJgKIef8PzJ_3", - "focus": -0.09854225858871378, - "gap": 6.62195749841635 - }, - "endBinding": { - "elementId": "hBs1AR-Q_Wepzw5OWxDTX", - "focus": -0.3971027505723035, - "gap": 12.040959083307484 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -1.9445299793619597, - 94.12237613238392 - ] - ] - }, - { - "type": "rectangle", - "version": 362, - "versionNonce": 1420802472, - "isDeleted": false, - "id": "8Qo930v2IJgKIef8PzJ_3", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1223, - "y": 688.2147072858922, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 142, - "height": 139, - "seed": 1282488635, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "LQ4VuBguNE5Tq7LEva47l" - }, - { - "id": "NzUOjmCp9A-z7IspYG6IS", - "type": "arrow" - }, - { - "id": "kFd8ox0PSsU-MUz5OJA3e", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 343, - "versionNonce": 1518343384, - "isDeleted": false, - "id": "LQ4VuBguNE5Tq7LEva47l", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1228.400001525879, - "y": 724.1147072858922, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 131.1999969482422, - "height": 67.2, - "seed": 2114738651, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "Other\nservices", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "8Qo930v2IJgKIef8PzJ_3", - "originalText": "Other\nservices", - "lineHeight": 1.2, - "baseline": 61 - }, - { - "type": "rectangle", - "version": 164, - "versionNonce": 484066472, - "isDeleted": false, - "id": "XbTEznU_-hciqkoWpef1u", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1514, - "y": 587, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 163, - "height": 246, - "seed": 1542889813, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "SUzTbAbUdj3Ad2DLmZ6Yo", - "type": "arrow" - }, - { - "id": "Wg3t97YKu0hXFR7qivqQq", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 136, - "versionNonce": 1750579672, - "isDeleted": false, - "id": "6gm3IWWQP6drDVVlYloMK", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1516, - "y": 584, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 159, - "height": 48, - "seed": 2141490805, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [ - { - "id": "Wg3t97YKu0hXFR7qivqQq", - "type": "arrow" - } - ], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 86, - "versionNonce": 897281960, - "isDeleted": false, - "id": "YEDta8CmkAAEzx7mnJUTQ", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1564, - "y": 721, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 82, - "height": 67.2, - "seed": 374127957, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "Graph\nDB", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Graph\nDB", - "lineHeight": 1.2, - "baseline": 61 - }, - { - "type": "ellipse", - "version": 229, - "versionNonce": 99794648, - "isDeleted": false, - "id": "w0NUYW8rIvimxX1ynP7aV", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1567.5768451845186, - "y": 662.4345184518451, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 449842001, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 261, - "versionNonce": 381631144, - "isDeleted": false, - "id": "FXoqeCZ-f1pidw1gxzqNS", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1567.7458370837087, - "y": 697.5848334833483, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 1815378225, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 312, - "versionNonce": 602219480, - "isDeleted": false, - "id": "YkCXhSZgst2NL7t592bjU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1604.7550630063008, - "y": 662.772502250225, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 1452288785, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 355, - "versionNonce": 1397859752, - "isDeleted": false, - "id": "XdM9RMpXFcXa50QUSdo3v", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1604.417079207921, - "y": 697.4158415841584, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 1113235697, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 266, - "versionNonce": 4384984, - "isDeleted": false, - "id": "NlJ3ldww-tSzTy6IXkI6n", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1539.693181818182, - "y": 639.1136363636363, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 488331985, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 325, - "versionNonce": 1214165160, - "isDeleted": false, - "id": "JD7qJ4rZ9JqNcyPPRfcJQ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1637.0325157515754, - "y": 677.6437893789379, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 9.801530153015372, - "height": 9.801530153015372, - "seed": 929683633, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 250, - "versionNonce": 1990200792, - "isDeleted": false, - "id": "GvxFoC222MOuusTStqypV", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1548.3117686768678, - "y": 647.2252475247524, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 20.44801980198025, - "height": 16.899189918991937, - "seed": 1659738769, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 20.44801980198025, - 16.899189918991937 - ] - ] - }, - { - "type": "line", - "version": 245, - "versionNonce": 1301437352, - "isDeleted": false, - "id": "cXfrG_CbbkRAqF2TBoI6X", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1577.378375337534, - "y": 667.3352835283529, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 27.3766876687669, - "height": 0.16899189918989255, - "seed": 1348345969, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 27.3766876687669, - 0.16899189918989255 - ] - ] - }, - { - "type": "line", - "version": 244, - "versionNonce": 1343263448, - "isDeleted": false, - "id": "0rBLg_KJowxx8xGy6VoMY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1614.3876012601263, - "y": 669.025202520252, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 23.489873987398823, - "height": 10.646489648964918, - "seed": 763554385, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 23.489873987398823, - 10.646489648964918 - ] - ] - }, - { - "type": "line", - "version": 232, - "versionNonce": 1696114344, - "isDeleted": false, - "id": "_0IT1JLGrfRPOukHlrnzS", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1572.6466021602162, - "y": 672.2360486048605, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 0, - "height": 25.517776777677827, - "seed": 53704753, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 25.517776777677827 - ] - ] - }, - { - "type": "line", - "version": 234, - "versionNonce": 321419224, - "isDeleted": false, - "id": "_7ls_9CWXMHLaWKbDkIKg", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1577.378375337534, - "y": 702.9925742574259, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 27.20769576957705, - "height": 0.16899189918991367, - "seed": 1398229521, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 27.20769576957705, - 0.16899189918991367 - ] - ] - }, - { - "type": "line", - "version": 246, - "versionNonce": 1805488552, - "isDeleted": false, - "id": "5gCw2u-jBy5amSV8VoEwq", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1609.8248199819984, - "y": 672.2360486048605, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 0.1689918991899348, - "height": 25.68676867686776, - "seed": 1994776561, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397463, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0.1689918991899348, - 25.68676867686776 - ] - ] - }, - { - "type": "line", - "version": 254, - "versionNonce": 1409006808, - "isDeleted": false, - "id": "n8UBuUkmQ3rJtVJ-L67q9", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1639.7338658829135, - "y": 686.6203740328572, - "strokeColor": "#1e1e1e", - "backgroundColor": "#9775fa", - "width": 25.51525652197721, - "height": 14.006313635909795, - "seed": 1004976593, - "groupIds": [ - "ZvM7IH46azdb6c9CzIth9" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -25.51525652197721, - 14.006313635909795 - ] - ] - }, - { - "type": "rectangle", - "version": 326, - "versionNonce": 1213013160, - "isDeleted": false, - "id": "z1zWGySh9akh-gVPshUYx", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1679.166666666667, - "y": 676.3795180722891, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 102.12048192771084, - "height": 154.12048192771084, - "seed": 1694838577, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "8vWdUTWIJczxpSW_bkk-_" - }, - { - "id": "6hEAqnwGecJRYDoIgXNyt", - "type": "arrow" - }, - { - "id": "XauRwNq9LQL2SARU3wh_y", - "type": "arrow" - } - ], - "updated": 1703077397464, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 100, - "versionNonce": 69099992, - "isDeleted": false, - "id": "8vWdUTWIJczxpSW_bkk-_", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1695.093572516997, - "y": 705.4397590361446, - "strokeColor": "#1e1e1e", - "backgroundColor": "#2f9e44", - "width": 70.26667022705078, - "height": 96, - "seed": 1491193937, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "\nTime-\nseries\nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "z1zWGySh9akh-gVPshUYx", - "originalText": "\nTime-\nseries\nDB", - "lineHeight": 1.2, - "baseline": 92 - }, - { - "type": "ellipse", - "version": 255, - "versionNonce": 483608488, - "isDeleted": false, - "id": "f5MlM2EE9GTFL2NP10jvq", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1679.4196787148596, - "y": 675.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 99.61445783132531, - "height": 30.072289156626507, - "seed": 534389009, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 295, - "versionNonce": 1118070488, - "isDeleted": false, - "id": "fWXHS53yH1NNcjlqQBkgS", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1461.666666666667, - "y": 335.4, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffa94d", - "width": 358.70001220703125, - "height": 86.39999999999999, - "seed": 813733105, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "fontSize": 36, - "fontFamily": 3, - "text": "Rhize environment\n (K8s)", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Rhize environment\n (K8s)", - "lineHeight": 1.2, - "baseline": 78 - }, - { - "type": "arrow", - "version": 178, - "versionNonce": 1968968360, - "isDeleted": false, - "id": "SUzTbAbUdj3Ad2DLmZ6Yo", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1589.666666666667, - "y": 835, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffa94d", - "width": 2.33333333333303, - "height": 95, - "seed": 385051007, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "XbTEznU_-hciqkoWpef1u", - "focus": 0.10534072275151264, - "gap": 2 - }, - "endBinding": { - "elementId": "hBs1AR-Q_Wepzw5OWxDTX", - "focus": 0.3584085575214535, - "gap": 10 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 2.33333333333303, - 95 - ] - ] - }, - { - "type": "arrow", - "version": 177, - "versionNonce": 740412376, - "isDeleted": false, - "id": "6hEAqnwGecJRYDoIgXNyt", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1736.614024020199, - "y": 832.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffa94d", - "width": 0, - "height": 99, - "seed": 905519825, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "z1zWGySh9akh-gVPshUYx", - "focus": -0.12508982075109754, - "gap": 2 - }, - "endBinding": { - "elementId": "hBs1AR-Q_Wepzw5OWxDTX", - "focus": 0.7238573860387234, - "gap": 8.5 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0, - 99 - ] - ] - }, - { - "type": "rectangle", - "version": 153, - "versionNonce": 946139352, - "isDeleted": false, - "id": "wNTvL2ykeCyJnOX1ctQcC", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1176.666666666667, - "y": 404, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 474, - "height": 108, - "seed": 891911825, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "avGQftH-6xWaiHIUAN7TM", - "type": "arrow" - }, - { - "id": "kFd8ox0PSsU-MUz5OJA3e", - "type": "arrow" - }, - { - "id": "XauRwNq9LQL2SARU3wh_y", - "type": "arrow" - }, - { - "id": "Wg3t97YKu0hXFR7qivqQq", - "type": "arrow" - }, - { - "id": "3lWppf32GdRGyXJgulqyV", - "type": "arrow" - } - ], - "updated": 1703077488593, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 147, - "versionNonce": 715821272, - "isDeleted": false, - "id": "VB_6trTlhJNvS9aFAgbf9", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1340.666666666667, - "y": 423.2, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 164, - "height": 67.2, - "seed": 851541791, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "API router\n(GraphQL)", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "API router\n(GraphQL)", - "lineHeight": 1.2, - "baseline": 61 - }, - { - "type": "arrow", - "version": 192, - "versionNonce": 396724392, - "isDeleted": false, - "id": "avGQftH-6xWaiHIUAN7TM", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1227.666666666667, - "y": 529, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 52.16657069570215, - "height": 134, - "seed": 1626523775, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "wNTvL2ykeCyJnOX1ctQcC", - "focus": 0.4634627233518176, - "gap": 17 - }, - "endBinding": { - "elementId": "01jP5L_uql0cNdoJ0YLDE", - "gap": 25, - "focus": 0.2934959349593536 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -46, - 58 - ], - [ - -52.16657069570215, - 134 - ] - ] - }, - { - "type": "arrow", - "version": 116, - "versionNonce": 1171437016, - "isDeleted": false, - "id": "kFd8ox0PSsU-MUz5OJA3e", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1294.666666666667, - "y": 668, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 28, - "height": 138, - "seed": 1691458527, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "8Qo930v2IJgKIef8PzJ_3", - "focus": -0.006136020494092893, - "gap": 20.214707285892246 - }, - "endBinding": { - "elementId": "wNTvL2ykeCyJnOX1ctQcC", - "focus": 0.21667668871517337, - "gap": 18 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 1, - -81 - ], - [ - 28, - -138 - ] - ] - }, - { - "type": "arrow", - "version": 177, - "versionNonce": 1044263848, - "isDeleted": false, - "id": "XauRwNq9LQL2SARU3wh_y", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1592.666666666667, - "y": 525, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 144, - "height": 133, - "seed": 433881361, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "wNTvL2ykeCyJnOX1ctQcC", - "focus": 0.23769832565621116, - "gap": 13 - }, - "endBinding": { - "elementId": "z1zWGySh9akh-gVPshUYx", - "focus": 0.3565068000287827, - "gap": 18.379518072289102 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 126, - 29 - ], - [ - 144, - 133 - ] - ] - }, - { - "type": "arrow", - "version": 203, - "versionNonce": 1924020952, - "isDeleted": false, - "id": "Wg3t97YKu0hXFR7qivqQq", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1513.666666666667, - "y": 592, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 48, - "height": 73, - "seed": 322778815, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "6gm3IWWQP6drDVVlYloMK", - "focus": -0.1430735742491258, - "gap": 10.551476466510707 - }, - "endBinding": { - "elementId": "wNTvL2ykeCyJnOX1ctQcC", - "focus": -0.1998658618376928, - "gap": 7 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -44, - -11 - ], - [ - -48, - -73 - ] - ] - }, - { - "type": "arrow", - "version": 436, - "versionNonce": 42565288, - "isDeleted": false, - "id": "Dy0BoTuUc1GtWWmiUiePa", - "fillStyle": "cross-hatch", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 960, - "y": 1300, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 480, - "height": 240, - "seed": 1524393457, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397464, - "link": null, - "locked": false, - "startBinding": { - "elementId": "QjAXk0eq9qciL21xR8klr", - "focus": -0.11453320500481233, - "gap": 1 - }, - "endBinding": { - "elementId": "hBs1AR-Q_Wepzw5OWxDTX", - "focus": -0.0009117195029823363, - "gap": 2 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 80, - -80 - ], - [ - 446.66666666666697, - -82 - ], - [ - 480, - -240 - ] - ] - }, - { - "type": "rectangle", - "version": 263, - "versionNonce": 268733096, - "isDeleted": false, - "id": "j1lQfnnrkl7K6wFtYmYYb", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 480, - "y": -40, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 1017.9999999999999, - "height": 228, - "seed": 1787992881, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "3lWppf32GdRGyXJgulqyV", - "type": "arrow" - } - ], - "updated": 1703077494403, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 74, - "versionNonce": 1639583144, - "isDeleted": false, - "id": "LLOfh08Frmr40rSxaRXAV", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 844.3333333333329, - "y": -2.799999999999997, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 211, - "height": 43.199999999999996, - "seed": 299353873, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "fontSize": 36, - "fontFamily": 3, - "text": "Interfaces", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Interfaces", - "lineHeight": 1.2, - "baseline": 35 - }, - { - "type": "rectangle", - "version": 1053, - "versionNonce": 1031411880, - "isDeleted": false, - "id": "B69lECfuPuyF-MlMZxVCr", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 504.4775641025642, - "y": 48.307692307692406, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 1304613329, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "PFWMawg4MwqJVyxg_Ezit" - } - ], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1024, - "versionNonce": 1526776744, - "isDeleted": false, - "id": "PFWMawg4MwqJVyxg_Ezit", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 509.4775641025642, - "y": 56.4076923076924, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 65.4000015258789, - "height": 100.80000000000001, - "seed": 1568266577, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "\nBPMN\nUI", - "textAlign": "left", - "verticalAlign": "middle", - "containerId": "B69lECfuPuyF-MlMZxVCr", - "originalText": "\nBPMN\nUI", - "lineHeight": 1.2, - "baseline": 95 - }, - { - "type": "line", - "version": 281, - "versionNonce": 142216872, - "isDeleted": false, - "id": "gCT1pqFHnAClMEIoNWYj1", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 562.5673627879346, - "y": 51.14102564102569, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 28.16143497757849, - "height": 28.16143497757849, - "seed": 451759921, - "groupIds": [ - "UaccyybyYhFj-eM3gbcG3" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 14.080717488789245, - 14.080717488789245 - ], - [ - 0, - 28.16143497757849 - ], - [ - -14.080717488789245, - 14.080717488789245 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 332, - "versionNonce": 1855060392, - "isDeleted": false, - "id": "Hik-cvf3Vcl8ufd3gTU6M", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 557.8737902916715, - "y": 60.52817063355185, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 10.036434977578438, - "height": 9.09893497757848, - "seed": 599671057, - "groupIds": [ - "UaccyybyYhFj-eM3gbcG3" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 10.036434977578438, - 9.09893497757848 - ] - ] - }, - { - "type": "line", - "version": 326, - "versionNonce": 1081377960, - "isDeleted": false, - "id": "txxajZ5BEgpPj6JkwE2cT", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 557.8737902916715, - "y": 69.91531562607801, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 10.348934977578438, - "height": 9.098934977578494, - "seed": 760608497, - "groupIds": [ - "UaccyybyYhFj-eM3gbcG3" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 10.348934977578438, - -9.098934977578494 - ] - ] - }, - { - "type": "arrow", - "version": 629, - "versionNonce": 260777688, - "isDeleted": false, - "id": "F75rXFgUUjRnH6_R0UgCs", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 576.3547319957073, - "y": 64.92839484879846, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 41.36210762331841, - "height": 19.654334828101696, - "seed": 1117438079, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077405690, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": { - "elementId": "LJeXDSlPcFibjk0c3F5_P", - "focus": 0.18749999999999206, - "gap": 7.773729446935874 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 8.272421524663683, - 0 - ], - [ - 8.272421524663683, - 19.654334828101696 - ], - [ - 41.36210762331841, - 19.654334828101696 - ] - ] - }, - { - "type": "ellipse", - "version": 342, - "versionNonce": 1221163688, - "isDeleted": false, - "id": "pkOqO5qPnIgPgHk6qD5B_", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 618.4502103215669, - "y": 71.3820570311602, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 28.16143497757849, - "height": 28.16143497757849, - "seed": 449335967, - "groupIds": [ - "LiYkrbdFHbf3PIwmGdTj1" - ], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "F75rXFgUUjRnH6_R0UgCs", - "type": "arrow" - } - ], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 433, - "versionNonce": 1242817960, - "isDeleted": false, - "id": "EDC3tEION33pNTtTlH8IM", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 620.7969965696984, - "y": 73.72884327929177, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 23.46786248131541, - "height": 23.46786248131541, - "seed": 1149413055, - "groupIds": [ - "LiYkrbdFHbf3PIwmGdTj1" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 318, - "versionNonce": 752414888, - "isDeleted": false, - "id": "LJeXDSlPcFibjk0c3F5_P", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 625.4905690659615, - "y": 80.76920202368638, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 14.080717488789245, - "height": 9.387144992526164, - "seed": 1209890527, - "groupIds": [ - "LiYkrbdFHbf3PIwmGdTj1" - ], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "F75rXFgUUjRnH6_R0UgCs", - "type": "arrow" - } - ], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 283, - "versionNonce": 537061032, - "isDeleted": false, - "id": "crLiEzyTczsz6FP8uGREh", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 625.4905690659615, - "y": 80.76920202368638, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.040358744394623, - "height": 4.693572496263082, - "seed": 204030719, - "groupIds": [ - "LiYkrbdFHbf3PIwmGdTj1" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 7.040358744394623, - 4.693572496263082 - ] - ] - }, - { - "type": "line", - "version": 283, - "versionNonce": 1329582504, - "isDeleted": false, - "id": "ghKwqKFohKyCMVNOW_1Fn", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 632.5309278103562, - "y": 85.46277451994945, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.040358744394623, - "height": 4.693572496263082, - "seed": 1361480479, - "groupIds": [ - "LiYkrbdFHbf3PIwmGdTj1" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 7.040358744394623, - -4.693572496263082 - ] - ] - }, - { - "type": "rectangle", - "version": 1093, - "versionNonce": 2108120232, - "isDeleted": false, - "id": "pvJ09TNiBQg74Yt08PYas", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 816.7132077991453, - "y": 47.86498397435895, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 14456561, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "LE6tL6RbuHA6Abs4ZIkjm" - } - ], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1083, - "versionNonce": 753239976, - "isDeleted": false, - "id": "LE6tL6RbuHA6Abs4ZIkjm", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 821.7132077991453, - "y": 72.76498397435896, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 131.1999969482422, - "height": 67.2, - "seed": 1676579025, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 3, - "text": "API\nexplorer", - "textAlign": "left", - "verticalAlign": "middle", - "containerId": "pvJ09TNiBQg74Yt08PYas", - "originalText": "API\nexplorer", - "lineHeight": 1.2, - "baseline": 61 - }, - { - "type": "ellipse", - "version": 429, - "versionNonce": 1227248296, - "isDeleted": false, - "id": "InVA8HFNCcgYu_5zoieqU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 887.6666666666664, - "y": 69.05980850210108, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 137753471, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 495, - "versionNonce": 1494597032, - "isDeleted": false, - "id": "yidq9pqqUYCJ7v8VGFfMa", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 887.8228379936144, - "y": 80.745316547389, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 2034838431, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 498, - "versionNonce": 769640616, - "isDeleted": false, - "id": "lEVim6Motvhr6Y2-g1BNO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 907.2031656581041, - "y": 68.54607830698757, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 796942271, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 562, - "versionNonce": 321942440, - "isDeleted": false, - "id": "rU8H_wDmGxitKkJ2xn5o3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 907.3593369850521, - "y": 80.23158635227873, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 1560023007, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 480, - "versionNonce": 2134097576, - "isDeleted": false, - "id": "-RVMjIR5nZWTYC-gEXH2z", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 897.2344061123483, - "y": 60.333333333333314, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 466402303, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 565, - "versionNonce": 1117104552, - "isDeleted": false, - "id": "JF6qlrwjeVY7KLAPDjrIg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 897.8042670089984, - "y": 86.4077826026271, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 3.984561459968496, - "height": 3.9501072219071296, - "seed": 1878189087, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 422, - "versionNonce": 948057256, - "isDeleted": false, - "id": "xsaF0C4w0cST01Z9LKEdU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 889.9564468972683, - "y": 72.65723419805082, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.6348173470059866, - "height": 8.184848711237326, - "seed": 157222975, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.6348173470059866, - 8.184848711237326 - ] - ] - }, - { - "type": "line", - "version": 471, - "versionNonce": 1990549416, - "isDeleted": false, - "id": "Z_Z2vgXDWSPMi7k2QwAUT", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 909.3933355487494, - "y": 72.07749745531663, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 0.6348173470059866, - "height": 8.184848711237326, - "seed": 1173465183, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.6348173470059866, - 8.184848711237326 - ] - ] - }, - { - "type": "line", - "version": 434, - "versionNonce": 2099980968, - "isDeleted": false, - "id": "fzGD3kntXVwPOe8aEJF3_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 891.2045311129486, - "y": 68.87469089993772, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.3300441044307325, - "height": 5.964429115732022, - "seed": 1937458303, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404545, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 7.3300441044307325, - -5.964429115732022 - ] - ] - }, - { - "type": "line", - "version": 511, - "versionNonce": 1723831720, - "isDeleted": false, - "id": "xTWPwhV0tQjjHECF3fiu7", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 902.0149642627888, - "y": 87.73422296649551, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 6.689704627303995, - "height": 3.7602988743059136, - "seed": 1371298975, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 6.689704627303995, - -3.7602988743059136 - ] - ] - }, - { - "type": "line", - "version": 500, - "versionNonce": 412000424, - "isDeleted": false, - "id": "r4EHeDUGcCrgvVhsDSjxG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 891.2300218380857, - "y": 83.77895464826548, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 4.863894603012394, - "height": 2.807102902354121, - "seed": 1415934143, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 4.863894603012394, - 2.807102902354121 - ] - ] - }, - { - "type": "line", - "version": 458, - "versionNonce": 1917078440, - "isDeleted": false, - "id": "Woacy_s8D-rr7-54_VRYL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 902.5189992234807, - "y": 63.40229136380444, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 8.008855366908458, - "height": 5.696416343704233, - "seed": 622264543, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 8.008855366908458, - 5.696416343704233 - ] - ] - }, - { - "type": "line", - "version": 546, - "versionNonce": 2114754216, - "isDeleted": false, - "id": "0JjgFuCQ0imSrl0ri0nVy", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 891.4403827806892, - "y": 81.25383198440028, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 7.419926501704146, - "height": 16.764049878898106, - "seed": 1700891903, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 7.419926501704146, - -16.764049878898106 - ] - ] - }, - { - "type": "line", - "version": 709, - "versionNonce": 546537896, - "isDeleted": false, - "id": "vXlvoyOxM8iUhjYSqBWKx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 5.35479946847648, - "x": 899.6996493300513, - "y": 81.27407931764822, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 8.986818181617247, - "height": 17.167157870167557, - "seed": 818255135, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 8.986818181617247, - -17.167157870167557 - ] - ] - }, - { - "type": "line", - "version": 446, - "versionNonce": 1225067688, - "isDeleted": false, - "id": "UDPQoav8Vzra7F60QRkNB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 891.9780256580759, - "y": 83.01466918946977, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 15.940509192438453, - "height": 0.2676591231895943, - "seed": 1588828479, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 15.940509192438453, - -0.2676591231895943 - ] - ] - }, - { - "type": "text", - "version": 702, - "versionNonce": 554514344, - "isDeleted": false, - "id": "5XHuffupivj00TwRoTFNd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 903.3310998935661, - "y": 87.68773942210129, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 24.233333587646484, - "height": 7.242728206279829, - "seed": 76290399, - "groupIds": [ - "WgozbZ9EezSGdIu65qbLg", - "DV0vXs3Lzwbx4mMN9ouk4" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 5.794182565023864, - "fontFamily": 1, - "text": "GraphQL", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "GraphQL", - "lineHeight": 1.2499999999999998, - "baseline": 5 - }, - { - "type": "rectangle", - "version": 1143, - "versionNonce": 1020789416, - "isDeleted": false, - "id": "UuQjRWs5hO3bPHEoJWcuF", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 989.8382077991454, - "y": 47.23998397435895, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 1177886737, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 175, - "versionNonce": 1259433384, - "isDeleted": false, - "id": "VcRoont-enGWCqAxAUWOQ", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 995.7757077991454, - "y": 107.61498397435895, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 123.9000015258789, - "height": 28.0625, - "seed": 337385343, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 23.385416666666668, - "fontFamily": 3, - "text": "Analytics", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Analytics", - "lineHeight": 1.2, - "baseline": 23 - }, - { - "type": "rectangle", - "version": 1136, - "versionNonce": 1155889320, - "isDeleted": false, - "id": "VHuGS4u2aREzmG0FiEsmK", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1167.5491452991455, - "y": 44.72435897435895, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 2127427679, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 406, - "versionNonce": 503325608, - "isDeleted": false, - "id": "ZzLzbE1sWIudl_zDyaUFa", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1255.530833524053, - "y": 72.64840457448224, - "strokeColor": "#1e1e1e", - "backgroundColor": "#e9ecef", - "width": 39.39955608911738, - "height": 13.31857546642027, - "seed": 630069279, - "groupIds": [ - "wxRuGYrzPx16Vjg5fBjjK" - ], - "frameId": null, - "roundness": { - "type": 1 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 420, - "versionNonce": 1955425960, - "isDeleted": false, - "id": "Z5k8qOxokNAxrlPkpIO2x", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1282.034744986428, - "y": 70.66633626378723, - "strokeColor": "#000000", - "backgroundColor": "white", - "width": 17.28271208781007, - "height": 17.28271208781007, - "seed": 1299430463, - "groupIds": [ - "wxRuGYrzPx16Vjg5fBjjK" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 385, - "versionNonce": 1094277544, - "isDeleted": false, - "id": "9gcxZbra8M5mAJObwLoPf", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1264.66306445583, - "y": 74.41873611511244, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ced4da", - "width": 10.699999809265137, - "height": 10, - "seed": 223337567, - "groupIds": [ - "wxRuGYrzPx16Vjg5fBjjK" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 7.822329908127899, - "fontFamily": 1, - "text": "ON", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "ON", - "lineHeight": 1.2783914917228643, - "baseline": 7 - }, - { - "type": "text", - "version": 254, - "versionNonce": 120579240, - "isDeleted": false, - "id": "jpCDCY3KCq6WYhU_C-dHf", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1180.5119048237293, - "y": 85.02644230769252, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 123.9000015258789, - "height": 56.125, - "seed": 1390646911, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 23.385416666666668, - "fontFamily": 3, - "text": "Low-\ncode apps", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Low-\ncode apps", - "lineHeight": 1.2, - "baseline": 51 - }, - { - "type": "rectangle", - "version": 1091, - "versionNonce": 69013416, - "isDeleted": false, - "id": "-z6XKBc4fD4mgckJcw3Wc", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 660.4658119658095, - "y": 47.89102564102595, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 1843849087, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 337, - "versionNonce": 1613552296, - "isDeleted": false, - "id": "DrpyePqoxJtDcNgpAtVRj", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 671.2991452991428, - "y": 93.99519230769258, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 82.5999984741211, - "height": 56.125, - "seed": 2003129617, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 23.385416666666668, - "fontFamily": 3, - "text": "Models\nUI", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Models\nUI", - "lineHeight": 1.2, - "baseline": 51 - }, - { - "type": "line", - "version": 3178, - "versionNonce": 1577797032, - "isDeleted": false, - "id": "MGxYXJmptNcOoK9h8bM2v", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 5.322742949876956, - "x": 752.8345140046868, - "y": 61.47861977565242, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 5.146182778469899, - "height": 33.619987981165465, - "seed": 765262015, - "groupIds": [ - "yMzT2Tg03Gocq7RVqDU3E" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -1.49188563834283, - 0.055416744216406175 - ], - [ - -1.885448557101054, - 1.033038121963335 - ], - [ - -2.6667928143025335, - 6.094940748967313 - ], - [ - -0.7305049533447014, - 8.484485527577283 - ], - [ - -0.5236633203544202, - 12.008600693335953 - ], - [ - -0.6549150102497949, - 28.9239407353383 - ], - [ - -0.7508262546550706, - 32.95168759611172 - ], - [ - -0.6015165509841344, - 33.619987981165465 - ], - [ - 0.978997283704209, - 33.60962984316546 - ], - [ - 0.978997283704209, - 32.936639021494926 - ], - [ - 0.7617998021060735, - 28.86975243883541 - ], - [ - 0.7437417883305049, - 12.027264406294975 - ], - [ - 0.8370603531248496, - 8.481158944110268 - ], - [ - 2.479389964167365, - 6.030487492762875 - ], - [ - 1.7706479628896838, - 1.201398709756714 - ], - [ - 1.4480275622692367, - 0.10296892312671119 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 2063, - "versionNonce": 182735016, - "isDeleted": false, - "id": "Ijoqk3V7jLl0Hi86SBzjc", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 5.322742949876956, - "x": 777.9978426151238, - "y": 82.1138819669427, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 7.8809831388590315, - "height": 27.37636346501326, - "seed": 2115864799, - "groupIds": [ - "yMzT2Tg03Gocq7RVqDU3E" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -3.0174548432249266, - -0.27978071563891205 - ], - [ - -3.573008390154078, - 0.7850439183840203 - ], - [ - -3.438245610894324, - 1.9443990563280331 - ], - [ - -2.4163251751258006, - 2.1047003011547605 - ], - [ - -2.303485387435643, - 2.9624886339435736 - ], - [ - -2.8057627389725344, - 8.66439982935754 - ], - [ - -3.904902282758769, - 19.230070986144923 - ], - [ - -3.965409143340566, - 27.096582749374345 - ], - [ - 2.983610189191, - 26.901329974913825 - ], - [ - 3.5145000621997293, - 19.394195329562287 - ], - [ - 2.719310736870321, - 8.425362405652548 - ], - [ - 2.657935977602425, - 2.9220793323806693 - ], - [ - 2.853578248543317, - 2.285039201584659 - ], - [ - 3.9155739955184656, - 2.2048885791710697 - ], - [ - 3.8153857175019517, - 1.0627422097830657 - ], - [ - 3.354519638625937, - -0.19963009322532257 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "rectangle", - "version": 1166, - "versionNonce": 1852046248, - "isDeleted": false, - "id": "cYcVAuLoMYeiy3Mvf184P", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1333.2991452991432, - "y": 44.89102564102609, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 149.99999999999997, - "height": 117, - "seed": 537038417, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 333, - "versionNonce": 985024168, - "isDeleted": false, - "id": "-4mof0M06Z-yEnJUscS_9", - "fillStyle": "cross-hatch", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1342.261904823727, - "y": 58.19310897435966, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 137.6666717529297, - "height": 84.1875, - "seed": 1869897169, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 23.385416666666668, - "fontFamily": 3, - "text": "real-\ntime\ndashboards", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "real-\ntime\ndashboards", - "lineHeight": 1.2, - "baseline": 79 - }, - { - "type": "line", - "version": 960, - "versionNonce": 2089234856, - "isDeleted": false, - "id": "ccaYwOiMvN4JSsgPXI0--", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1030.8282953599255, - "y": 60.942759167323004, - "strokeColor": "#000000", - "backgroundColor": "#12b886", - "width": 0, - "height": 40, - "seed": 1861129169, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 40 - ] - ] - }, - { - "type": "text", - "version": 974, - "versionNonce": 1258470568, - "isDeleted": false, - "id": "aM8GdHHbX2Op-TKwWzUfy", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1031.2436673367565, - "y": 55.05769230769283, - "strokeColor": "#000000", - "backgroundColor": "#be4bdb", - "width": 25, - "height": 4.571428571428572, - "seed": 1013838257, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "fontSize": 2.857142857142857, - "fontFamily": 1, - "text": "Calendar heatmap", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Calendar heatmap", - "lineHeight": 1.6, - "baseline": 3 - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 2010441640, - "isDeleted": false, - "id": "wvAaPuY0v1i0NdpLg8wqa", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1059.7494572033702, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1107727249, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 532, - "versionNonce": 1059697320, - "isDeleted": false, - "id": "ZrmJM1Lwd5U4jeIm9couv", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1062.6066000605133, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 871364977, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 2007834024, - "isDeleted": false, - "id": "HicHOO7sscxHYQXj9pt3N", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1065.463742917656, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1399956305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 1116416168, - "isDeleted": false, - "id": "3Nszov1Sd8OuHz3xbriDM", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1068.320885774799, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1289949489, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 997184424, - "isDeleted": false, - "id": "C5Dk9mdFdxPe2Rh7PlY4d", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1071.1780286319417, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1437319953, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 533, - "versionNonce": 679943848, - "isDeleted": false, - "id": "q6x9Rk0FIvdo96BpbotRC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1074.0351714890844, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 172177649, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 525, - "versionNonce": 712837544, - "isDeleted": false, - "id": "jC37bnWW_xnP8vore7QU_", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1076.8923143462275, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 204534481, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 531, - "versionNonce": 1820169384, - "isDeleted": false, - "id": "Q0S9CKXpqhD5Y8lFCLfYR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1079.7494572033702, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1611428017, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 528, - "versionNonce": 1412743080, - "isDeleted": false, - "id": "2fdLsrr2ANm-fhOdt8Tty", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1082.6066000605133, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 192754321, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 528, - "versionNonce": 835619496, - "isDeleted": false, - "id": "5eazxr3tMEbS3aave8-Mx", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1085.463742917656, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1933228145, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 530, - "versionNonce": 1878455720, - "isDeleted": false, - "id": "AWmIH4iqgJWnhVNyGm5BF", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2030862929, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 1138360488, - "isDeleted": false, - "id": "P4SV46bGN7ACke2a7Q5GQ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1506414641, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 534, - "versionNonce": 1562618792, - "isDeleted": false, - "id": "ey6a_iI6uZ6SQjLsmg6-T", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1264247313, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 534, - "versionNonce": 369096360, - "isDeleted": false, - "id": "bt5HqT8TLSjjmqexGXq4t", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1521907697, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 588964264, - "isDeleted": false, - "id": "I4foK5R4ureMZafZhr_DY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 165958097, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 1134587048, - "isDeleted": false, - "id": "OJOvkAmVWNDYp9XLlN_Ve", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 771485617, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 1899796392, - "isDeleted": false, - "id": "Gecc5tSGetzMuf24cewnO", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 220516753, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 270230184, - "isDeleted": false, - "id": "zHS-awY_mQzcA-BapHt1U", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1016493937, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 518573480, - "isDeleted": false, - "id": "huoQHGYMnqyt9TDTmeNOY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1050173777, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 987, - "versionNonce": 1724962984, - "isDeleted": false, - "id": "IEJ63t3ez_mLnMz4OeMHk", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1114.1801264534888, - "y": 61.01877905932791, - "strokeColor": "#000000", - "backgroundColor": "#12b886", - "width": 0, - "height": 40, - "seed": 1619136305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 40 - ] - ] - }, - { - "type": "line", - "version": 948, - "versionNonce": 729777064, - "isDeleted": false, - "id": "kvSU2143n10JSb_Xo5Y5B", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1031.3334969033485, - "y": 101.12339353584949, - "strokeColor": "#000000", - "backgroundColor": "#12b886", - "width": 82.85714285714286, - "height": 0, - "seed": 1488650513, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 82.85714285714286, - 0 - ] - ] - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 1528876712, - "isDeleted": false, - "id": "bL_Aeh0H_JJhNLrZ1isFg", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1056.8923143462275, - "y": 60.771978021978526, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 616216305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 1046526376, - "isDeleted": false, - "id": "inw4v9W1ppahW4MmKRK6i", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1071.1780286319417, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 654880977, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 678118568, - "isDeleted": false, - "id": "kxdMc0B7F7nZkxNHlvLyW", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1074.0351714890844, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 87846577, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 653029288, - "isDeleted": false, - "id": "FnNnxk7Fu4mgj4Ct4K-NC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1076.8923143462275, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1174237329, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 547, - "versionNonce": 839924392, - "isDeleted": false, - "id": "Jvr9hnvYHX46LlL0h84PO", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1079.7494572033702, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 788739697, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 559, - "versionNonce": 1552065960, - "isDeleted": false, - "id": "ejlTqFifYq2FWe9i_1p5I", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1082.6066000605133, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1662337105, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 57651368, - "isDeleted": false, - "id": "IJSXvipm1w2LdQvFtC07H", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1085.463742917656, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1074466353, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 534, - "versionNonce": 2122537896, - "isDeleted": false, - "id": "IHBG-DuwhVEcwVV_5XdPS", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1088.320885774799, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2093752337, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 1340712616, - "isDeleted": false, - "id": "sY9t5c2p3pLvOi5QRzqOR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 122680817, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 1414435240, - "isDeleted": false, - "id": "C7qrGFGkF8bO5jaVpz9sl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 580784081, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 1927158952, - "isDeleted": false, - "id": "8xB2zHuCRYOOhzOzflAwG", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1154346417, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1296320424, - "isDeleted": false, - "id": "OOq4vFF9VlbmBP0OeMpIP", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 889655185, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 1873613480, - "isDeleted": false, - "id": "_qyYRGoUX8aA47jbWvPJu", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1770059121, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 12877224, - "isDeleted": false, - "id": "6Z7Zu1p2bkC_c1Y9cmmQT", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 629350225, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 1907787944, - "isDeleted": false, - "id": "Avy0L_61zdM3W7CJaEdOw", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1466240305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 774845352, - "isDeleted": false, - "id": "i4IcDY_ZWV39iwn7ildPK", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 915291921, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 558, - "versionNonce": 1280999080, - "isDeleted": false, - "id": "lB3UxFHdHq-7dInkpiwAv", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1068.320885774799, - "y": 63.629120879121416, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 561394929, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 553, - "versionNonce": 1021602216, - "isDeleted": false, - "id": "poD6iuirZNSnZ2ogiXSG7", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1082.6066000605133, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1000632017, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 2063135912, - "isDeleted": false, - "id": "BHoV-fCUWGf0Iqrs_4orZ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1085.463742917656, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1269853361, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 554, - "versionNonce": 1011097512, - "isDeleted": false, - "id": "jeTmuE7ihXIjLHnwEoDgL", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1088.320885774799, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1497476753, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 552725160, - "isDeleted": false, - "id": "b83aH1HmteTBgDLp5Quyf", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1091.1780286319417, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 185578609, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 561, - "versionNonce": 1672369576, - "isDeleted": false, - "id": "Ul327RZ89g0xNctaF_Pw4", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1094.0351714890844, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1155661393, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 161833128, - "isDeleted": false, - "id": "yy8MiD4nwupCpHOK96Wr-", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1096.8923143462275, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 93326385, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 536, - "versionNonce": 310578088, - "isDeleted": false, - "id": "CiP5lyGPLY9VsqpkHuFjO", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1099.7494572033702, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 83975697, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 678647464, - "isDeleted": false, - "id": "im80BjV-ydcn4rTqhfOIo", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 304968689, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1344422312, - "isDeleted": false, - "id": "GMM3KPOSB7_1ZZBgdBb-0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 823905745, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 414960808, - "isDeleted": false, - "id": "2hyTE1Xlvk2h9dl4vu3am", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2028202929, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 1273755560, - "isDeleted": false, - "id": "nAvLk3qk1XEhHsIOdWcFF", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 833441169, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 560, - "versionNonce": 501138088, - "isDeleted": false, - "id": "1YoI2-CF3iiQBG3srXDcF", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1079.7494572033702, - "y": 66.48626373626426, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 850359153, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 1564487080, - "isDeleted": false, - "id": "teC-KZKMftdDNSQxU3Eid", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1042.6066000605133, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 3267921, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 591149224, - "isDeleted": false, - "id": "_aJtJdHR5jskyQ6ivGUfF", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1045.463742917656, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 697043761, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 58647464, - "isDeleted": false, - "id": "DHo0CYmnqkfPSi70hP2ej", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1048.320885774799, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1730510097, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 1010052776, - "isDeleted": false, - "id": "W82LtTIJQjftdKWUnzOOQ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1051.1780286319417, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2020979441, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 564, - "versionNonce": 1711806888, - "isDeleted": false, - "id": "yJ9Y9_zyCBTAcNkWUB_nx", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1054.0351714890844, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1107569873, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 547, - "versionNonce": 606512296, - "isDeleted": false, - "id": "46SLiWKdhD0KVMMlE_bAO", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1056.8923143462275, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 728263345, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1413205928, - "isDeleted": false, - "id": "nwMr10i0MjJbiG-imyoMf", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1059.7494572033702, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1028254865, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1047763624, - "isDeleted": false, - "id": "fWocogiA_cMMS86TmZvH3", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1062.6066000605133, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2137010801, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 1165624744, - "isDeleted": false, - "id": "84cAd6brpFTIIfdmZ7rsp", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1065.463742917656, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 376618065, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 377163944, - "isDeleted": false, - "id": "uMXDi7M7xfaxzvj4fh0RD", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1068.320885774799, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 576260657, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 1495448488, - "isDeleted": false, - "id": "bGNPSJ7b12hjhyjg9yhul", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1071.1780286319417, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1543150609, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 1604126376, - "isDeleted": false, - "id": "OugnHLtSmsvOrJ3iUaC6K", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1074.0351714890844, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1934553585, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 1452667304, - "isDeleted": false, - "id": "Tcj9U8gDKLi-Y4DaOIFOs", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1076.8923143462275, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 761105361, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 1966701736, - "isDeleted": false, - "id": "ucD5EwtPrP8BqG4C5cjY9", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1079.7494572033702, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1111353777, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 553, - "versionNonce": 758359976, - "isDeleted": false, - "id": "-uX_Gz80tQ84CqmoXnOHN", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1082.6066000605133, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2065140625, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 1521513128, - "isDeleted": false, - "id": "ZXL100A_I39wtGyfLuE8f", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1085.463742917656, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 270659953, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 562, - "versionNonce": 1952177576, - "isDeleted": false, - "id": "l_6c64Mc-3EsuNolApjL-", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1185192785, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 559, - "versionNonce": 996272296, - "isDeleted": false, - "id": "WmHb72kd4F1xJsRbZuhwc", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1324812593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 559, - "versionNonce": 1802408872, - "isDeleted": false, - "id": "NWgrepIzHsGe05W7p6vC1", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1652603665, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 563, - "versionNonce": 1789779624, - "isDeleted": false, - "id": "n4GYfseplQaQmvpRq4kBf", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1039.7494572033702, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 565784817, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 2043398568, - "isDeleted": false, - "id": "XRwtUUL4kugmMrs6xuKvB", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1059.7494572033702, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 841476817, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1676956840, - "isDeleted": false, - "id": "1EZQvGKPTUlNbonND97ix", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1062.6066000605133, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 476342449, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 785612712, - "isDeleted": false, - "id": "OIq1Jhm-ucjPWwiGmtrQg", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1065.463742917656, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1779837585, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1251297960, - "isDeleted": false, - "id": "m2ZN6_YUvTfNKZxuJMzy4", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1068.320885774799, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 66367601, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 1105573288, - "isDeleted": false, - "id": "jejqaEfxGSdwBT-7Ysz5w", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1071.1780286319417, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1338473041, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 1777385640, - "isDeleted": false, - "id": "-jWvkQyuF6xRu_ut3amFk", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1074.0351714890844, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 241567793, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 532, - "versionNonce": 308439976, - "isDeleted": false, - "id": "xfpsSkHJKJCzGUp9SLopQ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1076.8923143462275, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2042092049, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 895923880, - "isDeleted": false, - "id": "sRJDsuyYFaz16rIGg3MUR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1079.7494572033702, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 582250481, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 665428392, - "isDeleted": false, - "id": "49TKBFNG5veXg0iwn7_63", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1082.6066000605133, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 258165201, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 1213672616, - "isDeleted": false, - "id": "rVdWp7hjUoQlib_jTXnYL", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1085.463742917656, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 417064881, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 823875496, - "isDeleted": false, - "id": "JH5_iZAgK2q5I00FbhsbK", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 155568529, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 1713513128, - "isDeleted": false, - "id": "-uAVnM9OB-4Hfowv38q04", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2044227441, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 102206888, - "isDeleted": false, - "id": "UnMB1dGT3AGdNlk7q-0D2", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1893423441, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404546, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 2049415336, - "isDeleted": false, - "id": "TuZbCkbFRH7V-RLK2meRd", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1067845425, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 637420456, - "isDeleted": false, - "id": "QIV2hD24W0LPdQjuyevJn", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 547354897, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 398954152, - "isDeleted": false, - "id": "0VYtz4D68YwReJ46AtCBH", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 356560625, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 942635432, - "isDeleted": false, - "id": "wuJoeu517Eq2bcITDLMVl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 68135121, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 2053244072, - "isDeleted": false, - "id": "PpqrP2HxHdu0dSAtjVlIN", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 379872945, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 202059688, - "isDeleted": false, - "id": "4gr1yN25UrdbRtiD5nTc2", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1470523537, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 89586344, - "isDeleted": false, - "id": "FX2ck-QGjjVtEq7pi3iNy", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1056.8923143462275, - "y": 75.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 281882225, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 554, - "versionNonce": 418473384, - "isDeleted": false, - "id": "_qoJ-OSgM4gbzGb0aDUlB", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1082.6066000605133, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1759524945, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 1141272744, - "isDeleted": false, - "id": "kEFoNuq1LXwZq16z1mTQg", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1085.463742917656, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1102513713, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 2118261672, - "isDeleted": false, - "id": "pghWsgs9t2636D_PdDGzR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1088.320885774799, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1446582289, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 1775265448, - "isDeleted": false, - "id": "rtj-RCnCFIstzfy5BFKw9", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1091.1780286319417, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 408808945, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 562, - "versionNonce": 56447400, - "isDeleted": false, - "id": "XhTRdqth3YWB6dpmQeN-n", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1094.0351714890844, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1328351185, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1377098920, - "isDeleted": false, - "id": "x6Mjg0EmuB-zRoJjSit_N", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1096.8923143462275, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1958602161, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 396560296, - "isDeleted": false, - "id": "LEiNTSZ-CyHTAyhfrb2fr", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1099.7494572033702, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1412958097, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 3396264, - "isDeleted": false, - "id": "mO6Qdgkm19IDeifWhiHS0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1741876593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 1383284136, - "isDeleted": false, - "id": "cIEebIotfaPk4pFyspK9P", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1993742161, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 529352872, - "isDeleted": false, - "id": "cUd6qyLUeorrHXZQu-KNb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1939408177, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 1932391336, - "isDeleted": false, - "id": "RCVBaz7Zsr9tqe4AqLTGE", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 428029713, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 561, - "versionNonce": 58801832, - "isDeleted": false, - "id": "NA1Bm92NX_3B5gdO_TGrK", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1079.7494572033702, - "y": 77.9148351648357, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1259089137, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 1630742952, - "isDeleted": false, - "id": "FsXve_obra7gFRAnF2qfd", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1068.320885774799, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 800810705, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 661632168, - "isDeleted": false, - "id": "JlMp3V6kafUdF-NknsGt5", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1071.1780286319417, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 304637105, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 736288680, - "isDeleted": false, - "id": "Iiks2Xk-yoEMwLryzrHoS", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1074.0351714890844, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2113578641, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 783854248, - "isDeleted": false, - "id": "W4U-BomQgKl6ehABL4Iat", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1076.8923143462275, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 501853297, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 558, - "versionNonce": 178066856, - "isDeleted": false, - "id": "Pp9_fTrBwomVXyCsi063C", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1079.7494572033702, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1505556049, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 1690050728, - "isDeleted": false, - "id": "KEt2ADTxSa497qP2MA8ue", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1082.6066000605133, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 877397041, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 533, - "versionNonce": 1556204456, - "isDeleted": false, - "id": "YVzMdAsDcfQgXNuLLqnrL", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1085.463742917656, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1769887249, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1020925608, - "isDeleted": false, - "id": "0pias-XRi4JRUhCz7PZdR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1280011249, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 536, - "versionNonce": 699466152, - "isDeleted": false, - "id": "AJ67K_0xt1NIy7-j1B6gn", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1689961937, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 536, - "versionNonce": 1383238824, - "isDeleted": false, - "id": "OsNSAEEYeZwOKdPVkgC4K", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1306780593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 550156200, - "isDeleted": false, - "id": "AfYDlqNED-HCnnY3D65DX", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1408124305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1759871656, - "isDeleted": false, - "id": "s8ELTMbnyLegMRAr1aI3m", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1376873329, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 426700200, - "isDeleted": false, - "id": "Ev6JRZoMuXj2NpzVsK7k7", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1351931217, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 1804794024, - "isDeleted": false, - "id": "pvOikq4AKqAGy_JjOJmCb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1657799473, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 547, - "versionNonce": 318612392, - "isDeleted": false, - "id": "AsL-b9Er2exVD_QQD_KA1", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1160410385, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 1843064488, - "isDeleted": false, - "id": "qUvDq3iT-7yLRR0r_P0zM", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 991668977, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 886495656, - "isDeleted": false, - "id": "3gQMGjZvsOs6N8pekk31E", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1065.463742917656, - "y": 80.77197802197855, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 757802193, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 554, - "versionNonce": 723346600, - "isDeleted": false, - "id": "zEyDa4HPFH_IHFlbsLjot", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1045.463742917656, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 116417201, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 1314557864, - "isDeleted": false, - "id": "GZwG-srfJsgbeUigJsYve", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1048.320885774799, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1427301521, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 112876200, - "isDeleted": false, - "id": "ymeg7J26BdKfj5Rxk8SPk", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1051.1780286319417, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 592063089, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 1458095528, - "isDeleted": false, - "id": "TrnlTcNt2IkwdJI176BBb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1054.0351714890844, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 442348625, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 562, - "versionNonce": 202494120, - "isDeleted": false, - "id": "G-8p50F0FHCxcvYFPh8Ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1056.8923143462275, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1579483697, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1843493800, - "isDeleted": false, - "id": "pOsUMRexb2v1J18Vug7pC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1059.7494572033702, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 730305553, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 1854129832, - "isDeleted": false, - "id": "UmYrqlEF8gvm_0oyH_e0S", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1062.6066000605133, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 914156017, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 1520742824, - "isDeleted": false, - "id": "a8-II_MoF2sGjkb_1Mb6O", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1065.463742917656, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1208779729, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 158350504, - "isDeleted": false, - "id": "0_vWAZg765a50GopzTMeW", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1068.320885774799, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 474866097, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 210921384, - "isDeleted": false, - "id": "fv9Skhg61RCT5y8KoytuY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1071.1780286319417, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 6849425, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 1614230184, - "isDeleted": false, - "id": "Ph6Jpro3MGMWDTgtMInGT", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1074.0351714890844, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 814999921, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 453680552, - "isDeleted": false, - "id": "5oDafiC_SncCuNQ326h8M", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1076.8923143462275, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1981256529, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 507029672, - "isDeleted": false, - "id": "ReeD7tmaRQRsWIHigQV6r", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1079.7494572033702, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 88801585, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 1164792744, - "isDeleted": false, - "id": "oHIPUQinfjyf0LoaJm8Rf", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1082.6066000605133, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 462795537, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 383033000, - "isDeleted": false, - "id": "5qtSiRN1yxJZZDM8xe135", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1085.463742917656, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1567566065, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 553, - "versionNonce": 1931119016, - "isDeleted": false, - "id": "n6cVXN-c6Vft6ur5uSpYY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1952375505, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 560, - "versionNonce": 1164645544, - "isDeleted": false, - "id": "cVmF_TlgRJu6IVB9kifIh", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1828479153, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 863125416, - "isDeleted": false, - "id": "axQO_zPQpK8dG6FHOfULl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1424958097, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 1297877672, - "isDeleted": false, - "id": "bO2iIIuMLz_Y0qtJABSpc", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 418293873, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 561, - "versionNonce": 1037333928, - "isDeleted": false, - "id": "ZWbb4-nkJEXplGj0u7qCq", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1042.6066000605133, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 583168593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 2047312040, - "isDeleted": false, - "id": "8m1ecvLqNGHjteFjehY-R", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1065.463742917656, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 927072305, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1906387880, - "isDeleted": false, - "id": "mpdjJ-IQByx49bScJdi-B", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1068.320885774799, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 341103121, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 1053652648, - "isDeleted": false, - "id": "4qsLKfrY9nL5HyQN86xLr", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1071.1780286319417, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1324509169, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 1446535592, - "isDeleted": false, - "id": "I7_eM6j9vWywI_aeA4bXU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1074.0351714890844, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1898070481, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 923659432, - "isDeleted": false, - "id": "TFkTkUTOVVLgBUohdJNHj", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1076.8923143462275, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1476124593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 452597672, - "isDeleted": false, - "id": "xZAt_vOI5pJOThz5Rkjn1", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1079.7494572033702, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1369883025, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 532, - "versionNonce": 640213672, - "isDeleted": false, - "id": "g95LFtemBUM-XKOq6DzH9", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1082.6066000605133, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2069522289, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 390483368, - "isDeleted": false, - "id": "lVPa4wfVYtbcCpJ495kMj", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1085.463742917656, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1600016721, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 2004768936, - "isDeleted": false, - "id": "2qN5FK6-cnfkCwZ8uE4vo", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1088.320885774799, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1393164081, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 1249706920, - "isDeleted": false, - "id": "TRGc4V77rmjSUYPzXRZLM", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1091.1780286319417, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 348451089, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 1047416488, - "isDeleted": false, - "id": "Ursnihonws7F_nsl2AASI", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1094.0351714890844, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 705079025, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 1543387560, - "isDeleted": false, - "id": "xx7ar2mxGxqNjJUdXJhXe", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2102829265, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 911787176, - "isDeleted": false, - "id": "E3D9xuGcyI53y0A7vQ1rn", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1011637937, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 541, - "versionNonce": 455733160, - "isDeleted": false, - "id": "Ls0icVINpwVWNEarF_tab", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1972330641, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 1117633192, - "isDeleted": false, - "id": "L2sUEFPErOO9dHvnd1hwl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1993811569, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 2137007528, - "isDeleted": false, - "id": "eOok5-A_P18eneTm_BYoo", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1793798225, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 1855795368, - "isDeleted": false, - "id": "5cvwoR8g5ADqd6nmLY5jU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 933428785, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 671144872, - "isDeleted": false, - "id": "rhGW85UIDOBeVTPfyMa_n", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1062.6066000605133, - "y": 89.34340659340714, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 468062225, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 1840719528, - "isDeleted": false, - "id": "g8-3PApPGBjHOTaaYB8xb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1085.463742917656, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 229369329, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 1550586280, - "isDeleted": false, - "id": "tgC2jbS0zCayP7Wt44S-k", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1088.320885774799, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1476132817, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 550, - "versionNonce": 457940136, - "isDeleted": false, - "id": "61-X83jyIPuddg0EpT7sj", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1091.1780286319417, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2028854705, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 201443240, - "isDeleted": false, - "id": "9K4qczQqCvvQE8qbXj_xC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1094.0351714890844, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1068040081, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 557, - "versionNonce": 2059047592, - "isDeleted": false, - "id": "bKwRJpI6Wv-Miz8eysSbP", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1096.8923143462275, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 711255409, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 540, - "versionNonce": 1310850472, - "isDeleted": false, - "id": "SNnOHtI1SOXpI86ZUS-_W", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1099.7494572033702, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 73994065, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 532, - "versionNonce": 929302696, - "isDeleted": false, - "id": "WA4WO541I28MUmSz1oJjy", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1102.6066000605133, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1141701937, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 1647096744, - "isDeleted": false, - "id": "8qqzfYvSwdgYpE3gvoyG3", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 683159313, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 614989480, - "isDeleted": false, - "id": "1gEApPLh4BNhrtyC5dOUZ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 417473777, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 535, - "versionNonce": 797043112, - "isDeleted": false, - "id": "M1w8JkScD2SIhYHFN1g_7", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1074945745, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 1038513320, - "isDeleted": false, - "id": "vfr6tkMsY4PQ8afqGrKfl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1082.6066000605133, - "y": 92.20054945054997, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1826643121, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 1166122920, - "isDeleted": false, - "id": "_G9s1Htv69COuuUCb1A2l", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1094.0351714890844, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 787717777, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 645884584, - "isDeleted": false, - "id": "zZ32KIJoNfmvW-7peIXux", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1096.8923143462275, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 889431153, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 1535890856, - "isDeleted": false, - "id": "viZGIlOTIRcxHuSfZkQ1t", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1099.7494572033702, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1792536145, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404547, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 701685928, - "isDeleted": false, - "id": "wWYgBl4jZIGjv9mjZ20dI", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1102.6066000605133, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1464335409, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 1358990248, - "isDeleted": false, - "id": "pGOz3_uTFnM5Zip7VHse1", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 70, - "angle": 0, - "x": 1105.463742917656, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 976965137, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 539, - "versionNonce": 994105000, - "isDeleted": false, - "id": "0LneOWX21KUbjZoTOEkyY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 80, - "angle": 0, - "x": 1108.320885774799, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1789486065, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 531, - "versionNonce": 759153064, - "isDeleted": false, - "id": "DHkD-yIVAVhIx8gtqvF2j", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 90, - "angle": 0, - "x": 1111.1780286319417, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1956232657, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 1982418088, - "isDeleted": false, - "id": "JLeNrLb0T9VoikpwwwLB9", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1091.1780286319417, - "y": 95.05769230769283, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1998838705, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 547, - "versionNonce": 531199912, - "isDeleted": false, - "id": "EM4-Od7vZmQ91Rtrnhx7N", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1102.6066000605133, - "y": 97.91483516483567, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1114586513, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 537, - "versionNonce": 502022824, - "isDeleted": false, - "id": "1hVDVIyiRpap9vXTLzb6t", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1105.463742917656, - "y": 97.91483516483567, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 900948849, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 2141040040, - "isDeleted": false, - "id": "CEHfLNDRMOtfjds_7YySH", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1108.320885774799, - "y": 97.91483516483567, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1563938129, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 501856424, - "isDeleted": false, - "id": "klxl6bT9CcfoUAT9emXbp", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1111.1780286319417, - "y": 97.91483516483567, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1347681073, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 554, - "versionNonce": 1283220392, - "isDeleted": false, - "id": "SHIG3cf1elTN6Weug-GUr", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1099.7494572033702, - "y": 97.91483516483567, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1332702481, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 542, - "versionNonce": 159493800, - "isDeleted": false, - "id": "AtoNHVg5xO2zERTqT7k1-", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 20, - "angle": 0, - "x": 1102.7494572033706, - "y": 99.20054945055, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 570532593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 532, - "versionNonce": 765827496, - "isDeleted": false, - "id": "ooJAN5YcAj401XS29suPt", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 30, - "angle": 0, - "x": 1105.6066000605133, - "y": 99.20054945055, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 881990865, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 543, - "versionNonce": 471082152, - "isDeleted": false, - "id": "CqflGvaptsqCZx3zz-aHz", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 50, - "angle": 0, - "x": 1108.463742917656, - "y": 99.20054945055, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1991793329, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 538, - "versionNonce": 1920552872, - "isDeleted": false, - "id": "5v0Mk8PBCoabwghVBxBrA", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 60, - "angle": 0, - "x": 1111.3208857747986, - "y": 99.20054945055, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 2031869073, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 549, - "versionNonce": 956373672, - "isDeleted": false, - "id": "bjMmSg_wMugC_XdqUWj3F", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 10, - "angle": 0, - "x": 1099.8923143462275, - "y": 99.20054945055, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1265902193, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 546, - "versionNonce": 307725736, - "isDeleted": false, - "id": "pm0s1hdvuyektOibmJosA", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1096.8923143462275, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 445164625, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 548, - "versionNonce": 1806209192, - "isDeleted": false, - "id": "rD1a4368jNCI8tC9osZs4", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 238090801, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 748698536, - "isDeleted": false, - "id": "Ks1B8NSBpIA3tQs2eHfFm", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1733594129, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 1735034536, - "isDeleted": false, - "id": "C1qtU-879SyiNRbuorUeD", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1575674353, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 552, - "versionNonce": 145977768, - "isDeleted": false, - "id": "SzhpChwQKdscB1yDJeUyV", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1056668625, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 545, - "versionNonce": 128384168, - "isDeleted": false, - "id": "oeIORfRKMM8tq7Hrgd-mv", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1099.7494572033702, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1251858865, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 547, - "versionNonce": 368125864, - "isDeleted": false, - "id": "8SqytJu2P8nmY3ZGqEW41", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1102.6066000605133, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1375304593, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 554, - "versionNonce": 1337848488, - "isDeleted": false, - "id": "XkKrLlMJP_v-zwwWC0Jzs", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1105.463742917656, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 356901233, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 1807310248, - "isDeleted": false, - "id": "DU70vHvVvPkW6hhhBIka8", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1108.320885774799, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1640663889, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 551, - "versionNonce": 1796171944, - "isDeleted": false, - "id": "MJ8VXDwaMNqmjYn8Ce_m7", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 86.48626373626428, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 1876883761, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 555, - "versionNonce": 1231819688, - "isDeleted": false, - "id": "mbxdQsvMOvwJaiT-zymTN", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1111.1780286319417, - "y": 69.34340659340711, - "strokeColor": "#ffffff", - "backgroundColor": "#fa5252", - "width": 2.857142857142857, - "height": 2.857142857142857, - "seed": 15379217, - "groupIds": [ - "ncI3Lm5Nr5K5kfrt7zlo0" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 770, - "versionNonce": 754671272, - "isDeleted": false, - "id": "u-3zpSu5EtufYVpb3niGr", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1417.6401924732513, - "y": 77.72379023974844, - "strokeColor": "#000000", - "backgroundColor": "#12b886", - "width": 0, - "height": 26.561813527935698, - "seed": 934632127, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 26.561813527935698 - ] - ] - }, - { - "type": "line", - "version": 779, - "versionNonce": 375998888, - "isDeleted": false, - "id": "JnQJ305ELD1p6asgFAcP0", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1417.5962147240416, - "y": 104.40555317802256, - "strokeColor": "#000000", - "backgroundColor": "#12b886", - "width": 55.020899450723945, - "height": 0, - "seed": 718908127, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 55.020899450723945, - 0 - ] - ] - }, - { - "type": "text", - "version": 778, - "versionNonce": 283235496, - "isDeleted": false, - "id": "dFHdpI6E8UEksScBmNfKl", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1417.5365638191138, - "y": 73.95125315736561, - "strokeColor": "#000000", - "backgroundColor": "#be4bdb", - "width": 3.4666666984558105, - "height": 3.03563583176408, - "seed": 826210047, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "fontSize": 1.8972723948525498, - "fontFamily": 1, - "text": "Line", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Line", - "lineHeight": 1.6, - "baseline": 2 - }, - { - "type": "line", - "version": 463, - "versionNonce": 1645281192, - "isDeleted": false, - "id": "ndeMalldzIv4yhAc3PdWT", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1421.416578482289, - "y": 101.19206913165215, - "strokeColor": "#c92a2a", - "backgroundColor": "#fd7e14", - "width": 51.66905155315114, - "height": 21.518231078286007, - "seed": 828751647, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 18.9727239485255, - -3.7945447897050997 - ], - [ - 35.12062010915942, - -16.45883802534587 - ], - [ - 51.66905155315114, - -21.518231078286007 - ] - ] - }, - { - "type": "line", - "version": 507, - "versionNonce": 975358632, - "isDeleted": false, - "id": "JgGckAswP9FvY85IpOONl", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1421.4026448305444, - "y": 100.51306668530128, - "strokeColor": "#862e9c", - "backgroundColor": "#fd7e14", - "width": 51.81212399660219, - "height": 18.82481666655492, - "seed": 1841201983, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 24.664541133083148, - -1.8972723948525498 - ], - [ - 37.945447897051, - -13.280906763967849 - ], - [ - 51.81212399660219, - -18.82481666655492 - ] - ] - }, - { - "type": "line", - "version": 527, - "versionNonce": 1673737640, - "isDeleted": false, - "id": "TF24P-w8WBt3bNaABaeqD", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1432.8464734162426, - "y": 100.59772545843157, - "strokeColor": "#2b8a3e", - "backgroundColor": "#fd7e14", - "width": 39.84272029190355, - "height": 13.280906763967849, - "seed": 111788895, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 20.869996343378048, - -1.8972723948525498 - ], - [ - 30.356358317640797, - -9.48636197426275 - ], - [ - 39.84272029190355, - -13.280906763967849 - ] - ] - }, - { - "type": "line", - "version": 493, - "versionNonce": 1948139688, - "isDeleted": false, - "id": "YQnH1KXhqQWlkJe3kA4QO", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1430.8174705830816, - "y": 98.61579429044878, - "strokeColor": "#364fc7", - "backgroundColor": "#228be6", - "width": 41.739992686756096, - "height": 17.07545155367295, - "seed": 1014497151, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 11.383634369115299, - -13.280906763967849 - ], - [ - 26.561813527935698, - -17.07545155367295 - ], - [ - 41.739992686756096, - -15.178179158820399 - ] - ] - }, - { - "type": "line", - "version": 515, - "versionNonce": 2061495208, - "isDeleted": false, - "id": "i_wQgbm3rCNVxBlGAZWuK", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1421.49698767384, - "y": 100.60087878688574, - "strokeColor": "#e67700", - "backgroundColor": "#228be6", - "width": 51.06047559599768, - "height": 17.07545155367295, - "seed": 1902753695, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 11.383634369115299, - -13.280906763967849 - ], - [ - 26.561813527935698, - -17.07545155367295 - ], - [ - 51.06047559599768, - -5.779629286142081 - ] - ] - }, - { - "type": "line", - "version": 537, - "versionNonce": 842282664, - "isDeleted": false, - "id": "MAI_WXBISECP45E2R_YGN", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1421.3590042957862, - "y": 99.04341293016972, - "strokeColor": "#0b7285", - "backgroundColor": "#228be6", - "width": 51.19845897405172, - "height": 21.297614983099006, - "seed": 1806658495, - "groupIds": [ - "hLM2FYlZwxDh_ulwliqGE", - "MoEsWlsMXpGUyUnXC1ktn" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077404548, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 11.383634369115299, - -13.280906763967849 - ], - [ - 26.53391784096857, - -21.297614983099006 - ], - [ - 51.19845897405172, - -9.913980613983707 - ] - ] - }, - { - "type": "line", - "version": 98, - "versionNonce": 37467048, - "isDeleted": false, - "id": "HIxqUqOV3VAx0VOnF-AXv", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 1152.3824786324767, - "y": 882.5576923076928, - "strokeColor": "#1e1e1e", - "backgroundColor": "#e9ecef", - "width": 585, - "height": 1, - "seed": 1756588351, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077397465, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 585, - -1 - ] - ] - }, - { - "type": "text", - "version": 65, - "versionNonce": 390642392, - "isDeleted": false, - "id": "-nLuxx8r_gLuJTuq8wzb7", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 1409.3824786324767, - "y": 861.1576923076929, - "strokeColor": "#1e1e1e", - "backgroundColor": "#e9ecef", - "width": 82.13333129882812, - "height": 24, - "seed": 788361919, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397465, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "Pub/sub", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Pub/sub", - "lineHeight": 1.2, - "baseline": 19 - }, - { - "type": "text", - "version": 88, - "versionNonce": 1792474792, - "isDeleted": false, - "id": "BTc5eJi1cgxrzI4wG4Fx6", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 1260, - "y": 1200, - "strokeColor": "#1e1e1e", - "backgroundColor": "#e9ecef", - "width": 82.13333129882812, - "height": 24, - "seed": 237288881, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1703077397465, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "Pub/sub", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Pub/sub", - "lineHeight": 1.2, - "baseline": 19 - }, - { - "type": "arrow", - "version": 595, - "versionNonce": 1093320616, - "isDeleted": false, - "id": "3lWppf32GdRGyXJgulqyV", - "fillStyle": "cross-hatch", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 3.156698708986003, - "x": 1382.5234201241065, - "y": 395.3722407772692, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 482.96633092051536, - "height": 192.7265503172183, - "seed": 2114780376, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1703077494403, - "link": null, - "locked": false, - "startBinding": { - "elementId": "j1lQfnnrkl7K6wFtYmYYb", - "focus": 0.29099010855131896, - "gap": 12.00000000000017 - }, - "endBinding": { - "elementId": "wNTvL2ykeCyJnOX1ctQcC", - "focus": -0.012211122517421416, - "gap": 4 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -54.234721940998156, - -82.39131214863966 - ], - [ - -424.0301080147304, - -84.39131214863966 - ], - [ - -482.96633092051536, - -192.7265503172183 - ] - ] - } - ], - "appState": { - "gridSize": 20, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/content/versions/v4.0.0/get-started/diagram-rhize-arch-overview.png b/content/versions/v4.0.0/get-started/diagram-rhize-arch-overview.png deleted file mode 100644 index 2a3a4f51b..000000000 Binary files a/content/versions/v4.0.0/get-started/diagram-rhize-arch-overview.png and /dev/null differ diff --git a/content/versions/v4.0.0/get-started/how-rhize-works.md b/content/versions/v4.0.0/get-started/how-rhize-works.md deleted file mode 100644 index ff370e3bb..000000000 --- a/content/versions/v4.0.0/get-started/how-rhize-works.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: 'How Rhize works' -date: '2023-10-03T19:39:39-03:00' -draft: false -categories: "concepts" -description: >- - A high-level overview of how Rhize collects, exchanges, and stores data, starting with data collection and ending with user interaction. -weight: 200 ---- - -This article provides a high-level overview of how Rhize works, starting with data collection and ending with user interaction. -To make these concepts more concrete, the next section provides examples of each process. - -The heart of the Rhize platform is its manufacturing knowledge graph, which stores data from all levels of the operation and exposes this data through a single endpoint. -Around the database are services that exchange messages and process events in real-time. -The system runs on distributed, containerized systems, ensuring horizontal scalability and high availability. - -Finally, outside of the Rhize deployment are the two most important components: the manufacturing operation, which sends event data to Rhize, and the Rhize users, who interact with Rhize data through a number of special-purpose interfaces. - -{{< bigFigure -src="/get-started/diagram-rhize-arch-overview.png" -alt="A simplified diagram of Rhize's architecture" -width="70%" -caption="A simplified view of Rhize's architecture" ->}} - -## Examples in practice - -To make the next sections less abstract, consider these examples of how Rhize creates a common data hub for diverse human and system interaction. - -- **[Data inputs](#data-inputs)** - - An instrument fitter configures an MQTT-compatible device to send sensor data to Rhize. - - A business analyst sends an ERP order through an integration with the GraphQL API. -- **[Message exchange](#message-exchange)** - 1. A piece of equipment publishes information about its status over MQTT. - 1. A BPMN process subscribes to the equipment's `TestResult` subtopic. When the `TestResult` status changes to `fail`, the BPMN process publishes a maintenance order to the broker. - 1. The ERP system, which subscribes to the `maintenance` topic, prepares a document for maintenance personnel. -- **[Data storage](#storage)** - - A data scientist writes a Python script that discovers production outliers for a specific segment class across all production sites. - - A procurer uses an Excel-Rhize integration to call the API and receive a production order that the BPMN process wrote to the database one month earlier. -- **[User-data interaction](#interfaces)** - - An operator queries sensor values from a custom-built mobile interface. - - A quality-engineer observes real-time data in a custom dashboard built for statistical process control. -- **[Deployment](#deployment)** - - A DevOps engineer pushes an upgrade that handles message-streams more efficiently. This upgrade rolls out node-by-node across each instance. - - A plant process causes a heavy inflow of data. The system autoscales to meet the temporary computation demand. - -## Data inputs - -A manufacturing data hub is useless without manufacturing data. - -The Rhize agent collects data from MQTT brokers and devices, OPC-UA servers. -You can also send data and documents over HTTP through a [GraphQL call]({{< relref "../how-to/gql/call-the-graphql-api" >}}). -The Rhize UI also has a graphical interface to [model production]({{< relref "../how-to/model" >}}) objects. - -All this data is mapped to Rhize's ISA-95 schema, which creates a coherent model for all objects in the data hub. - -## Message exchange - -{{< bigFigure -src="/get-started/rhize-diagram-data-sources.png" -alt="More granular view of Rhize-Customer messaging" -caption="More granular view of Rhize-Customer messaging" -width="90%" ->}} - -Rhize's architecture is event-driven, low-latency, and scalable. -To communicate events in real-time and across services, Rhize uses a publish-subscribe model through the NATS message broker. -The message infrastructure enables complex interaction between services without creating dependencies between them. - -Services in the Rhize application subscribe to their relevant topics and handle events as they come in. -Services also publish events to the event broker. -Thus, Rhize services can communicate with each other and with customer systems in a completely decoupled manner. - -## Data storage {#database} - -With a schema defined by the ISA-95 standard, -the graph database creates contextual relationships that link all data stored in the system. -This graph data, accessible through a single endpoint, provides a single source to perform vast combinations of analysis. - -Along with event data from disparate places and decoupled services, -the database also stores declarative configuration data to instruct different services on how to respond to events. - -Finally, the time-series component of the database accepts real-time data streams. - -## The interfaces {#interfaces} - -The Rhize application comes with a graphical interface. -Some uses include: -- [**Configure BPMN rules.**]({{< relref "../how-to/bpmn" >}}) A low-code tool for analysts and operators to create programmable events. -- [**Upload master data.**]({{< relref "../how-to/model" >}}) Based on the ISA-95 object models. -- [**Administrate.**]({{< relref "../deploy" >}}) Authenticate and scope access to systems and personnel. - -These interfaces sit on top of the GraphQL API gateway, which serves as a programming interface for data analysis. -Rhize customers also use the GraphQL interface to build their own applications, either with dedicated frontend developers or through low-code tools like Appsmith. - -Last but not least, the time-series data is observable through monitoring tools like Grafana. - -## Deployment {#deployment} - -Rhize runs on Kubernetes and is configured through CI/CD servers. - -Using Kubernetes, Rhize can deploy to multiple instances using a common configuration. -Such distribution removes single points of failure, and system upgrades can happen on a rolling basis, with zero downtime. -All deployment is version controlled, which makes regressions easier to recover from. - -Deployment is vendor neutral, giving organizations complete control to run the system on their local networks or preferred cloud host. -The modern tools of DevOps also makes the system easier to maintain, as they come with vast tooling ecosystems and training material. - diff --git a/content/versions/v4.0.0/get-started/introduction.md b/content/versions/v4.0.0/get-started/introduction.md deleted file mode 100644 index e00dea6ac..000000000 --- a/content/versions/v4.0.0/get-started/introduction.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: 'What is Rhize?' -date: '2023-09-26T12:25:46-03:00' -draft: false -categories: "concepts" -description: A hub to join all manufacturing data in place. Build manufacturing execution systems and do deep analysis. -weight: 1 ---- - -Rhize is a real-time, event-driven [manufacturing data hub]({{< relref "../explanations/manufacturing-data-hub" >}}). -It unites data analysis, event monitoring, and process execution in one platform. -Its interface and architecture are designed to conform to your processes. -We assume nothing about what your operations looks like. - -Rhize has only one strong opinion: all manufacturing objects and data must be modeled on the [ISA-95 standard](https://www.isa.org/standards-and-publications/isa-standards/isa-standards-committees/isa95). -This standards-based schema is how Rhize connects every data event across an entire operation. -If you aren't an ISA-95 fan, we're happy to convert you, but you must adopt it to use the platform. - -And if you do adopt ISA-95, you open your organization to Rhize's far-reaching transformations. - -## A data hub for manufacturing - -Rhize is a data hub that collects, stores, integrates, and processes data from your manufacturing system. -Rhize accepts the _event_ as the driver of change in a manufacturing operation. -Its architecture is designed to receive and process message events emitted from the operation in real time. - -To make each event coherent in the context of all others, the event object must conform to a standard. -Rhize uses the ISA-95 standard as its data model, and the database schema is the most complete digital representation of ISA-95 in the world. -The flexibility of ISA-95 scales to an entire enterprise operation, and future changes in processes require no ad-hoc changes of the schema. - -The database represents data as a single graph, a structure ideally suited for the node and edge associations inherent in ISA-95. -The database is exposed through a single GraphQL endpoint. -Besides keeping the interface small, the GraphQL query language aligns exactly with the underlying graph model. - -The API is completely open. Your operators can use it as a backend to build any MES, MOM, and data-science applications they want. -Rhize also has a built-in low-code BPMN workflow creator, so operators can write logic to handle event data using only API calls and JSON transformation. - -Rhize's architecture supports distributed deployment, and its components are loosely coupled microservices. -This clustered approach is necessary for organizations to scale horizontally and maintain high reliability. - -## A tool that fits to your processes - -The development of Rhize is the culmination of decades of experience from real practitioners. -We know manufacturing is messy, and each process has thousands of particulars. -Even within the same company and segment, processes often differ from site to site. - -Our design philosophy empowers manufacturing operators to shape their tool for their work demands. -Some examples of the flexibility include: - -- **A headless MES**. While Rhize has a graphical interface, all data is reachable through a single API endpoint. This means your teams can rapidly build custom frontends―and do it with the most comfortable API for frontend development, GraphQL. -- **Low-code interface**. Model your schema and execute processes using BPMN, a visual programming language. The visual interface makes Rhize and your manufacturing automation accessible to the widest possible audience. -- **Generic data collection**. Rhize receives data from all levels of the manufacturing process. The [NATS](https://nats.io) broker publishes and subscribes to low-level data from [MQTT](https://mqtt.org/) and [OPC-UA](https://opcfoundation.org/about/opc-technologies/opc-ua/), but the database can also receive ERP inventories and documents sent over HTTP. - -[Read about use cases]({{< relref "../use-cases" >}}). - -## Modern IT for manufacturing - -Rhize's system design is flexible, practical, and built on modern tools and practices: - -- **All data is accessible through a single endpoint.** -While the data collected and processed may span multiple segments, events, units, areas, and even plants, all data is stored in a graph database and exposed through a [GraphQL](https://graphql.org) interface. - -- **Automated and containerized deployment.** -Rhize brings innovations from DevOps to manufacturing. -In practice, this means that Rhize is interoperable with whatever system the manufacturer uses, -deployment is version-controlled, and your system can use rolling upgrades with zero downtime. - -- **Built on open standards.** -Rhize is based on open standards, like ISA-95, and open protocols, like MQTT. -Open industry standards and protocols ensure that the application and your manufacturing processes speak a common language. -Rhize heavily uses open-source software, which brings interoperability, reduced vendor lock, and robust tooling ecosystems. diff --git a/content/versions/v4.0.0/get-started/rhize-diagram-data-sources.png b/content/versions/v4.0.0/get-started/rhize-diagram-data-sources.png deleted file mode 100644 index d17ee9b0b..000000000 Binary files a/content/versions/v4.0.0/get-started/rhize-diagram-data-sources.png and /dev/null differ diff --git a/content/versions/v4.0.0/isa-95/_index.md b/content/versions/v4.0.0/isa-95/_index.md deleted file mode 100644 index 906bccd40..000000000 --- a/content/versions/v4.0.0/isa-95/_index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Learn ISA-95 -description: >- - ISA-95 is vocabulary of entities and relationships to model the entire domain of manufacturing operations management. -cascade: - type: docs - icon: model ---- - -{{% reusable/isa-95-course %}} - -More than a standard about interop, -ISA-95 is a full _ontology_ of manufacturing: -a vocabulary of entities and relationships to model the entire domain of manufacturing operations management. - -{{< card-list >}} diff --git a/content/versions/v4.0.0/isa-95/how-to-speak-isa-95.md b/content/versions/v4.0.0/isa-95/how-to-speak-isa-95.md deleted file mode 100644 index 598ef8f47..000000000 --- a/content/versions/v4.0.0/isa-95/how-to-speak-isa-95.md +++ /dev/null @@ -1,308 +0,0 @@ ---- -title: How to speak ISA-95 -description: More than a standard, ISA-95 is a specialized vocabulary that describes all elements of a manufacturing operation. -icon: chat-alt-2 -weight: 100 -images: - - /images/og/graphic-rhize-how-to-speak-isa95.png -aliases: - - /explanations/how-to-speak-isa-95 ---- - -{{% reusable/isa-95-course %}} - -[ISA-95](https://www.isa.org/store?query=isa95) provides a common language to discuss manufacturing. -When you speak with other manufacturing stakeholders, you can use the standard's precise vocabulary to ensure that everyone is speaking about the same thing. - -The standard also describes how different manufacturing entities relate to each other. -[With the right application architecture](https://rhize.com/blog/reframing-perspective-on-isa95/), -these relationships can form a complete and coherent data model of a full manufacturing operation. -Learning how to speak the language of ISA-95 can help standardize communication between humans and machines. - -While ISA-95 is not as complex as a natural human language, it is lengthy. This document provides a brief introduction to essential terminology. - -## Foundational concepts - -The following concepts frame all conversation that involves ISA-95. -If you are a manufacturing veteran, these might be familiar to you. -But a high-level review never hurts. - -### The levels of a manufacturing operation - - -{{< bigFigure -alt="Levels of a manufacturing operation" -src="/images/s95/diagram-rhize-isa95-levels.svg" -width="80%" ->}} - -Discussions that involve ISA-95 frequently reference the _levels_ of a system. -You may hear phrases like "this workflow integrates level-4 data with level-3 activities," -or "the batch is a level-3 construct". -In this context, _level_ corresponds to the degree of granularity necessary to discuss and exchange data for different purposes in the manufacturing operation. - - - -| Level | Operational Perspective | Example system | -|-------|-------------------------------------|----------------------------------------------------------| -| 4 | Business planning | {{< abbr "ERP" >}} | -| 3 | Manufacturing operations management | {{< abbr "MES" >}}, {{< abbr "CMMS" >}}, Quality control | -| 2 | Monitoring and acquisition | SCADA | -| 1 | Sensors | PLCs | - -While **ISA-95 focuses on level 3 and the interaction between levels 3 and 4**, your models can incorporate data from level 2. - -### Role based equipment hierarchy: the view from up top {#rbeh} - -The _equipment hierarchy_ represents how equipment can contain other equipment, as a production line might contain a conveyor belt and a pneumatic actuator. - -ISA-95 defines equipment across multiple scales. -The scale may be as broad as the building where a plant makes items or as a granular as an individual unit that performs one small action within a complex process. - -{{< bigFigure -alt="Role-based equipment hierarchy" -src="/images/s95/diagram-rhize-isa95-equipment-hierarchy.svg" -width="65%" ->}} - -These equipment hierarchies often provide a naming convention to prefix addresses for plant data. -For example, an MQTT topic might be named `site1/bakery2/kitchenA/ovens/a_temp_sensor`. -In Rhize, the [Equipment UI]({{< relref "../how-to/model/master-definitions" >}}) provides an interface to model your plant according to this compositional hierarchy. - -### Relationships - -Most diagrams about models in ISA-95 show a collection of objects that are connected by lines and arrows. -These lines and arrows represent _relationships_. - -Understanding how entities relate is fundamental to understanding how to the manufacturing process works as a complete system. -Nothing in a manufacturing operation happens in a vacuum, -and ISA-95 describes these connections with a precise vocabulary of relation. - -Some important relations include: -- **Defined by**. As a member may be defined by a class. -- **References** As an operations definition references a bill of material -- **Assembled from**. As a final material lot may be assembled from various intermediate lots. -- **Made up of**. As work schedules are made up of work requests, and work centers are made up of work units. - -For the full list of relationships, refer to ISA-95 Part 2. -To explore the relationships in an interactive way, -you can use the Rhize [GraphQL]({{< relref "../how-to/gql" >}}) API explorer. - -## The activities of an MES - -Much of the ISA-95 standard discusses operations at the view of level 3, that is the MES or _Manufacturing Operations Management (MOM)_ system. But what activities are part of a MOM system? This is the subject of ISA-95 Part 3. - -{{< bigFigure -src="/images/s95/diagram-rhize-isa95-activity-model.svg" -alt="The activities of a level-3 system" -caption="Different activities of a level-3 system and their interactions with other levels. Broadly, activities can be categorized as reference, pre-execution, execution, and post-execution." -width="75%" ->}} - -The 8 major activities of a MOM are as follows: - -* **Product definition:** What goes into a product, and what resources does it require? -* **Resource management:** What resources are available to produce goods? -* **Detailed production scheduling:** When and what does the business want to produce? After a business determines its demand, it can build a schedule using its available resources. -* **Production dispatching:** How will the plant assign the available resources to produce the schedule? Once the schedule is received, the level-3 system can assign resources to orders by referencing the definitions and capabilities. -* **Production execution management:** How does the plant execute the order? -* **Production data collection:** What data is emitted and stored during execution? -* **Production tracking:** What components and actions went into production? For example, [EBR](https://docs.rhize.com/use-cases/ebr/), [Genealogy](https://docs.rhize.com/use-cases/genealogy/), and Track and Trace are all use-cases of production tracking. -* **Production performance analysis:** How well did the actual production run go, as compared to its ideal? For example, measures of OEE, deviation analysis, and golden batches are all use-cases of performance analysis. - -To make sense of these activities, you also need to have a concept of the relationship between planned and performed work. - -### Definition, demand, result - -Almost all manufacturing processes share a common flow, from _definition_ to _production_ to _analysis_: - -1. A business defines how a good is to be produced. -2. The business then creates a schedule that demands that a number of these goods are produced according to its definition. -3. The plant uses its available resources and references the existing definitions to execute the orders from the schedule. - - -{{< bigFigure -src="/images/s95/diagram-rhize-isa-definition-demand-result-l3-l4.svg" -alt="Models to define, demand, and produce work" -caption="**The relationships between requests, responses, segments, and resources across level 4 and level 3 systems.**" -width="85%" ->}} - - -As long as a business continues to make things, its processes always include a definition of work, a demand for work, and the result of production. -These categories inform not only the activities of manufacturing but also the models of production that make each of these activities sensible. - -## Frequently used models - -ISA-95 describes how production _entities_ relate to one another within and across the manufacturing activities. -Entities are physical or abstract objects that make up the composition of a manufacturing process in its past, present, future, and ideal state. -Here are some of the most common entities. - -### Resources - -All aspects of manufacturing involve resources. Without resources nothing can be done or made. ISA-95 Parts 1 and 2 provide a rich and extensive vocabulary for discussing resources. Generally the resource models have the following patterns: - -* _Classes_ provide groupings and associations -* The members of a class are objects that exist in the real world. These _instances_ are represented with versions. -* As the work executes, the _actuals_ define what resource was really used for a specific job. -* These resources are part of specifications and requirements for definitions of work -* All of these resource models can be extended with _properties_. - -#### Equipment - - -{{< watch -text="Creating an equipment model in Rhize" -src="https://www.youtube.com/watch?v=Wh6sYCuNYJI&list=PLeYowHxqJrUi5ojKBvYg3CnfYdvOqVMi5&index=1" ->}} - -Equipment is an object that has a defined role in the production process. -Important equipment models include the following: - -- **Equipment classes.** Equipment that shares some purpose, such as `rotating widget makers`. -- **Equipment (Instance).** An instance of an equipment class, such as `compressor-5, version 2`. -- **Actual.** The equipment that really performed a job. For example, the actual could be the ID of the compressor involved in some specific production. -- **Equipment Properties.** Attributes of an equipment or equipment class. For example, a property of an compressor might be `rotation_speed`. - -Relationships between equipment are organized according to the role-based equipment hierarchy and, optionally, the hierarchy scope. -To learn more, read the Rhize guide to [Equipment relationships]({{< relref "resources/equipment" >}}). - -#### Material - -{{< watch -text="Five ways to view material through ISA-95" -src="https://www.youtube.com/watch?v=Xd5kj1TUQkY" ->}} - -{{< bigFigure -alt="Material class, definition, lot, and sublot" -src="/images/s95/diagram-rhize-material-class-definition-lot.png" -width="80%" ->}} - -_Material_ is all the input matter required to produce a finished good. -Import material models include the following: - -- **Material classes.** Material classes represent a broad group of associated materials. An example might be `raw_sugar`. - -- **Material definitions.** A standardized definition of some material, ensuring consistency in the operation. -- **Material lots.** Material lots and sublots are the identifiable units that go into a larger assembly. -For example, a material lot might be a pallet of sugar from a supplier, and the sublot might be the individual sugar bags. - - Lots can have parent/child relationships to express material compositions. - To learn more, read the Rhize guide to [Material relationships]({{< relref "resources/material" >}}). - -- **Material Actual.** A material actual is the quantity of material in a job that is used, consumed, marked as scrap, and so on. -- **Material properties.** Properties of material that are relevant to the production process, for example, `meltingPoint` or `containsLactose`. - - -#### Personnel - -_Personnel_ are the people who execute a job. -Important personnel models include: - -- **Personnel class.** A group of people with an associated function, for example `coil_operators`. -- **Person.** The "instance" of a personnel class, where the "version" may track properties like certifications and years of experience. -- **Personnel actual.** The people who really perform a certain job. -- **Personnel properties.** Attributes such as `trained to operate heavy machinery`. Properties could also communicate a person's location or current assignment. - -### Hierarchy scope: multiple views of equipment hierarchies - -The hierarchy scope is a special grouping of equipment that does not necessarily follow the conventional role-based hierarchy. -For example, Rhize uses hierarchy scope to [ define calendar rules and calculate metrics ]({{< relref "../how-to/work-calendars/about-calendars-and-overrides/" >}})for a set of machines whose shift rules don't necessarily correspond to the hierarchy. You might also set a hierarchy scope to calculate metrics or track production across an arbitrary grouping of equipment. - -{{< bigFigure -src="/images/work-calendars/diagram-rhize-work-calendar-relationships.png" -caption="The calendar service uses the relationships between equipment, hierarchy scope, and work calendars." -alt="Diagram of relationship between three configurations" -width="50%" ->}} - -### Segments: process steps to execute - -The process segment defines the unit of work as it is visible from the business. -For example, a baking operation may have the segments `mixing`, `baking`, `cooling`, `testing`, and `storing`. - -A segment indicates that a unit of work is meaningful for the business to follow. -While `mixing` might be example of a valid segment, an individual turn of the mixing motor would be a very unlikely segment, as the action is too granular to provide any useful context to the business. - -A segment may specify its necessary work definitions and resources. -Process segments also serve as information containers to analyze and track the production of a good at some stage in its lifecycle. - -## Work done and requested - -{{< bigFigure -alt="Schedules and requests" -src="/images/s95/diagram-rhize-isa95-schedule-requests.svg" -caption="An operations schedule is associated with a work requests, which has associated job orders" -width="60%" ->}} - -Besides resources, manufacturers also need to track and describe how work is demanded and performed. - -ISA-95 offers vocabulary to describe the views of this work from both the level-4 (business) perspective and the level 3 (execution) perspective. -If you're wondering whether a model refers to level 3 or 4, keep this trick in mind: - -**Models that start with "operation" refer to level 4; models that start with "work" refer to level 3.** - - -### The operational view of work - -In all conventional manufacturing, demand originates from the "top," that is, from the business or level-4 system. Production results are compared against this original demand. Thus, all conventional models of manufacturing include a model of demand, definitions, and results from the level-4 perspective. - -This operational view of work is defined in ISA-95 Part 2. -Here is a quick primer on the major models: - -* **Operations definitions** define the resources required to perform a schedule. -* **Operations schedules** include the _requests_ to produce goods. -These requests typically demand that production occur at certain times or by certain deadlines. -* **Operations performance** is the collection of _responses_ to a request. Performance models provide information about the _state_ of a request, such as `WAITING`, `READY`, `RUNNING`, and `COMPLETED`. -* **Operations capability** provides information about the resources for past and future operations. These capability models provide a way to determine a plant's theoretical maximum capacity and a way to analyze how well previous runs performed against this capacity. - -### The level-3 view of work - -{{< bigFigure -alt="Requests and responses being passed" -src="/images/s95/diagram-rhize-isa-95-requests-responses.webp" -caption="The flow of requests and performance from level 4 to level 3" -width="50%" ->}} - -ISA-95 Part 4 defines the level-3 models of work. These models are more granular and detailed than their corresponding operational models. - -Typically, one operations request corresponds to one work request, and they differ in the degree of detail reported in the work request. For example, the operations request may ask for 1000 intermediate widgets, and the work request produces these intermediate widgets. - -However, a work request may also fulfill multiple or even fractional operations requests―for example, a work request may produce 1500 intermediate widgets, allocating 1000 to fulfill the operational request and sending the spare 500 to storage. - -#### Defined work - -The _Work Master_ provides a set of resource specifications to do some work. It may be associated with segment. -When it is planned in a real job order, the work master is "cloned" as a _Work Directive._ - -#### Planned work -Planned work broadly follows the following hierarchy: - -* **Work Schedule.** A schedule to perform some amount of work. The schedule contains one or more work requests. -* **Work Request.** A collection of job orders to make something -* **Job Order.** An order to execute a specific part in a work request - -#### Performed work - -{{< watch -text="Query a job response and its linked data" -src="https://www.youtube.com/watch?v=EkAbNbx6LQw&t=2s" ->}} - -The performance of a production run is queried through the _job response_. This response exists in the following hierarchy: - -* **Work Performance.** A collection of work responses that detail the performance of the work done for some work schedule -* **Work response.** A collection of job responses that map to a work request -* **Job response.** The data about the real performance of a job order, including its start and end times and resource actuals. - -## Now you're talking - -In this document, you've learned the basic vocabulary to discuss manufacturing according to a standardized model. -However, this is still an extremely brief entry into ISA-95, whose full standard has 9 parts and thousands of words. - -Nevertheless, the best way to acquire a language is to practice it. -Can you think of how all the preceding terms apply to your manufacturing operation? Try to apply the terms with some colleagues! diff --git a/content/versions/v4.0.0/isa-95/isa-95-diagrams.md b/content/versions/v4.0.0/isa-95/isa-95-diagrams.md deleted file mode 100644 index e62b09ac2..000000000 --- a/content/versions/v4.0.0/isa-95/isa-95-diagrams.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: ISA-95 diagrams -description: >- - Helpful diagrams to present a high-level overview of the ISA-95 models - for entities and information flows. -weight: 1000 -draft: false -aliases: - - /explanations/isa-95-diagrams -icon: diagram ---- - -{{% reusable/isa-95-course %}} - -These diagrams provide some highly simplified visual explanations gleaned from parts of the thorough [ISA-95 standard](https://www.isa.org/store?query=isa95). -To read about how the standard fits within the data architecture of Rhize, read our blog post [Rethinking perspectives on ISA-95](https://rhize.com/blog/reframing-perspective-on-isa95/). - -## Definition, demand, result - -At a high-level, manufacturing consists of: -- Goods being demanded -- Goods being produced - -Between these two points, the manufacturing operations performs this work according to its definitions -of work and the resources that it has available. -This diagram shows how ISA-95 defines these fundamental relationships from the perspective of the business (ERP) and manufacturing operation (MOM). - - -{{< bigFigure -src="/images/s95/diagram-rhize-isa-definition-demand-result-l3-l4.svg" -alt="Models to define, demand, and produce work" -caption="**Click to expand**" -width="90%" ->}} - -## Information exchange between models and levels - -This diagram shows how information exchanges between resource models and systems. -It is a highly simplified view of some flows described in parts 2 and 4 of the standard. -Each entity in the diagram carries information in multiple dimensions, including: -- The entity's position in the resource model (as shown by vertical orientation and color) -- Its relationship to other entities -- Its role in the integration between level-3 and level-4 systems. - -{{< watch - -text="Watch two manufacturing experts explain this diagram" -src="https://www.youtube.com/watch?v=qfUnX-_J-to" - - >}} - -{{< bigFigure -src="/images/s95/rhize-s95-p2-p4-high-level-overview-ISA95_P2_P4.svg" -alt="A large overview of the ISA-95 object model" -caption="**Click to expand**" -width="85%" ->}} - -## The activity model - -This diagram shows that activities that a manufacturing-operations-management system might perform. -Each activity provides information to or receives information from another activity, and all of these activities have their own necessary entities related to resources, planning, and performance. - -Though the focus of this model is on level-3 activities, the data that is exchanged may necessarily involve data from levels 2 and 3. -These activities are explained in thorough detail in [ISA-95 Part 3](https://webstore.ansi.org/standards/isa/ansiisa9500032013). - -{{< bigFigure -src="/images/s95/diagram-rhize-isa95-activity-model.svg" -alt="The activities of a level-3 system" -caption="**Click to expand**" -width="85%" ->}} - -{{< watch -text="Episode 2 of the Rhize podcast" -src="https://www.youtube.com/watch?v=NeYVCdmQq-o&t=130s&themeRefresh=1" ->}} - - - -## Overview of relations, levels, and stages - -This diagram shows the top-level relations of manufacturing entities in level-3 and level-4 systems across different stages of production. -These entities and their relationships also represent some foundational objects in the Rhize data model (exposed through the Rhize [GraphQL Interface](/how-to/gql/)). - -{{< bigFigure -src="/images/s95/diagram-rhize-isa95-big-overview.svg" -alt="A large overview of the ISA-95 object model" -caption="**Click to expand**" -width="85%" ->}} - - diff --git a/content/versions/v4.0.0/isa-95/models-of-work/_index.md b/content/versions/v4.0.0/isa-95/models-of-work/_index.md deleted file mode 100644 index 03581894d..000000000 --- a/content/versions/v4.0.0/isa-95/models-of-work/_index.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Models of work -description: ISA-95 provides ways to model work at different levels of granularity -weight: 300 -cascade: - icon: clipboard-check ---- - -{{% reusable/isa-95-course %}} - -ISA-95 provides ways to model work at different levels of granularity. - -{{< card-list >}} diff --git a/content/versions/v4.0.0/isa-95/models-of-work/process-segments.md b/content/versions/v4.0.0/isa-95/models-of-work/process-segments.md deleted file mode 100644 index 2fd555977..000000000 --- a/content/versions/v4.0.0/isa-95/models-of-work/process-segments.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: Process segments -description: Process segments represent shared steps across processes -images: - - /images/og/graphic-rhize-process-segment-explanation.png ---- - -{{% reusable/isa-95-course %}} - -A _process segment_ is a step that can be shared across processes. -Process segments are flexible information objects, -abstract enough to be shared by multiple procedures, -and coarse-grained enough to be appropriate for business planning and analytics. - -Process segments provide information that is relevant to both [levels 3 and 4]({{< relref "../how-to-speak-isa-95/#the-levels-of-a-manufacturing-operation" >}}). -In the manufacturing ontology, the process segment has relationships to diverse other entities, including objects for scheduling, definitions, and work performance. -As such, the proper use of process segments provides much flexibility in how you implement an MOM system for both operational and analytical use cases. - - -{{< figure -src="/images/s95/rhize-s95-p2-p4-high-level-overview-ISA95_P2_P4.svg" -alt="A large overview of the ISA-95 object model" -caption="A process segment exists in the middle of levels 3 and 4" ->}} - -## The scope of a process segment - -Process segments can have a [parent-child hierarchy](#is-made-up-of). -At higher levels of this hierarchy, the scope of a process segment is often broader than that of a particular product. - -For example, The Juice Factory produces five brands of juice. -While the particular material consumed and produced differs in the production of each brand, -all brands still follow the steps of `material receiving`, `kitting`, `mixing`, and `packing`. -These steps are process segments. - -```mermaid -flowchart LR -a[Material receiving]--> -b[Kitting]--> -c[Mixing]--> -d[packing] -``` - -## Reasons to use segments - -Process segments can serve operational and analytical functions. -Operational functions include: -- To avoid repetition when modeling steps that are common to different processes. -- To define work from a business-process perspective. More granular entities might define a route of segments to follow in specific situations. For details, read the example in the [corresponds to](#section). - - -You can also use process segments in various analytical functions, such as: -- Comparing different product processes that are all derived from a common procedure. - For example, the mixing segment might [correspond to](#correspond-) to the production of `mixed red juice` and `mixed blue juice`. -- Viewing data and parameters for similar steps in a single aggregation. - For example, you might compare the average time of all jobs associated with `mixing` against the other segments to find a general process bottleneck. - -## Segments vs. equipment hierarchies - -Process segments are not necessarily connected to the [role-based equipment hierarchy]({{< relref "../resources/equipment/#the-role-based-hierarchy" >}}). -Since a defining aspect of equipment in ISA-95 is that it plays a precise role, -you might wonder whether a process segment is just a needless duplication: -why add a `mixing` segment when the `mixers` equipment model serves the same role? - -However, the fact that process segments are decoupled from equipment can help you model a variety of conditions: -- Some steps have no equipment requirements. For example, in The Juice Factory, the `kitting` process segment requires no equipment. -- Some steps may be common to a number of processes, but each particular process may require a different set of equipment. - - -## Segment relationships - -Process segments have relationships to a number of other work and resource models. - -### Corresponds to - -Operations segments and work masters usually describe a step to create a particular product. -These models may _correspond_ to a process segment: -- From the business perspective, product steps are modeled in _operations segments_. -- From the more granular MES perspective, product steps are modeled in _work masters_. - -For example, the Juice Factory has various work masters to produce material definitions for different bulk juices: `Bulk blue juice`, `Bulk orange juice`, and so on. -Each of these work masters correspond to the same process segment, `mixing`. - -```mermaid -classDiagram -namespace work_masters{ -class `Bulk blue juice` -class `Bulk red juice` -class `Bulk orange juice` -} - -`Bulk blue juice` ..> `Process segment:
mixing` :corresponds to -`Bulk red juice` ..> `Process segment:
mixing` :corresponds to -`Bulk orange juice` ..> `Process segment:
mixing` :corresponds to -``` - -### Contains specifications - -A process segment may contain one or more resource _specifications_. -These specifications describe the necessary resources for the step. - -```mermaid -classDiagram -class `bulk juices`{use: produced} -class `ingredient kits`{use: consumed} - mixing *--> `equipment specification` :contains - `equipment specification` ..> `mixers` :corresponds to - mixing *--> `material specification` :contains - `material specification` ..> `bulk juices` :corresponds to - `material specification` ..> `ingredient kits` :corresponds to -``` -### Contains segment parameters - -A process segment can _contain_ process segment parameters. -Process segment parameters store additional information about the step. -For example, the `mixing` process segment might have a `mixing time` parameter. - -The parameter also can have a value or range of values. -This process segment parameter value may serve as a default for lower-level work models that [correspond to](#corresponds-to) this process segment. - -```mermaid -classDiagram -class `mixing time`{ - value: 20-30 - UoM: minutes -} -class `mixing speed`{ - value: 50 - UoM: RPM -} - `mixing` *--> `mixing time` - `mixing` *--> `mixing speed` -``` - -### Is made of - -A process segment can _be made of_ other process segments. -You can use this relationship to model sub-steps. - -For example, The Juice Factory might need to distinguish preparation steps from production steps. -A parent segment provides a model to aggregate the production steps in one parent process segment. - -```mermaid -flowchart LR - subgraph m[Parent: Juice Production] - direction LR - K[Child:
kitting] --> - M[Child:
mixing] --> - P[Child:packing] - end - A[Material receiving] --> m - - - classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; - classDef b fill:#fff,stroke:#000,stroke-width:1px,color:#000; - class A,C,D,N,X,m,T,V box -``` - -### Dependency - -In some instances, you might need to strictly model the order in which some or all steps happen. -For this, use _segment dependancies_. - -Segment dependencies become more important when steps might be executed in parallel or dynamically. -The dependency ensures nothing happens too early. - -If your process segment is independent of a particular product, -ensure that all entities that [correspond to](#correspond-to) that segment also have that dependency. -For example, in a pastry production, the `baking` segment might have a dependency on `mixing` and `preheating`. -This implies that all products that correspond to this `baking`—such as a `chocolate chip cookies` or `brownies`—must also require `mixing` and `preheating` as dependencies. - -```mermaid -classDiagram -baking ..> mixing : has execution dependency on -baking ..> pre-heating : has execution dependency on - -``` - -If a dependency is product-dependent, define it on the level of the {{< abbr "work master" >}} or operation definition instead. - diff --git a/content/versions/v4.0.0/isa-95/models-of-work/work-masters.md b/content/versions/v4.0.0/isa-95/models-of-work/work-masters.md deleted file mode 100644 index 4fa86035b..000000000 --- a/content/versions/v4.0.0/isa-95/models-of-work/work-masters.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: Work masters -description: The most granular work definition in ISA-95, defining the resources and instructions necessary to do a unit of work. ---- - -{{% reusable/isa-95-course %}} - -A _work master_ defines the resources and instructions necessary to do a unit of work. -As the most granular work definition in ISA-95, the work master can serve a variety of operational purposes: -- Define how to create a product from the perspective of a level-3 system -- Provide a reference document that can be cloned and overridden for detailed scheduling and dispatching -- Store recipes and parameters to be downloaded by the PLC -- Contain parameters to derive metrics for KPI calculations - -In the manufacturing {{< abbr "ontology" >}}, the work master has relationships to resources, other work definitions, and planning entities. Like other work definitions, a work master can be either a {{< abbr "pattern" >}}, defining a template for work, or an {{< abbr "instance" >}}, defining a unit of actual work. - -## Work master attributes - - -```mermaid -classDiagram -class workMaster{ -id: make.PBJ1000 -description: Make Packaged Blue Juice -workType: production -duration: 45 minutes -} - -``` -Along with relationships described in the following sections, work masters have attributes to identify and qualify the type of work being defined. -Important attributes include: - - -ID -: A unique ID - -Work type -: The category of work―one of `production`, `maintenance`, `quality`, or `inventory` - -Duration -: The expected time needed to perform the work - - -## Contains resources and parameter specifications {#contains} - -A work master may have _specifications_ that link the work master to its required resources and instructions. -In ISA-95 relations, the specification is an intermediary between the work master and the resource or parameter. -The work master _contains_ the specifications; -the specifications describe the necessary quantities and uses of the resource object that it _corresponds to_. - - -```mermaid -classDiagram -class materialSpecification{ - what and how much? - -} -class personnelSpecification{ - who and how many? -} -class equipmentSpecification{ -how? -} - -class parameterSpecification{ -instructions, checklists, -and so on -} - -workMaster *--> materialSpecification :contains -workMaster *--> personnelSpecification :contains -workMaster *--> equipmentSpecification :contains -workMaster *--> parameterSpecification :contains - -``` - - -### Example: material specifications - -Resource specifications may have attributes that describe information about the use, quantity, and location of the resource. -Some specifications, such as material, have additional attributes. - - -For example, to produce one pallet of `Cosmic Blue Juice`, The Juice Factory requires 5 cases of Blue Juice and one pallet. -The work master to produce this final product specifies three different materials, all of which are used in a different way: -- Consume 5 units of the `blue juice case`, a {{< abbr "material definition" >}} -- Produce 1 unit of `packed blue juice`, a {{< abbr "material definition" >}} -- Use one pallet, a consumable (material that has no {{< abbr "material lot">}}) - - -```mermaid -classDiagram -class `Work master: Make Cosmic Blue Juice`{ -description: procedure to produce pallet of Cosmic Blue Juice -} - -class `Specification: blue juice case`{ -use: consumed -quantity: 5 -quantity_unit_of_measure: juice_case -} -class `Specification: blue juice pallet`{ -use: produced -quantity: 1 -quantity_unit_of_measure: pallet -} - -class `Specification: pallet`{ -use: consumable -quantity: 1 -quantity_unit_of_measure: pallet -} -class `Material definition: PBJ`{ -description: One pallet of cosmic blue juice -} - -`Work master: Make Cosmic Blue Juice` *--> `Specification: blue juice case` -`Work master: Make Cosmic Blue Juice` *--> `Specification: blue juice pallet` -`Work master: Make Cosmic Blue Juice` *--> `Specification: pallet` -`Specification: blue juice case` --> `Material definition: PBJ` -`Specification: blue juice pallet` --> `Material definition: blue juice case` - -``` - -{{< callout type="info" >}} -Note that the preceding diagram includes only the material specification. -The full work master may also contain specifications about the equipment, personnel, parameter specifications, and so on. -{{< /callout >}} - -### Parameter specifications - -Parameter specifications detail information that is specific to a work master but not specific to any particular resource. -For example, the production of bulk juice might have a parameter specification called `pre-mix checklist` that details a set of steps that the operator must perform before starting the equipment. - -## Relationships to planning models - -As work masters [contain](#contains) resource requirements and instructions, they also act as a source document for detailed scheduling and dispatching. -Conventionally, work masters are related to job orders through a work directive entity: -- The job order says what to make -- The work master provides a canonical definition of how to make it -- The work directive provides a copy of the work master, specific to the particular order - - -```mermaid -classDiagram -class jobOrder{ -make bulk blue juice -} - -class workMaster{ -id: WM.Bulk_Blue_Juice -} -class workDirective{ -id: WD.Bulk_blue_juice -} - -jobOrder --> workDirective :corresponds to -workDirective --> workMaster :derived from - -``` - -### Corresponds to work directive - -A work directive is a clone of the work master that is made at the time of dispatching. -If the actual work performed needs to deviate from the work defined in the work master, -the work directive provides a way to record the changes in a new definition. - -For example, the work master to `make bulk blue juice` might specify sugar from a specific provider. -At the time of production, however, the plant might have only sugar from a different supplier. -In this case, the work directive would override the material specification to reflect the substitute material definition. - -## Relationships to other work masters - -A work master might have relationships to other work masters: -- A work master may _contain_ children work master. -- An {{< abbr "instance" >}} work master may _be defined by_ a _{{< abbr "pattern" >}}_ work master. - -### Parent child-work masters {#parent} - -You can group sub-definitions of a work master using a parent-child relationship. -For example, the work master to `make juice` might have child work masters for the production recipe from the quality testing procedure. - - -```mermaid -classDiagram -class `WM: bottle`{ -equipment_specifcation: bottler -equipment_specifcation: capper -} -class `WM: quality inspection`{ -personnel_specifcation: tester -} - -`WM:make juice` *--> `WM: bottle` :contains -`WM:make juice` *--> `WM: quality inspection` :contains - - -``` - - -### Defined by patterns {#pattern} - -A _pattern_ work master provides a template to build _instance_ work masters for similar production processes. - -For example, to produce bulk juice for all five of its juice lines, -The Juice Factory requires exactly the same equipment and quantity of sugar. -The only item that changes is the material definition for the kits that are dumped into the mixer. - -To minimize configuration, The Juice Factory might use a pattern work master that specifies the equipment, sugar, and kit class. -Then each brand of juice may have an instance work master that overrides the `kits` class with its specific kit definition. - -```mermaid -classDiagram -class patternWorkMaster{ -description: make bulk juice -equipment specifications: - - mixers -material specifications: - - 200LB sugar - - 1 kit from kits class -} - -class instanceWorkMaster_blue{ -- make bulk blue juice -- requires 1 blue kit -} - -class instanceWorkMaster_red{ -- make bulk red juice -- requires 1 red kit -} - -patternWorkMaster --> instanceWorkMaster_blue :defines -patternWorkMaster --> instanceWorkMaster_red :defines - - -``` - -### Corresponds to a process segment - -Work masters _correspond to_ [process segments]({{< relref "process-segments" >}}), which are less granular, business-level definitions of work. -For example, the `make juice` process segment might have five corresponding work masters that describe how to produce each line of juice at the level of detail necessary for a manufacturing execution system. - -```mermaid -classDiagram -namespace process_segment_kitting{ -class `WM: make blue juice kit` -class `WM: make red juice kit` -class `WM: make green juice kit` - -} - -``` - - -## Workflow specifications - -The work master may be linked to other work masters in a sequence through a _workflow specification_. -The workflow specification provides an overview of the steps to execute masters in sequence. - -Each master can _have_ a node that exists in the workflow specification. -For example, here are the production steps to make blue juice. -Each node in this workflow might correspond to a work master, with the `pack` node being a {{< abbr "call-activity" >}} that corresponds to the `pack` [parent](#parent) work master. - -![workflow specification to make blue juice](/BPMNs/workflow-spec-make-bulk-blue-juice.png) - diff --git a/content/versions/v4.0.0/isa-95/resources/_index.md b/content/versions/v4.0.0/isa-95/resources/_index.md deleted file mode 100644 index 224562731..000000000 --- a/content/versions/v4.0.0/isa-95/resources/_index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Resources in ISA-95 -description: No matter what you make, your manufacturing operation needs resources -weight: 200 -cascade: - icon: cube ---- - -{{% reusable/isa-95-course %}} - -No matter what you make, your manufacturing operation is going to use resources: - -- Without material, you can’t make anything. -- Without equipment, you can't transform material into a product. -- Without personnel, no one can run the equipment. - -Resources are present everywhere in a manufacturing operation, and the resource models are present everywhere in ISA-95. When you define processes, you need to mention material. When you plan production, you need information about resource definitions and availability. When you execute production, you need to use resources. And when you collect data, you need a model to record what resources were used. - - -{{< card-list >}} diff --git a/content/versions/v4.0.0/isa-95/resources/equipment.md b/content/versions/v4.0.0/isa-95/resources/equipment.md deleted file mode 100644 index 35f3cf8db..000000000 --- a/content/versions/v4.0.0/isa-95/resources/equipment.md +++ /dev/null @@ -1,320 +0,0 @@ ---- -title: Equipment models in ISA-95 -description: A guide to equipment entities and relationships in ISA-95 -icon: wrench -images: - - "/images/s95/diagram-rhize-isa-equipment-relationships-packing.png" - ---- - -{{% reusable/isa-95-course %}} - -Equipment is an object that has a defined role in the production process. -Equipment can have _properties_, which define some temporary or permanent value, -and can belong to _classes_, which provide templates to define and categorize related objects. - -{{< figure -alt="A packaging class, instance and sub units" -src="/images/s95/diagram-rhize-isa-equipment-relationships-packing.png" ->}} - -All the equipment entities are connected through relationships. -This page describes what these relationships are and when to use them. - - -{{< details title="Abstract diagram of equipment entity-relationships" >}} - -```mermaid -classDiagram -equipment --> `equipment class` : defined by -`equipment class` o--> `equipment class` :made up of -`equipment class` --> `equipment class` :includes properties of -equipment *--> `equipment property` :has values of -`equipment class` *--> `equipment class property` :has properties of -`equipment class property` <.. `equipment property` :maps to -equipment o--> equipment : made up of -`equipment property` o--> `equipment property` : contains -`equipment class property` o--> `equipment class property` : contains -``` - -{{< /details >}} - - -## The role-based hierarchy - - -The word _role_ is key to understanding the ISA-95 equipment models. -All equipment has a particular function in the wider operation. -The scope of a role varies widely, from the execution of an enterprise-level schedule to the production of a single unit of material. - -Equipment with broader scopes occupy higher _levels_, -and they may be composed of lower-level equipment objects that perform more specialized roles. -This composition of equipment is called -the _role-based equipment hierarchy_. - -{{< figure -alt="Role-based equipment hierarchy" -src="/images/s95/diagram-rhize-isa95-equipment-hierarchy.svg" -width="65%" ->}} - -Your model can be explicit about the equipment's position in the hierarchy through the `equipmentLevel` attribute. - -```mermaid -classDiagram -class equipment { -id: "JF.SF.PA.PackL4.Capper" -description: "Capper line 4" -equipmentLevel: "workUnit" -} - -``` - -Note that the lowest two levels distinguish equipment that has a storage role from equipment that has a production role. - -When equipment has a production role, that role typically is scoped to the execution of an order or collection of orders. -For example, in our fictional juice factory, equipment roles include: -- The Springfield plant. A site-level equipment that organizes the production of all brands of juice. -- The sugar storage zone. Where the Springfield site stores raw sugar in silos. -- The mixing unit. a work unit that receives raw coloring, flavoring, and sugar as input and produces a bulk volume of `Cosmic Blue juice` material as output. - - -The role of work units, equipment on the lowest level, is typically to execute one order at a time. -For that reason, PLCs and other controls-level equipment is typically below the scope of the ISA-95 equipment model -—though **the model may provide an interface for PLC to level-3 interaction.** - - - -## Equipment is made up of equipment - -Equipment is made up of other equipment. -High-level equipment items are composed of equipment items with more granular functions. -For example, the juice factory has a work center, `packaging line 1`, that is composed of 4 lower level units that perform specific packaging functions. - -```mermaid -classDiagram - equipment o--> equipment : made up of -``` - -### Reasons to use `isMadeOf` - -The `isMadeOf` relationship provides a way to organize equipment in its hierarchical structure. -This structure often mimics the spatial hierarchy of the plant or the social hierarchy of the organization. - -Besides this, the `isMadeOf` relationship provides a way to do the following: -- **Set required assemblies for sub items**. For example, a process specifies a `Sweeteners storage center` it also logically specifies the equipment that that storage center contains (e.g. `silos`) -- **Query and compare work by zone of interest.** For example, you could compare performance across all packing lines by querying the parent center. -- **Provide a view of the manufacturing operation that is intelligible from the business perspective.** -The equipment model focuses on the production of new material, not individual controls. - -### Query example: full composition of The Juice Factory - - -In the RhizeDB, the equipment `isMadeUpOf` relationship can be queried as follows. -This response shows the entire equipment hierarchy for The Juice Factory enterprise. - -{{< details title="Query and response" closed="true" >}} -{{% tabs items="Query,Response" %}} -{{% tab %}} - -```gql -query enterprise{ - enterprise: getEquipment(id:"JF.SF") { - ...active - isMadeUpOf { - ...active - isMadeUpOf { - ...active - isMadeUpOf { - ...active - isMadeUpOf { - ...active - isMadeUpOf { - ...active - } - } - } - } - } - } -} - -fragment active on Equipment{ - activeVersion { - id - description - equipmentLevel - } -} -``` - -{{% /tab %}} -{{% tab %}} -```json -{{% reusable/jf %}} -``` - -{{% /tab %}} -{{% /tabs %}} - -{{< /details >}} - - -## Equipment can have properties - -Properties are _key value_ pairs that report some permanent or temporary condition of an object. -Equipment can have 0 or many properties. - -```mermaid -classDiagram -equipment *--> `equipment property` :has values of -``` - -For example, the `Packaging line` work center has the properties: -- `State`, which reports whether the center is active or not. -- `infeed`, the number of empty containers at the beginning of the line -- `outfeed`, the number of filled containers at the end of the line - -The value of these properties can used to calculate metrics or trigger workflows. - -### Equipment properties can contain properties - -A property itself can have a composition of properties. -For example, a unit might have the `dimension` property that contains subproperties of `width` and `height`. - -```mermaid -classDiagram -rectangularThing *--> `dimension (property)` : "has values of" -`dimension (property)` *--> length : "contains" -`dimension (property)` *--> width : "contains" - -`dimension (property)` *--> height : "contains" -``` - - -This `contains` relationship creates a container to group granular properties by some commonality. -It also saves configuration time, since any equipment that has the parent property can logically have its child properties as well. - - -## Equipment classes define equipment - -Similar equipment might be _defined_ by its equipment class. -Classes minimize repetitive modelling of equal equipment and properties. - -```mermaid -classDiagram -equipment --> `equipment class` : defined by -``` - -For example, the `packing line` work center always has a `filler` work unit as part of its composition. -So, when there are 4 `packing lines`, there logically must be 4 fillers. -To avoid individually tracking each filler and its configuration, you can create a `fillers` class that defines each member. - -```mermaid -classDiagram -namespace Fillers { - class `filler line 1` - class `filler line 2` - class `filler line 3` - class `filler line 4` -} -``` - -### Query example: all members of `Packaging` class - - -This example queries the Rhize DB for all members of the `Packaging` equipment class. - -{{< details title="Example: query class for members" >}} -{{< tabs items="Query,Result" >}} -{{< tab >}} - -```gql -query equipmentClass{ - getEquipmentClass(id:"Packaging") { - id - equipmentVersions { - id - description - } - } -} - -``` -{{< /tab >}} -{{< tab >}} -```json -{ - "data": { - "getEquipmentClass": { - "id": "Packaging", - "equipmentVersions": [ - { - "id": "JF.SF.PA.PackL1", - "description": "Packaging line 1" - }, - { - "id": "JF.SF.PA.PackL2", - "description": "Packaging line 2" - }, - { - "id": "JF.SF.PA.PackL3", - "description": "Packaging line 3" - }, - { - "id": "JF.SF.PA.PackL4", - "description": "Packaging line 4" - } - ] - } - } -} - -``` -{{< /tab >}} -{{< /tabs >}} - - -{{< /details >}} - -### Equipment properties map to class properties - - -As equipment can have equipment properties, an equipment class can have equipment class properties. -However, an equipment class property is only a key, not a value. -When an equipment belongs to an equipment class, that equipment receives its properties. -So, equipment properties _map to_ the class properties. - -```mermaid -classDiagram - -equipment *--> `equipment \n property` :has values of -equipment *--> `equipment \n class` :defined by -`equipment \n class` *--> `equipment \n class \n property` :has properties of -`equipment \n class \n property` <.. `equipment \n property` :maps to -``` - - -Classes are abstract, and so class properties are abstract keys. -An Equipment is tangible, and thus has a property key and an actual value. - - - -### Equipment classes can be made of other classes - -As equipment can be _made of_ equipment, so equipment classes can be made of equipment classes. - -```mermaid -classDiagram -`packaging (class)` *-- fillers -`packaging (class)` *-- cappers -`packaging (class)` *-- packers -`packaging (class)` *-- palletizers - -`packaging line 1` *-- filler 1 -`packaging line 1` *-- capper 1 -`packaging line 1` *-- packer 1 -`packaging line 1` *-- palletizer 1 - -``` - diff --git a/content/versions/v4.0.0/isa-95/resources/material.md b/content/versions/v4.0.0/isa-95/resources/material.md deleted file mode 100644 index cc7774273..000000000 --- a/content/versions/v4.0.0/isa-95/resources/material.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -title: Material models in ISA-95 -description: A guide to material entities and relationships in ISA-95 -icon: beaker ---- - -{{% reusable/isa-95-course %}} - -In ISA-95, _material_ can be a finished good or anything that goes into this good. -Examples of material include: -- A final product, such as packaged watch -- A part, such as a gear in this watch -- An intermediate substance, such as a produced reactant to be used in combination with another chemical -- Raw materials, like the flour and water that make dough - - -Like [equipment]({{< relref "equipment" >}}), material can have classes and properties. -However, to account for detailed tracking of unique material units, -the material model has more entities than equipment. - -{{< details title="Full diagram of abstract relationships" closed="true" >}} - -```mermaid -classDiagram -`material sublot` o--> `material lot` :assembled from -`material lot` o--> `material lot` :assembled from -`material definition` o--> `material definition` :assembled from -`material class` o--> `material class` :assembled from -`material class` o--> `material class` :assembled from -`material lot` -->`material definition` :defined by -`material definition` -->`material class` :defined by -`material lot` *--> `material lot properties` :has values of -`material sublot` *--> `material lot properties` :has values of -`material definition` *-->`material definition properties` :has properties of -`material class` -->`material class properties` :has properties of -`material lot properties` ..> `material definition properties` :maps to -`material definition properties` ..> `material class properties` :maps to -`material lot properties` *--> `material lot properties` :contains -`material definition properties` *--> `material definition properties` :contains -`material class properties` *--> `material class properties` :contains -``` - -{{< /details >}} - -## Defined by - -The `defined by` relationship associates material with common categories and definitions. - -```mermaid -classDiagram -`material lot` -->`material definition` :defined by -`material definition` -->`material class` :defined by -`Cosmic Blue Juice,\npallet 1` -->`Cosmic Blue Juice,\ndefinition` :defined by -`Cosmic Blue Juice,\ndefinition` -->`Juices class` :defined by -``` - -### Material lots are `defined by` material definitions - -_Material definitions_ provide a way to ensure units of the same substance -have a consistent name and set of properties. -_Material lots_ provide a way to uniquely identify each specific instance of that definition. - -For example, the Springfield plant might produce 100 pallets of its flagship product, `Cosmic Blue Juice`. -Obviously, these pallets are not literally the same: otherwise they would just be one pallet. -Rather, each pallet is a separate _lots_, and all these lots share the same material definition. - - -### Definitions are defined by classes - -If you need another level of abstraction, you can also categorize your material definitions by _material class_. -Material classes provide a way to categorize material by function or shared [properties](#material-properties). -For example, `The Juice Factory` has five juice definitions, all part of the class `Juices`. - -```mermaid -classDiagram -namespace juices { -class `Nuclear Green Juice` -class `Tropical Orange Juice` -class `Cosmic blue juice` -class `Royal Purple Juice` -class `Berry Red Juice` -} - -``` -Note that material classes can contain material classes. For example, the `raw_materials` class might contain all raw ingredients. - -```mermaid ---- -subtitle: Material classes can contain material classes ---- -classDiagram -namespace raw_materials{ - class sweeteners - class flavors - class colors -} -namespace sweeteners{ - class sugar - class aspertame -} -namespace flavors{ - class `blue flavoring` - class `orange flavoring` -} -namespace colors{ - class `blue` - class `orange` -} - - - -``` - -## Is assembled from - -Material lots also might be _assembled from_ material _sublots_. - - -```mermaid -classDiagram -`material lot` o--> `material sublot` :is assembled from -``` - -Sublots are uniquely identifiable components of a material lot. -For example, -the pallet `PBJ.1000.1` might be assembled from a set of packed juice cases. -Each case might be modelled as a sublot with a unique ID, such as `PBJ.1000.1.1`. - - -## Has material properties - -Material can have _properties_, or characteristics that describe some aspect of its implementation. -You can set material definitions at the level of the class, definition, or lot. - -If a material class or definition has members, then all members _inherit_ the properties associated with its defining entity. -If using class or definition properties, you can also set a default value to be inherited by its members. - -For example, the `juices` class has the property `sugarContent`. -The material definition `Cosmic Blue Juice` is a member of this class, and thus it inherits the `sugarContent` property. -The `Cosmic Blue Juice` product has a defined standard value for its `sugarContent`, `100 grams`. -The material lot `CBJ.Pallet1` is a pallet of Cosmic Blue Juice. -This lot inherits the `sugarContent` property from the definition that it belongs to, and its value might deviate from the default value of its definition. - -```mermaid -classDiagram -class materialClass{ - id: juices -} -class materialDefinition{ - id: Cosmic blue juice -} - -class materialLot{ - id: Cosmic blue juice, pallet 1 -} - - -class materialLotProperty{ - id: cbj.1.sugarContent, - UnitOfMeasure: g, - value: 99.5 -} -class materialDefinitionProperty{ - id: cbj.sugarContent, - value: 100 - UnitOfMeasure: g, -} -class materialClassProperty{ - id: sugarContent, - UnitOfMeasure: g, -} - -materialClass *--> materialClassProperty :has property of -materialDefinition *--> materialDefinitionProperty :has property of -materialLot *--> materialLotProperty :has value of -materialLot *--> materialDefinition :defined by -materialDefinition *--> materialClass :defined by -materialLotProperty *--> materialDefinitionProperty :maps to -materialDefinitionProperty *--> materialClassProperty :maps to - - -``` - - -### Properties contain properties - -```mermaid -classDiagram -flavor_profile *--> sweetness -flavor_profile *--> umami -flavor_profile *--> aciditiy - -``` - -As with equipment properties, all properties can contain properties. -For example, the property `flavor_profile` might contain properties for `sweetness`, `acidity` and `umami`. diff --git a/data/versionCompat.yaml b/data/versionCompat.yaml index 9a33ee735..d0685b05c 100644 --- a/data/versionCompat.yaml +++ b/data/versionCompat.yaml @@ -1,12 +1,15 @@ -- version: "3.2.1" - apollo_router: "1.61.0" - grafana: "9.4.7" - keycloak_postgres: "15.3.0" - keycloak: "21.1.2" - loki: "2.9.12" - nats: "2.10.25" +- version: "4.2.0" + keycloak: "26.4" + prometheus: "3.7.3" + questdb: "9.1.1" + redpanda_console: "3.2.2" + redpanda: "25.2.10" + restate: "1.5.3" + audit-postgres: "17.6.0" + keycloak-postgres: "17.6.0" tempo: "2.7.1" -- version: "4.0.0" + loki: "2.9.12" +- version: "3.2.1" apollo_router: "1.61.0" grafana: "9.4.7" keycloak_postgres: "15.3.0" @@ -46,11 +49,3 @@ loki: "2.9.3" nats: "2.10.17" tempo: "2.3.1" -- version: "3.0.0" - apollo_router: "1.15.1" - grafana: "9.4.7" - keycloak_postgres: "15.3.0" - keycloak: "21.1.1" - loki: "2.3.9" - nats: "2.10.10" - tempo: "2.3.1" diff --git a/layouts/_partials/version-picker.html b/layouts/_partials/version-picker.html index 0ef97f44f..bb42bd2ed 100644 --- a/layouts/_partials/version-picker.html +++ b/layouts/_partials/version-picker.html @@ -1,14 +1,11 @@ {{ $versions := slice }} -{{ range sort site.Data.versionCompat .version }} - {{if gt .version "3.0.2"}} +{{ range sort site.Data.versionCompat .version "desc" }} {{ $versions = $versions | append ( printf "%s" .version) }} - {{end}} {{ end }} {{- $class := .class | default "hx:h-7 hx:px-2 hx:text-xs hx:text-gray-600 hx:transition-colors hx:dark:text-gray-400 hx:hover:bg-gray-100 hx:hover:text-gray-900 hx:dark:hover:bg-primary-100/5 hx:dark:hover:text-gray-50" -}} {{ $lastVersion := index $versions 0 }} - {{- $page := .context -}} {{- $iconName := .iconName | default "clock" -}} {{- $iconHeight := .iconHeight | default 12 -}} @@ -31,7 +28,7 @@
{{- partial "utils/icon" (dict "name" $iconName "attributes" (printf "height=%d" $iconHeight)) -}} - {{- if not $hideLabel }}{{if eq page.Params.V $lastVersion}}{{ page.Params.V }} (latest){{else}}{{ page.Params.V }}{{ end }}{{ end -}} + {{- if not $hideLabel }}{{if eq page.Params.V $lastVersion}}{{ page.Params.V }} (latest){{else}}{{ page.Params.V }} {{ end }}{{ end -}}
    {{ with .apollo_router }}
  • Apollo router {{ . }}
  • {{ end }} + {{ with .audit_postgres }}
  • Audit Postgres {{ . }}
  • {{ end }} {{ with .grafana }}
  • Grafana: {{ . }}
  • {{ end }} {{ with .keycloak }}
  • Keycloak: {{ . }}
  • {{ end }} {{ with .keycloak_postgres }}
  • Keycloak Postgres: {{ . }}
  • {{ end }} {{ with .loki }}
  • Loki: {{ . }}
  • {{ end }} {{ with .nats }}
  • NATS: {{ . }}
  • {{ end }} + {{ with .prometheus }}
  • Prometheus: {{ . }}
  • {{ end }} + {{ with .restate }}
  • Restate: {{ . }}
  • {{ end }} + {{ with .redpanda }}
  • Redpanda: {{ . }}
  • {{ end }} + {{ with .redpanda_console }}
  • Redpanda Console: {{ . }}
  • {{ end }} {{ with .tempo }}
  • Tempo: {{ . }}
  • {{ end }}