Skip to content

infoderm/patients

Repository files navigation

πŸ€’ patients Build Tests Types Lint Code coverage (cov)

An app to manage patient records, consultations, appointments, lab reports, ...

The stack (provided by Meteor):

The tests are declared via Mocha thanks to meteor-testing:mocha.

πŸ’‘ We would replace Mocha by AVA or Jest here and now if only there was a Meteor package for that.

User Interface tests are facilitated by @testing-library/react, @testing-library/dom, and @testing-library/user-event.

⚠️ Code coverage is currently both incomplete and broken most probably due to a TypeScript/Istanbul incompatibility.

In what follows, dev refers to the development machine, and prod refers to the production machine.

πŸ‘©β€πŸ’» Setup dev

β˜„οΈ Install Meteor

curl https://install.meteor.com | sh

πŸ“œ Get source

git clone gh:infoderm/patients
cd patients

πŸ“¦ Install dependencies

meteor npm ci

🎣 Install pre-commit hook (.husky/pre-commit)

This will run the linter and the type checker on staged files before each commit.

meteor npm run install-hooks

πŸ‘• Linter

To lint source files we use xo with configuration inside package.json. You can run the linter with

meteor npm run lint

You can attempt to autofix some errors with

meteor npm run lint-and-fix

β˜‘οΈ Type checker

The entire code base is checked for type errors with tsc, the TypeScript compiler. You can run the type checker with

meteor npm run tsc

To run it in watch mode during development use

meteor npm run tsc:watch

πŸ”¬ Tests

Watch tests

You can set host and port via the $HOST and $PORT environment variables (default localhost:12348).

meteor npm run test

To run client tests non-interactively you can use

NB: this uses PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium

meteor npm run test:dev:non-interactive

Run once

You can set host and port via the $HOST and $PORT environment variables (default localhost:12348).

meteor npm run test -- --once

Emulate CI tests (GitHub Actions)

⚠️ We recommend using the chromium executable of your distribution. Installation of the puppeteer chromium executable can be avoided by placing the line puppeteer_skip_chromium_download=true in your ~/.npmrc. If you wish to use the chromium executable that comes with puppeteer remove the assignment of the variable PUPPETEER_EXECUTABLE_PATH.

PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium meteor npm run ci:test

βš—οΈ Run dev server

You can set host and port via the $HOST and $PORT environment variables (default localhost:12345).

meteor npm run dev

🐘 Run bundle visualizer

You can set host and port via the $HOST and $PORT environment variables (default localhost:12345).

meteor npm run bundle-visualizer

🎁 Dependency management

meteor npm run upgrade

Some dependencies need manual upgrade. Their versions depends on the used Meteor version. Hereunder are the information links for the latest stable release of Meteor:

NB: @types/mongodb does not need explicit pinning because it is a dependency of @types/meteor.

Direct ESM dependencies cannot be added and CJS dependencies cannot be upgraded to ESM. See the relevant discussion.

πŸ‘©β€βš•οΈ Production

πŸ”§ Setup

dev Create ssh keys on the development machine

ssh-keygen -m PEM -t rsa -b 4096 -a 100 -f .ssh/meteorapp

prod On the production machine

Install and enable docker
pacman -S docker
systemctl enable --now docker
Create a user
useradd -m meteorapp
gpasswd -a meteorapp wheel
gpasswd -a meteorapp docker
Copy dev public key on prod

Append it to /home/meteorapp/.ssh/authorized_keys. Remember: chmod .ssh 700 and chmod .ssh/authorized_keys 640.

dev On the development machine

Install dependencies, custom certificates, and MongoDB on server:

meteor npm run setup-deploy

πŸš€ Deploy from dev on prod

Deploy the current state of dev

meteor npm run build-and-upload

Deploy the last commit

meteor npm run deploy

Deploy a specific tag

TAG=vYYYY.MM.DD meteor npm run deploy

Generate a Docker compose configuration

🚧 This is work in progress. 🚧

ROOT_URL=https://example.local IMAGE_TAG=v1 \
docker compose \
  --env-file .env -f compose.yaml \
  --env-file .deploy/ghcr.io/.env -f .deploy/ghcr.io/compose.yaml \
  config

♻️ Backup & Restore

The current backup system requires age and the encryption/decryption key at ~/key/patients on the production machine. It saves the database as an encrypted (age) compressed MongoDB archive (--archive --gzip).

πŸŽ₯ Backup

sh .backup/fs/backup.sh

πŸ“½οΈ Restore

sh .backup/restore.sh

πŸ“œ Changelog

Now

The backup system uses encrypted (age) compressed MongoDB archives (--archive --gzip). They can be restored with

age --decrypt -i "$KEYFILE" < 'patients.gz.age' |
  mongorestore --drop --nsInclude 'patients.*' --archive --gzip

Until 2021-04-20

The backup system uses encrypted gzipped TAR archives. They can be processed by first decrypting with age to obtain a .gz file, then decompressing and unarchiving with tar xzf to obtain a dump directory, and finally using mongorestore --drop --db patients to restore the database.