Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
erikao1998 committed Jul 5, 2024
1 parent 16132b8 commit 57b87d1
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 118 deletions.
25 changes: 7 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ Riksutin (officially known as **Risk-i** or **International collaboration risk a

### Survey

The main part of the app is a form that includes multiple questions about the project.
The main part of the app is a form that includes multiple questions about the project. [Docs](./docs/Survey.md) include a more detailed explanation.

### Risk calculation

After sending the entry to backend, the app calculates different risk levels for the project. The risks are based on the form and the data for calculating risks is either fetched from different external data sources or from `data/results.ts`. More information on the algorithm is found in the docs (coming soon).
After sending the entry to backend, the app calculates different risk levels for the project. The risks are based on the form and the data for calculating risks is either fetched from different external data sources or from `data/results.ts`. More information on the algorithm is found in the [docs](./docs/Algorithm.md).

### Results

The results page contains the risks in a table format which contains three columns: name, level and info text. The list of answers to the form is found below the table
The results page contains the risks in a table format which contains three columns: name, level and info text. The list of answers to the form is found below the table.

### User page

Expand All @@ -31,18 +31,7 @@ The user page contains a summary of the user's entries.

Four tabs can be found in the admin page:

- Summary

Contains a table of all the entries. The table can be exported to .xlsx file.

- Edit survey

There the admin can edit general survey texts and order of the questions.

- Edit questions

As the name suggests, this tab is for editing question titles and info texts.

- Edit results

Here one can edit the result titles and info texts.
- **Summary**: this tab contains a table of all the entries. The table can be exported as .xlsx file.
- **Edit survey**: here the admin can edit general survey texts and order of the questions.
- **Edit questions**: as the name suggests, this tab is for editing question titles and info texts.
- **Edit results**: here the admin can edit the result titles and info texts.
171 changes: 171 additions & 0 deletions docs/Algorithm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Algorithm documentation

This app contains an algorithm that calculates different risks for the project based on the answers user has provided in the survey. The algorithm is located in the backend at `util/algorithm`. In general, the algorithm receives a `FormValues` object and returns a `RiskData` object which is appended to the entry that is saved to the database.

## RiskData

`RiskData` object is one of the most important components of the app because it contains information of the risks related to the project. The object consists of the following properties.

### Answers

`Answers` contains all the data collected in the survey. It is a `FormValues` object.

### Country

`Country` includes all the country risks. These risks are based on the country the user has selected. It is a simple key-value object where the key is a title of the risk and value is either a risk level (a number from 1 to 3) or a some other value if it requires information from the survey before it can be converted to a risk level.

The object includes the following data. The source for data is in the brackets:

- Academic freedom (CSV)
- Corruption (Worldbank API)
- Human development index (CSV)
- Safety level (Ministry for Foreign Affairs of Finland's matkustustiedotteet, RSS feed)
- Sanctions (EU sanctions map API)
- Political stability (Worldbank API)
- Rule of Law (CSV)
- Universities (WHED, web scraper)

Risk levels of sanctions, safety level and universities are calculated based on the form data.

### Risks

`Risks` property is an array of `Risk` objects that are not included in `CountryData`. `Risk` object looks like this

```typescript
export interface Risk {
id: string // unique id
title: string // title for the risk that is rendered in the risk table
level: any // risk level which can be a number from 1 to 3 or a falsy value
infoText?: string // info text tells more information about the risk level and if the level requires some additional actions. The text is appended to the risk object in the client-side.
}
```

### UpdatedData

The app can recalculate the risks. This action is triggered in two occasions:

1. The user presses a button in the user page
2. A cron job recalculates them once a week

The recalculated data is saved to `UpdatedData`. It is an array of objects, and one object contains the same properties as `RiskData` and additionally `createdAt` string.

## Structure

The algorithm consists of the following files:

### createRiskData.ts

**What does it do**

This file is the main file of the algorithm. It contains one function - `createRiskData` - that is responsible for collecting all the risks together and returning the ready `RiskData` object to `entryRouter`.

In addition, this function gets all the country risks.

**Props**

`createRiskData` accepts an object with type `FormValues` as props.

---

### getCountryRisks.ts

**What does it do**

This file contains a function `getCountryRisks`. It updates `sanctions`, `gdpr` and `safetyLevel` risks so that they have numeric values.

**Props**

`getCountryRisks` has two parameters: `countryData: CountryData` and `formData: FormValues`

---

### getOtherRisks.ts

**What does it do**

The file contains a `getOtherRisks` function that creates a `Risk[]` object which looks like this:

```typescript
const riskArray: Risk[] = [
{
id: 'country',
title: 'riskTable:countryRiskLevel',
level: countryRiskValues ? countryRiskValues[0] : null,
},
{
id: 'university',
title: 'riskTable:universityRiskLevel',
level: universityRisk(formData['20'], country?.universities),
},
{
id: 'duration',
title: 'riskTable:durationRiskLevel',
level: questions
.find((question) => question.id === 12)
?.optionData.options.find((o) => o.id === formData[12])?.risk,
},
{
id: 'dualUse',
title: 'riskTable:dualUseRiskLevel',
level: dualUseRiskValue,
},
{
id: 'organisation',
title: 'riskTable:organisationRiskLevel',
level: organisationRiskValue,
},
{
id: 'economic',
title: 'riskTable:economicRiskLevel',
level: questions
.find((question) => question.id === 16)
?.optionData.options.find((o) => o.id === formData[16])?.risk,
},
{
id: 'ethical',
title: 'riskTable:ethicalRiskLevel',
level: ethicalRiskValue,
},
]
```

Consortium risk is added to the array if necessary.

Finally all risks that have null or undefined risk level are filtered out.

**Props**

`getOtherRisks(country: UpdatedCountryData, questions: Question[], formData: FormValues)`

---

### getTotalRisk.ts

**What does it do**

This file contains a function `getTotalRisk` which calculates a total risk level for the projects based on all the individual risks.

The level is calculated by calculating an average level of all risks and rounding it to the nearest integer. After that, the level is multiplied with a few multiplier and if the level happens to be over 3, it is set to 3.

**Props**

`getTotalRisk(riskArray: Risk[], country: UpdatedCountryData | undefined, formData: FormValues)`

---

### countryLists.ts

This file contains static lists of country codes used in the algorithm. There are four lists: `euCountries`, `eeaCountries`, `adequateProtectionCountries` and `globalNorthCountries`

---

### utils.ts

`utils.ts` contains a few different utility functions that are used to calculate specific risks. The file contains functions for:

- GDPR
- University
- Dual Use
- Organisation
- Consortium
- Total country risk
100 changes: 0 additions & 100 deletions docs/DataStructures.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,103 +458,3 @@ The `Result` model is used to map FormValues (the selections of a given survey)
}
}
```

# Recommendation

The `Recommendation` model represents the recommended tools or what ever that will be shown on the side of the survey.

Recommendations are really up to customization on a certain project.

## Properties

- `id` (number): The unique identifier for the recommendation.
- `surveyId` (number): The ID of the survey to which this recommendation belongs.
- `label` (string): The label identifying the recommendation (e.g., 'disclosure', 'clinic').
- `type` (string): The type of the recommendation eg. a category or something like that.
- `title` (Locales): The localized title of the recommendation.
- `text` (Locales): The localized description or text of the recommendation.

## Usage

### Defining recommendations

```json
[
{
"id": 1,
"surveyId": 1,
"label": "recommendation1",
"type": "common",
"title": {
"fi": "[Suositus 1 esimerkki](https://commonmark.org/help/)",
"sv": "[Rekommendation 1 exempel](https://commonmark.org/help/)",
"en": "[Recommendation 1 example](https://commonmark.org/help/)"
},
"text": {
"fi": "Voit käyttää Markdownia suositusten otsikko ja tekstikentissä.",
"sv": "Du kan använda Markdown i rekommendationens titel- och textfält.",
"en": "You can use Markdown in the recommendation title and text fields."
}
},
{
"id": 2,
"surveyId": 1,
"label": "recommendation2",
"type": "common",
"title": {
"fi": "Suositus 2 esimerkki ilman Markdown-sisältöä",
"sv": "Rekommendation 2 exempel utan Markdown-innehåll",
"en": "Recommendation 2 example without markdown content"
},
"text": {
"fi": "Sinun ei välttämättä tarvitse toimittaa tekstiä tekstikenttään.",
"sv": "Du behöver inte nödvändigtvis ange någon text i textfältet.",
"en": "You don't necessarily have to provide any text in the text field."
}
},
{
"id": 3,
"surveyId": 1,
"label": "recommendation3",
"type": "common",
"title": {
"fi": "Suositus 3 esimerkki",
"sv": "Rekommendation 3 exempel",
"en": "Recommendation 3 example"
},
"text": {
"fi": "Suosituksen \"type\"-kenttää voidaan tarvittaessa lisätä erilaisia vaihtoehtoja, joiden mukaan suosituksia voidaan hyödyntää eri tarkoituksiin.",
"sv": "Fältet \"type\" för rekommendationen kan utökas med olika alternativ vid behov, vilket möjliggör användning av rekommendationer för olika ändamål.",
"en": "The \"type\" field of the recommendation can be expanded with various options as needed, allowing recommendations to be utilized for different purposes."
}
},
{
"id": 4,
"surveyId": 1,
"label": "recommendation4",
"type": "common",
"title": {
"fi": "Suositus 4",
"sv": "Rekommendation 4",
"en": "Recommendation 4"
},
"text": {
"fi": "\"Label\"-kenttä on tarkoitettu suosituksien tunnistamiseen ja valitsemiseen admin-näkymässä. Se voi hyvin olla ihmisluettavassa muodossa.",
"sv": "Fältet \"Label\" är avsett för att identifiera och välja rekommendationer i admin-vyn. Det kan vara i en läsbar format för människor.",
"en": "The \"Label\" field is intended for identifying and selecting recommendations in the admin view. It can be in a human-readable format."
}
}
]
```

# Entry

The `Entry` model represents the data submitted for a survey. It captures the values provided by users in response to survey questions.

## Properties

- `id` (number): The unique identifier for the entry.
- `surveyId` (number): The ID of the survey to which this entry belongs.
- `userId` (string): The ID of the user who submitted the entry (optional).
- `data` (object): The data submitted for the survey. This is typically an object containing responses to various survey questions.
- `sessionToken` (string | null): A session token associated with the entry, if applicable.

0 comments on commit 57b87d1

Please sign in to comment.