From 57b87d114975d9f60b588d0be9ef2663f46af8e2 Mon Sep 17 00:00:00 2001 From: erikao1998 Date: Fri, 5 Jul 2024 15:00:23 +0300 Subject: [PATCH] Update documentation --- README.md | 25 ++---- docs/Algorithm.md | 171 +++++++++++++++++++++++++++++++++++++++++ docs/DataStructures.md | 100 ------------------------ 3 files changed, 178 insertions(+), 118 deletions(-) create mode 100644 docs/Algorithm.md diff --git a/README.md b/README.md index 2a8ab15..a07ee01 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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. diff --git a/docs/Algorithm.md b/docs/Algorithm.md new file mode 100644 index 0000000..f978c4d --- /dev/null +++ b/docs/Algorithm.md @@ -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 diff --git a/docs/DataStructures.md b/docs/DataStructures.md index 96ac836..bbae10b 100644 --- a/docs/DataStructures.md +++ b/docs/DataStructures.md @@ -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.