Skip to content

Commit

Permalink
Merge branch 'main' into patient-editor
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaRiewesell committed Aug 15, 2024
2 parents 4d10cf7 + 6433e44 commit 96335b8
Show file tree
Hide file tree
Showing 33 changed files with 1,235 additions and 671 deletions.
132 changes: 56 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,86 +1,66 @@
# K-dPS
# ![img.png](./frontend/public/favicon-32x32.png) Klinik-dPS
The K-dPS (the clinic variant of the dynamic patient simulation) simulation software for training medical personnel on how to act during medical
surges / during mass casualty incidents.
The Frontend website and backend server are two different projects. For setup instructions see the Readmes in the respective folders.
surges / during mass casualty incidents.

For a common understanding we use this
[Code Glossary Notion page](https://k-dps.notion.site/9e82c16b6d9248679b87e0403bbf81a9?v=06e889f90e834b7baf2f879f9ad9551b&pvs=4) (note that this
is an internal document and therefore neither formulated for others to understand nor
written in English)
It is currently only available in German at https://klinik-dps.de/.

## Deployment process
The described deployment process here is for setting up the frontend and backend at the same time via docker. If you want to deploy just one via
docker or want to run the frontend without docker, please refer to the respective Readmes in the frontend and backend folders.
The software is developed as part of a project at the Hasso Plattner Institute in Potsdam, Germany:
[Project Website](https://hpi.de/giese/teaching/bachelor-projects/digitale-simulationsuebungen-fuer-krankenhaeuser.html).

The deployment process is automatically started on each release and can be manually triggered by running the GitHub action `deploy`.
This uploads the needed images to [GitHub Packages](https://github.com/orgs/hpi-sam/packages?repo_name=dps.training_k) and saves the needed
environment variables as well as the docker-compose file as
[Actions Artifacts](https://github.com/hpi-sam/dps.training_k/actions/workflows/deploy.yml).
There are two environment files provided with the docker-compose file in the artifacts: `.env.prod` and `.env.dev`.
The `.env.prod` file is used for the production version on a server and the `.env.dev` file is used for the development version locally.
Replace `<prod/dev>` with `prod` or `dev` in the following commands to use the respective environment file.
0. Prerequisites: Install Docker and Docker Compose on the server where you want to deploy the software.
1. Download the action artifacts and extract them in a folder. Alternatively, you can manually copy the needed files from the repo (.
/docker-compose.yml, ./.env.<prod/dev>).
2. Recommended: As the env files are probably stored in a public repository, it is strongly encouraged to change the SECRET_KEY and the
POSTGRES_PASSWORD variables in the used `.env.<prod/dev>` file.
3. Log into the GitHub Packages registry with the following command. Ask a team member for valid credentials. Note: passing secrets as
command line arguments is insecure. consider using `--password-stdin` instead
```bash
docker login ghcr.io -u <username> -p <token>
```
4. Optional: If you want a clean start and have the application already running, execute following command in that folder in order to recreate the
database:
```bash
docker-compose --env-file .env.<prod/dev> down --volumes
```
5. Run following commands to pull the newest images (only needed if already setup once) and build and run the containers:
```bash
docker-compose --env-file .env.<prod/dev> pull
docker-compose --env-file .env.<prod/dev> up
```
## Features
The K-dPS offers the following features:
- **Create Exercises**: Trainers can quickly create exercises by adding areas, patients, personnel and material to them and customize names.
- **Dynamic Patients**: Patients dynamically change their state based on the current state as well as the material assigned and actions applied to them.
- **Real-time Interaction**: Trainees can interact with the patients in real-time by applying treatments, conducting examinations and more.
- **Resource Management**: Trainees can assign personnel and material to different patients and manage the resources effectively.
- **Triaging**: Trainees can triage patients based on their state and assign them different triage categories and move them to different areas.
- and much more...

The application is now deployed and the website should be accessible on port 5173. The images will be automatically updated on each release and
the containers restarted accordingly.
## Introduction
Upon entering the website, you will be greeted with a login screen. You can either log in as a trainer or as a patient. Entering a new username
and a password, one creates a new exercise and is automatically logged in as a trainer.

Keep in mind that the IP address of the server running the back- and frontend are hardcoded in the environment files. For
the backend a simple correction of the `CORS_ALLOWED_ORIGINS` variable within the `backend/dps_training_k/configuration/settings.py` file on the
server is enough, but for the frontend the `VITE_SERVER_URL` variable has to be adjusted in the associated env file and the image has
to be rebuilt and re-uploaded to the GitHub Packages registry.
![img.png](docs/login.png)

## Changing the project configuration
If you want to change the configuration of the project by e.g. updating a docker-compose or env file, you need to keep following aspects in mind:
- If you change the docker-compose file of the backend or frontend, you may need to also adjust the main docker-composer file in the root folder.
- The environment variables are backed in the image for the Frontend. Meaning you need to rebuild and re-upload e.g. a new Backend IP Address if you
want to change it.
- The environment variables are loaded during the container initialization for the backend. Therefore, you need to copy changes of the backend env
file to the env files in the root folder.
Upon login the Trainer can freely configure the exercise by creating areas and adding patients, personnel and material to them.
If ready, the trainer can start the exercise, activating the dynamic behavior of the patients. To treat the patients, the trainer can log
into a patient on a separate device by using the exercise-id displayed to the right of their name and the patient-id displayed on the left of
the patient list items. These logged-in devices can then be given to the trainees.

## MoSCoW and future plans
We follow this [MoSCoW Notion page](https://k-dps.notion.site/MoSCoW-78d8a9b852f7499bb7fb47a770c30723?pvs=4) (note that this is an internal
document and therefore neither formulated for others to understand nor written in English)
![img_1.png](docs/trainer.png)

In addition to that we aim to always incorporate following non-functional requirements into our development:
In the patient view the trainees can assign personnel and material to the patient and interact with the patient by applying treatments, conducting
examinations and more. The state of the patient displayed on the left is dynamically updated based on the actions of the trainees.

### Non-functional Requirements
- A00: Customizability
- Our software allows for high customizability before and during the exercise. This recognizes the educational key role of exercise instructors.
- A01: Intuitive Interface
- The interface is intuitive for hospital staff.
- A02: Easy Simulation Execution
- The simulation should be quick to prepare and execute.
- A03: 8-25 Participants
- The exercises are effectively playable by 8-25 participants.
- A04: Screen Ratio 3:4 to 1:2
- The web app should correctly scale on all screen ratios from 3:4 to 1:2.
- A05: Samsung S7 FE
- The web app should look good on the Samsung S7 FE.
- A06: Chrome, Firefox, and Safari
- The web app should work on the latest versions of Chrome, Firefox, and Safari.
- A07: Backend Performance
- A backend should be able to handle a single exercise with 30 clients.

## Interface Definition
The communication between the frontend and backend uses an Interface as defined in our
[interface definition Notion page](https://k-dps.notion.site/Interface-Definition-6852697ae02f41b29544550f84e1049a)(note that this is an internal
document and therefore not necessarily formulated for others to understand)
![img_2.png](docs/patient.png)

## Technical Documentation
The following list describes where to find the documentation for the different parts of the project:
- Frontend documentation with setup instructions: [frontend folder](./frontend/README.md).
- Backend documentation with setup instructions: [backend folder](./backend/README.md).
- Interface definition (Frontend <-> Backend): [docs file](./docs/interface-definition.md).
- Deployment process: [docs file](./docs/deployment-process.md).
- Tips regarding the project configuration: [docs file](./docs/configuration-tips.md).
- MoSCoW and future plans: [docs file](./docs/moscow.md).

## Thank you
First and foremost, we would like to thank the [Hasso Plattner Institute](https://hpi.de/) for giving us the opportunity to work on this project as well as our
supervisors Christian Schäffer and Matthias Barkowsky for their guidance and organization of the project.

Right after that come our official project partners, the [ZaNowi](https://zanowi.de/) ("Zentrum für angewandte Notfallwissenschaft") and the
[Johanniter](https://www.johanniter.de/bildungseinrichtungen/johanniter-akademie/johanniter-akademie-nordrhein-westfalen/standorte-der-akademie-in-nordrhein-westfalen/campus-muenster/)
("Johanniter Akademie NRW, Campus Münster"), for making the project possible by providing the necessary data and insights.

And last but not least, we would like to thank our supporters:
- [BABZ](https://www.bbk.bund.de/DE/Themen/Akademie-BABZ/akademie-babz_node.html) ("Bundesakademie für Bevölkerungsschutz und Zivile Verteidigung")
of the [BBK](https://www.bbk.bund.de/DE/Home/home_node.html) ("Bundesamtes für Bevölkerungsschutz und Katastrophenhilfe")
- [Evangelisches Krankenhaus Hubertus](https://www.johannesstift-diakonie.de/medizinische-versorgung/evangelisches-krankenhaus-hubertus)
Berlin-Zehlendorf
- [Universitätsklinikum Düsseldorf](https://www.uniklinik-duesseldorf.de/)

Special thanks to the following people for being directly available to us and providing us with valuable insights and feedback: Frank Sensen
(ZaNowi), Philipp Rocker (Johanniter) and Daniel Schmitz (Evangelisches Krankenhaus Hubertus).

![](docs/hpi_logo.png)
![](./docs/johanniter_logo.png)
![](./docs/zanowi_logo.png)
92 changes: 40 additions & 52 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,67 @@
# K-dPS Backend
# Klinik-dPS Backend
The simulation logic and database management for the K-dPS project. For the interactive website see the [frontend folder](../frontend/README.md).

## Running the project using Docker

For more information on the difference between `prod` and `dev`, see the project README.
Note that the `prod` env file here still assumes this is running locally -
meaning it will expect the frontend to run on localhost.

- inside dps_training_k folder, run `docker-compose --env-file .env.<prod/dev> up -d`
- create superuser account: `docker exec -it K-dPS-django python manage.py createsuperuser`
For general information on the project like e.g. licensing information or future plans, see the [Project README](../README.md).

## Running the project locally (NOT UP TO DATE)
## Setup
### Install Python
- install from official [python website](https://www.python.org/downloads/)
- version should be at least 3.12

### Setup a virtual environment for python
#### Linux

- navigate to backend folder
- `python3 -m venv env`
- `source env/bin/activate`

#### Windows

- navigate to backend folder
- `python -m venv env`
- `env/Scripts/Activate.ps1`
- in case the previous command failed due to execution policy, run: `powershell.exe -exec bypass`

### install requirements

### Install requirements
- navigate into backend folder
- `pip install -r requirements.txt`

## Setup Black Formatter
### Linux (for this project only)

- make sure python extension is installed
- type "Python: Select Interpreter" in command palette and set newest interpreter for virtual environment
- neavigate to venv in terminal
- pip install black
- create .vscode file in venv
- create settings.json file in .vscode folder
- paste:
```json
{
"python.formatting.blackPath": "path/to/bin/of black/formatter/in/venv",
"python.formatting.blackArgs": [
"-l 150"
],
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.formatOnType": true,
}
```

### Windows (for all python files open with VS Code)

### Setup Black Formatter
We are using black as a biased formatter for the whole project. For more information about black see: [Black](https://black.readthedocs.io/en/stable/)
- make sure you have python extension installed
- download "Black Formatter" from marketplace
- right click on a python file
- right-click on a python file
- select "Format Document with"
- select "Configure Default formatter"
- select "Black"
- head to VS Code settings
- search for "format on save"
- enable "Editor: Format on Save"

## Running the project using Docker
Running the project without docker is currently not tested/supported.
For more information on the difference between `prod` and `dev`, see the [docs file](../docs/deployment-process.md).
Note that the `prod` env file here still assumes this is running locally -
meaning it will expect the frontend to run on localhost.

Build and run:
```bash
docker compose --env-file .env.<prod/dev> up
```

Optionally, to access the database, create a superuser account:
```bash
docker exec -it K-dPS-django python manage.py createsuperuser
```
Afterwards, you can log into the admin interface at e.g. `http://localhost:80/admin/`<br/>
Note: this is only available if DEBUG = true, which is the case in the dev environment.


## Development

- to run tests: `docker exec -it K-dPS-django python manage.py test`
### Migrations
When changing models, you need to create migrations in order to update existing databases.
- Create new migrations: `docker exec -it K-dPS-django python manage.py makemigrations`
- Optionally, if you have conflicting migrations: `docker exec -it K-dPS-django python manage.py migrate --merge`
- Execute these migrations to update the database: `docker exec -it K-dPS-django python manage.py migrate`

### Running Tests
- start docker container with docker compose(see Running the project using Docker)
- wait until Application Startup is Completed
- run: `docker exec -it K-dPS-django python manage.py test`

### Working with Fixtures
- (clear database)
- fill database with data you want to export as fixture (e.g. `docker exec -it K-dPS-django python manage.py import_patient_states`)
- in this example, make PatientState.transition null=True and blank=True, migrate that
- if updating a fixture that is used by a model that doesn't allow null fields, make them nullable, migrate and discard the migration file
afterwards.
- create fixture:
- `docker exec -it K-dPS-django bash`
- `export PYTHONIOENCODING=utf8`
Expand Down
8 changes: 8 additions & 0 deletions backend/dps_training_k/configuration/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"corsheaders",
"game.apps.GameConfig",
"helpers.apps.GameConfig",
Expand Down Expand Up @@ -133,6 +134,11 @@

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/

STATIC_URL = "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

Expand All @@ -156,6 +162,8 @@

AUTH_USER_MODEL = "game.User"

STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

# Celery
# ------------------------------------------------------------------------------
# See: http://docs.celeryproject.org/en/latest/userguide/configuration.html
Expand Down
1 change: 1 addition & 0 deletions backend/dps_training_k/deployment/django/entrypoint
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ if [ "${RUN_MIGRATIONS:-0}" = "1" ]; then

python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py import_actions
python manage.py import_patient_information
python manage.py loaddata patient_states.json
Expand Down
12 changes: 12 additions & 0 deletions backend/dps_training_k/deployment/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# For the admin interface
location /admin {
proxy_pass http://django:8000/admin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /app/staticfiles/;
}
}
12 changes: 12 additions & 0 deletions backend/dps_training_k/deployment/nginx/nginx_deploy_dev.conf
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,16 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# For the admin interface
location /admin {
proxy_pass http://django:8000/admin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /app/staticfiles/;
}
}
11 changes: 0 additions & 11 deletions backend/dps_training_k/game/consumers/abstract_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class OutgoingMessageTypes:
EXERCISE_END = "exercise-end"
EXERCISE_START = "exercise-start"
FAILURE = "failure"
SUCCESS = "success"
TEST_PASSTHROUGH = "test-passthrough"
WARNING = "warning"

Expand Down Expand Up @@ -84,16 +83,6 @@ def send_warning(self, message="unknown warning", **kwargs):
message_dict[key] = value
self.send_json(message_dict)

def send_validation(self, request_type, **kwargs):
"""
Wrapper to send_json() in order to always have the same structure. Notifies the client
that the asked request was evaluated and executed.
"""
d = {"messageType": self.OutgoingMessageTypes.SUCCESS, "request": request_type}
for key, value in kwargs.items():
d[key] = value
self.send_json(d)

# entry point function for all incoming WebSocket messages
def receive_json(self, content):
self.dispatch_request(content)
Expand Down
Loading

0 comments on commit 96335b8

Please sign in to comment.