diff --git a/docs/images/groups-roles.png b/docs/images/groups-roles.png new file mode 100644 index 0000000000000000000000000000000000000000..3c73de60a81e3a9f1343b3f39f4f373daa42b680 Binary files /dev/null and b/docs/images/groups-roles.png differ diff --git a/docs/system.md b/docs/system.md index e423074df5e938354b04acb073a26dab3bb4d5aa..326570d85aacfdedf04e853843395cd145330e92 100644 --- a/docs/system.md +++ b/docs/system.md @@ -53,7 +53,8 @@ Very specific to the deployment of the organization. In our reference implementa markup language* (SAML) service provider and use our institutional SAML identity provider for obtaining account data through an encrypted channel. -From version 1.2 onwards we use Keycloak for authentication and deprecated the previous Spring Boot application. Consequently, +From version 1.2 onwards we use Keycloak for authentication and deprecated the previous Spring Boot application. +Consequently, the authentication will be through Keycloak. !!! warning "Unsupported Keycloak features" @@ -63,17 +64,163 @@ the authentication will be through Keycloak. * E-Mail verification * Temporary passwords -By default, the Authentication Service comes with a self-signed certificate valid 3 months from build date. For deployment -it is *highly encouraged* to use your own certificate, properly issued by a trusted PKI, e.g. GEÁNT. For local deployments -you can use the self-signed certificate. You need to accept the risk in most browsers when visiting the -[admin panel](https://localhost:8443/admin/). +By default, the Authentication Service comes with a self-signed certificate valid 3 months from build date. For +deployment it is *highly encouraged* to use your own certificate, properly issued by a trusted PKI, e.g. GEÁNT. For +local deployments you can use the self-signed certificate. You need to accept the risk in most browsers when visiting +the [admin panel](https://localhost:8443/admin/). -Sign in with the default credentials (username `fda`, password `fda`) or the one you configured during set-up. Be default, -users are created using the frontend and the sign-up page. But it is also possible to create users from Keycloak, they will -still act as "self-sign-up" created users. Since we do not support all features of Keycloak, leave out required user actions -as they will not be enforced, also the temporary password. +Sign in with the default credentials (username `fda`, password `fda`) or the one you configured during set-up. Be +default, users are created using the frontend and the sign-up page. But it is also possible to create users from +Keycloak, they will still act as "self-sign-up" created users. Since we do not support all features of Keycloak, leave +out required user actions as they will not be enforced, also the temporary password. -#### Obtain Access Token +Each user has attributes associated to them. In case you manually create a user in Keycloak directly, you need to add +them in Users > Add user > Attributes: + +* `theme_dark` (*boolean*, default: false) +* `orcid` (*string*) +* `affiliation` (*string*) + +#### Groups + +The authorization scheme follows a group-based access control (GBAC). Users are organized in three distinct +(non-overlapping) groups: + +1. Researchers (*default*) +2. Developers +3. Data Stewards + +Based on the membership in one of these groups, the user is assigned a set of roles that authorize specific actions. By +default, all users are assigned to the `researchers` group. + +#### Roles + +We organize the roles into default- and escalated composite roles. There are three composite roles, one for each group. +Each of the composite role has a set of other associated composite roles. + +<figure markdown> + +<figcaption>Three groups (Researchers, Developers, Data Stewards) and their composite roles associated.</figcaption> +</figure> + +There is one role for one specific action in the services. For example: the `create-database` role authorizes a user to +create a database in a Docker container. Therefore, +the [`DatabaseEndpoint.java`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/a5bdd1e2169bae6497e2f7eee82dad8b9b059850/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java#L78) +endpoint requires a JWT access token with this authority. + +```java +@PostMapping +@PreAuthorize("hasAuthority('create-database')") +public ResponseEntity<DatabaseBriefDto> create(@NotNull Long containerId, + @Valid @RequestBody DatabaseCreateDto createDto, + @NotNull Principal principal) { +... +} +``` + +##### Default Container Handling + +| Name | Description | +|--------------------------|--------------------------------------| +| `create-container` | Can create a container | +| `find-container` | Can find a specific container | +| `list-containers` | Can list all containers | +| `modify-container-state` | Can start and stop the own container | + +##### Default Database Handling + +| Name | Description | +|------------------------------|------------------------------------------------------| +| `check-database-access` | Can check the access to a database of a user | +| `create-database` | Can create a database | +| `create-database-access` | Can give a new access to a database of a user | +| `delete-database-access` | Can delete the access to a database of a user | +| `find-database` | Can find a specific database in a container | +| `list-databases` | Can list all databases in a container | +| `modify-database-visibility` | Can modify the database visibility (public, private) | +| `modify-database-owner` | Can modify the database owner | +| `update-database-access` | Can update the access to a database of a user | + +##### Default Table Handling + +| Name | Description | +|---------------------------------|------------------------------------------------------| +| `create-table` | Can create a table | +| `find-tables` | Can list a specific table in a database | +| `list-tables` | Can list all tables | +| `modify-table-column-semantics` | Can modify the column semantics of a specific column | + +##### Default Query Handling + +| Name | Description | +|---------------------------|-----------------------------------------------| +| `create-database-view` | Can create a view in a database | +| `delete-database-view` | Can delete a view in a database | +| `delete-table-data` | Can delete data in a table | +| `execute-query` | Can execute a query statement | +| `export-query-data` | Can export the data that a query has produced | +| `export-table-data` | Can export the data stored in a table | +| `find-database-view` | Can find a specific database view | +| `find-query` | Can find a specific query in the query store | +| `insert-table-data` | Can insert data into a table | +| `list-database-views` | Can list all database views | +| `list-queries` | Can list all queries in the query store | +| `persist-query` | Can persist a query in the query store | +| `re-execute-query` | Can re-execute a query to reproduce a result | +| `view-database-view-data` | Can view the data produced by a database view | +| `view-table-data` | Can view the data in a table | +| `view-table-history` | Can view the data history of a table | + +##### Default Identifier Handling + +| Name | Description | +|---------------------|---------------------------------------------| +| `create-identifier` | Can create an identifier (subset, database) | +| `find-identifier` | Can find a specific identifier | +| `list-identifier` | Can list all identifiers | + +##### Default User Handling + +| Name | Description | +|---------------------------|-----------------------------------------| +| `modify-user-theme` | Can modify the user theme (light, dark) | +| `modify-user-information` | Can modify the user information | + +##### Escalated Container Handling + +| Name | Description | +|----------------------------------|----------------------------------------------| +| `delete-container` | Can delete any container | +| `modify-foreign-container-state` | Can modify any container state (start, stop) | + +##### Escalated Database Handling + +| Name | Description | +|-------------------|------------------------------------------| +| `delete-database` | Can delete any database in any container | + +##### Escalated Table Handling + +| Name | Description | +|----------------|--------------------------------------| +| `delete-table` | Can delete any table in any database | + +##### Escalated Query Handling + +| Name | Description | +|------|-------------| + +##### Escalated Identifier Handling + +| Name | Description | +|------------------------------|---------------------------------------------------| +| `create-foreign-identifier` | Can create an identifier to any database or query | +| `delete-identifier` | Can delete any identifier | +| `modify-identifier-metadata` | Can modify any identifier metadata | + +#### API + +##### Obtain Access Token Access tokens are needed for almost all operations. @@ -101,7 +248,7 @@ Access tokens are needed for almost all operations. print(auth.json()["access_token"]) ``` -#### Refresh Access Token +##### Refresh Access Token Using the response from above, a new access token can be created via the refresh token provided. @@ -139,6 +286,11 @@ It holds exchanges and topics responsible for holding AMQP messages for later co use [RabbitMQ](https://www.rabbitmq.com/) in the reference implementation. The AMQP endpoint listens to port `5672` for regular declares and offers a management interface at port `15672`. +The default credentials are: + +* Username: `fda` +* Password: `fda` + ### Container Service !!! debug "Debug Information" @@ -213,13 +365,15 @@ identifier* (DOI) through our institutional library soon. * Ports: 3306/tcp, 9100/tcp * Prometheus: `http://:9100/metrics` -It is the core component of the project. It is a relational database that contains metadata about all researcher databases +It is the core component of the project. It is a relational database that contains metadata about all researcher +databases created in the database repository like column names, check expressions, value enumerations or key/value constraints and relevant data for citing data sets. Additionally, the concept, e.g. URI of units of measurements of numerical columns is stored in the Metadata Database in order to provide semantic knowledge context. We use MariaDB for its rich capabilities in the reference implementation. -The default credentials are `root:dbrepo` for the database `fda`. Connect to the database via the JDBC connector on port `3306`. +The default credentials are `root:dbrepo` for the database `fda`. Connect to the database via the JDBC connector on +port `3306`. ### Metadata Service @@ -264,7 +418,7 @@ Service. It processes search requests from the Gateway Service for full-text lookups in the Metadata Database. We use [Elasticsearch](https://www.elastic.co/) in the reference implementation. The Search Service implements Elastic Search -and creates a retrievable index on all databases that is getting updated with each save operation on databases in the +and creates a retrievable index on all databases that is getting updated with each save operation on databases in the metadata database. All requests need to be authenticated, by default the credentials `elastic:elastic` are used. diff --git a/misc/.$diagrams.drawio.dtmp b/misc/.$diagrams.drawio.dtmp new file mode 100644 index 0000000000000000000000000000000000000000..263e415abf950e3231509a299dd7b193376ce839 --- /dev/null +++ b/misc/.$diagrams.drawio.dtmp @@ -0,0 +1,98 @@ +<mxfile host="Electron" modified="2023-05-03T17:30:20.676Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.1.2 Chrome/106.0.5249.199 Electron/21.4.3 Safari/537.36" etag="vHet0lnKQv43rmJkCjy7" version="21.1.2" type="device"> + <diagram id="knNdf-EWXshwNRS6GdW0" name="groups-roles"> + <mxGraphModel dx="1434" dy="822" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="585" pageHeight="520" math="0" shadow="0"> + <root> + <mxCell id="0" /> + <mxCell id="1" parent="0" /> + <mxCell id="p7gkXpudOZQYVS-MGniQ-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-26" target="p7gkXpudOZQYVS-MGniQ-22"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-28" value="include" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="p7gkXpudOZQYVS-MGniQ-27"> + <mxGeometry x="-0.2248" y="1" relative="1" as="geometry"> + <mxPoint x="-9" y="-1" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-26" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="223.5" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-22" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="2" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-1" target="p7gkXpudOZQYVS-MGniQ-4"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-1" value="Researchers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="12" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-2" target="p7gkXpudOZQYVS-MGniQ-5"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-2" value="Developers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="234" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-3" target="p7gkXpudOZQYVS-MGniQ-6"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-3" value="Data Steward" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="452" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-4" target="p7gkXpudOZQYVS-MGniQ-22"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-4" value="default-researcher-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-5" target="p7gkXpudOZQYVS-MGniQ-26"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="294.17499999999995" y="155.27999999999997" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-5" value="default-developer-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-6" target="p7gkXpudOZQYVS-MGniQ-30"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-6" value="default-data-steward-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="452" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-11" value="default-user-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="466" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-12" value="default-identifier-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="406" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-13" value="default-database-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="226" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-14" value="default-container-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="166" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-15" value="default-table-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="286" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-17" value="default-query-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="346" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-18" value="escalated-container-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="166" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-19" value="escalated-database-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="226" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-20" value="escalated-query-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="346" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-21" value="escalated-table-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="286" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-30" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="441.5" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-31" value="escalated-identifier-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="452" y="166" width="120" height="40" as="geometry" /> + </mxCell> + </root> + </mxGraphModel> + </diagram> +</mxfile> diff --git a/misc/diagrams.drawio b/misc/diagrams.drawio index 71be41bb3c2fcc8cde6cf1e40bd985fe80fa3c3d..f9e4ecf5018a9b1afff2db72eea11784302f688c 100644 --- a/misc/diagrams.drawio +++ b/misc/diagrams.drawio @@ -1 +1,98 @@ -<mxfile host="Electron" modified="2022-04-22T06:22:19.022Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/17.4.2 Chrome/100.0.4896.60 Electron/18.0.1 Safari/537.36" etag="kMcGUnc7b8fgl017WGgv" version="17.4.2" type="device" pages="2"><diagram id="31b32b95-0358-9bc7-6ba0-a27c054ed1a7" name="Page-1">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</diagram><diagram id="SixR3OZ22FMnOk72hDml" name="Architecture">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</diagram></mxfile> \ No newline at end of file +<mxfile host="Electron" modified="2023-05-03T17:30:17.440Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.1.2 Chrome/106.0.5249.199 Electron/21.4.3 Safari/537.36" etag="4X_A0JANa8ZCwBx5qeTt" version="21.1.2" type="device"> + <diagram id="knNdf-EWXshwNRS6GdW0" name="groups-roles"> + <mxGraphModel dx="1434" dy="822" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="585" pageHeight="520" math="0" shadow="0"> + <root> + <mxCell id="0" /> + <mxCell id="1" parent="0" /> + <mxCell id="p7gkXpudOZQYVS-MGniQ-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-26" target="p7gkXpudOZQYVS-MGniQ-22"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-28" value="include" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="p7gkXpudOZQYVS-MGniQ-27"> + <mxGeometry x="-0.2248" y="1" relative="1" as="geometry"> + <mxPoint x="-9" y="-1" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-26" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="223.5" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-22" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="2" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-1" target="p7gkXpudOZQYVS-MGniQ-4"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-1" value="Researchers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="12" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-2" target="p7gkXpudOZQYVS-MGniQ-5"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-2" value="Developers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="234" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-3" target="p7gkXpudOZQYVS-MGniQ-6"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-3" value="Data Steward" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="452" y="4" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-4" target="p7gkXpudOZQYVS-MGniQ-22"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-4" value="default-researcher-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-5" target="p7gkXpudOZQYVS-MGniQ-26"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="294.17499999999995" y="155.27999999999997" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-5" value="default-developer-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="p7gkXpudOZQYVS-MGniQ-6" target="p7gkXpudOZQYVS-MGniQ-30"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-6" value="default-data-steward-roles" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="452" y="74" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-11" value="default-user-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="466" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-12" value="default-identifier-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="406" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-13" value="default-database-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="226" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-14" value="default-container-handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="166" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-15" value="default-table-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="286" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-17" value="default-query-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="12.5" y="346" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-18" value="escalated-container-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="166" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-19" value="escalated-database-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="226" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-20" value="escalated-query-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="346" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-21" value="escalated-table-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="234" y="286" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-30" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=7;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="441.5" y="156" width="141" height="360" as="geometry" /> + </mxCell> + <mxCell id="p7gkXpudOZQYVS-MGniQ-31" value="escalated-identifier-<br>handling" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxGeometry x="452" y="166" width="120" height="40" as="geometry" /> + </mxCell> + </root> + </mxGraphModel> + </diagram> +</mxfile>